bridge_ui: WalletConnect support for EVM chains

Updated ethers dependency
This commit is contained in:
Kevin Peters 2022-05-05 20:16:36 +00:00 committed by Evan Gray
parent a2917095a9
commit 62968c3535
13 changed files with 2232 additions and 1167 deletions

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@
"@solana/wallet-adapter-wallets": "^0.16.1", "@solana/wallet-adapter-wallets": "^0.16.1",
"@solana/web3.js": "^1.35.1", "@solana/web3.js": "^1.35.1",
"@terra-money/wallet-provider": "^3.8.0", "@terra-money/wallet-provider": "^3.8.0",
"@walletconnect/web3-provider": "^1.7.8",
"algosdk": "^1.15.0", "algosdk": "^1.15.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"bech32": "^1.1.4", "bech32": "^1.1.4",
@ -26,7 +27,7 @@
"borsh": "^0.4.0", "borsh": "^0.4.0",
"bs58": "^4.0.1", "bs58": "^4.0.1",
"clsx": "^1.1.1", "clsx": "^1.1.1",
"ethers": "^5.4.1", "ethers": "^5.6.8",
"js-base64": "^3.6.1", "js-base64": "^3.6.1",
"luxon": "^2.3.1", "luxon": "^2.3.1",
"notistack": "^1.0.10", "notistack": "^1.0.10",

View File

