Added deposit and participate functionality

This commit is contained in:
sairaj mote 2023-10-02 04:17:31 +05:30
parent e2a50e1034
commit 0730690291
4 changed files with 391 additions and 51 deletions

View File

@ -87,6 +87,22 @@ a:any-link:focus-visible {
outline: rgba(var(--text-color), 1) 0.1rem solid; outline: rgba(var(--text-color), 1) 0.1rem solid;
} }
input[type=datetime-local] {
width: 100%;
padding: 0.8rem 0.6rem;
border: none;
border-radius: 0.5rem;
font-weight: 500;
font-family: inherit;
font-size: inherit;
color: inherit;
background-color: rgba(var(--text-color), 0.06);
}
input[type=datetime-local]:focus {
outline: none;
box-shadow: 0 0 0 0.1rem var(--accent-color);
}
button, button,
.button { .button {
-webkit-user-select: none; -webkit-user-select: none;
@ -198,7 +214,7 @@ details summary {
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
align-items: center; align-items: center;
justify-content: space-between; gap: 1rem;
color: var(--accent-color); color: var(--accent-color);
} }
@ -575,6 +591,17 @@ ul {
display: none; display: none;
} }
.password-field label {
display: flex;
flex-shrink: 0;
}
.password-field label input:checked ~ .visible {
display: none;
}
.password-field label input:not(:checked) ~ .invisible {
display: none;
}
.multi-state-button { .multi-state-button {
display: grid; display: grid;
text-align: center; text-align: center;
@ -586,6 +613,7 @@ ul {
} }
.multi-state-button button { .multi-state-button button {
z-index: 1; z-index: 1;
width: 100%;
} }
#confirmation_popup, #confirmation_popup,
@ -1170,15 +1198,16 @@ theme-toggle {
min-width: 12rem; min-width: 12rem;
} }
#smart_contract_list { .smart-contract-list {
display: grid; display: grid;
gap: 1rem; gap: 1rem;
margin-top: 1rem; margin-top: 1rem;
grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
} }
.sc-card { .sc-card {
display: grid; display: flex;
flex-direction: column;
gap: 1rem; gap: 1rem;
background-color: rgba(var(--foreground-color), 1); background-color: rgba(var(--foreground-color), 1);
padding: max(1rem, 1.5vw); padding: max(1rem, 1.5vw);
@ -1209,16 +1238,19 @@ theme-toggle {
.sc-card__info-link .icon { .sc-card__info-link .icon {
fill: var(--accent-color); fill: var(--accent-color);
} }
.sc-card > :last-child { .sc-card .sc-card__actions {
justify-content: flex-end; justify-content: flex-end;
padding-top: 1rem; padding-top: 1rem;
} }
.sc-card > :last-child .button { .sc-card .sc-card__actions .button {
background-color: transparent; background-color: transparent;
border: solid 1px var(--accent-color); border: solid 1px var(--accent-color);
font-size: 0.9rem; font-size: 0.9rem;
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
} }
.sc-card .badge {
margin-right: auto;
}
.involved-tokens li { .involved-tokens li {
padding: 0.2rem 0.5rem; padding: 0.2rem 0.5rem;

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -76,7 +76,21 @@ a {
a:any-link:focus-visible { a:any-link:focus-visible {
outline: rgba(var(--text-color), 1) 0.1rem solid; outline: rgba(var(--text-color), 1) 0.1rem solid;
} }
input[type="datetime-local"] {
width: 100%;
padding: 0.8rem 0.6rem;
border: none;
border-radius: 0.5rem;
font-weight: 500;
font-family: inherit;
font-size: inherit;
color: inherit;
background-color: rgba(var(--text-color), 0.06);
&:focus {
outline: none;
box-shadow: 0 0 0 0.1rem var(--accent-color);
}
}
button, button,
.button { .button {
user-select: none; user-select: none;
@ -177,7 +191,7 @@ details summary {
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
align-items: center; align-items: center;
justify-content: space-between; gap: 1rem;
color: var(--accent-color); color: var(--accent-color);
} }
@ -536,6 +550,18 @@ ul {
.observe-empty-state:not(:empty) ~ .empty-state { .observe-empty-state:not(:empty) ~ .empty-state {
display: none; display: none;
} }
.password-field {
label {
display: flex;
flex-shrink: 0;
input:checked ~ .visible {
display: none;
}
input:not(:checked) ~ .invisible {
display: none;
}
}
}
.multi-state-button { .multi-state-button {
display: grid; display: grid;
text-align: center; text-align: center;
@ -546,6 +572,7 @@ ul {
} }
button { button {
z-index: 1; z-index: 1;
width: 100%;
} }
} }
@ -1068,14 +1095,15 @@ theme-toggle {
#smart_contract_page { #smart_contract_page {
} }
#smart_contract_list { .smart-contract-list {
display: grid; display: grid;
gap: 1rem; gap: 1rem;
margin-top: 1rem; margin-top: 1rem;
grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
} }
.sc-card { .sc-card {
display: grid; display: flex;
flex-direction: column;
gap: 1rem; gap: 1rem;
background-color: rgba(var(--foreground-color), 1); background-color: rgba(var(--foreground-color), 1);
padding: max(1rem, 1.5vw); padding: max(1rem, 1.5vw);
@ -1105,7 +1133,12 @@ theme-toggle {
fill: var(--accent-color); fill: var(--accent-color);
} }
} }
> :last-child { &.closed,
&.expired {
h4 {
}
}
.sc-card__actions {
justify-content: flex-end; justify-content: flex-end;
padding-top: 1rem; padding-top: 1rem;
.button { .button {
@ -1115,6 +1148,9 @@ theme-toggle {
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
} }
} }
.badge {
margin-right: auto;
}
} }
.involved-tokens { .involved-tokens {
li { li {

View File

@ -88,6 +88,20 @@
</button> </button>
</footer> </footer>
</sm-popup> </sm-popup>
<sm-popup id="smart_contract_popup">
<header slot="header" class="popup__header">
<button class="popup__header__close" onclick="closePopup()">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" />
<path
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
</svg>
</button>
<h3 id="smart_contract_popup__title"></h3>
</header>
<sm-form id="smart_contract_popup__content" class="grid gap-1-5"></sm-form>
</sm-popup>
<!-- Set urls for token and flo Apis --> <!-- Set urls for token and flo Apis -->
<script> <script>
const testMode = false const testMode = false
@ -95,6 +109,7 @@
blockchain: testMode ? "FLO_TEST" : "FLO", blockchain: testMode ? "FLO_TEST" : "FLO",
tokenApiUrl: testMode ? 'https://ranchimallflo-testnet-blockbook.ranchimall.net' : 'https://ranchimallflo.ranchimall.net', tokenApiUrl: testMode ? 'https://ranchimallflo-testnet-blockbook.ranchimall.net' : 'https://ranchimallflo.ranchimall.net',
floApiUrl: testMode ? 'https://blockbook-testnet.ranchimall.net' : 'https://flosight.ranchimall.net', floApiUrl: testMode ? 'https://blockbook-testnet.ranchimall.net' : 'https://flosight.ranchimall.net',
expirationDays: 60,
} }
</script> </script>
<script> <script>
@ -309,15 +324,12 @@
if (document.activeElement.classList.contains('suggestion')) if (document.activeElement.classList.contains('suggestion'))
getRef("main_search_field").value = document.activeElement.textContent.trim() getRef("main_search_field").value = document.activeElement.textContent.trim()
}); });
this.addEventListener("click", (e) => {
if (e.target.closest('.suggestion')) {
let searchBox = document.getElementById('main_search_field');
searchBox.value = e.target.textContent.trim();
processNavbarSearch()
}
});
}); });
function handleSuggestionClick(e) {
let searchBox = document.getElementById('main_search_field');
searchBox.value = e.target.textContent.trim();
processNavbarSearch()
}
function createRipple(event, target) { function createRipple(event, target) {
const circle = document.createElement("span"); const circle = document.createElement("span");
@ -413,7 +425,30 @@
} }
} }
} }
function buttonLoader(id, show) {
const button = typeof id === 'string' ? document.getElementById(id) : id;
button.disabled = show;
const animOptions = {
duration: 200,
fill: 'forwards',
easing: 'ease'
}
if (show) {
button.parentNode.append(document.createElement('sm-spinner'))
button.animate([
{
clipPath: 'circle(100%)',
},
{
clipPath: 'circle(0)',
},
], animOptions)
} else {
button.getAnimations().forEach(anim => anim.cancel())
const potentialTarget = button.parentNode.querySelector('sm-spinner')
if (potentialTarget) potentialTarget.remove();
}
}
const slideInLeft = [ const slideInLeft = [
{ {
opacity: 0, opacity: 0,
@ -1187,7 +1222,8 @@
floGlobals.appliedFilters.types = new Set([...getRef('type_filter_list').querySelectorAll('input[type="checkbox"]:checked')] floGlobals.appliedFilters.types = new Set([...getRef('type_filter_list').querySelectorAll('input[type="checkbox"]:checked')]
.map(elem => elem.value)) .map(elem => elem.value))
let filteredContracts = floGlobals.smartContractList let filteredContracts = Object.values(floGlobals.smartContractList).sort((a, b) => b.blockNumber - a.blockNumber)
// filter by tokens and types
const { tokens, types } = floGlobals.appliedFilters const { tokens, types } = floGlobals.appliedFilters
if (tokens.size || types.size) { if (tokens.size || types.size) {
filteredContracts = filteredContracts.filter(sc => { filteredContracts = filteredContracts.filter(sc => {
@ -1199,27 +1235,33 @@
return true return true
}) })
} }
// update filter button text
const totalFilters = tokens.size + types.size const totalFilters = tokens.size + types.size
getRef('apply_filter_button').lastChild.textContent = totalFilters ? `Filter (${totalFilters})` : 'Filter'; getRef('apply_filter_button').lastChild.textContent = totalFilters ? `Filter (${totalFilters})` : 'Filter';
if (getRef('clear_filter_button')) if (getRef('clear_filter_button'))
getRef('clear_filter_button').classList[totalFilters ? 'remove' : 'add']('hidden') getRef('clear_filter_button').classList[totalFilters ? 'remove' : 'add']('hidden')
console.log(filteredContracts)
return filteredContracts return filteredContracts
} }
function renderSmartContracts() { function renderSmartContracts() {
const smartContracts = filterSmartContracts().map(contract => { let activeContracts = []
let inactiveContracts = []
filterSmartContracts().forEach(contract => {
const { tokenIdentification, acceptingToken, blockNumber, contractAddress, contractName, contractSubType, const { tokenIdentification, acceptingToken, blockNumber, contractAddress, contractName, contractSubType,
contractType, incorporationDate, oracle_address, price, sellingToken, status, transactionHash } = contract contractType, incorporationDate, oracle_address, price, sellingToken, status, transactionHash } = contract
const smartContractAddress = `${contractName}-${contractAddress}`
let type = '' let type = ''
let actions let actions = ''
switch (contractSubType) { switch (contractSubType) {
case 'tokenswap': case 'tokenswap':
type = 'Token Swap' type = 'Token Swap'
if (status !== 'active') break;
actions = html` actions = html`
<div class="flex align-center gap-0-5"> <div class="flex align-center gap-0-5 sc-card__actions">
<button class="button button--small button--colored" onclick=${() => openPopup('token_swap_popup', contract)}> <button class="button button--small button--colored" onclick=${() => handleSmartContractAction(smartContractAddress, 'deposit')}>
Sell ${acceptingToken} Sell ${acceptingToken}
</button> </button>
<button class="button button--small button--colored" onclick=${() => openPopup('token_swap_popup', contract, true)}> <button class="button button--small button--colored" onclick=${() => handleSmartContractAction(smartContractAddress, 'participate')}>
Sell ${sellingToken} Sell ${sellingToken}
</button> </button>
</div> </div>
@ -1227,9 +1269,10 @@
break; break;
case 'time-trigger': case 'time-trigger':
type = 'Timed Event' type = 'Timed Event'
if (status !== 'active') break;
actions = html` actions = html`
<div class="flex align-center gap-0-5"> <div class="flex align-center gap-0-5 sc-card__actions">
<button class="button button--small button--colored" onclick=${() => openPopup('time_trigger_popup', contract)}> <button class="button button--small button--colored" onclick=${() => handleSmartContractAction(smartContractAddress, 'participate')}>
Participate Participate
</button> </button>
</div> </div>
@ -1237,8 +1280,9 @@
break; break;
case 'external-trigger': case 'external-trigger':
type = 'External Trigger' type = 'External Trigger'
if (status !== 'active') break;
actions = html` actions = html`
<div class="flex align-center gap-0-5"> <div class="flex align-center gap-0-5 sc-card__actions">
<button class="button button--small button--colored" onclick=${() => openPopup('external_trigger_popup', contract)}> <button class="button button--small button--colored" onclick=${() => openPopup('external_trigger_popup', contract)}>
Participate Participate
</button> </button>
@ -1246,8 +1290,9 @@
` `
break; break;
} }
return html` const rendered = html`
<li class="sc-card"> <li class=${`sc-card ${status}`} .dataset=${{ address: `${contractName}-${contractAddress}` }}>
${status !== 'active' ? html` <div class="badge">${status}</div> ` : ''}
<div class="flex align-center space-between"> <div class="flex align-center space-between">
<p class="sc-card__type">${type}</p> <p class="sc-card__type">${type}</p>
<a href=${`#/contract/${contractName}-${contractAddress}`} class="sc-card__info-link"> <a href=${`#/contract/${contractName}-${contractAddress}`} class="sc-card__info-link">
@ -1276,18 +1321,38 @@
${actions} ${actions}
</li> </li>
` `
if (status === 'active')
activeContracts.push(rendered)
else
inactiveContracts.push(rendered)
}) })
renderElem(getRef('smart_contract_wrapper'), html` renderElem(getRef('smart_contract_wrapper'), html`
${smartContracts.length ? html` <div class="flex flex-direction-column gap-0-5">
<ul id="smart_contract_list"> <div class="flex align-center gap-0-5">
${smartContracts} <h4>Active contracts</h4>
</ul> <div class="badge">${activeContracts.length}</div>
`: html`
<div class="flex flex-direction-column align-center">
<h3>No smart contracts found</h3>
<p>Try changing the filters</p>
</div> </div>
`} ${activeContracts.length ? html`
<ul id="active_smart_contract_list" class="smart-contract-list">
${activeContracts}
</ul>
`: html`
<p>No active contracts found</p>
`}
</div>
<div class="flex flex-direction-column gap-0-5">
<div class="flex align-center gap-0-5">
<h4>Inactive contracts</h4>
<div class="badge">${inactiveContracts.length}</div>
</div>
${inactiveContracts.length ? html`
<ul id="inactive_smart_contract_list" class="smart-contract-list">
${inactiveContracts}
</ul>
`: html`
<p>No inactive contracts found</p>
`}
</div>
`) `)
closePopup() closePopup()
} }
@ -1305,7 +1370,7 @@
} }
router.addRoute('smart-contracts', async state => { router.addRoute('smart-contracts', async state => {
renderElem(getRef("page_container"), html` renderElem(getRef("page_container"), html`
<div id="smart_contract_page" class="page"> <div id="smart_contract_page" class="page flex flex-direction-column gap-1-5">
<header class='flex space-between flex-wrap gap-1'> <header class='flex space-between flex-wrap gap-1'>
<h2>Smart contracts</h2> <h2>Smart contracts</h2>
<div class="flex align-center gap-0-5"> <div class="flex align-center gap-0-5">
@ -1319,7 +1384,7 @@
</button> </button>
</div> </div>
</header> </header>
<div id="smart_contract_wrapper"></div> <div id="smart_contract_wrapper" class="flex flex-direction-column gap-3"></div>
</div> </div>
`) `)
renderSmartContracts() renderSmartContracts()
@ -1831,7 +1896,7 @@
let results = flexSearchIndex.search(e.target.value, 10) let results = flexSearchIndex.search(e.target.value, 10)
const renderedSuggestions = results.map(suggestionIndex => { const renderedSuggestions = results.map(suggestionIndex => {
return html` return html`
<li class="suggestion wrap-around" tabindex="0"> <li class="suggestion wrap-around" tabindex="0" onclick=${handleSuggestionClick}>
${allSuggestions[suggestionIndex]} ${allSuggestions[suggestionIndex]}
</li> </li>
` `
@ -2241,7 +2306,7 @@
//console.log('data entered is a token name'); //console.log('data entered is a token name');
location.href = `#/token/${text}` location.href = `#/token/${text}`
resolve('token') resolve('token')
} else if (floGlobals.smartContractNameAddressList.has(text)) { } else if (floGlobals.smartContractList[text]) {
location.href = `#/contract/${text}` location.href = `#/contract/${text}`
resolve('contract') resolve('contract')
} else if (text.length == 64 && returnHexNumber(text)) { } else if (text.length == 64 && returnHexNumber(text)) {
@ -2272,8 +2337,9 @@
async function processNavbarSearch() { async function processNavbarSearch() {
const query = getRef('main_search_field').value.trim(); const query = getRef('main_search_field').value.trim();
try { try {
await getAllSuggestions();
if (query === '') return if (query === '') return
loading()
await getAllSuggestions();
await categorizeText(query) await categorizeText(query)
getRef('main_search_field').value = '' getRef('main_search_field').value = ''
renderElem(getRef('suggestions'), html``) renderElem(getRef('suggestions'), html``)
@ -2286,11 +2352,10 @@
window.allSuggestions = []; window.allSuggestions = [];
let { tokens, smartContracts } = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/tokenSmartContractList`); let { tokens, smartContracts } = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/tokenSmartContractList`);
floGlobals.tokenList = tokens; floGlobals.tokenList = tokens;
floGlobals.smartContractList = smartContracts; floGlobals.smartContractList = {}
floGlobals.smartContractNameAddressList = new Set(); smartContracts.forEach(contract => {
floGlobals.smartContractList.forEach(contract => { floGlobals.smartContractList[`${contract.contractName}-${contract.contractAddress}`] = contract;
allSuggestions.push(`${contract.contractName}-${contract.contractAddress}`); allSuggestions.push(`${contract.contractName}-${contract.contractAddress}`);
floGlobals.smartContractNameAddressList.add(`${contract.contractName}-${contract.contractAddress}`);
}) })
allSuggestions = allSuggestions.concat(tokens); allSuggestions = allSuggestions.concat(tokens);
window.flexSearchIndex = new FlexSearch.Index({ window.flexSearchIndex = new FlexSearch.Index({
@ -2302,6 +2367,213 @@
flexSearchIndex.add(index, suggestion); flexSearchIndex.add(index, suggestion);
}) })
} }
function togglePrivateKeyVisibility(input) {
const target = input.closest('sm-input')
target.type = target.type === 'password' ? 'text' : 'password';
target.focusIn()
}
function handleSmartContractAction(smartContractAddress, action) {
switch (action) {
case 'create':
if (!type && !subtype)
getRef('smart_contract_creation_form').classList.add('split-layout')
else
getRef('smart_contract_creation_form').classList.remove('split-layout')
renderElem(getRef('smart_contract_creation_form'), render.contractCreationForm(type, subtype))
break;
case 'deposit': {
const { price, contractName, contractAddress, acceptingToken, sellingToken, tokenIdentification, contractSubType } = floGlobals.smartContractList[smartContractAddress]
const defaultExpiration = new Date(new Date().getTime() + (floGlobals.expirationDays * 24 * 60 * 60 * 1000))
.toISOString().slice(0, -8);
getRef('smart_contract_popup__title').textContent = `Swap ${sellingToken} with ${acceptingToken}`
renderElem(getRef('smart_contract_popup__content'), html`
<strong>Exchange rate: 1 ${sellingToken} = ${price} ${acceptingToken}</strong>
<div class="grid gap-0-5">
<span class="label">Amount (${sellingToken})</span>
<sm-input id="deposit_amount" type="number" type="number" step="0.00000001" min="0.00000001"></sm-input>
</div>
<div class="grid gap-0-5">
<span class="label">Expiration (Time after which unsold amount will be returned)</span>
<input id="deposit_expiration" value=${defaultExpiration} type="datetime-local" required>
</div>
<div class="grid gap-0-5">
<span class="label">FLO private key</span>
<sm-input id="depositor_private_key" class="password-field" type="password" data-private-key required>
<label slot="right" class="interact">
<input type="checkbox" class="hidden" readonly onchange="togglePrivateKeyVisibility(this)">
<svg class="icon invisible" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <title>Hide password</title> <path d="M0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0z" fill="none"></path> <path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"></path> </svg>
<svg class="icon visible" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <title>Show password</title> <path d="M0 0h24v24H0z" fill="none"></path> <path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"></path> </svg>
</label>
</sm-input>
</div>
<div class="multi-state-button">
<button id="deposit_button" class="button button--primary" onclick=${() => deposit(smartContractAddress)} type="submit" disabled>Sell</button>
</div>
`)
break;
}
case 'participate': {
const { price, contractName, contractAddress, acceptingToken, sellingToken, tokenIdentification, userChoices, contractSubType } = floGlobals.smartContractList[smartContractAddress]
if (userChoices) {
getRef('smart_contract_popup__title').textContent = `Participate`
}
if (contractSubType === 'tokenswap') {
getRef('smart_contract_popup__title').textContent = `Swap ${acceptingToken} with ${sellingToken}`
}
renderElem(getRef('smart_contract_popup__content'), html`
${userChoices ? html`
<fieldset>
<legend>Choices</legend>
<div class="grid gap-0-5">
${userChoices.map(choice => html`
<label class="flex align-center">
<input type="radio" name="choice" value="${choice}" required>
<span class="capitalize">${choice}</span>
</label>
`)}
</div>
`: ''}
${contractSubType === 'tokenswap' ? html`
<strong>Exchange rate: 1 ${sellingToken} = ${price} ${acceptingToken}</strong>
`: ''}
<div class="grid gap-0-5">
<span id="participation_amount_label" class="label">Participation amount (${acceptingToken || tokenIdentification})</span>
<sm-input id="participation_amount" type="number" step="0.00000001" min="0.00000001" required></sm-input>
</div>
<div class="grid gap-0-5">
<span class="label">FLO private key</span>
<sm-input id="participant_private_key" class="password-field" type="password" data-private-key required>
<label slot="right" class="interact">
<input type="checkbox" class="hidden" readonly onchange="togglePrivateKeyVisibility(this)">
<svg class="icon invisible" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <title>Hide password</title> <path d="M0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0z" fill="none"></path> <path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"></path> </svg>
<svg class="icon visible" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <title>Show password</title> <path d="M0 0h24v24H0z" fill="none"></path> <path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"></path> </svg>
</label>
</sm-input>
</div>
<div class="multi-state-button">
<button id="participate_button" class="button button--primary" onclick=${() => participate(smartContractAddress)} type="submit" disabled>Sell</button>
</div>
`)
break;
}
}
openPopup('smart_contract_popup')
}
function deposit(smartContractAddress) {
const { sellingToken, contractName, contractAddress } = floGlobals.smartContractList[smartContractAddress]
const depositAmount = parseFloat(document.getElementById('deposit_amount').value.trim())
const depositExpiration = document.getElementById('deposit_expiration').value
const depositorPrivateKey = document.getElementById('depositor_private_key').value.trim()
const depositorAddress = floCrypto.getFloID(depositorPrivateKey)
const floData = `Deposit ${depositAmount} ${sellingToken}# to ${contractName}@ its FLO address being ${contractAddress}$ with deposit-conditions: (1) expiryTime= ${new Date(depositExpiration).toString()}`
console.log(floData)
buttonLoader('deposit_button', true)
floTokenAPI.getBalance(depositorAddress, sellingToken).then(balance => {
if (balance < depositAmount) {
buttonLoader('deposit_button', false)
return notify(`Insufficient balance.\n You have ${balance} ${sellingToken}`, 'error')
}
getConfirmation('Deposit', {
message: `Are you sure you want to deposit ${depositAmount} ${sellingToken} in ${contractName}?`,
confirmText: 'Deposit',
}).then(res => {
if (!res) return
floBlockchainAPI.sendTx(depositorAddress, contractAddress, floGlobals.sendAmt, depositorPrivateKey, floData).then(txid => {
showTransactionResult(true, txid, {
title: `${sellingToken} tokens deposited`,
description: `If your tokens are not exchanged before the expiry time, you will get them back.`
})
getRef('smart_contract_deposit_form').reset()
document.getElementById('deposit_button').disabled = true
}).catch(error => {
showTransactionResult(false, error)
console.error(error)
}).finally(() => {
buttonLoader('deposit_button', false)
})
})
}).catch(error => {
notify(`Error getting balance.`, 'error')
buttonLoader('deposit_button', false)
console.error(error)
})
}
function participate(smartContractAddress) {
const { acceptingToken, tokenIdentification, contractName, contractAddress, contractType, contractSubType } = floGlobals.smartContractList[smartContractAddress]
const participationAmount = parseFloat(document.getElementById('participation_amount').value.trim())
const participantPrivateKey = document.getElementById('participant_private_key').value.trim()
const participantAddress = floCrypto.getFloID(participantPrivateKey)
let floData
let title = 'Participation successful'
switch (contractType) {
case 'one-time-event': {
// check min,max subscription and participation amount
switch (contractSubType) {
case 'time-trigger':
floData = `send ${participationAmount} ${tokenIdentification}# to ${contractName}@`
description = html`You have participated in the event. Check out details <a href=${`https://ranchimall.github.io/floscout/#/contract/${contractName}-${contractAddress}`} target='_blank'>here</a>`
break
case 'external-trigger':
const userChoice = getRef('smart_contract_participate_form').querySelector('input[name="choice"]:checked').value
if (!userChoice)
return notify('Please select a choice', 'error')
floData = `send ${participationAmount} ${tokenIdentification}# to ${contractName}@ to FLO address ${contractAddress} with the userchoice: ${userChoice}`
description = html`You have casted your vote. Check out details <a href=${`https://ranchimall.github.io/floscout/#/contract/${contractName}-${contractAddress}`} target='_blank'>here</a>`
break
}
}
break;
case 'continuos-event': {
switch (contractSubType) {
case 'tokenswap':
floData = `send ${participationAmount} ${acceptingToken}# to ${contractName}@`
title = 'Token swap initiated'
description = html`Check your transactions and token balance <a href=${`https://ranchimall.github.io/flowallet/#/transactions/${participantAddress}`} target='_blank'>here</a>`
break;
default:
break;
}
}
break
}
console.log(floData)
buttonLoader('participate_button', true)
floTokenAPI.getBalance(participantAddress, acceptingToken || tokenIdentification).then(balance => {
if (balance < participationAmount) {
buttonLoader('participate_button', false)
return notify(`Insufficient balance. You have ${balance} ${acceptingToken || tokenIdentification}`, 'error')
}
getConfirmation('Participate', {
message: `Are you sure you want to participate in ${contractName} with ${participationAmount} ${acceptingToken || tokenIdentification}?`,
confirmText: 'Participate',
}).then(res => {
if (!res) return
floBlockchainAPI.sendTx(participantAddress, contractAddress, floGlobals.sendAmt, participantPrivateKey, floData).then(txid => {
showTransactionResult(true, txid, {
title,
description
})
getRef('smart_contract_participate_form').reset()
document.getElementById('participate_button').disabled = true
}).catch(error => {
showTransactionResult(false, error)
console.error(error)
}).finally(() => {
buttonLoader('participate_button', false)
})
})
}).catch(error => {
notify(`Error getting balance.`, 'error')
buttonLoader('participate_button', false)
console.error(error)
})
}
</script> </script>
</body> </body>