Contractless-GUI-Wallet/frontend/js/create_token_form.js

172 lines
5.6 KiB
JavaScript

const CREATE_TOKEN_FEE_ATOMIC = 50000000000n;
const TOKEN_ATOMIC_UNITS = 100000000n;
function setCreateTokenMessage(message, type = "") {
setScopedTransactionMessage("Create Token", createTokenMessage, message, type);
}
function tokenDecimalToAtomic(value) {
const text = String(value || "").trim();
if (!/^\d+(\.\d{0,8})?$/.test(text)) {
return null;
}
const [whole, fraction = ""] = text.split(".");
const paddedFraction = fraction.padEnd(8, "0");
return BigInt(whole || "0") * TOKEN_ATOMIC_UNITS + BigInt(paddedFraction || "0");
}
function tokenAtomicToDecimal(value) {
const atomic = BigInt(value || 0);
const whole = atomic / TOKEN_ATOMIC_UNITS;
const fraction = String(atomic % TOKEN_ATOMIC_UNITS).padStart(8, "0");
return `${whole}.${fraction}`;
}
function updateCreateTokenDerivedFields() {
if (createTokenFeeInput) {
createTokenFeeInput.value = tokenAtomicToDecimal(CREATE_TOKEN_FEE_ATOMIC);
}
if (createTokenFeeLabel) {
createTokenFeeLabel.textContent = `${tokenAtomicToDecimal(CREATE_TOKEN_FEE_ATOMIC)} ${activeBaseCoin()}`;
}
if (createTokenCap) {
createTokenCap.textContent = createTokenAllowMoreInput?.checked ? "Future issuance allowed" : "Hard capped";
}
if (createTokenCreator) {
createTokenCreator.textContent = activeWalletAddressShort || activeWalletAddressHex || "--";
}
}
function validateCreateTokenForm() {
if (!walletLoaded) {
return "Load a wallet before creating a token.";
}
if (!registrationRegistered) {
return "Address registration is required before creating a token.";
}
const ticker = String(createTokenTickerInput?.value || "").trim();
if (!ticker) {
return "Token ticker is required.";
}
if (!/^[A-Za-z0-9\s]+$/.test(ticker)) {
return "Token ticker can only contain letters, numbers, and spaces.";
}
const canonicalTicker = ticker.replace(/\s+/g, "").toLowerCase();
if (canonicalTicker.length < 3 || canonicalTicker.length > 15) {
return "Token ticker must normalize to 3 to 15 letters or numbers.";
}
if (canonicalTicker.toUpperCase() === activeBaseCoin()) {
return "Token ticker is reserved for the base coin.";
}
const number = tokenDecimalToAtomic(createTokenNumberInput?.value);
if (number === null || number <= 0n) {
return "Enter a valid initial supply with up to 8 decimal places.";
}
return "";
}
function createTokenPayload() {
return {
ticker: String(createTokenTickerInput?.value || "").trim(),
number: String(tokenDecimalToAtomic(createTokenNumberInput?.value) || 0n),
allowMore: Boolean(createTokenAllowMoreInput?.checked),
txfee: String(CREATE_TOKEN_FEE_ATOMIC)
};
}
function clearCreateTokenForm() {
if (createTokenTickerInput) {
createTokenTickerInput.value = "";
}
if (createTokenNumberInput) {
createTokenNumberInput.value = "";
}
if (createTokenAllowMoreInput) {
createTokenAllowMoreInput.checked = false;
}
updateCreateTokenDerivedFields();
}
function setCreateTokenButtonsDisabled(disabled) {
document.querySelector("[data-create-token-save]")?.toggleAttribute("disabled", disabled);
document.querySelector("[data-create-token-broadcast]")?.toggleAttribute("disabled", disabled);
}
async function handleCreateTokenAction(action) {
const error = validateCreateTokenForm();
if (error) {
setCreateTokenMessage(error, "error");
return;
}
const invoke = window.__TAURI__?.core?.invoke;
if (!invoke) {
setCreateTokenMessage("Wallet bridge is not available.", "error");
return;
}
const walletKey = await requestSigningWalletKey();
if (guiRuntimeSettings.require_key_before_signing !== false && !walletKey) {
setCreateTokenMessage("Signing cancelled.");
return;
}
setCreateTokenButtonsDisabled(true);
try {
if (action === "save") {
setCreateTokenMessage("Saving token transaction...");
const review = await invoke("save_create_token_transaction", {
...createTokenPayload(),
walletKey
});
clearCreateTokenForm();
setCreateTokenMessage(`Token transaction saved: ${review.file_name}`, "success");
if (typeof refreshUnbroadcastTransactions === "function") {
refreshUnbroadcastTransactions();
}
} else {
const broadcastNode = activeBroadcastNode();
if (!broadcastNode) {
throw new Error("Select a broadcast node before broadcasting.");
}
setCreateTokenMessage("Broadcasting token transaction...");
const result = await invoke("broadcast_create_token_transaction", {
...createTokenPayload(),
broadcastNode,
walletKey
});
if (typeof invalidateAssetsCatalog === "function") {
invalidateAssetsCatalog();
}
clearCreateTokenForm();
setCreateTokenMessage(result.response || "Token transaction broadcast.", "success");
}
} catch (error) {
setCreateTokenMessage(String(error), "error");
} finally {
setCreateTokenButtonsDisabled(false);
}
}
function prepareCreateTokenForm() {
updateCreateTokenDerivedFields();
setCreateTokenMessage("");
}
createTokenTickerInput?.addEventListener("input", () => {
updateCreateTokenDerivedFields();
setCreateTokenMessage("");
});
createTokenNumberInput?.addEventListener("input", () => setCreateTokenMessage(""));
createTokenAllowMoreInput?.addEventListener("change", () => {
updateCreateTokenDerivedFields();
setCreateTokenMessage("");
});
document.querySelector("[data-create-token-save]")?.addEventListener("click", () => handleCreateTokenAction("save"));
document.querySelector("[data-create-token-broadcast]")?.addEventListener("click", () => handleCreateTokenAction("broadcast"));