Added crowd fund progress tracking

This commit is contained in:
sairaj mote 2023-10-05 06:45:12 +05:30
parent 8bc58793ae
commit d43ae1dfe0
4 changed files with 363 additions and 102 deletions

View File

@ -17,7 +17,7 @@ body {
body { body {
--accent-color: #3d5afe; --accent-color: #3d5afe;
--secondary-color: #ffac2e; --secondary-color: #ffac2e;
--text-color: 34, 34, 34; --text-color: 54, 54, 54;
--foreground-color: 252, 253, 255; --foreground-color: 252, 253, 255;
--background-color: 241, 243, 248; --background-color: 241, 243, 248;
--danger-color: rgb(255, 75, 75); --danger-color: rgb(255, 75, 75);
@ -705,6 +705,9 @@ ul {
background: rgba(var(--text-color), 0.06); background: rgba(var(--text-color), 0.06);
margin: 1.5rem 0; margin: 1.5rem 0;
} }
.card + .card {
margin-top: 0;
}
.card h2 { .card h2 {
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
} }
@ -881,18 +884,30 @@ header.grid-2 {
} }
#highlights { #highlights {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
gap: 1.5rem; gap: 1.5rem;
margin-top: 2rem; margin-top: 2rem;
} }
#highlights .highlight-item { #highlights .highlight-item {
position: relative;
opacity: 0; opacity: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 1rem 1.5rem; padding: 1rem 1.5rem;
border-left: 0.1rem solid rgba(var(--text-color), 0.2); border-left: 1px solid var(--accent-color);
--animation-duration: 0.3s; --animation-duration: 0.3s;
} }
#highlights .highlight-item::before {
content: "";
position: absolute;
width: 0.2rem;
height: 1rem;
top: 0;
left: 0;
border-radius: 0 0.1rem 0.1rem 0;
display: inline-block;
background-color: var(--accent-color);
}
#highlights .highlight-item .label { #highlights .highlight-item .label {
margin-top: auto; margin-top: auto;
} }
@ -1021,6 +1036,9 @@ header.grid-2 {
.status.active::before { .status.active::before {
background-color: var(--green); background-color: var(--green);
} }
.status.expired::before {
background-color: var(--yellow);
}
.status.closed::before { .status.closed::before {
background-color: var(--danger-color); background-color: var(--danger-color);
} }
@ -1037,6 +1055,7 @@ header.grid-2 {
.address { .address {
text-transform: none !important; text-transform: none !important;
word-break: break-all; word-break: break-all;
font-weight: 700;
} }
#winners_container { #winners_container {
@ -1142,7 +1161,7 @@ header.grid-2 {
#all_blocks_page, #all_blocks_page,
#top_blocks_container { #top_blocks_container {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
gap: 1rem; gap: 1rem;
} }
@ -1218,11 +1237,79 @@ header.grid-2 {
min-width: 12rem; min-width: 12rem;
} }
#goal_progress_wrapper {
position: relative;
display: flex;
height: 0.1rem;
background-color: rgba(var(--text-color), 0.3);
border-radius: 1rem;
}
.progress-bar {
position: relative;
background-color: var(--accent-color);
width: var(--progress);
border-radius: 1rem;
}
.progress-bar::before {
content: "";
position: absolute;
border-style: solid;
border-width: 0.3rem 0.3rem 0 0.3rem;
border-color: var(--accent-color) transparent transparent transparent;
width: 0;
height: 0;
left: calc(100% - 0.3rem);
bottom: 100%;
box-shadow: 0 0.3rem 0.3rem rgba(0, 0, 0, 0.1);
z-index: 1;
}
#progress_pin {
position: absolute;
bottom: calc(100% + 0.3rem);
padding: 0.4rem 0.6rem;
font-size: 0.85rem;
background-color: var(--accent-color);
font-weight: 500;
color: rgba(var(--foreground-color), 1);
border-radius: 0.3rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.2);
z-index: 1;
}
.goal-milestone {
position: relative;
display: flex;
align-items: center;
padding-top: 1rem;
font-size: 0.9rem;
max-width: 6rem;
text-align: center;
}
.goal-milestone:last-of-type {
margin-left: auto;
text-align: end;
align-items: flex-end;
margin-top: -12rem;
}
.goal-milestone:last-of-type::before {
top: calc(100% + 1.07rem);
}
.goal-milestone::before {
content: "";
position: absolute;
width: 0.2rem;
height: 0.8rem;
top: -0.45rem;
background-color: var(--accent-color);
}
.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-fit, minmax(18rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
} }
.sc-card { .sc-card {

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -17,7 +17,7 @@ body {
body { body {
--accent-color: #3d5afe; --accent-color: #3d5afe;
--secondary-color: #ffac2e; --secondary-color: #ffac2e;
--text-color: 34, 34, 34; --text-color: 54, 54, 54;
--foreground-color: 252, 253, 255; --foreground-color: 252, 253, 255;
--background-color: 241, 243, 248; --background-color: 241, 243, 248;
--danger-color: rgb(255, 75, 75); --danger-color: rgb(255, 75, 75);
@ -658,6 +658,9 @@ ul {
border-radius: 0.5rem; border-radius: 0.5rem;
background: rgba(var(--text-color), 0.06); background: rgba(var(--text-color), 0.06);
margin: 1.5rem 0; margin: 1.5rem 0;
& + & {
margin-top: 0;
}
h2 { h2 {
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
} }
@ -802,15 +805,27 @@ header.grid-2 {
} }
#highlights { #highlights {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
gap: 1.5rem; gap: 1.5rem;
margin-top: 2rem; margin-top: 2rem;
.highlight-item { .highlight-item {
position: relative;
opacity: 0; opacity: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 1rem 1.5rem; padding: 1rem 1.5rem;
border-left: 0.1rem solid rgba(var(--text-color), 0.2); border-left: 1px solid var(--accent-color);
&::before {
content: "";
position: absolute;
width: 0.2rem;
height: 1rem;
top: 0;
left: 0;
border-radius: 0 0.1rem 0.1rem 0;
display: inline-block;
background-color: var(--accent-color);
}
.label { .label {
margin-top: auto; margin-top: auto;
} }
@ -932,6 +947,11 @@ header.grid-2 {
background-color: var(--green); background-color: var(--green);
} }
} }
&.expired {
&::before {
background-color: var(--yellow);
}
}
&.closed { &.closed {
&::before { &::before {
background-color: var(--danger-color); background-color: var(--danger-color);
@ -949,6 +969,7 @@ header.grid-2 {
.address { .address {
text-transform: none !important; text-transform: none !important;
word-break: break-all; word-break: break-all;
font-weight: 700;
} }
#winners_container { #winners_container {
display: grid; display: grid;
@ -1044,7 +1065,7 @@ header.grid-2 {
#all_blocks_page, #all_blocks_page,
#top_blocks_container { #top_blocks_container {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
gap: 1rem; gap: 1rem;
} }
.block-card { .block-card {
@ -1110,6 +1131,70 @@ header.grid-2 {
min-width: 12rem; min-width: 12rem;
} }
} }
#goal_progress_wrapper {
position: relative;
display: flex;
height: 0.1rem;
background-color: rgba(var(--text-color), 0.3);
border-radius: 1rem;
}
.progress-bar {
position: relative;
background-color: var(--accent-color);
width: var(--progress);
border-radius: 1rem;
&::before {
content: "";
position: absolute;
border-style: solid;
border-width: 0.3rem 0.3rem 0 0.3rem;
border-color: var(--accent-color) transparent transparent transparent;
width: 0;
height: 0;
left: calc(100% - 0.3rem);
bottom: 100%;
box-shadow: 0 0.3rem 0.3rem rgba(0, 0, 0, 0.1);
z-index: 1;
}
}
#progress_pin {
position: absolute;
bottom: calc(100% + 0.3rem);
padding: 0.4rem 0.6rem;
font-size: 0.85rem;
background-color: var(--accent-color);
font-weight: 500;
color: rgba(var(--foreground-color), 1);
border-radius: 0.3rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.2);
z-index: 1;
}
.goal-milestone {
position: relative;
display: flex;
align-items: center;
padding-top: 1rem;
font-size: 0.9rem;
max-width: 6rem;
text-align: center;
&:last-of-type {
margin-left: auto;
text-align: end;
align-items: flex-end;
margin-top: -12rem;
&::before {
top: calc(100% + 1.07rem);
}
}
&::before {
content: "";
position: absolute;
width: 0.2rem;
height: 0.8rem;
top: -0.45rem;
background-color: var(--accent-color);
}
}
#smart_contract_page { #smart_contract_page {
} }
@ -1117,7 +1202,7 @@ header.grid-2 {
display: grid; display: grid;
gap: 1rem; gap: 1rem;
margin-top: 1rem; margin-top: 1rem;
grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
} }
.sc-card { .sc-card {
display: flex; display: flex;
@ -1154,11 +1239,6 @@ header.grid-2 {
.sc-card__actions { .sc-card__actions {
justify-content: flex-end; justify-content: flex-end;
padding-top: 1rem; padding-top: 1rem;
// .button {
// background-color: transparent;
// border: solid 1px var(--accent-color);
// padding: 0.5rem 1rem;
// }
} }
.badge { .badge {
margin-right: auto; margin-right: auto;

View File

@ -139,7 +139,7 @@
</sm-popup> </sm-popup>
<!-- Set urls for token and flo Apis --> <!-- Set urls for token and flo Apis -->
<script> <script>
const testMode = false const testMode = true
const floGlobals = { const floGlobals = {
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',
@ -213,6 +213,13 @@
let zIndex = 10 let zIndex = 10
// function required for popups or modals to appear // function required for popups or modals to appear
function openPopup(popupId, pinned) { function openPopup(popupId, pinned) {
if (popupStack.peek() === undefined) {
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closePopup()
}
})
}
zIndex++ zIndex++
getRef(popupId).setAttribute('style', `z-index: ${zIndex}`) getRef(popupId).setAttribute('style', `z-index: ${zIndex}`)
getRef(popupId).show({ pinned }) getRef(popupId).show({ pinned })
@ -268,6 +275,12 @@
renderElem(getRef('filter_s_c_popup__content'), html``) renderElem(getRef('filter_s_c_popup__content'), html``)
break; break;
} }
if (popupStack.peek() === undefined)
document.removeEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closePopup()
}
})
}) })
// displays a popup for asking permission. Use this instead of JS confirm // displays a popup for asking permission. Use this instead of JS confirm
const getConfirmation = (title, options = {}) => { const getConfirmation = (title, options = {}) => {
@ -1349,34 +1362,52 @@
router.routeTo(location.hash) router.routeTo(location.hash)
closePopup() closePopup()
} }
function getSmartContractActions(smartContractAddress) { function getSmartContractActions(smartContractAddress, priceType = 'predetermined', showAdminOptions = false) {
const { acceptingToken, sellingToken, contractSubType, status } = floGlobals.smartContractList[smartContractAddress] const { acceptingToken, sellingToken, contractSubType, status } = floGlobals.smartContractList[smartContractAddress]
if (status !== 'active') return ''; if (!showAdminOptions && status !== 'active') return ''
let actions = ''; let actions = '';
switch (contractSubType) { if (contractSubType === 'tokenswap') {
case 'tokenswap': actions = html`
actions = html` <div class="flex align-center gap-0-5 sc-card__actions">
<div class="flex align-center gap-0-5 sc-card__actions"> ${status === 'active' ? html`
<button class="button button--small button--outlined" onclick=${() => handleSmartContractAction(smartContractAddress, 'deposit')}> <button class="button button--small button--outlined" onclick=${() => handleSmartContractAction(smartContractAddress, 'deposit')}>
Sell ${sellingToken} Swap ${sellingToken}
</button> </button>
<button class="button button--small button--outlined" onclick=${() => handleSmartContractAction(smartContractAddress, 'participate')}> <button class="button button--small button--outlined" onclick=${() => handleSmartContractAction(smartContractAddress, 'participate')}>
Sell ${acceptingToken} Swap ${acceptingToken}
</button> </button>
</div> `: ''}
` ${showAdminOptions && priceType === 'dynamic' ? html`
break; <button class="button button--small button--outlined" onclick=${() => handleSmartContractAction(smartContractAddress, 'updateprice')}>
case 'time-trigger': Update price
case 'external-trigger': </button>
actions = html` `: ''}
<div class="flex align-center gap-0-5 sc-card__actions"> </div>
`
} else if (contractSubType === 'time-trigger' && status === 'active') {
actions = html`
<div class="flex align-center gap-0-5 sc-card__actions">
<button class="button button--small button--outlined" onclick=${() => handleSmartContractAction(smartContractAddress, 'participate')}>
Participate
</button>
</div>
`
} else if (contractSubType === 'external-trigger') {
actions = html`
<div class="flex align-center gap-0-5 sc-card__actions">
${status === 'active' ? html`
<button class="button button--small button--outlined" onclick=${() => handleSmartContractAction(smartContractAddress, 'participate')}> <button class="button button--small button--outlined" onclick=${() => handleSmartContractAction(smartContractAddress, 'participate')}>
Participate Participate
</button > </button>
</div > `: ''}
` ${showAdminOptions && status === 'expired' ? html`
break; <button class="button button--small button--outlined" onclick=${() => handleSmartContractAction(smartContractAddress, 'trigger')}>
}; Trigger
</button>
`: ''}
</div>
`
}
return actions; return actions;
} }
function renderSmartContracts(smartContracts) { function renderSmartContracts(smartContracts) {
@ -1577,10 +1608,10 @@
const [contractId] = state.wildcards const [contractId] = state.wildcards
if (!contractId) return; if (!contractId) return;
const contractIdObj = splitContractNameAddress(contractId) const contractIdObj = splitContractNameAddress(contractId)
const { let {
status, contract, contractType, contractSubtype, contractAddress, expiration, token, status, contract, contractType, contractSubtype, contractAddress, expiration, token,
participationFees, userChoices, payeeAddress, minAmount, maxAmount, acceptingToken, participationFees, userChoices, payeeAddress, minAmount, maxAmount, acceptingToken,
sellingToken, numberOfDeposits, numberOfParticipants, totalHonorAmount, totalParticipationAmount, sellingToken, numberOfDeposits, numberOfParticipants, totalHonorAmount, totalParticipationAmount = 0,
priceType, oracle_address, price, currentDepositBalance priceType, oracle_address, price, currentDepositBalance
} = await getContractInfo(contractIdObj) } = await getContractInfo(contractIdObj)
const detailsToFetch = [getContractTransactions(contractIdObj), getContractParticipants(contractIdObj)] const detailsToFetch = [getContractTransactions(contractIdObj), getContractParticipants(contractIdObj)]
@ -1613,11 +1644,48 @@
if (consolidatedParticipants[participant].winningAmount) if (consolidatedParticipants[participant].winningAmount)
winners.push(render.contractChoiceCard(consolidatedParticipants[participant])) winners.push(render.contractChoiceCard(consolidatedParticipants[participant]))
} }
const contractActions = getSmartContractActions(contractId) const contractActions = getSmartContractActions(contractId, priceType, true)
const progress = Math.min((() => {
if (!minAmount && !maxAmount) return 0
if (minAmount && !maxAmount) return totalParticipationAmount / minAmount * 100
if (maxAmount) return totalParticipationAmount / maxAmount * 100
})(), 100)
let minGoal = 0
if (minAmount && maxAmount) {
minGoal = minAmount / maxAmount * 100
}
renderElem(getRef("page_container"), html` renderElem(getRef("page_container"), html`
<div id="contract_page" class="page"> <div id="contract_page" class="page">
${status ? html` <div class=${`status ${status}`}>${status}</div> ` : ''} ${status ? html` <div class=${`status ${status}`}>${status}</div> ` : ''}
<h2 class="uppercase">${replaceDash(contract)}</h2> <h2 class="uppercase">${replaceDash(contract)}</h2>
${minAmount || maxAmount ? html`
<div class="card grid gap-2">
<div class='grid gap-0-5'>
<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="M12.36 6l.4 2H18v6h-3.36l-.4-2H7V6h5.36M14 4H5v17h2v-7h5.6l.4 2h7V6h-5.6L14 4z"/></svg>
<h3>Collection Goal</h3>
</div>
<div class='grid'>
<div id="goal_progress_wrapper">
<div id="goal_progress" class="progress-bar" style=${`width: ${progress}%`}></div>
<div id="progress_pin">${progress}%</div>
</div>
<div class="flex align-center gap-0-5">
${minAmount ? html`
<div class="flex flex-direction-column goal-milestone" style=${maxAmount ? `left: calc(${minGoal}% - 3rem)` : ''}>
<h5 class="label">Minimum</h5>
<h4>${formatAmount(minAmount)} ${token}</h4>
</div>
`: ''}
${maxAmount ? html`
<div class="flex flex-direction-column goal-milestone">
<h5 class="label">Maximum</h5>
<h4>${formatAmount(maxAmount)} ${token}</h4>
</div>
`: ''}
</div>
</div>
</div>
`: ''}
<div id="contract_info" class="card"> <div id="contract_info" class="card">
<div class="flex info-row"> <div class="flex info-row">
<h5 class="label">Contract Type</h5> <h5 class="label">Contract Type</h5>
@ -1653,21 +1721,9 @@
</div> </div>
</div> </div>
`: ''} `: ''}
${minAmount ? html`
<div class="flex info-row">
<h5 class="label">Min. Subscription Amount</h5>
<h4>${formatAmount(minAmount)} ${token}</h4>
</div>
`: ''}
${maxAmount ? html`
<div class="flex info-row">
<h5 class="label">Max. Subscription Amount</h5>
<h4>${formatAmount(maxAmount)} ${token}</h4>
</div>
`: ''}
${participationFees ? html` ${participationFees ? html`
<div class="flex info-row"> <div class="flex info-row">
<h5 class="label">Participation Fees</h5> <h5 class="label">Participation Amount</h5>
<h4>${formatAmount(participationFees)} ${token}</h4> <h4>${formatAmount(participationFees)} ${token}</h4>
</div> </div>
`: ''} `: ''}
@ -1766,6 +1822,10 @@
</div> </div>
`); `);
getRef("page_title").textContent = "Contract"; getRef("page_title").textContent = "Contract";
// position progress pin on goal progress bar in percentage
if (getRef('progress_pin')) {
getRef('progress_pin').style.left = `calc(${progress}% - ${getRef('progress_pin').getBoundingClientRect().width / 2}px)`
}
} catch (e) { } catch (e) {
console.trace(e) console.trace(e)
renderElem(getRef("page_container"), html`${render.errorPage(e)}`); renderElem(getRef("page_container"), html`${render.errorPage(e)}`);
@ -1778,23 +1838,34 @@
try { try {
const [blockInfo, blockTxs] = await Promise.all([getBlockInfo(blockId), getBlockTransactions(blockId)]) const [blockInfo, blockTxs] = await Promise.all([getBlockInfo(blockId), getBlockTransactions(blockId)])
const { blockHeight, size, reward, hash, difficulty, nonce } = blockInfo; const { blockHeight, size, reward, hash, difficulty, nonce } = blockInfo;
console.log(blockInfo, blockTxs)
renderElem(getRef("page_container"), html` renderElem(getRef("page_container"), html`
<div id="block_page" class="page"> <div id="block_page" class="page">
<h5 class="label">Block Height</h5> <h5 class="label">Block Height</h5>
<h2 class="block-height">${blockHeight}</h2> <h2 class="block-height">${blockHeight}</h2>
<div class="card"> <div class="card grid gap-1-5">
<h5 class="label">Relevant Transactions</h5> <div class="flex flex-wrap gap-1-5">
<h4>${blockTxs.length}</h4> <div class="grid">
<h5 class="label">Confirmations</h5> <h5 class="label">Confirmations</h5>
<h4>${size}</h4> <h4>${size}</h4>
<h5 class="label">Reward</h5> </div>
<h4>${reward}</h4> <div class="grid">
<h5 class="label">Block Hash</h5> <h5 class="label">Reward</h5>
<sm-copy value=${hash} clip-text></sm-copy> <h4>${reward}</h4>
<h5 class="label">Difficulty</h5> </div>
<h4>${difficulty}</h4> <div class="grid">
<h5 class="label">Nonce</h5> <h5 class="label">Difficulty</h5>
<h4>${nonce}</h4> <h4>${difficulty}</h4>
</div>
<div class="grid">
<h5 class="label">Nonce</h5>
<h4>${nonce}</h4>
</div>
</div>
<div class="grid">
<h5 class="label">Block Hash</h5>
<sm-copy value=${hash} clip-text></sm-copy>
</div>
</div> </div>
<h3 class="heading">Transactions</h3> <h3 class="heading">Transactions</h3>
<ul id="block_transaction_container" class="grid gap-1 top-bottom-padding"> <ul id="block_transaction_container" class="grid gap-1 top-bottom-padding">
@ -2124,7 +2195,7 @@
}, contractAddress, }, contractAddress,
contractName contractName
} = info } = info
return { const details = {
contract: contractName, contract: contractName,
contractAddress, contractAddress,
contractType, contractType,
@ -2148,6 +2219,11 @@
price, price,
currentDepositBalance currentDepositBalance
} }
floGlobals.smartContractList[`${contractName}-${contractAddress}`] = {
...details,
...floGlobals.smartContractList[`${contractName}-${contractAddress}`]
}
return details
} }
async function getContractParticipants(contract) { async function getContractParticipants(contract) {
@ -2649,13 +2725,14 @@
openPopup('smart_contract_creation_popup', true) openPopup('smart_contract_creation_popup', true)
} }
function togglePrivateKeyVisibility(input) { function togglePrivateKeyVisibility(input) {
const target = input.closest('sm-input') const target = input.closest('sm-input')
target.type = target.type === 'password' ? 'text' : 'password'; target.type = target.type === 'password' ? 'text' : 'password';
target.focusIn() target.focusIn()
} }
function handleSmartContractAction(smartContractAddress, action) { async function handleSmartContractAction(smartContractAddress, action) {
renderElem(getRef('smart_contract_popup__content'), html`<sm-spinner></sm-spinner>`) openPopup('smart_contract_popup')
switch (action) { switch (action) {
// TODO: check minimum amount // TODO: check minimum amount
case 'deposit': { case 'deposit': {
@ -2683,15 +2760,30 @@
</sm-input> </sm-input>
</div> </div>
<div class="multi-state-button"> <div class="multi-state-button">
<button id="deposit_button" class="button button--primary" onclick=${() => deposit(smartContractAddress)} type="submit" disabled>Sell</button> <button id="deposit_button" class="button button--primary" onclick=${() => deposit(smartContractAddress)} type="submit" disabled>Swap</button>
</div> </div>
`) `)
break; break;
} }
case 'participate': { case 'participate': {
const { price, contractName, contractAddress, acceptingToken, sellingToken, tokenIdentification, userChoices, contractSubType } = floGlobals.smartContractList[smartContractAddress] let { price, contractName, contractAddress, acceptingToken, sellingToken, tokenIdentification, userChoices, contractSubType, participationFees } = floGlobals.smartContractList[smartContractAddress]
if (userChoices) { if (userChoices) {
getRef('smart_contract_popup__title').textContent = `Participate` getRef('smart_contract_popup__title').textContent = `Participate`
renderElem(getRef('smart_contract_popup__content'), html`<sm-spinner class="justify-self-center"></sm-spinner>`)
if (typeof participationFees === 'undefined') {
try {
// TODO: remove this when smart contract list api is updated
const details = await getContractInfo({
name: contractName,
address: contractAddress
})
participationFees = details.participationFees
} catch (err) {
console.error(err)
renderElem(getRef('smart_contract_popup__content'), html`<p class="error">Failed to fetch contract info</p>`)
return
}
}
} }
if (contractSubType === 'tokenswap') { if (contractSubType === 'tokenswap') {
getRef('smart_contract_popup__title').textContent = `Swap ${acceptingToken} with ${sellingToken}` getRef('smart_contract_popup__title').textContent = `Swap ${acceptingToken} with ${sellingToken}`
@ -2714,8 +2806,13 @@
<strong>Exchange rate: 1 ${sellingToken} = ${price} ${acceptingToken}</strong> <strong>Exchange rate: 1 ${sellingToken} = ${price} ${acceptingToken}</strong>
`: ''} `: ''}
<div class="grid gap-0-5"> <div class="grid gap-0-5">
<span id="participation_amount_label" class="label">Participation amount (${acceptingToken || tokenIdentification})</span> ${typeof participationFees !== 'undefined' ? html`
<sm-input id="participation_amount" type="number" step="0.00000001" min="0.00000001" error-text="The amount should be above 0.00000001" required></sm-input> <span id="participation_amount_label" class="label">Pre-defined participation amount (${acceptingToken || tokenIdentification})</span>
<sm-input id="participation_amount" type="number" step="0.00000001" value=${participationFees} readonly required></sm-input>
`: html`
<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" error-text="The amount should be above 0.00000001" required></sm-input>
`}
</div> </div>
<div class="grid gap-0-5"> <div class="grid gap-0-5">
<span class="label">FLO private key</span> <span class="label">FLO private key</span>
@ -2728,7 +2825,7 @@
</sm-input> </sm-input>
</div> </div>
<div class="multi-state-button"> <div class="multi-state-button">
<button id="participate_button" class="button button--primary" onclick=${() => participate(smartContractAddress)} type="submit" disabled>Sell</button> <button id="participate_button" class="button button--primary" onclick=${() => participate(smartContractAddress)} type="submit" disabled>Swap</button>
</div> </div>
`) `)
break; break;
@ -2737,33 +2834,31 @@
const { contractName, contractAddress, oracle_address, price, acceptingToken } = floGlobals.smartContractList[smartContractAddress] const { contractName, contractAddress, oracle_address, price, acceptingToken } = floGlobals.smartContractList[smartContractAddress]
getRef('smart_contract_popup__title').textContent = `Update price` getRef('smart_contract_popup__title').textContent = `Update price`
renderElem(getRef('smart_contract_popup__content'), html` renderElem(getRef('smart_contract_popup__content'), html`
<sm-form> <div class="grid gap-0-5">
<div class="grid gap-0-5"> <span class="label">Oracle FLO Address</span>
<span class="label">Oracle FLO Address</span> <sm-copy id="oracle_address" value=${oracle_address}></sm-copy>
<sm-copy id="oracle_address" value=${oracle_address}></sm-copy> </div>
</div> <div class="grid gap-0-5">
<div class="grid gap-0-5"> <span class="label">Oracle FLO private key</span>
<span class="label">Oracle FLO private key</span> <sm-input id="oracle_private_key" class="password-field" type="password" data-private-key="" required="">
<sm-input id="oracle_private_key" class="password-field" type="password" data-private-key="" required=""> <label slot="right" class="interact">
<label slot="right" class="interact"> <input type="checkbox" class="hidden" readonly="" onchange="togglePrivateKeyVisibility(this)">
<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 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>
<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>
</label> </sm-input>
</sm-input> </div>
</div> <p>
<p> <span class="label">Current price: </span>
<span class="label">Current price: </span> <span id="current_price" class="label">${price} ${acceptingToken}</span>
<span id="current_price" class="label">${price} ${acceptingToken}</span> </p>
</p> <div class="grid gap-0-5">
<div class="grid gap-0-5"> <span id="updated_price_label" class="label">Updated price (${acceptingToken})</span>
<span id="updated_price_label" class="label">Updated price (${acceptingToken})</span> <sm-input id="updated_price" type="number" step="0.00000001" min="0.00000001" error-text="Minimum 0.00000001 required" required></sm-input>
<sm-input id="updated_price" type="number" step="0.00000001" min="0.00000001" error-text="Minimum 0.00000001 required" required></sm-input> </div>
</div> <div class="multi-state-button">
<div class="multi-state-button"> <button id="update_price_button" class="button button--primary" type="submit" onclick=${() => updatePrice(smartContractAddress)} disabled>Update</button>
<button id="update_price_button" class="button button--primary" type="submit" onclick=${() => updatePrice(smartContractAddress)} disabled>Update</button> </div>
</div>
</sm-form>
`) `)
break; break;
} }
@ -2801,7 +2896,6 @@
break; break;
} }
} }
openPopup('smart_contract_popup')
} }