/* * Copyright (C) 2022 - 2023 Partisia Blockchain Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ import { setTokenContractType, getTokenApi, getContractAddress, isConnected, setContractAddress, } from "./AppState"; import { connectMetaMaskWalletClick, connectMpcWalletClick, connectLedgerWalletClick, connectPrivateKeyWalletClick, validateLedgerConnectionClick, disconnectWalletClick, fetchAndDisplayMoreBalances, updateContractState, updateInteractionVisibility, } from "./WalletIntegration"; import { TokenV1Contract } from "./contract/TokenV1Contract"; import { TokenV2Contract } from "./contract/TokenV2Contract"; import { MpcTokenContract, MPC_TOKEN_CONTRACT_ADDRESS } from "./contract/MpcTokenContract"; import BN from "bn.js"; import { BlockchainAddress } from "@partisiablockchain/abi-client"; import { TransactionFailedError } from "../client/TransactionApi"; import { PutTransactionWasSuccessful } from "../client/TransactionData"; import { BROWSER_BASE_URL } from "../constant"; // Setup event listener to connect to the MPC wallet browser extension const connectWallet = document.querySelector("#wallet-connect-btn"); connectWallet.addEventListener("click", connectMpcWalletClick); // Setup event listener to connect to the MetaMask snap const metaMaskConnect = document.querySelector("#metamask-connect-btn"); metaMaskConnect.addEventListener("click", connectMetaMaskWalletClick); // Setup event listener to connect to the ledger snap const ledgerConnect = document.querySelector("#ledger-connect-btn"); ledgerConnect.addEventListener("click", connectLedgerWalletClick); const ledgerConnectValidate = document.querySelector("#connection-link-ledger-validate"); ledgerConnectValidate.addEventListener("click", validateLedgerConnectionClick); // Setup event listener to login using private key const pkConnect = document.querySelector("#private-key-connect-btn"); pkConnect.addEventListener("click", connectPrivateKeyWalletClick); // Setup event listener to drop the connection again const disconnectWallet = document.querySelector("#wallet-disconnect-btn"); disconnectWallet.addEventListener("click", disconnectWalletClick); // Setup event listener that sends a transfer transaction to the contract. // This requires that a wallet has been connected. const transferBtn = document.querySelector("#transfer-btn"); transferBtn.addEventListener("click", transferAction); const addressBtn = document.querySelector("#address-btn"); addressBtn.addEventListener("click", contractAddressClick); const updateStateBtn = document.querySelector("#update-state-btn"); updateStateBtn.addEventListener("click", updateContractState); const getBalanceBtn = document.querySelector("#get-balance-btn"); getBalanceBtn.addEventListener("click", getBalance); const loadMoreBtn = document.querySelector("#balances-load-more-btn"); loadMoreBtn.addEventListener("click", fetchAndDisplayMoreBalances); function setModeText(modeText: string) { let items = document.querySelectorAll("title"); items.forEach((item) => { item.innerText = modeText; }); items = document.querySelectorAll(".mode"); items.forEach((item) => { item.innerText = modeText; }); } function setTokenContractByGetMode() { const mode = window.location.search.substr(1); if (mode == "mpc20-v1") { setTokenContractType((client, transactionApi) => new TokenV1Contract(client, transactionApi)); setModeText("MPC20-V1"); const getBalanceForm = document.querySelector("#get-balance-form"); getBalanceForm.classList.add("hidden"); } else if (mode == "mpc20-v2") { setTokenContractType((client, transactionApi) => new TokenV2Contract(client, transactionApi)); setModeText("MPC20-V2"); } else if (mode == "mpc-token") { setTokenContractType((client, transactionApi) => new MpcTokenContract(client, transactionApi)); setContractAddressUI(MPC_TOKEN_CONTRACT_ADDRESS); setModeText("MPC Token"); } } // Setup token contract type setTokenContractByGetMode(); function setContractAddressUI(address: BlockchainAddress) { const currentAddress = document.querySelector("#current-address"); const inputAddress = document.querySelector("#address-value"); currentAddress.innerText = address.asString(); currentAddress.href = `${BROWSER_BASE_URL}/contracts/${address.asString()}`; inputAddress.value = address.asString(); setContractAddress(address); updateInteractionVisibility(); updateContractState(); } /** Function for the contract address form. * This is called when the user clicks on the connect to contract button. * It validates the address, and then gets the state for the contract. */ function contractAddressClick() { const address = (document.querySelector("#address-value")).value; const regex = /[0-9A-Fa-f]{42}/g; if (address === undefined) { throw new Error("Need to provide a contract address"); } else if (address.length != 42 || address.match(regex) == null) { // Validate that address is 21 bytes in hexidecimal format throw new Error(`${address} is not a valid PBC address`); } setContractAddressUI(BlockchainAddress.fromString(address)); } const transactionErrorMessage = document.querySelector("#sign-transaction-error"); const transactionLinkElement = document.querySelector("#sign-transaction-link"); function setTransactionLink(transaction: PutTransactionWasSuccessful) { const transactionLinkElement = document.querySelector("#sign-transaction-link"); transactionLinkElement.innerHTML = `Transaction link in browser`; transactionErrorMessage.innerText = ""; } /** Action for the sign petition button */ function transferAction() { const api = getTokenApi(); const contractAddress = getContractAddress(); if (isConnected() && api !== undefined && contractAddress !== undefined) { const to = document.querySelector("#address-to"); const amount = document.querySelector("#amount"); const memo = document.querySelector("#memo"); transactionErrorMessage.innerHTML = '
'; transactionLinkElement.innerText = ""; api .transfer(contractAddress, BlockchainAddress.fromString(to.value), new BN(amount.value, 10), memo.value) .then(setTransactionLink) .catch((error) => { console.error(error); if (error instanceof TransactionFailedError) { setTransactionLink(error.putTransaction); } transactionErrorMessage.innerText = error; }); } } function getBalance() { const address = getContractAddress(); const regex = /[0-9A-Fa-f]{42}/g; const tokenAbi = getTokenApi(); if (address !== undefined && tokenAbi != undefined) { const balanceAddress = (document.querySelector("#get-balance-address")).value; if (balanceAddress.length != 42 || balanceAddress.match(regex) == null) { // Validate that address is 21 bytes in hexidecimal format console.error(`${address} is not a valid PBC address`); } else if (tokenAbi.tokenBalance != undefined) { const balanceValue = document.querySelector("#balance-value"); balanceValue.innerHTML = '
'; tokenAbi .tokenBalance(address, BlockchainAddress.fromString(balanceAddress)) .then((value) => { balanceValue.innerHTML = `
Value: ${value.toString(10)}`; }) .catch((error) => { console.error(error); balanceValue.innerText = error; }); } } }