Added deposit and participate functionality
This commit is contained in:
parent
e2a50e1034
commit
0730690291
44
css/main.css
44
css/main.css
@ -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
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -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 {
|
||||||
|
|||||||
348
index.html
348
index.html
@ -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>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user