diff --git a/dapps/react-dapp-v2/src/App.tsx b/dapps/react-dapp-v2/src/App.tsx index 89a7283..61dfc85 100644 --- a/dapps/react-dapp-v2/src/App.tsx +++ b/dapps/react-dapp-v2/src/App.tsx @@ -1,849 +1,180 @@ -import * as React from "react"; -import styled from "styled-components"; - -import Client, { CLIENT_EVENTS } from "@walletconnect/client"; -import QRCodeModal from "@walletconnect/legacy-modal"; -import { PairingTypes, SessionTypes } from "@walletconnect/types"; -import { ERROR, getAppMetadata } from "@walletconnect/utils"; -import * as encoding from "@walletconnect/encoding"; -import { apiGetChainNamespace, ChainsMap } from "caip-api"; -import { formatDirectSignDoc, stringifySignDocValues } from "cosmos-wallet"; -import { BigNumber } from "ethers"; +import React, { useEffect, useState } from "react"; +import { version } from "@walletconnect/client/package.json"; import Banner from "./components/Banner"; import Blockchain from "./components/Blockchain"; -import Button from "./components/Button"; import Column from "./components/Column"; import Header from "./components/Header"; import Modal from "./components/Modal"; -import Wrapper from "./components/Wrapper"; -import { - DEFAULT_APP_METADATA, - DEFAULT_MAIN_CHAINS, - DEFAULT_LOGGER, - DEFAULT_EIP155_METHODS, - DEFAULT_COSMOS_METHODS, - DEFAULT_PROJECT_ID, - DEFAULT_RELAY_URL, - DEFAULT_TEST_CHAINS, - DEFAULT_CHAINS, -} from "./constants"; -import { - apiGetAccountAssets, - AccountAction, - eip712, - hashPersonalMessage, - hashTypedDataMessage, - verifySignature, - AccountBalances, - formatTestTransaction, - ChainNamespaces, - setInitialStateTestnet, - getInitialStateTestnet, -} from "./helpers"; -import { fonts } from "./styles"; +import { DEFAULT_MAIN_CHAINS, DEFAULT_TEST_CHAINS } from "./constants"; +import { AccountAction, setInitialStateTestnet, getInitialStateTestnet } 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"; -const SLayout = styled.div` - position: relative; - width: 100%; - min-height: 100vh; - text-align: center; -`; +export default function App() { + const [isTestnet, setIsTestnet] = useState(getInitialStateTestnet()); -const SContent = styled(Wrapper as any)` - width: 100%; - height: 100%; - padding: 0 16px; -`; + const [modal, setModal] = useState(""); -const SLanding = styled(Column as any)` - /* height: 600px; */ -`; + const closeModal = () => setModal(""); + const openPairingModal = () => setModal("pairing"); + const openPingModal = () => setModal("ping"); + const openRequestModal = () => setModal("request"); -const SButtonContainer = styled(Column as any)` - width: 250px; - margin: 50px 0; -`; + const { + client, + session, + connect, + disconnect, + chains, + accounts, + balances, + fetching, + loading, + setChains, + } = useWalletConnectClient(); -const SConnectButton = styled(Button as any)` - border-radius: 8px; - font-size: ${fonts.size.medium}; - height: 44px; - width: 100%; - margin: 12px 0; -`; + const { chainData, ping, ethereumRpc, cosmosRpc, isRpcRequestPending, rpcResult } = useJsonRpc(); -const SAccountsContainer = styled(SLanding as any)` - height: 100%; - padding-bottom: 30px; - & h3 { - padding-top: 30px; - } -`; - -const SToggleContainer = styled.div` - width: 100%; - display: flex; - justify-content: center; - align-items: center; - margin: 10px auto; - & > p { - margin-right: 10px; - } -`; - -const SFullWidthContainer = styled.div` - width: 100%; - display: flex; - justify-content: center; - align-items: center; - flex-wrap: wrap; -`; - -const SAccounts = styled(SFullWidthContainer)` - justify-content: space-between; - & > div { - margin: 12px 0; - flex: 1 0 100%; - @media (min-width: 648px) { - flex: 0 1 48%; + useEffect(() => { + // Close the pairing modal after a session is established. + if (session && modal === "pairing") { + closeModal(); } - } -`; + }, [session, modal]); -interface AppState { - client: Client | undefined; - session: SessionTypes.Created | undefined; - testnet: boolean; - loading: boolean; - fetching: boolean; - chains: string[]; - pairings: string[]; - modal: string; - pending: boolean; - uri: string; - accounts: string[]; - result: any | undefined; - balances: AccountBalances; - chainData: ChainNamespaces; -} - -const INITIAL_STATE: AppState = { - client: undefined, - session: undefined, - testnet: true, - loading: false, - fetching: false, - chains: [], - pairings: [], - modal: "", - pending: false, - uri: "", - accounts: [], - result: undefined, - balances: {}, - chainData: {}, -}; - -class App extends React.Component { - public state: AppState = { - ...INITIAL_STATE, - testnet: getInitialStateTestnet(), - }; - public componentDidMount() { - this.init(); - } - - public init = async () => { - this.setState({ loading: true }); - - try { - await this.loadChainData(); - - const client = await Client.init({ - logger: DEFAULT_LOGGER, - relayUrl: DEFAULT_RELAY_URL, - projectId: DEFAULT_PROJECT_ID, - }); - this.setState({ loading: false, client }); - this.subscribeToEvents(); - await this.checkPersistedState(); - } catch (e) { - this.setState({ loading: false }); - throw e; - } - }; - - public getAllNamespaces() { - const namespaces: string[] = []; - DEFAULT_CHAINS.forEach(chainId => { - const [namespace] = chainId.split(":"); - if (!namespaces.includes(namespace)) { - namespaces.push(namespace); - } - }); - return namespaces; - } - - public async loadChainData(): Promise { - const namespaces = this.getAllNamespaces(); - const chainData: ChainNamespaces = {}; - await Promise.all( - namespaces.map(async namespace => { - let chains: ChainsMap | undefined; - try { - chains = await apiGetChainNamespace(namespace); - } catch (e) { - // ignore error - } - if (typeof chains !== "undefined") { - chainData[namespace] = chains; - } - }), - ); - this.setState({ chainData }); - } - - public subscribeToEvents = () => { - if (typeof this.state.client === "undefined") { - return; - } - - this.state.client.on( - CLIENT_EVENTS.pairing.proposal, - async (proposal: PairingTypes.Proposal) => { - const { uri } = proposal.signal.params; - this.setState({ uri }); - console.log("EVENT", "QR Code Modal open"); - QRCodeModal.open(uri, () => { - console.log("EVENT", "QR Code Modal closed"); - }); - }, - ); - - this.state.client.on(CLIENT_EVENTS.pairing.created, async (proposal: PairingTypes.Settled) => { - if (typeof this.state.client === "undefined") return; - this.setState({ pairings: this.state.client.pairing.topics }); - }); - - this.state.client.on(CLIENT_EVENTS.session.deleted, (session: SessionTypes.Settled) => { - if (session.topic !== this.state.session?.topic) return; - console.log("EVENT", "session_deleted"); - this.resetApp(); - }); - }; - - public checkPersistedState = async () => { - if (typeof this.state.client === "undefined") { + const onConnect = () => { + if (typeof client === "undefined") { throw new Error("WalletConnect is not initialized"); } - // populates existing pairings to state - this.setState({ pairings: this.state.client.pairing.topics }); - if (typeof this.state.session !== "undefined") return; - // populates existing session to state (assume only the top one) - if (this.state.client.session.topics.length) { - const session = await this.state.client.session.get(this.state.client.session.topics[0]); - const chains = session.state.accounts.map(account => - account.split(":").slice(0, -1).join(":"), - ); - this.setState({ accounts: session.state.accounts, chains }); - this.onSessionConnected(session); + if (client.pairing.topics.length) { + return openPairingModal(); } + connect(); }; - public connect = async (pairing?: { topic: string }) => { - if (typeof this.state.client === "undefined") { - throw new Error("WalletConnect is not initialized"); - } - console.log("connect", pairing); - if (this.state.modal === "pairing") { - this.closeModal(); - } - try { - const chains = this.state.chains; - const supportedNamespaces: string[] = []; - chains.forEach(chainId => { - const [namespace] = chainId.split(":"); - if (!supportedNamespaces.includes(namespace)) { - supportedNamespaces.push(namespace); - } - }); - const methods: string[] = supportedNamespaces - .map(namespace => { - switch (namespace) { - case "eip155": - return DEFAULT_EIP155_METHODS; - case "cosmos": - return DEFAULT_COSMOS_METHODS; - default: - throw new Error(`No default methods for namespace: ${namespace}`); - } - }) - .flat(); - const session = await this.state.client.connect({ - metadata: getAppMetadata() || DEFAULT_APP_METADATA, - pairing, - permissions: { - blockchain: { - chains, - }, - jsonrpc: { - methods, - }, - }, - }); - - this.onSessionConnected(session); - } catch (e) { - // ignore rejection - } - - // close modal in case it was open - QRCodeModal.close(); + const onPing = async () => { + openPingModal(); + await ping(); }; - public disconnect = async () => { - if (typeof this.state.client === "undefined") { - throw new Error("WalletConnect is not initialized"); - } - if (typeof this.state.session === "undefined") { - throw new Error("Session is not connected"); - } - await this.state.client.disconnect({ - topic: this.state.session.topic, - reason: ERROR.USER_DISCONNECTED.format(), - }); + const getEthereumActions = (): AccountAction[] => { + const onSendTransaction = async (chainId: string) => { + openRequestModal(); + await ethereumRpc.testSendTransaction(chainId); + }; + const onSignPersonalMessage = async (chainId: string) => { + openRequestModal(); + await ethereumRpc.testSignPersonalMessage(chainId); + }; + const onSignTypedData = async (chainId: string) => { + openRequestModal(); + await ethereumRpc.testSignTypedData(chainId); + }; + + return [ + { method: "eth_sendTransaction", callback: onSendTransaction }, + { method: "personal_sign", callback: onSignPersonalMessage }, + { method: "eth_signTypedData", callback: onSignTypedData }, + ]; }; - public resetApp = async () => { - const { client, chainData } = this.state; - this.setState({ ...INITIAL_STATE, client, chainData }); + const getCosmosActions = (): AccountAction[] => { + const onSignDirect = async (chainId: string) => { + openRequestModal(); + await cosmosRpc.testSignDirect(chainId); + }; + const onSignAmino = async (chainId: string) => { + openRequestModal(); + await cosmosRpc.testSignAmino(chainId); + }; + return [ + { method: "cosmos_signDirect", callback: onSignDirect }, + { method: "cosmos_signAmino", callback: onSignAmino }, + ]; }; - public toggleTestnets = () => { - const testnet = !this.state.testnet; - this.setState({ testnet }); - setInitialStateTestnet(testnet); - }; - - public onSessionConnected = async (session: SessionTypes.Settled) => { - this.setState({ session }); - this.onSessionUpdate(session.state.accounts, session.permissions.blockchain.chains); - }; - - public onSessionUpdate = async (accounts: string[], chains: string[]) => { - this.setState({ chains, accounts }); - await this.getAccountBalances(); - }; - - public getAccountBalances = async () => { - this.setState({ fetching: true }); - try { - const arr = await Promise.all( - this.state.accounts.map(async account => { - const [namespace, reference, address] = account.split(":"); - const chainId = `${namespace}:${reference}`; - const assets = await apiGetAccountAssets(address, chainId); - return { account, assets }; - }), - ); - - const balances: AccountBalances = {}; - arr.forEach(({ account, assets }) => { - balances[account] = assets; - }); - this.setState({ fetching: false, balances }); - } catch (e) { - console.error(e); - this.setState({ fetching: false }); - } - }; - - public openPairingModal = () => this.setState({ modal: "pairing" }); - - public openRequestModal = () => this.setState({ pending: true, modal: "request" }); - - public openPingModal = () => this.setState({ pending: true, modal: "ping" }); - - public openModal = (modal: string) => this.setState({ modal }); - - public closeModal = () => this.setState({ modal: "" }); - - public onConnect = () => { - if (typeof this.state.client === "undefined") { - throw new Error("WalletConnect is not initialized"); - } - if (this.state.client.pairing.topics.length) { - return this.openPairingModal(); - } - this.connect(); - }; - - public testSendTransaction = async (chainId: string) => { - if (typeof this.state.client === "undefined") { - throw new Error("WalletConnect is not initialized"); - } - if (typeof this.state.session === "undefined") { - throw new Error("Session is not connected"); - } - - try { - // get ethereum address - const account = this.state.accounts.find(account => account.startsWith(chainId)); - if (account === undefined) throw new Error("Account is not found"); - const address = account.split(":").pop(); - if (address === undefined) throw new Error("Address is invalid"); - - // open modal - this.openRequestModal(); - - const tx = await formatTestTransaction(account); - - const balance = BigNumber.from(this.state.balances[account][0].balance || "0"); - if (balance.lt(BigNumber.from(tx.gasPrice).mul(tx.gasLimit))) { - const formattedResult = { - method: "eth_sendTransaction", - address, - valid: false, - result: "Insufficient funds for intrinsic transaction cost", - }; - this.setState({ pending: false, result: formattedResult || null }); - return; - } - - const result = await this.state.client.request({ - topic: this.state.session.topic, - chainId, - request: { - method: "eth_sendTransaction", - params: [tx], - }, - }); - - // format displayed result - const formattedResult = { - method: "eth_sendTransaction", - address, - valid: true, - result, - }; - - // display result - this.setState({ pending: false, result: formattedResult || null }); - } catch (e) { - console.error(e); - this.setState({ pending: false, result: null }); - } - }; - - public testSignPersonalMessage = async (chainId: string) => { - if (typeof this.state.client === "undefined") { - throw new Error("WalletConnect is not initialized"); - } - if (typeof this.state.session === "undefined") { - throw new Error("Session is not connected"); - } - - try { - // test message - const message = `My email is john@doe.com - ${Date.now()}`; - - // encode message (hex) - const hexMsg = encoding.utf8ToHex(message, true); - - // get ethereum address - const account = this.state.accounts.find(account => account.startsWith(chainId)); - if (account === undefined) throw new Error("Account is not found"); - const address = account.split(":").pop(); - if (address === undefined) throw new Error("Address is invalid"); - - // personal_sign params - const params = [hexMsg, address]; - - // open modal - this.openRequestModal(); - - // send message - const result = await this.state.client.request({ - topic: this.state.session.topic, - chainId, - request: { - method: "personal_sign", - params, - }, - }); - - // split chainId - const [namespace, reference] = chainId.split(":"); - - const chainData = this.state.chainData[namespace][reference]; - - if (typeof chainData === "undefined") { - throw new Error(`Missing chain data for chainId: ${chainId}`); - } - - const rpcUrl = chainData.rpc[0]; - - // verify signature - const hash = hashPersonalMessage(message); - const valid = await verifySignature(address, result, hash, rpcUrl); - - // format displayed result - const formattedResult = { - method: "personal_sign", - address, - valid, - result, - }; - - // display result - this.setState({ pending: false, result: formattedResult || null }); - } catch (e) { - console.error(e); - this.setState({ pending: false, result: null }); - } - }; - - public testSignTypedData = async (chainId: string) => { - if (typeof this.state.client === "undefined") { - throw new Error("WalletConnect is not initialized"); - } - if (typeof this.state.session === "undefined") { - throw new Error("Session is not connected"); - } - try { - // test message - const message = JSON.stringify(eip712.example); - - // get ethereum address - const account = this.state.accounts.find(account => account.startsWith(chainId)); - if (account === undefined) throw new Error("Account is not found"); - const address = account.split(":").pop(); - if (address === undefined) throw new Error("Address is invalid"); - - // eth_signTypedData params - const params = [address, message]; - - // open modal - this.openRequestModal(); - - // send message - const result = await this.state.client.request({ - topic: this.state.session.topic, - chainId, - request: { - method: "eth_signTypedData", - params, - }, - }); - - // split chainId - const [namespace, reference] = chainId.split(":"); - - const chainData = this.state.chainData[namespace][reference]; - - if (typeof chainData === "undefined") { - throw new Error(`Missing chain data for chainId: ${chainId}`); - } - - const rpcUrl = chainData.rpc[0]; - - // verify signature - const hash = hashTypedDataMessage(message); - const valid = await verifySignature(address, result, hash, rpcUrl); - - // format displayed result - const formattedResult = { - method: "eth_signTypedData", - address, - valid, - result, - }; - - // display result - this.setState({ pending: false, result: formattedResult || null }); - } catch (e) { - console.error(e); - this.setState({ pending: false, result: null }); - } - }; - - public testSignDirect = async (chainId: string) => { - if (typeof this.state.client === "undefined") { - throw new Error("WalletConnect is not initialized"); - } - if (typeof this.state.session === "undefined") { - throw new Error("Session is not connected"); - } - - try { - // test direct sign doc inputs - const inputs = { - fee: [{ amount: "2000", denom: "ucosm" }], - pubkey: "AgSEjOuOr991QlHCORRmdE5ahVKeyBrmtgoYepCpQGOW", - gasLimit: 200000, - accountNumber: 1, - sequence: 1, - bodyBytes: - "0a90010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e6412700a2d636f736d6f7331706b707472653766646b6c366766727a6c65736a6a766878686c63337234676d6d6b38727336122d636f736d6f7331717970717870713971637273737a673270767871367273307a716733797963356c7a763778751a100a0575636f736d120731323334353637", - authInfoBytes: - "0a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a21034f04181eeba35391b858633a765c4a0c189697b40d216354d50890d350c7029012040a020801180112130a0d0a0575636f736d12043230303010c09a0c", - }; - - // split chainId - const [namespace, reference] = chainId.split(":"); - - // format sign doc - const signDoc = formatDirectSignDoc( - inputs.fee, - inputs.pubkey, - inputs.gasLimit, - inputs.accountNumber, - inputs.sequence, - inputs.bodyBytes, - reference, - ); - - // get cosmos address - const account = this.state.accounts.find(account => account.startsWith(chainId)); - if (account === undefined) throw new Error("Account is not found"); - const address = account.split(":").pop(); - if (address === undefined) throw new Error("Address is invalid"); - - // cosmos_signDirect params - const params = { - signerAddress: address, - signDoc: stringifySignDocValues(signDoc), - }; - - // open modal - this.openRequestModal(); - - // send message - const result = await this.state.client.request({ - topic: this.state.session.topic, - chainId, - request: { - method: "cosmos_signDirect", - params, - }, - }); - - const chainData = this.state.chainData[namespace][reference]; - - if (typeof chainData === "undefined") { - throw new Error(`Missing chain data for chainId: ${chainId}`); - } - - // TODO: check if valid - const valid = true; - - // format displayed result - const formattedResult = { - method: "cosmos_signDirect", - address, - valid, - result: result.signature.signature, - }; - - // display result - this.setState({ pending: false, result: formattedResult || null }); - } catch (e) { - console.error(e); - this.setState({ pending: false, result: null }); - } - }; - - public testSignAmino = async (chainId: string) => { - if (typeof this.state.client === "undefined") { - throw new Error("WalletConnect is not initialized"); - } - if (typeof this.state.session === "undefined") { - throw new Error("Session is not connected"); - } - - try { - // split chainId - const [namespace, reference] = chainId.split(":"); - - // test amino sign doc - const signDoc = { - msgs: [], - fee: { amount: [], gas: "23" }, - chain_id: "foochain", - memo: "hello, world", - account_number: "7", - sequence: "54", - }; - - // get cosmos address - const account = this.state.accounts.find(account => account.startsWith(chainId)); - if (account === undefined) throw new Error("Account is not found"); - const address = account.split(":").pop(); - if (address === undefined) throw new Error("Address is invalid"); - - // cosmos_signAmino params - const params = { signerAddress: address, signDoc }; - - // open modal - this.openRequestModal(); - - // send message - const result = await this.state.client.request({ - topic: this.state.session.topic, - chainId, - request: { - method: "cosmos_signAmino", - params, - }, - }); - - const chainData = this.state.chainData[namespace][reference]; - - if (typeof chainData === "undefined") { - throw new Error(`Missing chain data for chainId: ${chainId}`); - } - - // TODO: check if valid - const valid = true; - - // format displayed result - const formattedResult = { - method: "cosmos_signAmino", - address, - valid, - result: result.signature.signature, - }; - - // display result - this.setState({ pending: false, result: formattedResult || null }); - } catch (e) { - console.error(e); - this.setState({ pending: false, result: null }); - } - }; - - public ping = async () => { - if (typeof this.state.client === "undefined") { - throw new Error("WalletConnect is not initialized"); - } - if (typeof this.state.session === "undefined") { - throw new Error("Session is not connected"); - } - - try { - // open modal - this.openPingModal(); - - let valid = false; - - try { - await this.state.client.session.ping(this.state.session.topic); - valid = true; - } catch (e) { - valid = false; - } - - // format displayed result - const formattedResult = { - method: "ping", - valid, - }; - - // display result - this.setState({ pending: false, result: formattedResult || null }); - } catch (e) { - console.error(e); - this.setState({ pending: false, result: null }); - } - }; - - public handleChainSelectionClick = (chainId: string) => { - const { chains } = this.state; - if (chains.includes(chainId)) { - this.setState({ chains: chains.filter(x => x !== chainId) }); - } else { - this.setState({ chains: [...chains, chainId] }); - } - }; - - public getBlockchainActions = (chainId: string) => { + const getBlockchainActions = (chainId: string) => { const [namespace] = chainId.split(":"); switch (namespace) { case "eip155": - return this.getEthereumActions(); + return getEthereumActions(); case "cosmos": - return this.getCosmosActions(); + return getCosmosActions(); default: break; } }; - public getEthereumActions = (): AccountAction[] => { - return [ - { method: "eth_sendTransaction", callback: this.testSendTransaction }, - { method: "personal_sign", callback: this.testSignPersonalMessage }, - { method: "eth_signTypedData", callback: this.testSignTypedData }, - ]; + const toggleTestnets = () => { + const nextIsTestnetState = !isTestnet; + setIsTestnet(nextIsTestnetState); + // TODO: rename "setLocalStorage..." + setInitialStateTestnet(nextIsTestnetState); }; - public getCosmosActions = (): AccountAction[] => { - return [ - { method: "cosmos_signDirect", callback: this.testSignDirect }, - { method: "cosmos_signAmino", callback: this.testSignAmino }, - ]; + const handleChainSelectionClick = (chainId: string) => { + if (chains.includes(chainId)) { + setChains(chains.filter(chain => chain !== chainId)); + } else { + setChains([...chains, chainId]); + } }; - public renderModal = () => { - switch (this.state.modal) { + const renderModal = () => { + switch (modal) { case "pairing": - if (typeof this.state.client === "undefined") { + if (typeof client === "undefined") { throw new Error("WalletConnect is not initialized"); } - return ; + return ; case "request": - return ; + return ; case "ping": - return ; + return ; default: return null; } }; - public renderContent = () => { - const { balances, accounts, chains, chainData, testnet, fetching } = this.state; - const chainOptions = testnet ? DEFAULT_TEST_CHAINS : DEFAULT_MAIN_CHAINS; + const renderContent = () => { + const chainOptions = isTestnet ? DEFAULT_TEST_CHAINS : DEFAULT_MAIN_CHAINS; return !accounts.length && !Object.keys(balances).length ? (
- {`Using v${process.env.REACT_APP_VERSION || "2.0.0-beta"}`} + {`Using v${version || "2.0.0-beta"}`}
Select chains:

