206 lines
8.3 KiB
TypeScript
206 lines
8.3 KiB
TypeScript
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
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 = <Element>document.querySelector("#wallet-connect-btn");
|
|
connectWallet.addEventListener("click", connectMpcWalletClick);
|
|
|
|
// Setup event listener to connect to the MetaMask snap
|
|
const metaMaskConnect = <Element>document.querySelector("#metamask-connect-btn");
|
|
metaMaskConnect.addEventListener("click", connectMetaMaskWalletClick);
|
|
|
|
// Setup event listener to connect to the ledger snap
|
|
const ledgerConnect = <Element>document.querySelector("#ledger-connect-btn");
|
|
ledgerConnect.addEventListener("click", connectLedgerWalletClick);
|
|
|
|
const ledgerConnectValidate = <Element>document.querySelector("#connection-link-ledger-validate");
|
|
ledgerConnectValidate.addEventListener("click", validateLedgerConnectionClick);
|
|
|
|
// Setup event listener to login using private key
|
|
const pkConnect = <Element>document.querySelector("#private-key-connect-btn");
|
|
pkConnect.addEventListener("click", connectPrivateKeyWalletClick);
|
|
|
|
// Setup event listener to drop the connection again
|
|
const disconnectWallet = <Element>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 = <Element>document.querySelector("#transfer-btn");
|
|
transferBtn.addEventListener("click", transferAction);
|
|
|
|
const addressBtn = <Element>document.querySelector("#address-btn");
|
|
addressBtn.addEventListener("click", contractAddressClick);
|
|
|
|
const updateStateBtn = <Element>document.querySelector("#update-state-btn");
|
|
updateStateBtn.addEventListener("click", updateContractState);
|
|
|
|
const getBalanceBtn = <Element>document.querySelector("#get-balance-btn");
|
|
getBalanceBtn.addEventListener("click", getBalance);
|
|
|
|
const loadMoreBtn = <Element>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 = <HTMLElement>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 = <HTMLAnchorElement>document.querySelector("#current-address");
|
|
const inputAddress = <HTMLInputElement>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 = (<HTMLInputElement>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 = <HTMLInputElement>document.querySelector("#sign-transaction-error");
|
|
const transactionLinkElement = <HTMLInputElement>document.querySelector("#sign-transaction-link");
|
|
|
|
function setTransactionLink(transaction: PutTransactionWasSuccessful) {
|
|
const transactionLinkElement = <HTMLInputElement>document.querySelector("#sign-transaction-link");
|
|
transactionLinkElement.innerHTML = `<a href="${BROWSER_BASE_URL}/transactions/${transaction.transactionHash}" target="_blank">Transaction link in browser</a>`;
|
|
transactionErrorMessage.innerText = "";
|
|
}
|
|
|
|
/** Action for the sign petition button */
|
|
function transferAction() {
|
|
const api = getTokenApi();
|
|
const contractAddress = getContractAddress();
|
|
if (isConnected() && api !== undefined && contractAddress !== undefined) {
|
|
const to = <HTMLInputElement>document.querySelector("#address-to");
|
|
const amount = <HTMLInputElement>document.querySelector("#amount");
|
|
const memo = <HTMLInputElement>document.querySelector("#memo");
|
|
|
|
transactionErrorMessage.innerHTML = '<div class="loader"></div>';
|
|
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 = (<HTMLInputElement>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 = <HTMLInputElement>document.querySelector("#balance-value");
|
|
balanceValue.innerHTML = '<br><div class="loader"></div>';
|
|
tokenAbi
|
|
.tokenBalance(address, BlockchainAddress.fromString(balanceAddress))
|
|
.then((value) => {
|
|
balanceValue.innerHTML = `<br>Value: ${value.toString(10)}`;
|
|
})
|
|
.catch((error) => {
|
|
console.error(error);
|
|
balanceValue.innerText = error;
|
|
});
|
|
}
|
|
}
|
|
}
|