refactor(dapp-v2): separates chainData into own context/hook

This commit is contained in:
Ben Kremer 2022-03-17 16:56:54 +01:00
parent 6b14e13eaf
commit 59b9eb5867
4 changed files with 87 additions and 43 deletions

View File

@ -30,6 +30,7 @@ import {
} from "./components/app"; } from "./components/app";
import { useWalletConnectClient } from "./contexts/ClientContext"; import { useWalletConnectClient } from "./contexts/ClientContext";
import { useJsonRpc } from "./contexts/JsonRpcContext"; import { useJsonRpc } from "./contexts/JsonRpcContext";
import { useChainData } from "./contexts/ChainDataContext";
export default function App() { export default function App() {
const [modal, setModal] = useState(""); const [modal, setModal] = useState("");
@ -55,7 +56,6 @@ export default function App() {
// Use `JsonRpcContext` to provide us with relevant RPC methods and states. // Use `JsonRpcContext` to provide us with relevant RPC methods and states.
const { const {
chainData,
ping, ping,
ethereumRpc, ethereumRpc,
cosmosRpc, cosmosRpc,
@ -66,6 +66,8 @@ export default function App() {
setIsTestnet, setIsTestnet,
} = useJsonRpc(); } = useJsonRpc();
const { chainData } = useChainData();
// Close the pairing modal after a session is established. // Close the pairing modal after a session is established.
useEffect(() => { useEffect(() => {
if (session && modal === "pairing") { if (session && modal === "pairing") {

View File

@ -0,0 +1,70 @@
import { apiGetChainNamespace, ChainsMap } from "caip-api";
import { createContext, ReactNode, useContext, useEffect, useState } from "react";
import { SolanaChainData } from "../chains/solana";
import { ChainNamespaces, getAllChainNamespaces } from "../helpers";
/**
* Types
*/
interface IContext {
chainData: ChainNamespaces;
}
/**
* Context
*/
export const ChainDataContext = createContext<IContext>({} as IContext);
/**
* Provider
*/
export function ChainDataContextProvider({ children }: { children: ReactNode | ReactNode[] }) {
const [chainData, setChainData] = useState<ChainNamespaces>({});
const loadChainData = async () => {
const namespaces = getAllChainNamespaces();
const chainData: ChainNamespaces = {};
await Promise.all(
namespaces.map(async namespace => {
let chains: ChainsMap | undefined;
try {
if (namespace === "solana") {
chains = SolanaChainData;
} else {
chains = await apiGetChainNamespace(namespace);
}
} catch (e) {
// ignore error
}
if (typeof chains !== "undefined") {
chainData[namespace] = chains;
}
}),
);
setChainData(chainData);
};
useEffect(() => {
loadChainData();
}, []);
return (
<ChainDataContext.Provider
value={{
chainData,
}}
>
{children}
</ChainDataContext.Provider>
);
}
export function useChainData() {
const context = useContext(ChainDataContext);
if (context === undefined) {
throw new Error("useChainData must be used within a ChainDataContextProvider");
}
return context;
}

View File

@ -1,29 +1,26 @@
import { BigNumber, utils } from "ethers"; import { BigNumber, utils } from "ethers";
import { createContext, ReactNode, useContext, useEffect, useState } from "react"; import { createContext, ReactNode, useContext, useState } from "react";
import * as encoding from "@walletconnect/encoding"; import * as encoding from "@walletconnect/encoding";
import { TypedDataField } from "@ethersproject/abstract-signer";
import { formatDirectSignDoc, stringifySignDocValues } from "cosmos-wallet"; import { formatDirectSignDoc, stringifySignDocValues } from "cosmos-wallet";
import bs58 from "bs58"; import bs58 from "bs58";
import { verifyMessageSignature } from "solana-wallet"; import { verifyMessageSignature } from "solana-wallet";
import { clusterApiUrl, Connection, Keypair, SystemProgram, Transaction } from "@solana/web3.js";
import { import {
ChainNamespaces,
eip712, eip712,
formatTestTransaction, formatTestTransaction,
getAllChainNamespaces,
getLocalStorageTestnetFlag, getLocalStorageTestnetFlag,
hashPersonalMessage, hashPersonalMessage,
verifySignature, verifySignature,
} from "../helpers"; } from "../helpers";
import { useWalletConnectClient } from "./ClientContext"; import { useWalletConnectClient } from "./ClientContext";
import { apiGetChainNamespace, ChainsMap } from "caip-api";
import { TypedDataField } from "@ethersproject/abstract-signer";
import { import {
DEFAULT_COSMOS_METHODS, DEFAULT_COSMOS_METHODS,
DEFAULT_EIP155_METHODS, DEFAULT_EIP155_METHODS,
DEFAULT_SOLANA_METHODS, DEFAULT_SOLANA_METHODS,
} from "../constants"; } from "../constants";
import { clusterApiUrl, Connection, Keypair, SystemProgram, Transaction } from "@solana/web3.js"; import { useChainData } from "./ChainDataContext";
import { SolanaChainData } from "../chains/solana";
/** /**
* Types * Types
@ -59,7 +56,6 @@ interface IContext {
testSignMessage: TRpcRequestCallback; testSignMessage: TRpcRequestCallback;
testSignTransaction: TRpcRequestCallback; testSignTransaction: TRpcRequestCallback;
}; };
chainData: ChainNamespaces;
rpcResult?: IRpcResult | null; rpcResult?: IRpcResult | null;
isRpcRequestPending: boolean; isRpcRequestPending: boolean;
isTestnet: boolean; isTestnet: boolean;
@ -77,38 +73,11 @@ export const JsonRpcContext = createContext<IContext>({} as IContext);
export function JsonRpcContextProvider({ children }: { children: ReactNode | ReactNode[] }) { export function JsonRpcContextProvider({ children }: { children: ReactNode | ReactNode[] }) {
const [pending, setPending] = useState(false); const [pending, setPending] = useState(false);
const [result, setResult] = useState<IRpcResult | null>(); const [result, setResult] = useState<IRpcResult | null>();
const [chainData, setChainData] = useState<ChainNamespaces>({});
const [isTestnet, setIsTestnet] = useState(getLocalStorageTestnetFlag()); const [isTestnet, setIsTestnet] = useState(getLocalStorageTestnetFlag());
const { client, session, accounts, balances, solanaPublicKeys } = useWalletConnectClient(); const { client, session, accounts, balances, solanaPublicKeys } = useWalletConnectClient();
useEffect(() => { const { chainData } = useChainData();
loadChainData();
}, []);
const loadChainData = async () => {
const namespaces = getAllChainNamespaces();
const chainData: ChainNamespaces = {};
await Promise.all(
namespaces.map(async namespace => {
let chains: ChainsMap | undefined;
try {
if (namespace === "solana") {
chains = SolanaChainData;
} else {
chains = await apiGetChainNamespace(namespace);
}
} catch (e) {
// ignore error
}
if (typeof chains !== "undefined") {
chainData[namespace] = chains;
}
}),
);
setChainData(chainData);
};
const _createJsonRpcRequestHandler = const _createJsonRpcRequestHandler =
(rpcRequest: (chainId: string, address: string) => Promise<IFormattedRpcResponse>) => (rpcRequest: (chainId: string, address: string) => Promise<IFormattedRpcResponse>) =>
@ -568,7 +537,6 @@ export function JsonRpcContextProvider({ children }: { children: ReactNode | Rea
return ( return (
<JsonRpcContext.Provider <JsonRpcContext.Provider
value={{ value={{
chainData,
ping, ping,
ethereumRpc, ethereumRpc,
cosmosRpc, cosmosRpc,

View File

@ -1,8 +1,10 @@
import * as React from "react"; import * as React from "react";
import * as ReactDOM from "react-dom"; import * as ReactDOM from "react-dom";
import { createGlobalStyle } from "styled-components"; import { createGlobalStyle } from "styled-components";
import { ClientContextProvider } from "./contexts/ClientContext"; import { ClientContextProvider } from "./contexts/ClientContext";
import { JsonRpcContextProvider } from "./contexts/JsonRpcContext"; import { JsonRpcContextProvider } from "./contexts/JsonRpcContext";
import { ChainDataContextProvider } from "./contexts/ChainDataContext";
import App from "./App"; import App from "./App";
import { globalStyle } from "./styles"; import { globalStyle } from "./styles";
@ -20,11 +22,13 @@ declare global {
ReactDOM.render( ReactDOM.render(
<> <>
<GlobalStyle /> <GlobalStyle />
<ClientContextProvider> <ChainDataContextProvider>
<JsonRpcContextProvider> <ClientContextProvider>
<App /> <JsonRpcContextProvider>
</JsonRpcContextProvider> <App />
</ClientContextProvider> </JsonRpcContextProvider>
</ClientContextProvider>
</ChainDataContextProvider>
</>, </>,
document.getElementById("root"), document.getElementById("root"),
); );