diff --git a/index.html b/index.html index a58e575..9fcf521 100644 --- a/index.html +++ b/index.html @@ -1,250 +1,342 @@ - - - - + + + Binance Smart Chain - - - + + + - + href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap" + rel="stylesheet" + /> + - + -

-

-
- - -
+

+

+
+ + +
-
- - - -
- -
+ .st6 { + fill: #f6851b; + stroke: #f6851b; + } + + + + + + + + + + + + + + + +
Disconnected
+ + + + +
- -
+ +
- + - - + + - + renderSearchedAddressList(); + } + function renderError(title, description) { + if (!title) title = "MetaMask not installed"; + if (!description) description = ""; + renderElem( + getRef("page_container"), + html` +
+ + + + + + + + + + + + + + + +

${title}

+

${description}

+
+ ` + ); + } + function renderSearchedAddressList() { + compactIDB + .readAllData("contacts") + .then((contacts) => { + if (!getRef("searched_addresses_list")) return; + if (Object.keys(contacts).length === 0) { + renderElem( + getRef("searched_addresses_list"), + html`
  • +

    + Your searched addresses will appear here for easier access + in future. +

    +
  • ` + ); + return; + } + const renderedContacts = []; + for (const floAddress in contacts) { + const { BSCAddress } = contacts[floAddress]; + renderedContacts.push(html`
  • + ${floAddress === BSCAddress + ? html`` + : html` + + (e.target + .closest(".contact") + .querySelector("sm-copy").value = e.target.value)} + > + FLO + BSC + + `} + +
    + + +
    +
  • `); + } + renderElem( + getRef("searched_addresses_list"), + html`${renderedContacts}` + ); + }) + .catch((error) => { + console.error(error); + }); + } + function checkBalance(BSCAddress, floAddress) { + if (!BSCAddress) { + const keyToConvert = document + .querySelector("#check_balance_input") + .value.trim(); + if (bscOperator.isValidAddress(keyToConvert)) { + BSCAddress = keyToConvert; + } else { + if (/^[0-9a-fA-F]{64}$/.test(keyToConvert)) { + keyToConvert = coinjs.privkey2wif(keyToConvert); + } + const ethPrivateKey = coinjs.wif2privkey(keyToConvert).privkey; + BSCAddress = floEthereum.ethAddressFromPrivateKey(ethPrivateKey); + floAddress = floCrypto.getFloID(keyToConvert); + } + } + if (!BSCAddress) return; + buttonLoader("check_balance_button", true); + Promise.all([ + bscOperator.getBalance(BSCAddress), + bscOperator.getTokenBalance(BSCAddress, "usdc"), + bscOperator.getTokenBalance(BSCAddress, "usdt"), + ]) + .then(([BinanceBalance, usdcBalance, usdtBalance]) => { + compactIDB + .readData("contacts", floAddress || BSCAddress) + .then((result) => { + if (result) return; + compactIDB + .addData( + "contacts", + { + BSCAddress, + }, + floAddress || BSCAddress + ) + .then(() => { + renderSearchedAddressList(); + }) + .catch((error) => { + console.error(error); + }); + }); + renderElem( + getRef("BSC_balance_wrapper"), + html` +
    +
    BSC address
    + +
    + ${floAddress && floAddress !== BSCAddress + ? html` +
    +
    FLO address
    + +
    + ` + : ""} +
    +

    Balance

    + +
    + ` + ); + getRef("BSC_balance_wrapper").classList.remove("hidden"); + getRef("BSC_balance_wrapper").animate( + [ + { + transform: "translateY(-1rem)", + opacity: 0, + }, + { + transform: "none", + opacity: 1, + }, + ], + { + easing: "ease", + duration: 300, + fill: "forwards", + } + ); + }) + .catch((error) => { + notify(error, "error"); + }) + .finally(() => { + buttonLoader("check_balance_button", false); + }); + } + function handleInvalidSearch() { + if (document.startViewTransition) + document.startViewTransition(() => { + getRef("BSC_balance_wrapper").classList.add("hidden"); + }); + else { + getRef("BSC_balance_wrapper").classList.add("hidden"); + } + } + async function deleteContact(floAddress) { + const confirmed = await getConfirmation("Delete contact", { + message: "Are you sure you want to delete this contact?", + }); + if (!confirmed) return; + compactIDB + .removeData("contacts", floAddress) + .then(() => { + renderSearchedAddressList(); + }) + .catch((error) => { + console.error(error); + }); + } + + router.addRoute("send", (state) => { + getRef("page_container").dataset.page = "send"; + renderElem( + getRef("page_container"), + html` + +
    +
    +
    +

    Sender

    +

    + Amount will be deducted from equivalent Binance address +

    +
    + +
    + + + + + + + + + + +
    +
    +
    +

    Receiver

    +
    + +
    + +
    + + + + + + + + + + + + + + + + + +
    +
    + + Binance + USDC + USDT + +
    +
    +
    +
    + +
    +
    +
    + ` + ); + if ( + window.ethereum && + !(window.currentChainId && window.currentChainId === "0x1") + ) { + renderError("Please switch MetaMask to Binance Mainnet"); + } + }); + function togglePrivateKeyVisibility(input) { + const target = input.closest("sm-input"); + target.type = target.type === "password" ? "text" : "password"; + target.focusIn(); + } + function checkSenderBalance() { + let address; + const privateKey = getRef("private_key_input").value.trim(); + if (!privateKey) + return notify(`Please enter sender's private key to check balance`); + if ( + privateKey.startsWith("R") || + privateKey.startsWith("L") || + privateKey.startsWith("K") + ) { + address = floEthereum.ethAddressFromPrivateKey( + coinjs.wif2privkey(privateKey).privkey + ); + } else { + address = floEthereum.ethAddressFromPrivateKey(privateKey); + } + getRef("sender_balance_container").classList.remove("hidden"); + renderElem( + getRef("sender_balance_container"), + html` Loading balance... ` + ); + const promises = [bscOperator.getBalance(address)]; + const selectedAsset = getRef("asset_selector").value; + if (selectedAsset !== "Binance") + promises.push(bscOperator.getTokenBalance(address, selectedAsset)); + Promise.all(promises) + .then(([ethBalance, tokenBalance]) => { + renderElem( + getRef("sender_balance_container"), + html` +
    +
    +

    Sender address

    +

    ${address}

    +

    +
    +

    + Balance: + ${ethBalance} BSC + ${selectedAsset !== "Binance" + ? html`| + ${tokenBalance} ${selectedAsset.toUpperCase()}` + : ""} +

    +
    + ` + ); + }) + .catch((err) => { + notify(err, "error"); + }); + } + function handleSenderInput(e) { + getRef("check_balance_button").disabled = !e.target.isValid; + if (!e.target.isValid) { + getRef("sender_balance_container").classList.add("hidden"); + } + } + function handleAssetChange(e) { + const asset = e.target.value; + const amountInput = + getRef("send_tx_form").querySelector(".receiver-amount"); + amountInput.value = ""; + amountInput.setAttribute( + "error-text", + `Amount should be grater than 0.000001 ${asset.toUpperCase()}` + ); + document.querySelectorAll(".asset-symbol").forEach((elem) => { + elem.innerHTML = assetIcons[asset]; + }); + getRef("send_tx_button").textContent = `Send ${asset.toUpperCase()}`; + } + async function sendTx() { + const receiver = getRef("send_tx_form") + .querySelector(".receiver-address") + .value.trim(); + const amount = getRef("send_tx_form") + .querySelector(".receiver-amount") + .value.trim(); + const asset = getRef("asset_selector").value; + try { + const confirmation = await getConfirmation("Send transaction", { + message: `You are about to send ${amount} ${asset.toUpperCase()} to ${receiver}`, + confirmText: "Send", + }); + buttonLoader("send_tx_button", true); + if (!confirmation) return; + let privateKey = getRef("private_key_input").value.trim(); + if (/^[0-9a-fA-F]{64}$/.test(privateKey)) { + privateKey = coinjs.privkey2wif(privateKey); + } + privateKey = coinjs.wif2privkey(privateKey).privkey; + switch (asset) { + case "Binance": { + const tx = await bscOperator.sendTransaction({ + privateKey, + receiver, + amount, + }); + showTransactionResult("pending", { txHash: tx.hash }); + await tx.wait(); + showTransactionResult("confirmed", { txHash: tx.hash }); + break; + } + case "usdc": + case "usdt": { + const tx = await bscOperator.sendToken({ + privateKey, + receiver, + amount, + token: asset, + }); + showTransactionResult("pending", { txHash: tx.hash }); + await tx.wait(); + showTransactionResult("confirmed", { txHash: tx.hash }); + break; + } + } + getRef("send_tx_form").reset(); + getRef("sender_balance_container").classList.add("hidden"); + } catch (e) { + console.error(e.message); + const regex = /\(error=({.*?}),/; + const match = e.message.match(regex); + if (match && match[1]) { + const { code } = JSON.parse(match[1]); + if (code === -32000) + showTransactionResult("failed", { + description: `Insufficient ${asset.toUpperCase()} balance`, + }); + else { + showTransactionResult("failed", { description: e.message }); + } + } + } finally { + buttonLoader("send_tx_button", false); + } + } + function showTransactionResult(status, { txHash, description = "" }) { + switch (status) { + case "pending": + renderElem( + getRef("transaction_result_popup__content"), + html` + +
    + Transaction ID + +
    + Check transaction status + ` + ); + break; + case "confirmed": + renderElem( + getRef("transaction_result_popup__content"), + html` + + + + +
    +

    Transaction confirmed

    +

    Transaction has been confirmed on the blockchain.

    +
    +
    + Transaction ID + +
    + Check transaction status + ` + ); + break; + case "failed": + renderElem( + getRef("transaction_result_popup__content"), + html` + + + +
    +

    Transaction failed

    +

    ${description}

    +
    + ` + ); + break; + } + openPopup("transaction_result_popup"); + } + router.addRoute("create", (state) => { + getRef("page_container").dataset.page = "create"; + renderElem( + getRef("page_container"), + html` +
    +

    Don't have an Binance address? Create one

    + +
    +
    + ` + ); + }); + function generateNewID() { + const { floID, privKey } = floCrypto.generateNewID(); + const ethPrivateKey = coinjs.wif2privkey(privKey).privkey; + const BSCAddress = floEthereum.ethAddressFromPrivateKey(ethPrivateKey); + renderElem( + getRef("created_address_wrapper"), + html` + + ` + ); + } + + + diff --git a/index.min.html b/index.min.html index bc620fd..39a4335 100644 --- a/index.min.html +++ b/index.min.html @@ -1,4 +1,4 @@ - FLO Ethereum