/*
* 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;
});
}
}
}