Testnets Only?

- +
{chainOptions.map(chainId => ( ))} - + {"Connect"}
@@ -852,7 +183,7 @@ class App extends React.Component {

Accounts

- {this.state.accounts.map(account => { + {accounts.map(account => { const [namespace, reference, address] = account.split(":"); const chainId = `${namespace}:${reference}`; return ( @@ -864,7 +195,7 @@ class App extends React.Component { address={address} chainId={chainId} balances={balances} - actions={this.getBlockchainActions(chainId)} + actions={getBlockchainActions(chainId)} /> ); })} @@ -873,20 +204,15 @@ class App extends React.Component { ); }; - public render = () => { - const { loading, session, modal } = this.state; - return ( - - -
- {loading ? "Loading..." : this.renderContent()} - - - {this.renderModal()} - - - ); - }; + return ( + + +
+ {loading ? "Loading..." : renderContent()} + + + {renderModal()} + + + ); } - -export default App; diff --git a/dapps/react-dapp-v2/src/HooksApp.tsx b/dapps/react-dapp-v2/src/HooksApp.tsx deleted file mode 100644 index 61dfc85..0000000 --- a/dapps/react-dapp-v2/src/HooksApp.tsx +++ /dev/null @@ -1,218 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { version } from "@walletconnect/client/package.json"; - -import Banner from "./components/Banner"; -import Blockchain from "./components/Blockchain"; -import Column from "./components/Column"; -import Header from "./components/Header"; -import Modal from "./components/Modal"; -import { DEFAULT_MAIN_CHAINS, DEFAULT_TEST_CHAINS } from "./constants"; -import { AccountAction, setInitialStateTestnet, getInitialStateTestnet } 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"; - -export default function App() { - const [isTestnet, setIsTestnet] = useState(getInitialStateTestnet()); - - const [modal, setModal] = useState(""); - - const closeModal = () => setModal(""); - const openPairingModal = () => setModal("pairing"); - const openPingModal = () => setModal("ping"); - const openRequestModal = () => setModal("request"); - - const { - client, - session, - connect, - disconnect, - chains, - accounts, - balances, - fetching, - loading, - setChains, - } = useWalletConnectClient(); - - const { chainData, ping, ethereumRpc, cosmosRpc, isRpcRequestPending, rpcResult } = useJsonRpc(); - - useEffect(() => { - // Close the pairing modal after a session is established. - if (session && modal === "pairing") { - closeModal(); - } - }, [session, modal]); - - const onConnect = () => { - if (typeof client === "undefined") { - throw new Error("WalletConnect is not initialized"); - } - if (client.pairing.topics.length) { - return openPairingModal(); - } - connect(); - }; - - const onPing = async () => { - openPingModal(); - await ping(); - }; - - const getEthereumActions = (): AccountAction[] => { - const onSendTransaction = async (chainId: string) => { - openRequestModal(); - await ethereumRpc.testSendTransaction(chainId); - }; - const onSignPersonalMessage = async (chainId: string) => { - openRequestModal(); - await ethereumRpc.testSignPersonalMessage(chainId); - }; - const onSignTypedData = async (chainId: string) => { - openRequestModal(); - await ethereumRpc.testSignTypedData(chainId); - }; - - return [ - { method: "eth_sendTransaction", callback: onSendTransaction }, - { method: "personal_sign", callback: onSignPersonalMessage }, - { method: "eth_signTypedData", callback: onSignTypedData }, - ]; - }; - - const getCosmosActions = (): AccountAction[] => { - const onSignDirect = async (chainId: string) => { - openRequestModal(); - await cosmosRpc.testSignDirect(chainId); - }; - const onSignAmino = async (chainId: string) => { - openRequestModal(); - await cosmosRpc.testSignAmino(chainId); - }; - return [ - { method: "cosmos_signDirect", callback: onSignDirect }, - { method: "cosmos_signAmino", callback: onSignAmino }, - ]; - }; - - const getBlockchainActions = (chainId: string) => { - const [namespace] = chainId.split(":"); - switch (namespace) { - case "eip155": - return getEthereumActions(); - case "cosmos": - return getCosmosActions(); - default: - break; - } - }; - - const toggleTestnets = () => { - const nextIsTestnetState = !isTestnet; - setIsTestnet(nextIsTestnetState); - // TODO: rename "setLocalStorage..." - setInitialStateTestnet(nextIsTestnetState); - }; - - const handleChainSelectionClick = (chainId: string) => { - if (chains.includes(chainId)) { - setChains(chains.filter(chain => chain !== chainId)); - } else { - setChains([...chains, chainId]); - } - }; - - 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 ( - - -
- {loading ? "Loading..." : renderContent()} - - - {renderModal()} - - - ); -} diff --git a/dapps/react-dapp-v2/src/index.tsx b/dapps/react-dapp-v2/src/index.tsx index 3de3bd7..564dd79 100644 --- a/dapps/react-dapp-v2/src/index.tsx +++ b/dapps/react-dapp-v2/src/index.tsx @@ -4,7 +4,7 @@ import { createGlobalStyle } from "styled-components"; import { ClientContextProvider } from "./contexts/ClientContext"; import { JsonRpcContextProvider } from "./contexts/JsonRpcContext"; -import HooksApp from "./HooksApp"; +import App from "./App"; import { globalStyle } from "./styles"; const GlobalStyle = createGlobalStyle` ${globalStyle} @@ -22,7 +22,7 @@ ReactDOM.render( - + ,