@ -1,18 +1,36 @@
import { useCallback, useState } from "react";
import { Typography } from "@material-ui/core"; import { Typography } from "@material-ui/core";
import { useEthereumProvider } from "../contexts/EthereumProviderContext"; import { useEthereumProvider } from "../contexts/EthereumProviderContext";
import ToggleConnectedButton from "./ToggleConnectedButton"; import ToggleConnectedButton from "./ToggleConnectedButton";
import EvmConnectWalletDialog from "./EvmConnectWalletDialog";
import { ChainId } from "@certusone/wormhole-sdk";
const EthereumSignerKey = ({ chainId }: { chainId: ChainId }) => {
const { disconnect, signerAddress, providerError } = useEthereumProvider();
const [isDialogOpen, setIsDialogOpen] = useState(false);
const openDialog = useCallback(() => {
setIsDialogOpen(true);
}, [setIsDialogOpen]);
const closeDialog = useCallback(() => {
setIsDialogOpen(false);
}, [setIsDialogOpen]);
const EthereumSignerKey = () => {
const { connect, disconnect, signerAddress, providerError } =
useEthereumProvider();
return ( return (
<> <>
<ToggleConnectedButton <ToggleConnectedButton
connect={connect} connect={openDialog}
disconnect={disconnect} disconnect={disconnect}
connected={!!signerAddress} connected={!!signerAddress}
pk={signerAddress || ""} pk={signerAddress || ""}
/> />
<EvmConnectWalletDialog
isOpen={isDialogOpen}
onClose={closeDialog}
chainId={chainId}
/>
{providerError ? ( {providerError ? (
<Typography variant="body2" color="error"> <Typography variant="body2" color="error">
{providerError} {providerError}

View File

@ -0,0 +1,120 @@
import { ChainId } from "@certusone/wormhole-sdk";
import {
Dialog,
DialogTitle,
IconButton,
List,
ListItem,
ListItemIcon,
ListItemText,
makeStyles,
} from "@material-ui/core";
import CloseIcon from "@material-ui/icons/Close";
import { useCallback } from "react";
import {
Connection,
ConnectType,
useEthereumProvider,
} from "../contexts/EthereumProviderContext";
import { getEvmChainId } from "../utils/consts";
import { EVM_RPC_MAP } from "../utils/metaMaskChainParameters";
const useStyles = makeStyles((theme) => ({
flexTitle: {
display: "flex",
alignItems: "center",
"& > div": {
flexGrow: 1,
marginRight: theme.spacing(4),
},
"& > button": {
marginRight: theme.spacing(-1),
},
},
icon: {
height: 24,
width: 24,
},
}));
const WalletOptions = ({
connection,
connect,
onClose,
}: {
connection: Connection;
connect: (connectType: ConnectType) => void;
onClose: () => void;
}) => {
const classes = useStyles();
const handleClick = useCallback(() => {
connect(connection.connectType);
onClose();
}, [connect, connection, onClose]);
return (
<ListItem button onClick={handleClick}>
<ListItemIcon>
<img
src={connection.icon}
alt={connection.name}
className={classes.icon}
/>
</ListItemIcon>
<ListItemText>{connection.name}</ListItemText>
</ListItem>
);
};
const EvmConnectWalletDialog = ({
isOpen,
onClose,
chainId,
}: {
isOpen: boolean;
onClose: () => void;
chainId: ChainId;
}) => {
const { availableConnections, connect } = useEthereumProvider();
const classes = useStyles();
const availableWallets = availableConnections
.filter((connection) => {
if (connection.connectType === ConnectType.METAMASK) {
return true;
} else if (connection.connectType === ConnectType.WALLETCONNECT) {
const evmChainId = getEvmChainId(chainId);
// WalletConnect requires a rpc provider
return (
evmChainId !== undefined && EVM_RPC_MAP[evmChainId] !== undefined
);
} else {
return false;
}
})
.map((connection) => (
<WalletOptions
connection={connection}
connect={connect}
onClose={onClose}
key={connection.name}
/>
));
return (
<Dialog open={isOpen} onClose={onClose}>
<DialogTitle>
<div className={classes.flexTitle}>
<div>Select your wallet</div>
<IconButton onClick={onClose}>
<CloseIcon />
</IconButton>
</div>
</DialogTitle>
<List>{availableWallets}</List>
</Dialog>
);
};
export default EvmConnectWalletDialog;

View File

@ -12,7 +12,7 @@ import TerraWalletKey from "./TerraWalletKey";
function KeyAndBalance({ chainId }: { chainId: ChainId }) { function KeyAndBalance({ chainId }: { chainId: ChainId }) {
if (isEVMChain(chainId)) { if (isEVMChain(chainId)) {
return <EthereumSignerKey />; return <EthereumSignerKey chainId={chainId} />;
} }
if (chainId === CHAIN_ID_SOLANA) { if (chainId === CHAIN_ID_SOLANA) {
return <SolanaWalletKey />; return <SolanaWalletKey />;

View File

@ -345,7 +345,7 @@ export default function EvmQuickMigrate({ chainId }: { chainId: ChainId }) {
} into } into
Wormhole V2 tokens.`} Wormhole V2 tokens.`}
</Typography> </Typography>
<EthereumSignerKey /> <EthereumSignerKey chainId={chainId} />
{!isReady ? ( {!isReady ? (
<Typography variant="body1">Please connect your wallet.</Typography> <Typography variant="body1">Please connect your wallet.</Typography>
) : migratorsError ? ( ) : migratorsError ? (

View File

@ -231,7 +231,7 @@ export default function EvmWorkflow({
return ( return (
<div className={classes.containerDiv}> <div className={classes.containerDiv}>
<EthereumSignerKey /> <EthereumSignerKey chainId={chainId} />
{!isReady ? ( {!isReady ? (
<Typography variant="body1">Please connect your wallet.</Typography> <Typography variant="body1">Please connect your wallet.</Typography>
) : poolInfo.isLoading ? ( ) : poolInfo.isLoading ? (

View File

@ -218,7 +218,7 @@ function UnwrapNative() {
Unwrap (withdraw) native tokens from their wrapped form (e.g. WETH Unwrap (withdraw) native tokens from their wrapped form (e.g. WETH
&rarr; ETH) &rarr; ETH)
</Typography> </Typography>
<EthereumSignerKey /> <EthereumSignerKey chainId={selectedChainId} />
<TextField <TextField
select select
value={selectedChainId} value={selectedChainId}

View File

@ -1,35 +1,57 @@
import detectEthereumProvider from "@metamask/detect-provider"; import detectEthereumProvider from "@metamask/detect-provider";
import WalletConnectProvider from "@walletconnect/web3-provider";
import { BigNumber, ethers } from "ethers"; import { BigNumber, ethers } from "ethers";
import React, { import React, {
ReactChildren, ReactChildren,
useCallback, useCallback,
useContext, useContext,
useEffect,
useMemo, useMemo,
useState, useState,
} from "react"; } from "react";
import metamaskIcon from "../icons/metamask-fox.svg";
import walletconnectIcon from "../icons/walletconnect.svg";
import { EVM_RPC_MAP } from "../utils/metaMaskChainParameters";
const CacheSubprovider = require("web3-provider-engine/subproviders/cache");
export type Provider = ethers.providers.Web3Provider | undefined; export type Provider = ethers.providers.Web3Provider | undefined;
export type Signer = ethers.Signer | undefined; export type Signer = ethers.Signer | undefined;
export enum ConnectType {
METAMASK,
WALLETCONNECT,
}
export interface Connection {
connectType: ConnectType;
name: string;
icon: string;
}
interface IEthereumProviderContext { interface IEthereumProviderContext {
connect(): void; connect(connectType: ConnectType): void;
disconnect(): void; disconnect(): void;
provider: Provider; provider: Provider;
chainId: number | undefined; chainId: number | undefined;
signer: Signer; signer: Signer;
signerAddress: string | undefined; signerAddress: string | undefined;
providerError: string | null; providerError: string | null;
availableConnections: Connection[];
connectType: ConnectType | undefined;
} }
const EthereumProviderContext = React.createContext<IEthereumProviderContext>({ const EthereumProviderContext = React.createContext<IEthereumProviderContext>({
connect: () => {}, connect: (connectType: ConnectType) => {},
disconnect: () => {}, disconnect: () => {},
provider: undefined, provider: undefined,
chainId: undefined, chainId: undefined,
signer: undefined, signer: undefined,
signerAddress: undefined, signerAddress: undefined,
providerError: null, providerError: null,
availableConnections: [],
connectType: undefined,
}); });
export const EthereumProviderProvider = ({ export const EthereumProviderProvider = ({
children, children,
}: { }: {
@ -42,11 +64,74 @@ export const EthereumProviderProvider = ({
const [signerAddress, setSignerAddress] = useState<string | undefined>( const [signerAddress, setSignerAddress] = useState<string | undefined>(
undefined undefined
); );
const connect = useCallback(() => { const [availableConnections, setAvailableConnections] = useState<
Connection[]
>([]);
const [connectType, setConnectType] = useState<ConnectType | undefined>(
undefined
);
const [ethereumProvider, setEthereumProvider] = useState<any>(undefined);
const [walletConnectProvider, setWalletConnectProvider] = useState<
WalletConnectProvider | undefined
>(undefined);
useEffect(() => {
let cancelled = false;
(async () => {
const connections: Connection[] = [];
try {
const detectedProvider = await detectEthereumProvider();
if (detectedProvider) {
connections.push({
connectType: ConnectType.METAMASK,
name: "MetaMask",
icon: metamaskIcon,
});
}
} catch (error) {
console.error(error);
}
connections.push({
connectType: ConnectType.WALLETCONNECT,
name: "Wallet Connect",
icon: walletconnectIcon,
});
if (!cancelled) {
setAvailableConnections(connections);
}
})();
return () => {
cancelled = true;
};
}, []);
const disconnect = useCallback(() => {
setProviderError(null); setProviderError(null);
setProvider(undefined);
setChainId(undefined);
setSigner(undefined);
setSignerAddress(undefined);
setConnectType(undefined);
if (ethereumProvider && ethereumProvider.removeAllListeners) {
ethereumProvider.removeAllListeners();
setEthereumProvider(undefined);
}
if (walletConnectProvider) {
walletConnectProvider
.disconnect()
.catch((error: any) => console.error(error));
setWalletConnectProvider(undefined);
}
}, [ethereumProvider, walletConnectProvider]);
const connect = useCallback(
(connectType: ConnectType) => {
setConnectType(connectType);
if (connectType === ConnectType.METAMASK) {
detectEthereumProvider() detectEthereumProvider()
.then((detectedProvider) => { .then((detectedProvider) => {
if (detectedProvider) { if (detectedProvider) {
setEthereumProvider(detectedProvider);
const provider = new ethers.providers.Web3Provider( const provider = new ethers.providers.Web3Provider(
// @ts-ignore // @ts-ignore
detectedProvider, detectedProvider,
@ -119,14 +204,99 @@ export const EthereumProviderProvider = ({
.catch(() => { .catch(() => {
setProviderError("Please install MetaMask"); setProviderError("Please install MetaMask");
}); });
}, []); } else if (connectType === ConnectType.WALLETCONNECT) {
const disconnect = useCallback(() => { const walletConnectProvider = new WalletConnectProvider({
rpc: EVM_RPC_MAP,
storageId: "walletconnect-evm",
});
setWalletConnectProvider(walletConnectProvider);
walletConnectProvider
.enable()
.then(() => {
setProviderError(null); setProviderError(null);
setProvider(undefined); const provider = new ethers.providers.Web3Provider(
setChainId(undefined); walletConnectProvider,
setSigner(undefined); "any"
setSignerAddress(undefined); );
}, []); provider
.getNetwork()
.then((network) => {
setChainId(network.chainId);
})
.catch(() => {
setProviderError("An error occurred while getting the network");
});
walletConnectProvider.on("chainChanged", (chainId: number) => {
setChainId(chainId);
// HACK: clear the block-cache when switching chains by creating a new CacheSubprovider
// Otherwise ethers may not resolve transaction receipts/waits
const index = walletConnectProvider._providers.findIndex(
(subprovider: any) => subprovider instanceof CacheSubprovider
);
if (index >= 0) {
const subprovider = walletConnectProvider._providers[index];
walletConnectProvider.removeProvider(subprovider);
walletConnectProvider.addProvider(
new CacheSubprovider(),
index
);
// also reset the latest block
walletConnectProvider._blockTracker._resetCurrentBlock();
}
});
walletConnectProvider.on(
"accountsChanged",
(accounts: string[]) => {
try {
const signer = provider.getSigner();
setSigner(signer);
signer
.getAddress()
.then((address) => {
setSignerAddress(address);
})
.catch(() => {
setProviderError(
"An error occurred while getting the signer address"
);
});
} catch (error) {
console.error(error);
}
}
);
walletConnectProvider.on(
"disconnect",
(code: number, reason: string) => {
disconnect();
}
);
setProvider(provider);
const signer = provider.getSigner();
setSigner(signer);
signer
.getAddress()
.then((address) => {
setSignerAddress(address);
})
.catch((error) => {
setProviderError(
"An error occurred while getting the signer address"
);
console.error(error);
});
})
.catch((error) => {
if (error.message !== "User closed modal") {
setProviderError("Error enabling WalletConnect session");
console.error(error);
}
});
}
},
[disconnect]
);
const contextValue = useMemo( const contextValue = useMemo(
() => ({ () => ({
connect, connect,
@ -136,6 +306,8 @@ export const EthereumProviderProvider = ({
signer, signer,
signerAddress, signerAddress,
providerError, providerError,
availableConnections,
connectType,
}), }),
[ [
connect, connect,
@ -145,6 +317,8 @@ export const EthereumProviderProvider = ({
signer, signer,
signerAddress, signerAddress,
providerError, providerError,
availableConnections,
connectType,
] ]
); );
return ( return (

View File

@ -9,10 +9,16 @@ import { hexlify, hexStripZeros } from "@ethersproject/bytes";
import { useConnectedWallet } from "@terra-money/wallet-provider"; import { useConnectedWallet } from "@terra-money/wallet-provider";
import { useCallback, useMemo } from "react"; import { useCallback, useMemo } from "react";
import { useAlgorandContext } from "../contexts/AlgorandWalletContext"; import { useAlgorandContext } from "../contexts/AlgorandWalletContext";
import { useEthereumProvider } from "../contexts/EthereumProviderContext"; import {
ConnectType,
useEthereumProvider,
} from "../contexts/EthereumProviderContext";
import { useSolanaWallet } from "../contexts/SolanaWalletContext"; import { useSolanaWallet } from "../contexts/SolanaWalletContext";
import { CLUSTER, getEvmChainId } from "../utils/consts"; import { CLUSTER, getEvmChainId } from "../utils/consts";
import { METAMASK_CHAIN_PARAMETERS } from "../utils/metaMaskChainParameters"; import {
EVM_RPC_MAP,
METAMASK_CHAIN_PARAMETERS,
} from "../utils/metaMaskChainParameters";
const createWalletStatus = ( const createWalletStatus = (
isReady: boolean, isReady: boolean,
@ -44,6 +50,8 @@ function useIsWalletReady(
provider, provider,
signerAddress, signerAddress,
chainId: evmChainId, chainId: evmChainId,
connectType,
disconnect,
} = useEthereumProvider(); } = useEthereumProvider();
const hasEthInfo = !!provider && !!signerAddress; const hasEthInfo = !!provider && !!signerAddress;
const correctEvmNetwork = getEvmChainId(chainId); const correctEvmNetwork = getEvmChainId(chainId);
@ -56,6 +64,16 @@ function useIsWalletReady(
if (!isEVMChain(chainId)) { if (!isEVMChain(chainId)) {
return; return;
} }
if (
connectType === ConnectType.WALLETCONNECT &&
EVM_RPC_MAP[correctEvmNetwork] === undefined
) {
// WalletConnect requires a rpc url for this chain
// Force user to switch connect type
disconnect();
return;
}
try { try {
await provider.send("wallet_switchEthereumChain", [ await provider.send("wallet_switchEthereumChain", [
{ chainId: hexStripZeros(hexlify(correctEvmNetwork)) }, { chainId: hexStripZeros(hexlify(correctEvmNetwork)) },
@ -77,7 +95,7 @@ function useIsWalletReady(
} }
} }
} }
}, [provider, correctEvmNetwork, chainId]); }, [provider, correctEvmNetwork, chainId, connectType, disconnect]);
return useMemo(() => { return useMemo(() => {
if ( if (

View File

@ -0,0 +1 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 318.6 318.6" style="enable-background:new 0 0 318.6 318.6" xml:space="preserve"><style>.st1,.st2,.st3,.st4,.st5,.st6,.st9{fill:#e4761b;stroke:#e4761b;stroke-linecap:round;stroke-linejoin:round}.st2,.st3,.st4,.st5,.st6,.st9{fill:#d7c1b3;stroke:#d7c1b3}.st3,.st4,.st5,.st6,.st9{fill:#233447;stroke:#233447}.st4,.st5,.st6,.st9{fill:#cd6116;stroke:#cd6116}.st5,.st6,.st9{fill:#e4751f;stroke:#e4751f}.st6,.st9{fill:#f6851b;stroke:#f6851b}.st9{fill:#763d16;stroke:#763d16}</style><path style="fill:#e2761b;stroke:#e2761b;stroke-linecap:round;stroke-linejoin:round" d="m274.1 35.5-99.5 73.9L193 65.8z"/><path class="st1" d="m44.4 35.5 98.7 74.6-17.5-44.3zM238.3 206.8l-26.5 40.6 56.7 15.6 16.3-55.3zM33.9 207.7 50.1 263l56.7-15.6-26.5-40.6z"/><path class="st1" d="m103.6 138.2-15.8 23.9 56.3 2.5-2-60.5zM214.9 138.2l-39-34.8-1.3 61.2 56.2-2.5zM106.8 247.4l33.8-16.5-29.2-22.8zM177.9 230.9l33.9 16.5-4.7-39.3z"/><path class="st2" d="m211.8 247.4-33.9-16.5 2.7 22.1-.3 9.3zM106.8 247.4l31.5 14.9-.2-9.3 2.5-22.1z"/><path class="st3" d="m138.8 193.5-28.2-8.3 19.9-9.1zM179.7 193.5l8.3-17.4 20 9.1z"/><path class="st4" d="m106.8 247.4 4.8-40.6-31.3.9zM207 206.8l4.8 40.6 26.5-39.7zM230.8 162.1l-56.2 2.5 5.2 28.9 8.3-17.4 20 9.1zM110.6 185.2l20-9.1 8.2 17.4 5.3-28.9-56.3-2.5z"/><path class="st5" d="m87.8 162.1 23.6 46-.8-22.9zM208.1 185.2l-1 22.9 23.7-46zM144.1 164.6l-5.3 28.9 6.6 34.1 1.5-44.9zM174.6 164.6l-2.7 18 1.2 45 6.7-34.1z"/><path class="st6" d="m179.8 193.5-6.7 34.1 4.8 3.3 29.2-22.8 1-22.9zM110.6 185.2l.8 22.9 29.2 22.8 4.8-3.3-6.6-34.1z"/><path style="fill:#c0ad9e;stroke:#c0ad9e;stroke-linecap:round;stroke-linejoin:round" d="m180.3 262.3.3-9.3-2.5-2.2h-37.7l-2.3 2.2.2 9.3-31.5-14.9 11 9 22.3 15.5h38.3l22.4-15.5 11-9z"/><path style="fill:#161616;stroke:#161616;stroke-linecap:round;stroke-linejoin:round" d="m177.9 230.9-4.8-3.3h-27.7l-4.8 3.3-2.5 22.1 2.3-2.2h37.7l2.5 2.2z"/><path class="st9" d="m278.3 114.2 8.5-40.8-12.7-37.9-96.2 71.4 37 31.3 52.3 15.3 11.6-13.5-5-3.6 8-7.3-6.2-4.8 8-6.1zM31.8 73.4l8.5 40.8-5.4 4 8 6.1-6.1 4.8 8 7.3-5 3.6 11.5 13.5 52.3-15.3 37-31.3-96.2-71.4z"/><path class="st6" d="m267.2 153.5-52.3-15.3 15.9 23.9-23.7 46 31.2-.4h46.5zM103.6 138.2l-52.3 15.3-17.4 54.2h46.4l31.1.4-23.6-46zM174.6 164.6l3.3-57.7 15.2-41.1h-67.5l15 41.1 3.5 57.7 1.2 18.2.1 44.8h27.7l.2-44.8z"/></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1 @@
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"><g transform="translate(1.682 1.682) scale(1.7897)"><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath><g clip-path="url(#a)"><path d="M12.725 4.927c-2.594-2.588-6.856-2.588-9.45 0l-.344.345a.334.334 0 0 0 0 .471l1.074 1.073a.167.167 0 0 0 .236 0l.463-.462c1.809-1.806 4.783-1.806 6.592 0l.432.431a.167.167 0 0 0 .236 0l1.075-1.072a.33.33 0 0 0 0-.472l-.314-.314ZM15.902 8.1l-.956-.955a.336.336 0 0 0-.472 0l-3.06 3.055a.085.085 0 0 1-.118 0l-3.06-3.055a.336.336 0 0 0-.472 0L4.704 10.2a.085.085 0 0 1-.118 0l-3.06-3.055a.336.336 0 0 0-.472 0L.098 8.1a.33.33 0 0 0 0 .472l4.31 4.304c.131.13.343.13.473 0l3.06-3.055a.085.085 0 0 1 .118 0l3.06 3.055c.13.13.342.13.472 0l4.311-4.304a.33.33 0 0 0 0-.472Z" style="fill:#3b99fc;fill-rule:nonzero"/></g></g></svg>

After

Width:  |  Height:  |  Size: 925 B

View File

@ -27,14 +27,14 @@ export const METAMASK_CHAIN_PARAMETERS: {
chainId: "0x3", chainId: "0x3",
chainName: "Ropsten", chainName: "Ropsten",
nativeCurrency: { name: "Ropsten Ether", symbol: "ROP", decimals: 18 }, nativeCurrency: { name: "Ropsten Ether", symbol: "ROP", decimals: 18 },
rpcUrls: ["https://ropsten.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"], rpcUrls: ["https://rpc.ankr.com/eth_ropsten"],
blockExplorerUrls: ["https://ropsten.etherscan.io"], blockExplorerUrls: ["https://ropsten.etherscan.io"],
}, },
5: { 5: {
chainId: "0x5", chainId: "0x5",
chainName: "Görli", chainName: "Görli",
nativeCurrency: { name: "Görli Ether", symbol: "GOR", decimals: 18 }, nativeCurrency: { name: "Görli Ether", symbol: "GOR", decimals: 18 },
rpcUrls: ["https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"], rpcUrls: ["https://rpc.ankr.com/eth_goerli"],
blockExplorerUrls: ["https://goerli.etherscan.io"], blockExplorerUrls: ["https://goerli.etherscan.io"],
}, },
56: { 56: {
@ -172,3 +172,17 @@ export const METAMASK_CHAIN_PARAMETERS: {
blockExplorerUrls: ["https://testnet.aurorascan.dev"], blockExplorerUrls: ["https://testnet.aurorascan.dev"],
}, },
}; };
export interface EvmRpcMap {
[chainId: string]: string;
}
export const EVM_RPC_MAP = Object.entries(METAMASK_CHAIN_PARAMETERS).reduce(
(evmRpcMap, [evmChainId, { rpcUrls }]) => {
if (rpcUrls.length > 0) {
evmRpcMap[evmChainId] = rpcUrls[0];
}
return evmRpcMap;
},
{} as EvmRpcMap
);