import type { NextPage } from "next";
import React, { useEffect, useRef, useState } from "react";
import Banner from "../components/Banner";
import Blockchain from "../components/Blockchain";
import Column from "../components/Column";
import Dropdown from "../components/Dropdown";
import Header from "../components/Header";
import Modal from "../components/Modal";
import {
DEFAULT_COSMOS_METHODS,
DEFAULT_EIP155_METHODS,
DEFAULT_MAIN_CHAINS,
DEFAULT_SOLANA_METHODS,
DEFAULT_POLKADOT_METHODS,
DEFAULT_MULTIVERSX_METHODS,
DEFAULT_TEST_CHAINS,
DEFAULT_NEAR_METHODS,
DEFAULT_TRON_METHODS,
DEFAULT_TEZOS_METHODS,
DEFAULT_EIP155_OPTIONAL_METHODS,
} from "../constants";
import { AccountAction, setLocaleStorageTestnetFlag } from "../helpers";
import Toggle from "../components/Toggle";
import RequestModal from "../modals/RequestModal";
import PairingModal from "../modals/PairingModal";
import PingModal from "../modals/PingModal";
import {
SAccounts,
SAccountsContainer,
SButtonContainer,
SConnectButton,
SContent,
SLanding,
SLayout,
SToggleContainer,
} from "../components/app";
import { useWalletConnectClient } from "../contexts/ClientContext";
import { useJsonRpc } from "../contexts/JsonRpcContext";
import { useChainData } from "../contexts/ChainDataContext";
// Normal import does not work here
const { version } = require("@walletconnect/sign-client/package.json");
const Home: NextPage = () => {
const [modal, setModal] = useState("");
const closeModal = () => setModal("");
const openPairingModal = () => setModal("pairing");
const openPingModal = () => setModal("ping");
const openRequestModal = () => setModal("request");
// Initialize the WalletConnect client.
const {
client,
pairings,
session,
connect,
disconnect,
chains,
relayerRegion,
accounts,
balances,
isFetchingBalances,
isInitializing,
setChains,
setRelayerRegion,
} = useWalletConnectClient();
// Use `JsonRpcContext` to provide us with relevant RPC methods and states.
const {
ping,
ethereumRpc,
cosmosRpc,
solanaRpc,
polkadotRpc,
nearRpc,
multiversxRpc,
tronRpc,
tezosRpc,
isRpcRequestPending,
rpcResult,
isTestnet,
setIsTestnet,
} = useJsonRpc();
const { chainData } = useChainData();
// Close the pairing modal after a session is established.
useEffect(() => {
if (session && modal === "pairing") {
closeModal();
}
}, [session, modal]);
const onConnect = () => {
if (typeof client === "undefined") {
throw new Error("WalletConnect is not initialized");
}
// Suggest existing pairings (if any).
if (pairings.length) {
openPairingModal();
} else {
// If no existing pairings are available, trigger `WalletConnectClient.connect`.
connect();
}
};
const onPing = async () => {
openPingModal();
await ping();
};
async function emit() {
if (typeof client === "undefined") {
throw new Error("WalletConnect is not initialized");
}
await client.emit({
topic: session?.topic || "",
event: { name: "chainChanged", data: {} },
chainId: "eip155:5",
});
}
const getEthereumActions = (): AccountAction[] => {
const actions = {
[DEFAULT_EIP155_METHODS.ETH_SEND_TRANSACTION]: {
method: DEFAULT_EIP155_METHODS.ETH_SEND_TRANSACTION,
callback: async (chainId: string, address: string) => {
openRequestModal();
await ethereumRpc.testSendTransaction(chainId, address);
},
},
[DEFAULT_EIP155_METHODS.PERSONAL_SIGN]: {
method: DEFAULT_EIP155_METHODS.PERSONAL_SIGN,
callback: async (chainId: string, address: string) => {
openRequestModal();
await ethereumRpc.testSignPersonalMessage(chainId, address);
},
},
[DEFAULT_EIP155_OPTIONAL_METHODS.ETH_SIGN_TRANSACTION]: {
method: DEFAULT_EIP155_OPTIONAL_METHODS.ETH_SIGN_TRANSACTION,
callback: async (chainId: string, address: string) => {
openRequestModal();
await ethereumRpc.testSignTransaction(chainId, address);
},
},
[DEFAULT_EIP155_OPTIONAL_METHODS.ETH_SIGN]: {
method: DEFAULT_EIP155_OPTIONAL_METHODS.ETH_SIGN + " (standard)",
callback: async (chainId: string, address: string) => {
openRequestModal();
await ethereumRpc.testEthSign(chainId, address);
},
},
[DEFAULT_EIP155_OPTIONAL_METHODS.ETH_SIGN_TYPED_DATA]: {
method: DEFAULT_EIP155_OPTIONAL_METHODS.ETH_SIGN_TYPED_DATA,
callback: async (chainId: string, address: string) => {
openRequestModal();
await ethereumRpc.testSignTypedData(chainId, address);
},
},
};
let availableActions: AccountAction[] = [];
session?.namespaces?.["eip155"].methods.forEach((methodName) => {
const action: AccountAction | undefined =
actions[methodName as keyof typeof actions];
if (action) {
availableActions.push(action);
}
});
return availableActions;
};
const getCosmosActions = (): AccountAction[] => {
const onSignDirect = async (chainId: string, address: string) => {
openRequestModal();
await cosmosRpc.testSignDirect(chainId, address);
};
const onSignAmino = async (chainId: string, address: string) => {
openRequestModal();
await cosmosRpc.testSignAmino(chainId, address);
};
return [
{
method: DEFAULT_COSMOS_METHODS.COSMOS_SIGN_DIRECT,
callback: onSignDirect,
},
{
method: DEFAULT_COSMOS_METHODS.COSMOS_SIGN_AMINO,
callback: onSignAmino,
},
];
};
const getSolanaActions = (): AccountAction[] => {
const onSignTransaction = async (chainId: string, address: string) => {
openRequestModal();
await solanaRpc.testSignTransaction(chainId, address);
};
const onSignMessage = async (chainId: string, address: string) => {
openRequestModal();
await solanaRpc.testSignMessage(chainId, address);
};
return [
{
method: DEFAULT_SOLANA_METHODS.SOL_SIGN_TRANSACTION,
callback: onSignTransaction,
},
{
method: DEFAULT_SOLANA_METHODS.SOL_SIGN_MESSAGE,
callback: onSignMessage,
},
];
};
const getPolkadotActions = (): AccountAction[] => {
const onSignTransaction = async (chainId: string, address: string) => {
openRequestModal();
await polkadotRpc.testSignTransaction(chainId, address);
};
const onSignMessage = async (chainId: string, address: string) => {
openRequestModal();
await polkadotRpc.testSignMessage(chainId, address);
};
return [
{
method: DEFAULT_POLKADOT_METHODS.POLKADOT_SIGN_TRANSACTION,
callback: onSignTransaction,
},
{
method: DEFAULT_POLKADOT_METHODS.POLKADOT_SIGN_MESSAGE,
callback: onSignMessage,
},
];
};
const getNearActions = (): AccountAction[] => {
const onSignAndSendTransaction = async (
chainId: string,
address: string
) => {
openRequestModal();
await nearRpc.testSignAndSendTransaction(chainId, address);
};
const onSignAndSendTransactions = async (
chainId: string,
address: string
) => {
openRequestModal();
await nearRpc.testSignAndSendTransactions(chainId, address);
};
return [
{
method: DEFAULT_NEAR_METHODS.NEAR_SIGN_AND_SEND_TRANSACTION,
callback: onSignAndSendTransaction,
},
{
method: DEFAULT_NEAR_METHODS.NEAR_SIGN_AND_SEND_TRANSACTIONS,
callback: onSignAndSendTransactions,
},
];
};
const getMultiversxActions = (): AccountAction[] => {
const onSignTransaction = async (chainId: string, address: string) => {
openRequestModal();
await multiversxRpc.testSignTransaction(chainId, address);
};
const onSignTransactions = async (chainId: string, address: string) => {
openRequestModal();
await multiversxRpc.testSignTransactions(chainId, address);
};
const onSignMessage = async (chainId: string, address: string) => {
openRequestModal();
await multiversxRpc.testSignMessage(chainId, address);
};
return [
{
method: DEFAULT_MULTIVERSX_METHODS.MULTIVERSX_SIGN_TRANSACTION,
callback: onSignTransaction,
},
{
method: DEFAULT_MULTIVERSX_METHODS.MULTIVERSX_SIGN_TRANSACTIONS,
callback: onSignTransactions,
},
{
method: DEFAULT_MULTIVERSX_METHODS.MULTIVERSX_SIGN_MESSAGE,
callback: onSignMessage,
},
];
};
const getTronActions = (): AccountAction[] => {
const onSignTransaction = async (chainId: string, address: string) => {
openRequestModal();
await tronRpc.testSignTransaction(chainId, address);
};
const onSignMessage = async (chainId: string, address: string) => {
openRequestModal();
await tronRpc.testSignMessage(chainId, address);
};
return [
{
method: DEFAULT_TRON_METHODS.TRON_SIGN_TRANSACTION,
callback: onSignTransaction,
},
{
method: DEFAULT_TRON_METHODS.TRON_SIGN_MESSAGE,
callback: onSignMessage,
},
];
};
const getTezosActions = (): AccountAction[] => {
const onGetAccounts = async (chainId: string, address: string) => {
openRequestModal();
await tezosRpc.testGetAccounts(chainId, address);
};
const onSignTransaction = async (chainId: string, address: string) => {
openRequestModal();
await tezosRpc.testSignTransaction(chainId, address);
};
const onSignMessage = async (chainId: string, address: string) => {
openRequestModal();
await tezosRpc.testSignMessage(chainId, address);
};
return [
{
method: DEFAULT_TEZOS_METHODS.TEZOS_GET_ACCOUNTS,
callback: onGetAccounts,
},
{
method: DEFAULT_TEZOS_METHODS.TEZOS_SEND,
callback: onSignTransaction,
},
{
method: DEFAULT_TEZOS_METHODS.TEZOS_SIGN,
callback: onSignMessage,
},
];
};
const getBlockchainActions = (chainId: string) => {
const [namespace] = chainId.split(":");
switch (namespace) {
case "eip155":
return getEthereumActions();
case "cosmos":
return getCosmosActions();
case "solana":
return getSolanaActions();
case "polkadot":
return getPolkadotActions();
case "near":
return getNearActions();
case "mvx":
return getMultiversxActions();
case "tron":
return getTronActions();
case "tezos":
return getTezosActions();
default:
break;
}
};
// Toggle between displaying testnet or mainnet chains as selection options.
const toggleTestnets = () => {
const nextIsTestnetState = !isTestnet;
setIsTestnet(nextIsTestnetState);
setLocaleStorageTestnetFlag(nextIsTestnetState);
};
const handleChainSelectionClick = (chainId: string) => {
if (chains.includes(chainId)) {
setChains(chains.filter((chain) => chain !== chainId));
} else {
setChains([...chains, chainId]);
}
};
// Renders the appropriate model for the given request that is currently in-flight.
const renderModal = () => {
switch (modal) {
case "pairing":
if (typeof client === "undefined") {
throw new Error("WalletConnect is not initialized");
}
return ;
case "request":
return (
);
case "ping":
return ;
default:
return null;
}
};
const renderContent = () => {
const chainOptions = isTestnet ? DEFAULT_TEST_CHAINS : DEFAULT_MAIN_CHAINS;
return !accounts.length && !Object.keys(balances).length ? (
{`Using v${version || "2.0.0-beta"}`}
Select chains:
Testnets Only?
{chainOptions.map((chainId) => (
))}
{"Connect"}
) : (
Accounts
{accounts.map((account) => {
const [namespace, reference, address] = account.split(":");
const chainId = `${namespace}:${reference}`;
return (
);
})}
);
};
return (
{isInitializing ? "Loading..." : renderContent()}
{renderModal()}
);
};
export default Home;