From ccc39ab4e92c13211a94b8e41fa35369f6be359e Mon Sep 17 00:00:00 2001 From: RanchiMall Dev Date: Mon, 28 Jul 2025 08:01:22 +0000 Subject: [PATCH] Workflow updating files of floscout --- floscout/index.html | 2492 +++++++++++++++++++++++++++---------------- 1 file changed, 1573 insertions(+), 919 deletions(-) diff --git a/floscout/index.html b/floscout/index.html index 77a833e..87ef412 100644 --- a/floscout/index.html +++ b/floscout/index.html @@ -1,5 +1,6 @@ + @@ -143,7 +144,7 @@ const floGlobals = { blockchain: testMode ? "FLO_TEST" : "FLO", tokenApiUrl: testMode ? 'https://ranchimallflo-testnet.ranchimall.net' : 'https://ranchimallflo.ranchimall.net', - floApiUrl: testMode ? 'https://blockbook-testnet.ranchimall.net' : 'https://blockbook.ranchimall.net', + floApiUrl: testMode ? 'https://blockbook-testnet.ranchimall.net' : 'https://blockbook.flocard.app', expirationDays: 60, } @@ -832,22 +833,25 @@ }, contractChoiceCard(details) { const { participantFloAddress, userChoice, tokenAmount, transactionHash, winningAmount, tokenIdentification } = details; - let action; + let action, amount; if (winningAmount) { action = 'Won' amount = winningAmount - } else + } else { action = 'Invested' + amount = tokenAmount + } return html`
  • ${participantFloAddress} ${userChoice} - ${action} ${formatAmount(tokenAmount)} ${tokenIdentification} + ${action} ${formatAmount(amount)} ${tokenIdentification}
  • `; }, + contractDepositCard(obj) { const { hash, blockHeight, token, sender, receiver, amount, type, time, contractAddress, contractName } = obj; let title = 'Contract deposit'; @@ -869,7 +873,7 @@
    Receiver (Smart contract)
    - ${contractName}-${receiver} + ${contractName}_${receiver}
    @@ -917,7 +921,7 @@
    Receiver (Smart contract)
    -

    ${contractName}-${receiver}

    +

    ${contractName}_${receiver}

    @@ -1012,45 +1016,73 @@
    `; }, - contractTriggerCard(obj) { - // TODO: change committee address to actual committee address instead of contract address - const { hash, blockHeight, contractName, contractAddress, winningChoice, committeeAddress, time } = obj; - return html` -
  • - -
    -
    smart contract
    -

    trigger

    +contractTriggerCard(obj) { + const { + hash, blockHeight, contractName, contractAddress, + winningChoice, committeeAddress, + sender, receiver, amount, token, + time, onChain, + triggerCondition // ๐Ÿ”ง make sure it's destructured + } = obj; + + return html` +
  • + + + + +
    +
    smart contract
    +

    trigger

    +
    +
    + +
    +
    contract address
    + + ${contractName}_${contractAddress} + +
    + + ${onChain + ? html` +
    +
    Triggered Choice
    +

    ${triggerCondition ? triggerCondition : 'Triggered by Time'}

    -
    - -
    -
    contract address
    - - ${contractName}-${contractAddress} - -
    -
    -
    Winning Choice
    -

    ${winningChoice}

    -
    -
    -
    committee address
    - - ${committeeAddress} - -
    -
    -
    -
    Transaction ID
    - -
    - View details -
    + ` + : html` +
    +
    Sender
    + + ${sender} +
    -
  • - `; - }, +
    +
    Receiver
    + + ${receiver} + +
    +
    +
    Amount
    +

    ${amount} ${token || ''}

    +
    + ` + } + +
    +
    +
    Transaction ID
    + +
    + View details +
    +
    + + `; +}, + contractCreationCard(obj) { const { hash, blockHeight, token, contractName, incAddress, contractType, @@ -1071,7 +1103,7 @@ ` : ''}
    Contract ID
    - ${contractName}-${incAddress} + ${contractName}_${incAddress}
    contract type
    @@ -1166,14 +1198,20 @@
    +
    Sender address
    + + ${senderAddress} + +
    +
    Receiver address
    ${receiverAddress} -
    +
    Amount

    ${tokenAmount} ${tokenIdentification}

    @@ -1190,75 +1228,103 @@
    `; }, - compoundTransactionCard(details) { - const { time, hash, sender, receiver, contractName, token, amount, offChainTransactions = [], userChoice, contractAddress } = details - const smartContract = `${contractName}-${receiver || contractAddress}` - const renderedOffChainTransactions = offChainTransactions.map(tx => { - const { receiverAddress, tokenAmount, tokenIdentification } = tx - return html` +compoundTransactionCard(details) { + const { + time, hash, sender, receiver, + contractName, token, amount, + offChainTransactions = [], + userChoice, contractAddress, + triggerCondition + } = details; + + const smartContract = `${contractName}_${receiver || contractAddress}`; + const renderedOffChainTransactions = offChainTransactions.map(tx => { + const { receiverAddress, tokenAmount, tokenIdentification } = tx; + return html` +
  • +
    +
    +
    +
    Sender (Smart contract)
    +
    Off-chain
    +
    + ${smartContract} +
    +

    Sent: ${tokenAmount} ${tokenIdentification}

    +
    + + + + +
    +
    Receiver
    + + ${receiverAddress} + +
    +
  • + `; + }); + + return html` +
  • + + transfer + + + +
    +

    Smart contract transfer

    + + + ${triggerCondition ? html` +
    +
    Triggered Choice
    + ${triggerCondition} +
    + ` : ''} +
    + +
    +
      + ${sender ? html`
    • -
      -
      -
      Sender (Smart contract)
      -
      Off-chain
      -
      - ${smartContract} +
      +
      Sender
      + + ${sender} + +

      Sent:${(!amount || Number(amount) === 0) ? "Trigger" : `${amount} ${token}`}

      +
      -

      Sent: ${tokenAmount} ${tokenIdentification}

      - + + + +
      -
      Receiver
      - - ${receiverAddress} - +
      Receiver (Smart contract)
      + ${smartContract}
    • - ` - }) - return html` -
    • - transfer -
      -

      Smart contract transfer

      - + ` : ''} + ${renderedOffChainTransactions} +
    + + ${hash ? html` +
    +
    +
    Transaction ID
    +
    -
    -
      - ${sender ? html` -
    • -
      -
      -
      Sender
      - - ${sender} - -

      Sent: ${amount} ${token}

      -
      -
      - -
      -
      Receiver (Smart contract)
      - ${smartContract} -
      -
    • - `: ''} - ${renderedOffChainTransactions} -
    - ${hash ? html` -
    -
    -
    Transaction ID
    - -
    - View details -
    - `: ''} -
    -
  • - ` - }, + View details + + ` : ''} + + + `; +}, availableAssetOptions() { return (floGlobals.tokenList || []).map(token => html` ${token} `) }, @@ -1432,7 +1498,7 @@ filterSmartContracts().forEach(contract => { const { tokenIdentification, acceptingToken, blockNumber, contractAddress, contractName, contractSubType, contractType, incorporationDate, oracle_address, price, sellingToken, status, transactionHash } = contract; - const smartContractAddress = `${contractName}-${contractAddress}`; + const smartContractAddress = `${contractName}_${contractAddress}`; let type = ''; let actions = getSmartContractActions(smartContractAddress); if (contractSubType === 'tokenswap') { @@ -1447,7 +1513,7 @@ ${status !== 'active' ? html`
    ${status}
    ` : ''}

    ${type}

    - + View details @@ -1539,305 +1605,409 @@ closePopup() getRef("page_title").textContent = 'Smart Contracts'; }) - router.addRoute('address', async state => { - try { - const [floAddress] = state.wildcards - if (!floAddress) return; - let [ownedTokens = {}, floBalance, addressTxs] = await Promise.all([getAddressInfo(floAddress), floBlockchainAPI.getBalance(floAddress), getAddressTxs(floAddress)]); - console.log(ownedTokens) - const ownedTokensCards = [] - for (const token in ownedTokens) { - ownedTokensCards.push(render.tokenBalanceCard(token, ownedTokens[token].balance || 0)) - } - renderElem(getRef("page_container"), html` -
    -
    -

    ${floAddress}

    -
    FLO Balance
    -

    ${floBalance} FLO

    - ${ownedTokensCards.length ? html` -
    -
    Tokens
    -
      - ${ownedTokensCards} -
    -
    - `: ''} -
    -

    Transactions

    -
      - ${renderTransactions(addressTxs)} -
    -
    - `); - getRef("page_title").textContent = 'Address'; - } catch (e) { - console.error(e) - renderElem(getRef("page_container"), html`${render.errorPage(e)}`); - } - }) - router.addRoute('token', async state => { - const token = state.wildcards[0].toLowerCase() - if (!token) return; - try { - let [tokenInfo, tokenBalances, tokenTransactions] = await Promise.all([getTokenInfo(token), getTokenBalances(token), getTokenTransactions(token)]) - let { supply, incAddress } = tokenInfo - const tokenHolders = [] - for (const address in tokenBalances) { - tokenHolders.push(render.addrBalanceCard(address, tokenBalances[address], tokenInfo.token)) - } - renderElem(getRef("page_container"), html` -
    -
    -

    ${token}

    -
    Supply
    -

    ${supply ? formatAmount(supply, token.toLowerCase() === 'rupee' ? 'inr' : 'usd') : 'Infinite'}

    -
    Incorporation address
    - - ${incAddress} - -
    - - Transactions - Token holders - -
    -
      - ${renderTransactions(tokenTransactions)} -
    - -
    -
    - `); - getRef("page_title").textContent = "Token"; - } catch (e) { - console.trace(e) - renderElem(getRef("page_container"), html`${render.errorPage(e)}`); - } - }) - router.addRoute('contract', async state => { - try { - const [contractId] = state.wildcards - if (!contractId) return; - const contractIdObj = splitContractNameAddress(contractId) - let { - status, contract, contractType, contractSubtype, contractAddress, expiration, token, - participationFees, userChoices, payeeAddress, minAmount, maxAmount, acceptingToken, - sellingToken, numberOfDeposits, numberOfParticipants, totalHonorAmount, totalParticipationAmount = 0, - priceType, oracle_address, price, currentDepositBalance - } = await getContractInfo(contractIdObj) - const detailsToFetch = [getContractTransactions(contractIdObj), getContractParticipants(contractIdObj)] - if (contractType === 'continuos-event' && contractSubtype === 'tokenswap') - detailsToFetch.push(getContractDeposits(contractIdObj)) - let [contractTransactions = [], contractParticipants = {}, contractDeposits = []] = await Promise.all(detailsToFetch) - let participants = []; - let winners = [] - let deposits = contractDeposits.map(deposit => render.depositCard({ ...deposit, acceptingToken, sellingToken })) - // Consolidate participants with same address and choice - const consolidatedParticipants = {} - for (const participant in contractParticipants) { - const { participantFloAddress, tokenAmount, userChoice, winningAmount, participationAmount } = contractParticipants[participant] - const id = userChoice ? `${participantFloAddress}-${userChoice}` : participantFloAddress - if (!consolidatedParticipants[id]) { - consolidatedParticipants[id] = contractParticipants[participant] - } else { - if (tokenAmount) { - if (!consolidatedParticipants[id].tokenAmount) - consolidatedParticipants[id].tokenAmount = 0 - consolidatedParticipants[id].tokenAmount += tokenAmount - } - if (participationAmount) { - if (!consolidatedParticipants[id].participationAmount) - consolidatedParticipants[id].participationAmount = 0 - consolidatedParticipants[id].participationAmount += participationAmount - } - if (winningAmount) { - if (!consolidatedParticipants[id].winningAmount) - consolidatedParticipants[id].winningAmount = 0 - consolidatedParticipants[id].winningAmount += winningAmount +router.addRoute('address', async state => { + try { + const [floAddress] = state.wildcards; + if (!floAddress) return; + + let addressInfo = {}; + let floBalance = { balance: 0 }; + let addressTxs = []; + + // Always try to get FLO balance + try { + floBalance = await getAddressBalance(floAddress); + } catch (e) { + console.warn("โš ๏ธ Failed to fetch FLO balance:", e); + } + + try { + addressInfo = await getAddressInfo(floAddress); + } catch (e) { + console.warn("โš ๏ธ Failed to fetch address token info:", e); + } + + try { + addressTxs = await getAddressTxs(floAddress); + console.log("๐Ÿ“ฆ Raw addressTxs:", addressTxs); + } catch (e) { + console.warn("โš ๏ธ Failed to fetch token transactions:", e); + } + + + const ownedTokens = addressInfo?.floAddressBalances || {}; + console.log("โœ… ownedTokens fetched from addressInfo:", ownedTokens); + + const ownedTokensCards = []; + for (const token in ownedTokens) { + ownedTokensCards.push( + render.tokenBalanceCard(token, ownedTokens[token].balance || 0) + ); + } + + console.log("โœ… ownedTokensCards:", ownedTokensCards); + + renderElem(getRef("page_container"), html` +
    +
    +

    ${floAddress}

    +
    FLO Balance
    +

    ${floBalance?.balance || 0} FLO

    + + ${ownedTokensCards.length ? html` +
    +
    Token Balances
    +
    + ${ownedTokensCards} +
    +
    + ` : ''} +
    + +

    Transactions

    +
      + ${renderTransactions(addressTxs)} +
    +
    + `); + + getRef("page_title").textContent = 'Address'; + + } catch (e) { + console.error("๐Ÿ’ฅ Router-level failure:", e); + renderElem(getRef("page_container"), html`${render.errorPage(e)}`); + } +}); + + +router.addRoute('token', async state => { + const token = state.wildcards[0].toLowerCase(); + if (!token) return; + try { + console.log("๐Ÿ” Token route triggered for:", token); + + let [tokenInfo, tokenBalances, tokenTransactions] = await Promise.all([ + getTokenInfo(token), + getTokenBalances(token), + getTokenTransactions(token) + ]); + + console.log("โœ… tokenInfo:", tokenInfo); + console.log("โœ… tokenBalances:", tokenBalances); + console.log("โœ… tokenTransactions:", tokenTransactions); + console.log("โœ… Number of token transactions:", tokenTransactions?.length || 0); + + let { supply, incAddress } = tokenInfo; + + // Render token holders + const tokenHolders = []; + for (const address in tokenBalances) { + tokenHolders.push(render.addrBalanceCard(address, tokenBalances[address], tokenInfo.token)); + } + console.log("โœ… Number of token holders:", tokenHolders.length); + + // Render transactions with protection + let renderedTx; + try { + renderedTx = renderTransactions(tokenTransactions); + console.log("โœ… renderTransactions output:", renderedTx); + } catch (err) { + console.error("โŒ Error in renderTransactions:", err); + renderedTx = html`
    โš ๏ธ Rendering failed
    `; + } + + renderElem(getRef("page_container"), html` +
    +
    +

    ${token}

    +
    Supply
    +

    ${supply ? formatAmount(supply, token.toLowerCase() === 'rupee' ? 'inr' : 'usd') : 'Infinite'}

    +
    Incorporation address
    + + ${incAddress} + +
    + + Transactions + Token holders + +
    +
      + ${renderedTx} +
    + +
    +
    + `); + getRef("page_title").textContent = "Token"; + + } catch (e) { + console.trace("โŒ Error loading token page:", e); + renderElem(getRef("page_container"), html`${render.errorPage(e)}`); + } +}); + + router.addRoute('contract', async state => { + try { + const [contractId] = state.wildcards + if (!contractId) return; + const contractIdObj = splitContractNameAddress(contractId) + let { + status, contract, contractType, contractSubtype, contractAddress, expiration, token, + participationFees, userChoices, payeeAddress, minAmount, maxAmount, acceptingToken, + sellingToken, numberOfDeposits, numberOfParticipants, totalHonorAmount, totalParticipationAmount = 0, + priceType, oracle_address, price, currentDepositBalance + } = await getContractInfo(contractIdObj) + + console.log("DEBUG raw backend status:", status, "expiration:", expiration); + + if (typeof payeeAddress === 'string') { + try { + payeeAddress = JSON.parse(payeeAddress); + } catch (err) { + console.warn("โŒ Failed to parse payeeAddress JSON string:", payeeAddress, err); + payeeAddress = {}; } } - } - for (const participant in consolidatedParticipants) { - const participantCard = render.participantCard(consolidatedParticipants[participant]) - if (participantCard) - participants.push(participantCard) - if (consolidatedParticipants[participant].winningAmount) - winners.push(render.contractChoiceCard(consolidatedParticipants[participant])) - } - const contractActions = getSmartContractActions(contractId, priceType, true) - const progress = Math.min((() => { - if (!minAmount && !maxAmount) return 0 - if (minAmount) return totalParticipationAmount / minAmount * 100 - if (maxAmount) return totalParticipationAmount / maxAmount * 100 - })(), 100) - renderElem(getRef("page_container"), html` -
    - ${status ? html`
    ${status}
    ` : ''} -

    ${replaceDash(contract)}

    - ${minAmount || maxAmount ? html` -
    -
    - -
    -
    -
    -
    + + + let expirationTimestamp; + if (typeof expiration === "string") { + expirationTimestamp = new Date(expiration).getTime(); + } else if (typeof expiration === "number") { + expirationTimestamp = expiration > 1e12 + ? expiration + : expiration * 1000; + } + + + const isExpired = expirationTimestamp && Date.now() > expirationTimestamp; + + console.log("DEBUG isExpired:", isExpired); + + if (isExpired && (!status || status === "active")) { + status = "expired"; + } + + console.log("DEBUG final status:", status); + + const detailsToFetch = [getContractTransactions(contractIdObj), getContractParticipants(contractIdObj)] + if (contractType === 'continuos-event' && contractSubtype === 'tokenswap') + detailsToFetch.push(getContractDeposits(contractIdObj)) + let [contractTransactions = [], contractParticipants = {}, contractDeposits = []] = await Promise.all(detailsToFetch) + let participants = []; + let winners = [] + let deposits = contractDeposits.map(deposit => render.depositCard({ ...deposit, acceptingToken, sellingToken })) + // Consolidate participants with same address and choice + const consolidatedParticipants = {} + for (const participant in contractParticipants) { + const { participantFloAddress, tokenAmount, userChoice, winningAmount, participationAmount } = contractParticipants[participant] + const id = userChoice ? `${participantFloAddress}-${userChoice}` : participantFloAddress + if (!consolidatedParticipants[id]) { + consolidatedParticipants[id] = contractParticipants[participant] + } else { + if (tokenAmount) { + if (!consolidatedParticipants[id].tokenAmount) + consolidatedParticipants[id].tokenAmount = 0 + consolidatedParticipants[id].tokenAmount += tokenAmount + } + if (participationAmount) { + if (!consolidatedParticipants[id].participationAmount) + consolidatedParticipants[id].participationAmount = 0 + consolidatedParticipants[id].participationAmount += participationAmount + } + if (winningAmount) { + if (!consolidatedParticipants[id].winningAmount) + consolidatedParticipants[id].winningAmount = 0 + consolidatedParticipants[id].winningAmount += winningAmount + } + } + } + for (const participant in consolidatedParticipants) { + const participantCard = render.participantCard(consolidatedParticipants[participant]) + if (participantCard) + participants.push(participantCard) + if (consolidatedParticipants[participant].winningAmount) + winners.push(render.contractChoiceCard(consolidatedParticipants[participant])) + } + const contractActions = getSmartContractActions(contractId, priceType, true) + const progress = Math.min((() => { + if (!minAmount && !maxAmount) return 0 + if (minAmount) return totalParticipationAmount / minAmount * 100 + if (maxAmount) return totalParticipationAmount / maxAmount * 100 + })(), 100) + renderElem(getRef("page_container"), html` +
    + ${status ? html`
    ${status}
    ` : ''} +

    ${replaceDash(contract)}

    + ${minAmount || maxAmount ? html` +
    +
    +
    -
    -
    -
    Raised (${progress}%)
    -

    ${formatAmount(totalParticipationAmount)} ${token}

    +
    +
    +
    -
    -
    Goal
    -

    ${minAmount ? `${formatAmount(minAmount)} ${token}` : ''} ${maxAmount ? ` - ${formatAmount(maxAmount)} ${token}` : ''}

    +
    +
    +
    Raised (${progress}%)
    +

    ${formatAmount(totalParticipationAmount)} ${token}

    +
    +
    +
    Goal
    +

    ${minAmount ? `${formatAmount(minAmount)} ${token}` : ''} ${maxAmount ? ` - ${formatAmount(maxAmount)} ${token}` : ''}

    +
    -
    - `: ''} - ${userChoices ? html` -

    Available Choices

    -
      - ${Object.keys(userChoices).map(choice => html` -
    • ${userChoices[choice]}
    • - `)} -
    - `: ''} - ${contractActions ? html` -
    -

    Participate in this contract

    - ${contractActions} -
    - `: ''} -
    -
    -
    Contract Type
    -

    ${replaceDash(contractType) === 'continuos event' ? 'continuous event' : replaceDash(contractType)}

    -
    - ${contractSubtype ? html` -
    -
    Contract Sub-type
    -

    ${replaceDash(contractSubtype)}

    + `: ''} + ${userChoices ? html` +

    Available Choices

    +
      + ${Object.keys(userChoices).map(choice => html` +
    • ${userChoices[choice]}
    • + `)} +
    + `: ''} + ${contractActions ? html` +
    +

    Participate in this contract

    + ${contractActions}
    `: ''} -
    -
    Contract Address
    - - ${contractAddress} - -
    - ${expiration ? html` +
    -
    Expiration
    -

    ${getFormattedTime(new Date(expiration).getTime())}

    +
    Contract Type
    +

    ${replaceDash(contractType) === 'continuos event' ? 'continuous event' : replaceDash(contractType)}

    - `: ''} - ${payeeAddress ? html` -
    -
    Payee Addresses
    -
    - ${Object.keys(payeeAddress).map(address => html` - - ${address} - - `)} + ${contractSubtype ? html` +
    +
    Contract Sub-type
    +

    ${replaceDash(contractSubtype)}

    -
    - `: ''} - ${participationFees ? html` + `: ''}
    -
    Participation Amount
    -

    ${formatAmount(participationFees)} ${token}

    -
    - `: ''} - ${contractType === 'one-time-event' ? html` -
    -
    Token Used
    -

    ${token}

    -
    - `: ''} - ${contractType === 'continuos-event' && contractSubtype === 'tokenswap' ? html` -
    -
    deposit token
    -

    ${sellingToken}

    -
    -
    -
    participation token
    -

    ${acceptingToken}

    -
    -
    -
    Exchange rate (${priceType === 'dynamic' ? 'Dynamic' : 'Fixed'})
    -

    1 ${sellingToken} = ${price} ${acceptingToken}

    -
    - `: ''} - ${numberOfDeposits ? html` -
    -
    Number of deposits
    -

    ${numberOfDeposits}

    -
    - `: ''} - ${numberOfParticipants ? html` -
    -
    Number of participants
    -

    ${numberOfParticipants}

    -
    - `: ''} - ${oracle_address ? html` -
    -
    Oracle address
    - - ${oracle_address} +
    Contract Address
    + + ${contractAddress}
    - `: ''} - ${totalParticipationAmount ? html` -
    -
    Total participation amount
    -

    ${formatAmount(totalParticipationAmount)} ${acceptingToken}

    -
    - `: ''} - ${totalHonorAmount ? html` -
    -
    Total output amount
    -

    ${formatAmount(totalHonorAmount)} ${sellingToken}

    -
    - `: ''} - ${currentDepositBalance ? html` -
    -
    Total deposit balance
    -

    ${formatAmount(currentDepositBalance)} ${sellingToken}

    -
    - `: ''} + ${expiration ? html` +
    +
    Expiration
    +

    ${getFormattedTime(new Date(expiration).getTime())}

    +
    + `: ''} + ${payeeAddress ? html` +
    +
    Payee Addresses
    +
    + ${Object.keys(payeeAddress).map(address => html` +
    +

    ${address}

    +

    ${payeeAddress[address]}%

    +
    + `)} +
    + + +
    + ` : ''} + + + ${participationFees ? html` +
    +
    Participation Amount
    +

    ${formatAmount(participationFees)} ${token}

    +
    + `: ''} + ${contractType === 'one-time-event' ? html` +
    +
    Token Used
    +

    ${token}

    +
    + `: ''} + ${contractType === 'continuos-event' && contractSubtype === 'tokenswap' ? html` +
    +
    deposit token
    +

    ${sellingToken}

    +
    +
    +
    participation token
    +

    ${acceptingToken}

    +
    +
    +
    Exchange rate (${priceType === 'dynamic' ? 'Dynamic' : 'Fixed'})
    +

    1 ${sellingToken} = ${price} ${acceptingToken}

    +
    + `: ''} + ${numberOfDeposits ? html` +
    +
    Number of deposits
    +

    ${numberOfDeposits}

    +
    + `: ''} + ${numberOfParticipants ? html` +
    +
    Number of participants
    +

    ${numberOfParticipants}

    +
    + `: ''} + ${oracle_address ? html` +
    +
    Oracle address
    + + ${oracle_address} + +
    + `: ''} + ${totalParticipationAmount ? html` +
    +
    Total participation amount
    +

    ${formatAmount(totalParticipationAmount)} ${acceptingToken}

    +
    + `: ''} + ${totalHonorAmount ? html` +
    +
    Total output amount
    +

    ${formatAmount(totalHonorAmount)} ${sellingToken}

    +
    + `: ''} + ${currentDepositBalance ? html` +
    +
    Total deposit balance
    +

    ${formatAmount(currentDepositBalance)} ${sellingToken}

    +
    + `: ''} +
    + + Transactions + Participants + ${winners?.length ? html`Winners` : ''} + ${deposits?.length ? html`Deposits` : ''} + +
    +
      + ${renderTransactions(contractTransactions)} +
    + + ${winners?.length ? html`` : ''} + ${deposits?.length ? html`` : ''} +
    - - Transactions - Participants - ${winners?.length ? html`Winners` : ''} - ${deposits?.length ? html`Deposits` : ''} - -
    -
      - ${renderTransactions(contractTransactions)} -
    - - ${winners?.length ? html`` : ''} - ${deposits?.length ? html`` : ''} -
    -
    - `); - getRef("page_title").textContent = "Contract"; - } catch (e) { - console.trace(e) - renderElem(getRef("page_container"), html`${render.errorPage(e)}`); - } - }) + `); + getRef("page_title").textContent = "Contract"; + } catch (e) { + console.trace(e) + renderElem(getRef("page_container"), html`${render.errorPage(e)}`); + } + }) router.addRoute('block', async state => { const [blockId] = state.wildcards @@ -1895,102 +2065,172 @@
    `) }) - router.addRoute('transactions', async state => { - let allTxs = await getAllTxs(); - getRef("page_title").textContent = "All token transactions"; - renderElem(getRef("page_container"), html` -
    -
      - ${renderTransactions(allTxs)} -
    + +router.addRoute('transaction', async state => { + try { + let txIdArr = state.wildcards; + console.log("๐Ÿ” Wildcards:", txIdArr); + let txId = txIdArr[0]; + if (!txId) return; + + let txResult = await getTxInfo(txId); + console.log("๐Ÿ“ฅ Raw getTxInfo result:", txResult); + + let status = txResult[0]; + let txInfoRaw = txResult[1]; + + console.log("๐Ÿงช txInfoRaw before any patch:", txInfoRaw); + + if (!status) + return renderElem(getRef("page_container"), html`${render.errorPage(txInfoRaw)}`); + + // โœ… Clone to avoid accidental mutation + let txInfo = { ...txInfoRaw }; + + // โœ… Normalize type + if (txInfo.type) { + txInfo.type = txInfo.type.trim(); + } + console.log("๐Ÿ”  Normalized type:", txInfo.type); + + // โœ… Patch: trigger + onChain:false + contractAddress + if ( + txInfo.type === 'trigger' && + txInfo.onChain === false && + txInfo.contractAddress + ) { + txInfo.sender = txInfo.contractAddress; + txInfo.receiver = txInfo.contractAddress; + txInfo.senderAddress = txInfo.contractAddress; + txInfo.receiverAddress = txInfo.contractAddress; + console.log("๐Ÿ”ง Patched sender/receiver from contractAddress due to off-chain trigger"); + } else { + console.log("โŒ No patch applied"); + } + + console.log("๐Ÿงช txInfo after patch:", txInfo); + + // โœ… Destructure + let { + type, + tokenIdentification, + tokenAmount, + amount, + blockheight, + blockHeight, + senderAddress, + sender, + receiverAddress, + receiver, + txid, + hash, + floData, + confirmations, + nftHash, + subTransactions, + time + } = txInfo; + + console.log("๐Ÿ“ฆ Destructured values:"); + console.log({ type, tokenIdentification, tokenAmount, amount, blockheight, blockHeight, senderAddress, sender, receiverAddress, receiver, txid, hash, floData, confirmations, nftHash, subTransactions, time }); + + let name = tokenIdentification || txInfo.name || ''; + let finalAmount = tokenAmount ?? amount ?? ''; + let finalSender = senderAddress ?? sender ?? ''; + let finalReceiver = receiverAddress ?? receiver ?? ''; + let finalBlock = blockheight ?? blockHeight ?? ''; + let finalHash = txid ?? hash ?? ''; + + console.log("๐Ÿ”Ž Final computed values:"); + console.log({ name, finalAmount, finalSender, finalReceiver, finalBlock, finalHash }); + + switch (type) { + case 'smartContractPays': + name = ''; + break; + case 'nftIncorporation': + type = 'NFT Incorporation'; + break; + case 'nft transfer': + type = 'NFT Transfer'; + break; + } + + let renderedSubTransactions = subTransactions?.map(tx => + render.offChainTransferCard({ ...tx, hideUnnecessary: true }) + ); + + renderElem(getRef("page_container"), html` +
    +
    +
    ${type}
    +

    + ${name} +

    +
    Transaction ID
    +
    - `) - }) - router.addRoute('transaction', async state => { - try { - const [txId] = state.wildcards - if (!txId) return - const [status, txInfo] = await getTxInfo(txId); - if (!status) - return renderElem(getRef("page_container"), html`${render.errorPage(txInfo)}`); - const { type, name, blockHeight, amount, sender, receiver, floData, hash, confirmations, nftHash, subTransactions, time } = txInfo; - switch (type.trim()) { - case 'smartContractPays': - case 'smartContractPays': - name = '' - break - case 'nftIncorporation': - type = 'NFT Incorporation' - break - case 'nft transfer': - type = 'NFT Transfer' - break - } - const renderedSubTransactions = subTransactions?.map(tx => render.offChainTransferCard({ ...tx, hideUnnecessary: true })); - renderElem(getRef("page_container"), html` -
    -
    -
    ${type}
    -

    - ${name} -

    -
    Transaction ID
    - +
    +
    + +
    +
    Sender
    + + ${finalSender} +
    -
    -
    - -
    -
    Sender
    - - ${sender} - -
    - ${receiver ? html` -
    -
    Receiver
    - - ${receiver} - -
    - `: ''} - ${amount ? html` -
    -
    Amount
    -

    ${formatAmount(amount)}

    -
    - `: ''} + ${finalReceiver ? html` +
    +
    Receiver
    + + ${finalReceiver} +
    -
    -
    FLO Data
    -

    ${floData}

    -
    Block
    - ${blockHeight} -
    Block Confirmations
    -

    ${confirmations}

    - ${nftHash ? html` -
    NFT hash
    - - `: ''} + ` : ''} + ${finalAmount ? html` +
    +
    Amount
    +

    ${formatAmount(finalAmount)}

    -
    - ${subTransactions?.length ? html` -
    -
    -

    Sub Transactions

    -

    These are Off-chain transactions that are triggered by above transaction

    -
    -
      ${renderedSubTransactions}
    -
    - `: ''} + ` : ''}
    - `); - getRef("page_title").textContent = "Transaction"; - } catch (e) { - console.error(e) - renderElem(getRef("page_container"), html`${render.errorPage(e)}`); - } - }) +
    +
    FLO Data
    +

    ${floData}

    +
    Block
    + ${finalBlock} +
    Block Confirmations
    +

    ${confirmations}

    + ${nftHash ? html` +
    NFT hash
    + + ` : ''} +
    +
    + ${subTransactions?.length ? html` +
    +
    +

    Sub Transactions

    +

    These are Off-chain transactions that are triggered by above transaction

    +
    +
      ${renderedSubTransactions}
    +
    + ` : ''} +
    + `); + + getRef("page_title").textContent = "Transaction"; + } catch (e) { + console.error("๐Ÿ’ฅ Exception in route:", e); + renderElem(getRef("page_container"), html`${render.errorPage(e)}`); + } +}); + + + + + + router.addRoute('404', state => { renderElem(getRef("page_container"), html`${render.errorPage('404 Not Found')}`); }) @@ -2010,79 +2250,169 @@ return str.replace(/ /g, "-"); } - function renderTransactions(transactions = []) { - let parsedTxs = parseTransactions(transactions); - let groupedTxs = new Map(); +function renderTransactions(transactions = []) { + console.log("๐Ÿ’ก Raw token transactions (input):", transactions); - parsedTxs.forEach((tx) => { - const { hash, transactionTrigger } = tx; - const key = hash || transactionTrigger; + // โœ… Step 1: Merge nested fields and apply fallbacks + const mergedTxs = transactions.map((tx, i) => { + const merged = { + ...(tx.transactionDetails || {}), + ...(tx.parsedFloData || {}), + ...tx + }; - if (!groupedTxs.has(key)) { - groupedTxs.set(key, { - sourceTransaction: {}, - offChainTransactions: [], - type: transactionTrigger ? 'compoundTransaction' : undefined, - }); - } - - if (hash) { - groupedTxs.get(key).sourceTransaction = tx; - } else { - const { tokenIdentification, senderAddress, receiverAddress, onChain, tokenAmount, time, contractName } = tx; - groupedTxs.get(key).offChainTransactions.push({ - tokenIdentification, - receiverAddress, - tokenAmount, - }); - if (time) - groupedTxs.get(key).sourceTransaction.time = time - if (contractName) - groupedTxs.get(key).sourceTransaction.contractName = contractName - if (senderAddress) - groupedTxs.get(key).sourceTransaction.contractAddress = senderAddress - } - }); - - // Convert the Map to an array of values for sorting - const sortedTxs = [...groupedTxs.values()].sort((a, b) => b.sourceTransaction.time - a.sourceTransaction.time); - - // Replace parsedTxs with sortedTxs - parsedTxs = sortedTxs.map((tx) => { - if (tx.type === 'compoundTransaction') { - return { - ...tx.sourceTransaction, - offChainTransactions: tx.offChainTransactions, - type: tx.type, - }; - } - return tx.sourceTransaction; - }); - const renderedTransactions = parsedTxs.map(tx => { - switch (tx.type) { - case 'tokentransfer': - case 'nfttransfer': - return render.tokenTransferCard(tx) - case 'contractdeposit': - return render.contractDepositCard(tx) - case 'contracttransfer': - return render.contractTransferCard(tx); - case 'tokenincorp': - case 'nftincorp': - return render.tokenCreationCard(tx); - case 'contractincorp': - return render.contractCreationCard(tx); - case 'contracttrigger': - return render.contractTriggerCard(tx); - case 'offChainTransfer': - return render.offChainTransferCard(tx); - case 'compoundTransaction': - return render.compoundTransactionCard(tx) - } - }) - return html`${renderedTransactions.length ? renderedTransactions : html`
    No transactions found
    `}` + if (merged.onChain === undefined) { + merged.onChain = true; + console.log(`๐Ÿฉน TX #${i}: Defaulted onChain to true`); } + if (!merged.transactionTrigger && ( + merged.contractName || (merged.floData || "").includes('@') + )) { + merged.transactionTrigger = merged.txid || merged.hash; + console.log(`๐Ÿงท TX #${i}: Injected transactionTrigger = ${merged.transactionTrigger}`); + } + + console.log(`๐Ÿ”€ TX #${i} after merge:`, merged); + return merged; + }); + + console.log("๐Ÿ”ง Merged Transactions (post-merge):", mergedTxs); + + // โœ… Step 2: Parse + let parsedTxs = parseTransactions(mergedTxs); + console.log("๐Ÿงฉ Parsed Transactions (from parser):", parsedTxs); + + // โœ… Step 3: Grouping + let groupedTxs = new Map(); + + parsedTxs.forEach((tx, i) => { + console.log(`๐Ÿ“ฆ Grouping TX #${i}:`, tx); + const { hash, transactionTrigger, type } = tx; + const key = hash || transactionTrigger; + + if (!groupedTxs.has(key)) { + groupedTxs.set(key, { + sourceTransaction: undefined, + offChainTransactions: [], + }); + console.log(`๐Ÿ“Œ Created new group for key: ${key}`); + } + + const group = groupedTxs.get(key); + + if (hash || (type === 'trigger' && !tx.onChain)) { + group.sourceTransaction = tx; + console.log(`๐Ÿ“Œ Set sourceTransaction for group ${key}:`, tx); + } else if (type?.includes('tokenswap') || type === 'offChainTransfer') { + group.offChainTransactions.push(tx); + console.log(`๐Ÿ“Œ Added to offChainTransactions for group ${key}:`, tx); + + if (!group.sourceTransaction) group.sourceTransaction = {}; + if (!group.sourceTransaction.time && tx.time) + group.sourceTransaction.time = tx.time; + if (!group.sourceTransaction.contractName && tx.contractName) + group.sourceTransaction.contractName = tx.contractName; + if (!group.sourceTransaction.contractAddress && tx.senderAddress) + group.sourceTransaction.contractAddress = tx.senderAddress; + } else { + group.sourceTransaction = tx; + console.log(`๐Ÿ“Œ Set default sourceTransaction for group ${key}:`, tx); + } + }); + + // โœ… Step 3.5: Ensure fallback sourceTransaction + for (const [key, group] of groupedTxs.entries()) { + if (!group.sourceTransaction && group.offChainTransactions.length) { + group.sourceTransaction = group.offChainTransactions[0]; + console.log(`๐Ÿ”ง Fallback sourceTransaction assigned for group ${key}`); + } + } + + // โœ… Step 4: Flatten + sort + const sortedTxs = [...groupedTxs.values()].sort((a, b) => + (b.sourceTransaction?.time || 0) - (a.sourceTransaction?.time || 0) + ); + console.log("๐Ÿ“Š Sorted Transactions:", sortedTxs); + + parsedTxs = []; + + sortedTxs.forEach((group, i) => { + const { sourceTransaction, offChainTransactions } = group; + + if (offChainTransactions.length) { + console.log(`๐Ÿงฌ TX Group #${i} is compound:`, sourceTransaction); + parsedTxs.push({ + ...sourceTransaction, + offChainTransactions, + type: 'compoundTransaction', + }); + + if (['trigger', 'contracttrigger'].includes(sourceTransaction?.type)) { + const triggerCard = { + ...sourceTransaction, + type: 'trigger', + }; + + if (!triggerCard.hash && triggerCard.transactionTrigger) { + triggerCard.hash = triggerCard.transactionTrigger; + console.log(`๐Ÿ”– TX Group #${i}: Fallback hash set for trigger = ${triggerCard.hash}`); + } + + parsedTxs.push(triggerCard); + } + } else if (sourceTransaction) { + console.log(`โœ… TX Group #${i} has source only:`, sourceTransaction); + parsedTxs.push(sourceTransaction); + } else { + console.warn(`โ— TX Group #${i} has no sourceTransaction and was skipped`); + } + }); + + console.log("๐Ÿงฑ Final transactions for rendering (flattened):", parsedTxs); + + // โœ… Step 5: Rendering + const renderedTransactions = parsedTxs.map((tx, i) => { + console.log(`๐ŸŽจ Rendering TX #${i} of type '${tx.type}':`, tx); + switch (tx.type) { + case 'tokentransfer': + case 'nfttransfer': + return render.tokenTransferCard(tx); + case 'contractdeposit': + return render.contractDepositCard(tx); + case 'contracttransfer': + return render.contractTransferCard(tx); + case 'tokenincorp': + case 'nftincorp': + return render.tokenCreationCard(tx); + case 'contractincorp': + return render.contractCreationCard(tx); + case 'trigger': + return render.contractTriggerCard(tx); + case 'offChainTransfer': + return render.offChainTransferCard(tx); + case 'compoundTransaction': + return render.compoundTransactionCard(tx); + default: + console.warn(`โš ๏ธ Unrecognized transaction type '${tx.type}'`, tx); + return html`
    Unknown transaction
    `; + } + }); + + console.log("๐Ÿ“‹ Final rendered HTML cards:", renderedTransactions); + + return html`${renderedTransactions.length + ? renderedTransactions + : html`
    No transactions found
    `}`; +} + + + + + + + + getRef('suggestions').addEventListener('keyup', e => { if (e.target.closest('.suggestion') && e.key === 'Enter') { processNavbarSearch() @@ -2102,13 +2432,23 @@ renderElem(getRef('suggestions'), html`${renderedSuggestions}`) }, 100)) async function getBannerData() { - const { systemTransactionCount, systemAddressCount } = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/info`) - return { - topToken: "RUPEE", - totalTransactions: systemTransactionCount, - walletAddresses: systemAddressCount, + try { + console.log("๐Ÿ“ก Fetching banner data from /api/v2/info..."); + const { systemTransactionCount, systemAddressCount } = + await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/info`); + console.log("โœ… Banner data received:", { systemTransactionCount, systemAddressCount }); + + return { + topToken: "RUPEE", + totalTransactions: systemTransactionCount, + walletAddresses: systemAddressCount, + }; + } catch (err) { + console.error("โŒ Failed to fetch banner data:", err); + throw err; } } + let currentViewIndex = 0; function changeView(e) { const targetWrapper = e.target.dataset.target; @@ -2118,355 +2458,624 @@ } function getLatestTxs() { + console.log("๐Ÿ“ก Fetching latest transactions..."); return new Promise((resolve, reject) => { fetchJson(`${floGlobals.tokenApiUrl}/api/v2/latestTransactionDetails?limit=4`) .then(function (latestTxs) { - resolve(latestTxs.latestTransactions) - }).catch((err) => { - reject(err) + console.log("โœ… Latest transactions received:", latestTxs); + resolve(latestTxs.latestTransactions); + }) + .catch((err) => { + console.error("โŒ Failed to fetch latest transactions:", err); + reject(err); }); - }) + }); } + function getTokenInfo(thisToken) { + console.log(`๐Ÿ“ก Fetching token info for: ${thisToken}`); return new Promise((resolve, reject) => { - fetchJson( - `${floGlobals.tokenApiUrl}/api/v2/tokenInfo/${thisToken.toLowerCase()}` - ).then(function (tokenInfo) { - if (tokenInfo.result === "error") - reject(tokenInfo.description); - let associatedSC = {}; - tokenInfo.associatedSmartContracts.forEach((sc) => { - associatedSC[`${sc.contractName}-${sc.contractAddress}`] = sc; + fetchJson(`${floGlobals.tokenApiUrl}/api/v2/tokenInfo/${thisToken.toLowerCase()}`) + .then(function (tokenInfo) { + console.log("โœ… Token info received:", tokenInfo); + if (tokenInfo.result === "error") { + console.error("โŒ Token info error:", tokenInfo.description); + reject(tokenInfo.description); + return; + } + let associatedSC = {}; + tokenInfo.associatedSmartContracts.forEach((sc) => { + associatedSC[`${sc.contractName}_${sc.contractAddress}`] = sc; + }); + resolve({ + token: tokenInfo["token"], + supply: tokenInfo["tokenSupply"], + incAddress: tokenInfo["incorporationAddress"], + associatedContracts: associatedSC, + blockchainReference: tokenInfo["blockchainReference"], + }); + }) + .catch((err) => { + console.error("โŒ Failed to fetch token info:", err); + reject(err); }); - resolve({ - token: tokenInfo["token"], - supply: tokenInfo["tokenSupply"], - incAddress: tokenInfo["incorporationAddress"], - associatedContracts: associatedSC, - blockchainReference: tokenInfo["blockchainReference"], - }); - }).catch((err) => { - reject(err); - }); - }) + }); } + async function getTokenBalances(tokenName) { - const tokenDetails = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/tokenBalances/` + tokenName) - return tokenDetails.balances + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/tokenBalances/${tokenName}`; + console.log(`๐Ÿ“ก Fetching token balances from: ${url}`); + const tokenDetails = await fetchJson(url); + console.log("๐Ÿ“ฆ Token balances fetched:", tokenDetails); + return tokenDetails.balances; + } catch (error) { + console.error("โŒ Error fetching token balances:", error); + return []; + } } async function getTokenTransactions(tokenName) { - const transactions = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/tokenTransactions/` + tokenName) - return transactions.transactions + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/tokenTransactions/${tokenName}`; + console.log(`๐Ÿ“ก Fetching token transactions from: ${url}`); + const transactions = await fetchJson(url); + console.log("๐Ÿ“ฆ Token transactions fetched:", transactions); + return transactions.transactions; + } catch (error) { + console.error("โŒ Error fetching token transactions:", error); + return []; + } } + async function getBlockInfo(thisBlock) { - const info = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/blockDetails/${thisBlock}`); - const { height, size, reward, hash, difficulty, nonce, tx } = info.blockDetails - return { - blockHeight: height, - size: size, - transactions: tx, - reward: reward, - hash: hash, - difficulty: difficulty, - nonce: nonce, + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/blockDetails/${thisBlock}`; + console.log(`๐Ÿ“ก Fetching block info from: ${url}`); + const info = await fetchJson(url); + console.log("๐Ÿ“ฆ Block info fetched:", info); + + const { height, size, reward, hash, difficulty, nonce, tx } = info.blockDetails || {}; + + return { + blockHeight: height, + size: size, + transactions: tx, + reward: reward, + hash: hash, + difficulty: difficulty, + nonce: nonce, + }; + } catch (error) { + console.error("โŒ Error fetching block info:", error); + return null; } } async function getBlockTransactions(thisBlock) { - const blockTransactions = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/blockTransactions/${thisBlock}`) - return blockTransactions.transactions + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/blockTransactions/${thisBlock}`; + console.log(`๐Ÿ“ก Fetching block transactions from: ${url}`); + const blockTransactions = await fetchJson(url); + console.log("๐Ÿ“ฆ Block transactions fetched:", blockTransactions); + return blockTransactions.transactions || []; + } catch (error) { + console.error("โŒ Error fetching block transactions:", error); + return []; + } } async function getContractInfo(contract) { - const info = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/smartContractInfo?contractName=${contract.name}&contractAddress=${contract.address}`); - const { - contractInfo: { + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/smartContractInfo?contractName=${contract.name}&contractAddress=${contract.address}`; + console.log(`๐Ÿ“ก Fetching smart contract info from: ${url}`); + const info = await fetchJson(url); + console.log("๐Ÿ“ฆ Smart contract info fetched:", info); + + const { + contractInfo: { + contractType, + numberOfDeposits, + numberOfParticipants, + priceType, + oracle_address, + contractSubtype, + status, + expiryTime, + payeeAddress, + userChoices, + tokenIdentification, + acceptingToken, + sellingToken, + contractAmount, + minimumsubscriptionamount, + maximumsubscriptionamount, + totalHonorAmount, + totalParticipationAmount, + price, + currentDepositBalance + }, + contractAddress, + contractName + } = info; + + const details = { + contract: contractName, + contractAddress, contractType, + contractSubtype, + status, + expiration: expiryTime, + payeeAddress, + userChoices, + token: tokenIdentification, + acceptingToken, + sellingToken, + participationFees: contractAmount, + minAmount: minimumsubscriptionamount, + maxAmount: maximumsubscriptionamount, numberOfDeposits, numberOfParticipants, priceType, oracle_address, - contractSubtype, - status, - expiryTime, - payeeAddress, - userChoices, - tokenIdentification, - acceptingToken, - sellingToken, - contractAmount, - minimumsubscriptionamount, - maximumsubscriptionamount, totalHonorAmount, totalParticipationAmount, price, currentDepositBalance - }, contractAddress, - contractName - } = info - const details = { - contract: contractName, - contractAddress, - contractType, - contractSubtype, - status, - expiration: expiryTime, - payeeAddress, - userChoices, - token: tokenIdentification, - acceptingToken, - sellingToken, - participationFees: contractAmount, - minAmount: minimumsubscriptionamount, - maxAmount: maximumsubscriptionamount, - numberOfDeposits, - numberOfParticipants, - priceType, - oracle_address, - totalHonorAmount, - totalParticipationAmount, - price, - currentDepositBalance + }; + + const key = `${contractName}_${contractAddress}`; + console.log(`๐Ÿง  Caching contract info under key: ${key}`); + floGlobals.smartContractList[key] = { + ...details, + ...floGlobals.smartContractList[key] + }; + + return details; + } catch (error) { + console.error("โŒ Error fetching smart contract info:", error); + return null; } - floGlobals.smartContractList[`${contractName}-${contractAddress}`] = { - ...details, - ...floGlobals.smartContractList[`${contractName}-${contractAddress}`] - } - return details } + async function getContractParticipants(contract) { - const participants = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/smartContractParticipants?contractName=${contract.name}&contractAddress=${contract.address}`) - return participants.participantInfo + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/smartContractParticipants?contractName=${contract.name}&contractAddress=${contract.address}`; + console.log(`๐Ÿ“ก Fetching contract participants from: ${url}`); + const participants = await fetchJson(url); + console.log("๐Ÿ“ฆ Participants response:", participants); + return participants.participantInfo || []; + } catch (error) { + console.error("โŒ Error fetching contract participants:", error); + return []; + } } async function getContractTransactions(contract) { - const transactions = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/smartContractTransactions?contractName=${contract.name}&contractAddress=${contract.address}`) - return transactions.contractTransactions + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/smartContractTransactions?contractName=${contract.name}&contractAddress=${contract.address}`; + console.log(`๐Ÿ“ก Fetching contract transactions from: ${url}`); + const transactions = await fetchJson(url); + console.log("๐Ÿ“ฆ Transactions response:", transactions); + return transactions.contractTransactions || []; + } catch (error) { + console.error("โŒ Error fetching contract transactions:", error); + return []; + } } async function getContractDeposits(contract) { - const deposits = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/smartContractDeposits?contractName=${contract.name}&contractAddress=${contract.address}`) - return deposits.depositInfo + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/smartContractDeposits?contractName=${contract.name}&contractAddress=${contract.address}`; + console.log(`๐Ÿ“ก Fetching contract deposits from: ${url}`); + const deposits = await fetchJson(url); + console.log("๐Ÿ“ฆ Deposits response:", deposits); + return deposits.depositInfo || []; + } catch (error) { + console.error("โŒ Error fetching contract deposits:", error); + return []; + } } + function getReceiver(vin, vout) { return vout.find(output => output.scriptPubKey.addresses.find(address => address !== vin[0].addr))?.scriptPubKey.addresses[0] || vin[0].addr } - function parseTransactions(txList) { - if (!Array.isArray(txList)) - txList = [txList] - let latestTxArray = []; - txList.forEach(tx => { - const { - txid, blockHeight, vin, vout, time, receiverAddress, senderAddress, contractAddress, contractType, - contractConditions: { - expiryTime, accepting_token, selling_token, subtype, price, - participationAmount, minimumsubscriptionamount, maximumsubscriptionamount - } = {}, - contractAmount, type, tokenAmount, transferType, triggerCondition, userChoice, nftHash, depositAmount, - contractName, tokenIdentification, transactionTrigger, onChain - } = tx; - let obj = { - time - }; - if (txid) - obj["hash"] = txid; - if (blockHeight) - obj["blockHeight"] = blockHeight; - if (onChain) { - if (type === "smartContractPays") { - // transaction is a FLO Smart Contract Committee trigger - obj = Object.assign({}, obj, { - hash: txid, - blockHeight, - contractName, - contractAddress: receiverAddress, - winningChoice: triggerCondition, - committeeAddress: senderAddress, - type: 'contracttrigger' - }); - latestTxArray.push(obj); - } - else if (type === 'transfer') { - if (transferType == "token" || transferType == 'nft') { - obj = Object.assign({}, obj, { - sender: senderAddress, - receiver: receiverAddress, - amount: tokenAmount, - type: transferType == "token" ? "tokentransfer" : "nfttransfer", - token: tokenIdentification, - }); - latestTxArray.push(obj); - } else if (transferType == 'smartContract') { - // smart contract transfer - obj = Object.assign({}, obj, { - sender: senderAddress, - receiver: receiverAddress, - amount: tokenAmount, - contractName, - userChoice, - type: "contracttransfer", - token: tokenIdentification, - }); - latestTxArray.push(obj); - } - } else if (type === 'tokenIncorporation') { - // token incorporation - // smart contract incorporation - obj = Object.assign({}, obj, { - incAddress: senderAddress, - supply: tokenAmount, - type: "tokenincorp", - token: tokenIdentification, - }); - latestTxArray.push(obj); - } else if (type === 'smartContractIncorporation') { - // smart contract incorporation - // todo : add checks to determine obj for different types of smart contract incorporation - if (subtype == 'tokenswap') { - obj = Object.assign({}, obj, { - contractName, - incAddress: contractAddress, - contractType, - type: "contractincorp", - sellingToken: selling_token, - acceptingToken: accepting_token, - price, - }); - } else { - obj = Object.assign({}, obj, { - contractName, - incAddress: contractAddress, - contractType, - expiration: expiryTime, - participationFees: contractAmount, - availableChoices: "", - type: "contractincorp", - minAmount: minimumsubscriptionamount, - maxAmount: maximumsubscriptionamount, - token: tokenIdentification, - }); - } - latestTxArray.push(obj); - } else if (type === 'nftIncorporation') { - // nft incorporation - obj = Object.assign({}, obj, { - incAddress: senderAddress, - supply: tokenAmount, - type: "nftincorp", - nftHash, - token: tokenIdentification, - }); - latestTxArray.push(obj); - } else if (type === 'smartContractDeposit') { - // smart contract deposit - obj = Object.assign({}, obj, { - contractName, - contractAddress, - contractType, - amount: depositAmount, - type: "contractdeposit", - sender: senderAddress, - receiver: receiverAddress, - token: tokenIdentification, - }); - latestTxArray.push(obj); - } - } else { - obj = Object.assign({}, obj, { - transactionTrigger, - contractName, - contractAddress, - onChain: false, - type: 'offChainTransfer', - senderAddress, - receiverAddress, - tokenAmount, - tokenIdentification, - time - }); - latestTxArray.push(obj); - } - }) +const internalTransactionTypes = [ + "tokenswapDepositSettlement", + "tokenswapParticipationSettlement", + "smartContractDepositReturn", + "tokenswapRefund", + "smartContractPays" +]; - return latestTxArray; +function parseTransactions(txList) { + if (!Array.isArray(txList)) txList = [txList]; + + console.log("๐Ÿ’ก Raw input to parseTransactions:", txList); + let latestTxArray = []; + + txList.forEach((tx, index) => { + console.log(`๐Ÿ” Processing TX #${index}:`, tx); + + const { + txid, blockHeight, vin, vout, time, + receiverAddress, senderAddress, + contractAddress: rawContractAddress, contractType: rawContractType, + contractConditions: { + expiryTime, accepting_token, selling_token, subtype, price, + participationAmount, minimumsubscriptionamount, maximumsubscriptionamount + } = {}, + contractAmount, type, tokenAmount, transferType, + triggerCondition, userChoice, nftHash, depositAmount, + contractName, tokenIdentification, transactionTrigger, + onChain + } = tx; + + const contractAddress = rawContractAddress || receiverAddress || tx.contractAddress; + const contractType = rawContractType || tx.contractType; + + let obj = { time }; + if (txid) obj["hash"] = txid; + if (blockHeight) obj["blockHeight"] = blockHeight; + + console.log(`๐Ÿงช TX Type: ${type}, OnChain: ${onChain}, TXID: ${txid}`); + + if (type === "tokenswapParticipation") { + console.log("๐Ÿ”„ Handling tokenswapParticipation"); + obj = { + hash: txid, + sender: senderAddress, + receiver: receiverAddress, + amount: tokenAmount, + contractName, + userChoice, + type: "contracttransfer", + token: tokenIdentification, + transactionTrigger, + onChain: true, + time + }; + console.log("โœ… Parsed tokenswapParticipation:", obj); + latestTxArray.push(obj); + return; } - async function getAllBlocks(number) { - const allBlocks = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/latestBlockDetails${number ? `?limit=${number}` : ''}`) - return Object.values(allBlocks.latestBlocks).sort((a, b) => b.height - a.height) - } + if (!onChain) { + console.log("๐ŸŒ Off-chain transaction"); + if (internalTransactionTypes.includes(type) || type === 'trigger') { + console.log("๐Ÿ“ฉ Recognized internal or trigger off-chain TX"); - async function getAllTxs() { - const allTxs = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/latestTransactionDetails?limit=200`) - return allTxs.latestTransactions - } - - async function getAddressInfo(floAddress) { - const addressInfo = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/floAddressInfo/${floAddress}`) - return addressInfo.floAddressBalances - } - - async function getAddressTxs(floAddress) { - const transactions = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/floAddressTransactions/${floAddress}`) - return transactions.transactions - } - - async function getTxInfo(thisTx) { - try { - const transaction = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/transactionDetails/${thisTx}`) - console.log(transaction) - if (transaction.result === 'error') - return [false, transaction.description] - let { - floData, - tokenAmount, - tokenIdentification, - type, - nftHash, - blockheight, - vin, - vout, - confirmations, - transferType, + obj = { + hash: txid, + transactionTrigger: transactionTrigger || txid, + contractName, + contractAddress, + onChain: false, + type: 'offChainTransfer', senderAddress, receiverAddress, - txid, - onChain, - subTransactions, + tokenAmount, + tokenIdentification: tokenIdentification || accepting_token || 'unknown', time - } = transaction; - if (type == 'smartContractPays') { - tokenAmount = '-' - } - return [ - true, { - type: `${transferType || ''} ${type}`, - name: tokenIdentification, - blockHeight: blockheight, - amount: tokenAmount, - sender: senderAddress, - receiver: receiverAddress, - floData, - hash: txid, - confirmations, - nftHash, - onChain, - subTransactions, - time - } - ] + }; + console.log("โœ”๏ธ Parsed offChainTransfer:", obj); + latestTxArray.push(obj); + } else { + console.warn("โ›” Ignored off-chain TX:", tx); } - catch (err) { - throw err + return; + } + + if (type === "trigger") { + console.log("โšก Handling on-chain trigger"); + obj = { + hash: transactionTrigger || txid, + contractName, + contractAddress, + sender: senderAddress || contractAddress, + receiver: receiverAddress || contractAddress, + amount: tokenAmount, + type: "trigger", + token: tokenIdentification || accepting_token || 'unknown', + triggerCondition, + onChain: true, + time + }; + console.log("โšก Parsed on-chain trigger:", obj); + latestTxArray.push(obj); + return; + } + + if ((type === 'transfer' || type === 'participation') && transferType === 'smartContract') { + console.log("๐Ÿ” Handling smartContract transfer/participation"); + obj = { + hash: txid, + sender: senderAddress, + receiver: receiverAddress, + amount: tokenAmount, + contractName, + userChoice, + type: "contracttransfer", + token: tokenIdentification, + transactionTrigger, + time + }; + console.log("๐Ÿ” Parsed contracttransfer:", obj); + latestTxArray.push(obj); + return; + } + + if (type === 'transfer') { + console.log("๐Ÿ’ธ Handling regular token/nft transfer"); + if (transferType === "token" || transferType === 'nft') { + obj = { + hash: txid, + sender: senderAddress, + receiver: receiverAddress, + amount: tokenAmount, + type: transferType === "token" ? "tokentransfer" : "nfttransfer", + token: tokenIdentification, + time + }; + console.log("๐Ÿ’ธ Parsed token/nft transfer:", obj); + latestTxArray.push(obj); + return; + } else { + console.warn("๐Ÿšซ Unrecognized transferType:", transferType, "in TX:", tx); } } + if (type === 'tokenIncorporation') { + console.log("๐Ÿ“ฆ Handling token incorporation"); + obj = { + hash: txid, + incAddress: senderAddress, + supply: tokenAmount, + type: "tokenincorp", + token: tokenIdentification, + time + }; + console.log("๐Ÿ“ฆ Parsed tokenIncorporation:", obj); + latestTxArray.push(obj); + return; + } + + if (type === 'smartContractIncorporation' || type === 'incorporation') { + console.log("๐Ÿ—๏ธ Handling smart contract incorporation"); + if (subtype === 'tokenswap') { + obj = { + hash: txid, + contractName, + incAddress: contractAddress, + contractType, + type: "contractincorp", + sellingToken: selling_token, + acceptingToken: accepting_token, + price, + time + }; + } else { + obj = { + hash: txid, + contractName, + incAddress: contractAddress, + contractType, + expiration: expiryTime, + participationFees: contractAmount, + availableChoices: "", + type: "contractincorp", + minAmount: minimumsubscriptionamount, + maxAmount: maximumsubscriptionamount, + token: tokenIdentification, + time + }; + } + console.log("โœ… Parsed smartContractIncorporation:", obj); + latestTxArray.push(obj); + return; + } + + if (type === 'nftIncorporation') { + console.log("๐Ÿ–ผ๏ธ Handling NFT incorporation"); + obj = { + hash: txid, + incAddress: senderAddress, + supply: tokenAmount, + type: "nftincorp", + nftHash, + token: tokenIdentification, + time + }; + console.log("๐Ÿ–ผ๏ธ Parsed nftIncorporation:", obj); + latestTxArray.push(obj); + return; + } + + if (type === 'smartContractDeposit') { + console.log("๐Ÿช™ Handling smart contract deposit"); + obj = { + hash: txid, + contractName, + contractAddress, + contractType, + amount: typeof depositAmount !== "undefined" ? depositAmount : tokenAmount, + type: "contractdeposit", + sender: senderAddress, + receiver: receiverAddress, + token: tokenIdentification, + time + }; + console.log("๐Ÿช™ Parsed smartContractDeposit:", obj); + latestTxArray.push(obj); + return; + } + + console.warn("โ“ Unhandled TX type:", type, tx); + }); + + console.log("๐Ÿงฉ Final Parsed Transactions (types):", latestTxArray.map(t => t.type)); + console.log("๐Ÿงฉ Final Parsed Transactions (full):", latestTxArray); + return latestTxArray; +} + + + async function getAllBlocks(number) { + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/latestBlockDetails${number ? `?limit=${number}` : ''}`; + console.log(`๐Ÿ“ก Fetching latest blocks from: ${url}`); + const allBlocks = await fetchJson(url); + console.log("๐Ÿ“ฆ Fetched blocks:", allBlocks); + const blocks = Object.values(allBlocks.latestBlocks || {}).sort((a, b) => b.height - a.height); + return blocks; + } catch (error) { + console.error("โŒ Error fetching latest blocks:", error); + return []; + } + } + + + async function getAllTxs() { + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/latestTransactionDetails?limit=200`; + console.log(`๐Ÿ“ก Fetching latest transactions from: ${url}`); + const allTxs = await fetchJson(url); + console.log("๐Ÿ“ฆ Fetched transactions:", allTxs); + return allTxs.latestTransactions || []; + } catch (error) { + console.error("โŒ Error fetching latest transactions:", error); + return []; + } + } + + + async function getAddressInfo(floAddress) { + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/floAddressInfo/${floAddress}`; + console.log(`๐Ÿ“ก Fetching address info from: ${url}`); + const addressInfo = await fetchJson(url); + console.log("๐Ÿ“ฆ Address info response:", addressInfo); + return addressInfo; + } catch (error) { + console.error("โŒ Error fetching address info:", error); + return null; + } + } + + + + async function getAddressBalance(floAddress) { + try { + const url = `${floGlobals.floApiUrl}/api/v2/address/${floAddress}?details=basic`; + console.log(`๐Ÿ“ก Fetching address balance from: ${url}`); + const balance = await fetchJson(url); + console.log("๐Ÿ“ฆ Balance info:", balance); + return balance; + } catch (error) { + console.error("โŒ Error fetching address balance:", error); + return null; + } + } + + + + async function getAddressTxs(floAddress) { + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/floAddressTransactions/${floAddress}`; + console.log(`๐Ÿ“ก Fetching address transactions from: ${url}`); + const transactions = await fetchJson(url); + console.log("๐Ÿ“ฆ Address transactions:", transactions); + return transactions.transactions || []; + } catch (error) { + console.error("โŒ Error fetching address transactions:", error); + return []; + } + } + + + +async function getTxInfo(thisTx) { + try { + const url = `${floGlobals.tokenApiUrl}/api/v2/transactionDetails/${thisTx}`; + console.log(`๐Ÿ“ก Fetching transaction info from: ${url}`); + + const transaction = await fetchJson(url); + console.log("๐Ÿ“ฆ Transaction response:", transaction); + + if (transaction.result === 'error') + return [false, transaction.description]; + + // Extract all known fields safely + let { + floData, + tokenAmount, + tokenIdentification, + type, + nftHash, + blockheight, + vin, + vout, + confirmations, + transferType, + senderAddress, + receiverAddress, + txid, + onChain, + subTransactions, + time, + contractAddress, + contractName, + operation, + operationDetails + } = transaction; + + // Normalize amount for smart contract pays + if (type === 'smartContractPays') { + tokenAmount = '-'; + } + + return [ + true, + { + // Original and normalized values + txid, + hash: txid, // fallback for compatibility + type: transferType ? `${transferType.trim()} ${type.trim()}` : type.trim(), + name: tokenIdentification, + tokenAmount, + amount: tokenAmount, + blockheight, + blockHeight: blockheight, + confirmations, + sender: senderAddress, + senderAddress, + receiver: receiverAddress, + receiverAddress, + floData, + nftHash, + onChain, + subTransactions, + time, + + // โœ… Additional preserved fields + contractAddress, + contractName, + operation, + operationDetails + } + ]; + } catch (err) { + console.error("โŒ Error fetching transaction info:", err); + return [false, err.message || "Unknown error"]; + } +} + + + function returnHexNumber(s) { var regExp = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/; @@ -2482,89 +3091,134 @@ } function splitContractNameAddress(text) { - const index = text.lastIndexOf('-'); + const index = text.lastIndexOf('_'); return { name: text.substring(0, index), address: text.substring(index + 1) }; } - function categorizeText(text) { - return new Promise((resolve, reject) => { - // check if text have only numbers - if (/^\d+$/.test(text)) { - //console.log('this is a block number'); - location.href = `#/block/${text}` - resolve('block') - } else if (text.length == 34 && floCrypto.validateFloID(text)) { - //console.log('data entered is a FLO address'); - location.href = `#/address/${text}` - resolve('address') - } else if (floGlobals.tokenList.includes(text.toLowerCase())) { - //console.log('data entered is a token name'); - location.href = `#/token/${text}` - resolve('token') - } else if (floGlobals.smartContractList[text]) { - location.href = `#/contract/${text}` - resolve('contract') - } else if (text.length == 64 && returnHexNumber(text)) { - fetchJson(`${floGlobals.tokenApiUrl}/api/v2/categoriseString/` + text) - .then(function (myJson) { - console.log(`${floGlobals.tokenApiUrl}/api/v2/categoriseString/` + text) - if (myJson['type'] == 'transaction') { - //console.log('data entered is a transaction hash'); - location.href = `#/transaction/${text}` - } else if (myJson['type'] == 'block') { - // console.log('data entered is a block hash'); - location.href = `#/block/${text}` - } else { - renderElem(getRef("page_container"), html`${render.errorPage('The entered text is not a part of the token system')}`); - } - resolve() - }).catch(err => { - console.error(err) - resolve() - }) +function categorizeText(text) { + console.log("๐Ÿ” Categorizing input:", text); + return new Promise((resolve, reject) => { + // check if text has only numbers + if (/^\d+$/.test(text)) { + console.log("๐Ÿ“˜ Input detected as block number"); + location.href = `#/block/${text}`; + resolve('block'); + } else if (text.length === 34 && floCrypto.validateFloID(text)) { + console.log("๐Ÿ“˜ Input detected as valid FLO address"); + location.href = `#/address/${text}`; + resolve('address'); + } else if (floGlobals.tokenList.includes(text.toLowerCase())) { + console.log("๐Ÿ“˜ Input detected as token name"); + location.href = `#/token/${text}`; + resolve('token'); + } else if (floGlobals.smartContractList[text]) { + console.log("๐Ÿ“˜ Input detected as smart contract key"); + location.href = `#/contract/${text}`; + resolve('contract'); + } else if (text.length === 64 && returnHexNumber(text)) { + const url = `${floGlobals.tokenApiUrl}/api/v2/categoriseString/${text}`; + console.log("๐Ÿ“ก Fetching categorization from:", url); - } else { - renderElem(getRef("page_container"), html`${render.errorPage('Invalid search query')}`); - } - }) + fetchJson(url) + .then(function (myJson) { + console.log("โœ… Categorization result:", myJson); + const type = myJson['type']; + if (type === 'transaction') { + location.href = `#/transaction/${text}`; + } else if (type === 'block') { + location.href = `#/block/${text}`; +} else if (type === 'noise') { + console.warn("โš ๏ธ Categorized as noise โ€“ no match found."); + renderElem(getRef("page_container"), html` +
    + + + + + +

    Nothing found

    +

    + No transaction, block, token, or contract matched your input:
    + ${text} +

    + +
    + `); +} + + + else { + console.warn("โš ๏ธ Unknown categorization type:", type); + } + resolve(); // โœ… Ensure spinner clears + }) + .catch(err => { + console.error("โŒ Categorization fetch failed:", err); + resolve(); // โœ… Still resolve to clear spinner + }); + } else { + console.warn("โš ๏ธ Invalid search query format"); + renderElem(getRef("page_container"), html`${render.errorPage('Invalid search query')}`); + resolve(); // โœ… Added this resolve too } + }); +} + + + + +async function processNavbarSearch() { + const query = getRef('main_search_field').value.trim(); + try { + if (query === '') return; + loading(); // Start spinner + await getAllSuggestions(); + await categorizeText(query); + getRef('main_search_field').value = ''; + renderElem(getRef('suggestions'), html``); + } catch (err) { + console.error(err); + } finally { + loading(false); // โœ… Always stop spinner, even if error or "noise" + } +} + + + async function getAllSuggestions() { + console.log(`๐Ÿ“ก Fetching token and smart contract list from ${floGlobals.tokenApiUrl}/api/v2/tokenSmartContractList`); + window.allSuggestions = []; - async function processNavbarSearch() { - const query = getRef('main_search_field').value.trim(); try { - if (query === '') return - loading() - await getAllSuggestions(); - await categorizeText(query) - getRef('main_search_field').value = '' - renderElem(getRef('suggestions'), html``) + let { tokens, smartContracts } = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/tokenSmartContractList`); + console.log("โœ… Token & Smart Contract list received:", { tokensCount: tokens.length, smartContractsCount: smartContracts.length }); + + floGlobals.tokenList = tokens; + floGlobals.smartContractList = {}; + smartContracts.forEach(contract => { + floGlobals.smartContractList[`${contract.contractName}_${contract.contractAddress}`] = contract; + allSuggestions.push(`${contract.contractName}_${contract.contractAddress}`); + }); + allSuggestions = allSuggestions.concat(tokens); + + window.flexSearchIndex = new FlexSearch.Index({ + tokenize: "reverse", + suggest: true + }); + + allSuggestions.forEach((suggestion, index) => { + flexSearchIndex.add(index, suggestion); + }); + + console.log("๐Ÿ” Search suggestions initialized with", allSuggestions.length, "items"); } catch (err) { - console.error(err) + console.error("โŒ Failed to fetch suggestions:", err); + throw err; } } - async function getAllSuggestions() { - window.allSuggestions = []; - let { tokens, smartContracts } = await fetchJson(`${floGlobals.tokenApiUrl}/api/v2/tokenSmartContractList`); - floGlobals.tokenList = tokens; - floGlobals.smartContractList = {} - smartContracts.forEach(contract => { - floGlobals.smartContractList[`${contract.contractName}-${contract.contractAddress}`] = contract; - allSuggestions.push(`${contract.contractName}-${contract.contractAddress}`); - }) - allSuggestions = allSuggestions.concat(tokens); - window.flexSearchIndex = new FlexSearch.Index({ - tokenize: "reverse", - suggest: true - }); - - allSuggestions.forEach((suggestion, index) => { - flexSearchIndex.add(index, suggestion); - }) - } function initSmartContractCreation() { const [selectedSCTemplate, setSelectedSCTemplate] = $signal(null); @@ -2961,7 +3615,7 @@ description = html`

    You have participated in ${contractName} with ${participationAmount} ${tokenIdentification}

    - Check your participation + Check your participation
    ` break @@ -2973,7 +3627,7 @@ description = html`

    You have casted your vote for ${userChoice} in ${contractName} with ${participationAmount} ${tokenIdentification}

    - Check your vote + Check your vote
    ` break @@ -2988,7 +3642,7 @@ description = html`

    You have initiated a token swap in ${contractName} with ${participationAmount} ${acceptingToken}

    - Check swap status + Check swap status
    ` break; @@ -3094,7 +3748,7 @@ return notify(`You already have a smart contract with this address. Only one smart contract is allowed per address.`, 'error') let floData let confirmationMessage = '' - if (floGlobals.smartContractList.hasOwnProperty(`${contractName}-${creatorAddress}`)) + if (floGlobals.smartContractList.hasOwnProperty(`${contractName}_${creatorAddress}`)) return notify(`Contract with name: ${contractName} and address: ${creatorAddress} already exists`, 'error') switch (type) { case 'one-time-event': @@ -3297,4 +3951,4 @@ - \ No newline at end of file +