const ISSUE_TOKEN_FEE_ATOMIC = 10000000000n; let issueTokenEligibility = null; let issueTokenLookupId = 0; function setIssueTokenMessage(message, type = "") { setScopedTransactionMessage("Issue More Tokens", issueTokenMessage, message, type); } function setIssueTokenButtonsDisabled(disabled) { document.querySelector("[data-issue-token-save]")?.toggleAttribute("disabled", disabled); document.querySelector("[data-issue-token-broadcast]")?.toggleAttribute("disabled", disabled); } function updateIssueTokenFee() { const displayFee = tokenAtomicToDecimal(ISSUE_TOKEN_FEE_ATOMIC); if (issueTokenFeeInput) { issueTokenFeeInput.value = displayFee; } if (issueTokenFeeLabel) { issueTokenFeeLabel.textContent = `${displayFee} ${activeBaseCoin()}`; } } function resetIssueTokenDetails() { issueTokenEligibility = null; if (issueTokenCreator) { issueTokenCreator.textContent = "--"; } if (issueTokenPolicy) { issueTokenPolicy.textContent = "--"; } setIssueTokenButtonsDisabled(true); } async function refreshIssueTokenEligibility() { const invoke = window.__TAURI__?.core?.invoke; const broadcastNode = activeBroadcastNode(); const walletAddress = activeWalletAddressShort || activeWalletAddressHex || ""; const ticker = String(issueTokenTickerSelect?.value || "").trim(); const lookupId = ++issueTokenLookupId; resetIssueTokenDetails(); if (!ticker || !invoke || !broadcastNode || !walletLoaded) { return; } setIssueTokenMessage("Checking token issuance policy..."); try { const details = await invokeWalletRpcWithBackoff( "Token details lookup", () => invoke("issue_token_details", { broadcastNode, ticker }), () => lookupId === issueTokenLookupId && walletLoaded && (activeWalletAddressShort || activeWalletAddressHex || "") === walletAddress && activeBroadcastNode() === broadcastNode && issueTokenTickerSelect?.value === ticker ); if (lookupId !== issueTokenLookupId) { return; } issueTokenEligibility = details; if (issueTokenCreator) { issueTokenCreator.textContent = details.creator || "--"; } if (issueTokenPolicy) { issueTokenPolicy.textContent = details.hard_limit ? "Hard capped" : "Future issuance allowed"; } if (!details.eligible) { setIssueTokenMessage( details.reason || "This token cannot be issued by the active wallet.", "error" ); return; } setIssueTokenMessage("The active wallet may issue more of this token.", "success"); setIssueTokenButtonsDisabled(false); } catch (error) { if (lookupId !== issueTokenLookupId) { return; } setIssueTokenMessage(String(error), "error"); } } async function refreshIssueTokenList() { issueTokenLookupId += 1; const invoke = window.__TAURI__?.core?.invoke; const broadcastNode = activeBroadcastNode(); const walletAddress = activeWalletAddressShort || activeWalletAddressHex || ""; resetIssueTokenDetails(); if (!issueTokenTickerSelect) { return; } issueTokenTickerSelect.innerHTML = ""; const loadingOption = document.createElement("option"); loadingOption.value = ""; loadingOption.textContent = "Loading tokens..."; issueTokenTickerSelect.appendChild(loadingOption); if (!invoke || !walletLoaded || !broadcastNode) { loadingOption.textContent = "Load a wallet and select a node"; return; } try { const tokens = await invokeWalletRpcWithBackoff( "Token list lookup", () => invoke("token_list", { broadcastNode }), () => walletLoaded && (activeWalletAddressShort || activeWalletAddressHex || "") === walletAddress && activeBroadcastNode() === broadcastNode ); if ( !walletLoaded || (activeWalletAddressShort || activeWalletAddressHex || "") !== walletAddress || activeBroadcastNode() !== broadcastNode ) { return; } issueTokenTickerSelect.innerHTML = ""; const tokenItems = Array.isArray(tokens) ? tokens : []; if (!tokenItems.length) { const option = document.createElement("option"); option.value = ""; option.textContent = "No tokens exist"; issueTokenTickerSelect.appendChild(option); setIssueTokenMessage("No tokens are available to issue.", "error"); return; } tokenItems.forEach((token) => { const ticker = String(token?.ticker || "").trim(); if (!ticker) { return; } const option = document.createElement("option"); option.value = ticker; option.textContent = ticker; issueTokenTickerSelect.appendChild(option); }); await refreshIssueTokenEligibility(); } catch (error) { issueTokenTickerSelect.innerHTML = ""; const option = document.createElement("option"); option.value = ""; option.textContent = "Token list unavailable"; issueTokenTickerSelect.appendChild(option); setIssueTokenMessage(String(error), "error"); } } function validateIssueTokenForm() { if (!walletLoaded) { return "Load a wallet before issuing tokens."; } if (!registrationRegistered) { return "Address registration is required before issuing tokens."; } if (!issueTokenEligibility?.eligible) { return issueTokenEligibility?.reason || "Select a token the active wallet may issue."; } const number = tokenDecimalToAtomic(issueTokenNumberInput?.value); if (number === null || number <= 0n) { return "Enter a valid additional supply with up to 8 decimal places."; } const baseCoin = activeBaseCoin(); const baseBalance = (Array.isArray(activeWalletBalances) ? activeWalletBalances : []).find( (balance) => String(balance.asset || "").trim().toUpperCase() === baseCoin && !Number(balance.nft_series || 0) ); if (baseBalance && balanceAtomicValue(baseBalance) < ISSUE_TOKEN_FEE_ATOMIC) { return `This transaction requires ${tokenAtomicToDecimal(ISSUE_TOKEN_FEE_ATOMIC)} ${baseCoin}.`; } return ""; } function issueTokenPayload() { return { broadcastNode: activeBroadcastNode(), ticker: String(issueTokenTickerSelect?.value || "").trim(), number: String(tokenDecimalToAtomic(issueTokenNumberInput?.value) || 0n), txfee: String(ISSUE_TOKEN_FEE_ATOMIC) }; } function clearIssueTokenForm() { if (issueTokenNumberInput) { issueTokenNumberInput.value = ""; } } async function handleIssueTokenAction(action) { const error = validateIssueTokenForm(); if (error) { setIssueTokenMessage(error, "error"); return; } const invoke = window.__TAURI__?.core?.invoke; if (!invoke) { setIssueTokenMessage("Wallet bridge is not available.", "error"); return; } const walletKey = await requestSigningWalletKey(); if (guiRuntimeSettings.require_key_before_signing !== false && !walletKey) { setIssueTokenMessage("Signing cancelled."); return; } setIssueTokenButtonsDisabled(true); try { if (action === "save") { setIssueTokenMessage("Saving issue-token transaction..."); const review = await invoke("save_issue_token_transaction", { ...issueTokenPayload(), walletKey }); clearIssueTokenForm(); setIssueTokenMessage(`Issue-token transaction saved: ${review.file_name}`, "success"); if (typeof refreshUnbroadcastTransactions === "function") { refreshUnbroadcastTransactions(); } } else { setIssueTokenMessage("Broadcasting issue-token transaction..."); const result = await invoke("broadcast_issue_token_transaction", { ...issueTokenPayload(), walletKey }); if (typeof invalidateAssetsCatalog === "function") { invalidateAssetsCatalog(); } clearIssueTokenForm(); setIssueTokenMessage(result.response || "Issue-token transaction broadcast.", "success"); } } catch (actionError) { setIssueTokenMessage(String(actionError), "error"); } finally { setIssueTokenButtonsDisabled(!issueTokenEligibility?.eligible); } } function prepareIssueTokenForm() { updateIssueTokenFee(); setIssueTokenMessage(""); refreshIssueTokenList(); } function resetIssueTokenSession() { issueTokenLookupId += 1; resetIssueTokenDetails(); if (issueTokenTickerSelect) { issueTokenTickerSelect.innerHTML = ''; } clearIssueTokenForm(); setIssueTokenMessage(""); } issueTokenTickerSelect?.addEventListener("change", refreshIssueTokenEligibility); issueTokenNumberInput?.addEventListener("input", () => { if (issueTokenEligibility?.eligible) { setIssueTokenMessage(""); } }); document .querySelector("[data-issue-token-save]") ?.addEventListener("click", () => handleIssueTokenAction("save")); document .querySelector("[data-issue-token-broadcast]") ?.addEventListener("click", () => handleIssueTokenAction("broadcast"));