Commit 8e11098f authored by tom goriunov's avatar tom goriunov Committed by GitHub

Merge pull request #849 from blockscout/update-wagmi

update wagmi and fix proxi contract write
parents 07d53241 6ec31b69
import type { ExternalProvider } from 'types/client/wallets'; import type { WindowProvider } from 'wagmi';
type CPreferences = { type CPreferences = {
zone: string; zone: string;
...@@ -8,9 +8,7 @@ type CPreferences = { ...@@ -8,9 +8,7 @@ type CPreferences = {
declare global { declare global {
export interface Window { export interface Window {
ethereum?: { ethereum?: WindowProvider;
providers?: Array<ExternalProvider>;
};
coinzilla_display: Array<CPreferences>; coinzilla_display: Array<CPreferences>;
ga?: { ga?: {
getAll: () => Array<{ get: (prop: string) => string }>; getAll: () => Array<{ get: (prop: string) => string }>;
......
...@@ -10,8 +10,7 @@ export function walletConnect(): CspDev.DirectiveDescriptor { ...@@ -10,8 +10,7 @@ export function walletConnect(): CspDev.DirectiveDescriptor {
return { return {
'connect-src': [ 'connect-src': [
'*.walletconnect.com', '*.walletconnect.com',
'wss://*.bridge.walletconnect.org', 'wss://relay.walletconnect.com',
'wss://www.walletlink.org',
], ],
'img-src': [ 'img-src': [
'*.walletconnect.com', '*.walletconnect.com',
......
import React from 'react'; import React from 'react';
import type { WindowProvider } from 'wagmi';
import type { ExternalProvider } from 'types/client/wallets'; import 'wagmi/window';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
export default function useProvider() { export default function useProvider() {
const [ provider, setProvider ] = React.useState<ExternalProvider>(); const [ provider, setProvider ] = React.useState<WindowProvider>();
React.useEffect(() => { React.useEffect(() => {
if (!('ethereum' in window)) { if (!('ethereum' in window)) {
......
...@@ -28,6 +28,7 @@ const moduleExports = withTM({ ...@@ -28,6 +28,7 @@ const moduleExports = withTM({
use: [ '@svgr/webpack' ], use: [ '@svgr/webpack' ],
}, },
); );
config.resolve.fallback = { fs: false, net: false, tls: false };
return config; return config;
}, },
......
...@@ -43,14 +43,13 @@ ...@@ -43,14 +43,13 @@
"@tanstack/react-query-devtools": "^4.0.10", "@tanstack/react-query-devtools": "^4.0.10",
"@types/papaparse": "^5.3.5", "@types/papaparse": "^5.3.5",
"@types/react-scroll": "^1.8.4", "@types/react-scroll": "^1.8.4",
"@web3modal/ethereum": "^2.0.0-rc.2", "@web3modal/ethereum": "^2.4.1",
"@web3modal/react": "^2.0.0-rc.2", "@web3modal/react": "^2.4.1",
"bignumber.js": "^9.1.0", "bignumber.js": "^9.1.0",
"chakra-react-select": "^4.4.3", "chakra-react-select": "^4.4.3",
"d3": "^7.6.1", "d3": "^7.6.1",
"dayjs": "^1.11.5", "dayjs": "^1.11.5",
"dom-to-image": "^2.6.0", "dom-to-image": "^2.6.0",
"ethers": "^5.7.2",
"framer-motion": "^6.5.1", "framer-motion": "^6.5.1",
"graphiql": "^2.2.0", "graphiql": "^2.2.0",
"graphql": "^16.6.0", "graphql": "^16.6.0",
...@@ -78,7 +77,8 @@ ...@@ -78,7 +77,8 @@
"react-scroll": "^1.8.7", "react-scroll": "^1.8.7",
"swagger-ui-react": "^4.15.5", "swagger-ui-react": "^4.15.5",
"use-font-face-observer": "^1.2.1", "use-font-face-observer": "^1.2.1",
"wagmi": "^0.10.6" "viem": "^0.3.39",
"wagmi": "^1.0.9"
}, },
"devDependencies": { "devDependencies": {
"@playwright/experimental-ct-react": "1.32.3", "@playwright/experimental-ct-react": "1.32.3",
...@@ -100,6 +100,7 @@ ...@@ -100,6 +100,7 @@
"@types/swagger-ui-react": "^4.11.0", "@types/swagger-ui-react": "^4.11.0",
"@types/ws": "^8.5.3", "@types/ws": "^8.5.3",
"@typescript-eslint/eslint-plugin": "^5.53.0", "@typescript-eslint/eslint-plugin": "^5.53.0",
"@vitejs/plugin-react": "^4.0.0",
"css-loader": "^6.7.3", "css-loader": "^6.7.3",
"dotenv-cli": "^6.0.0", "dotenv-cli": "^6.0.0",
"eslint": "^8.32.0", "eslint": "^8.32.0",
......
import { ChakraProvider } from '@chakra-ui/react'; import { ChakraProvider } from '@chakra-ui/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { providers } from 'ethers'; import { w3mProvider } from '@web3modal/ethereum';
import React from 'react'; import React from 'react';
import { createClient, WagmiConfig } from 'wagmi'; import { configureChains, createConfig, WagmiConfig } from 'wagmi';
import { mainnet } from 'wagmi/chains'; import { mainnet } from 'wagmi/chains';
import { MockConnector } from 'wagmi/connectors/mock';
import { AppContextProvider } from 'lib/appContext'; import { AppContextProvider } from 'lib/appContext';
import type { Props as PageProps } from 'lib/next/getServerSideProps'; import type { Props as PageProps } from 'lib/next/getServerSideProps';
...@@ -28,25 +27,17 @@ const defaultAppContext = { ...@@ -28,25 +27,17 @@ const defaultAppContext = {
}; };
// >>> Web3 stuff // >>> Web3 stuff
const provider = new providers.JsonRpcProvider( const { publicClient } = configureChains(
'http://localhost:8545', [ mainnet ],
{ [
name: 'POA', w3mProvider({ projectId: '' }),
chainId: 99, ],
},
); );
const connector = new MockConnector({ const wagmiConfig = createConfig({
chains: [ mainnet ], autoConnect: false,
options: { connectors: [ ],
signer: provider.getSigner(), publicClient,
},
});
const wagmiClient = createClient({
autoConnect: true,
connectors: [ connector ],
provider,
}); });
// <<<< // <<<<
...@@ -65,7 +56,7 @@ const TestApp = ({ children, withSocket, appContext = defaultAppContext }: Props ...@@ -65,7 +56,7 @@ const TestApp = ({ children, withSocket, appContext = defaultAppContext }: Props
<QueryClientProvider client={ queryClient }> <QueryClientProvider client={ queryClient }>
<SocketProvider url={ withSocket ? `ws://localhost:${ PORT }` : undefined }> <SocketProvider url={ withSocket ? `ws://localhost:${ PORT }` : undefined }>
<AppContextProvider { ...appContext }> <AppContextProvider { ...appContext }>
<WagmiConfig client={ wagmiClient }> <WagmiConfig config={ wagmiConfig }>
{ children } { children }
</WagmiConfig> </WagmiConfig>
</AppContextProvider> </AppContextProvider>
......
import type { providers } from 'ethers';
export type WalletType = 'metamask' | 'coinbase'; export type WalletType = 'metamask' | 'coinbase';
export interface WalletInfo { export interface WalletInfo {
name: string; name: string;
icon: React.ElementType; icon: React.ElementType;
} }
export interface ExternalProvider extends providers.ExternalProvider {
isCoinbaseWallet?: boolean;
// have to patch ethers here, since params could be not only an array
// eslint-disable-next-line @typescript-eslint/no-explicit-any
request?: (request: { method: string; params?: any }) => Promise<any>;
}
export type ArrayElement<ArrayType extends Array<unknown>> = export type ArrayElement<ArrType> = ArrType extends ReadonlyArray<infer ElementType>
ArrayType extends Array<(infer ElementType)> ? ElementType : never; ? ElementType
: never;
export type ExcludeNull<T> = T extends null ? never : T; export type ExcludeNull<T> = T extends null ? never : T;
......
import { test, expect } from '@playwright/experimental-ct-react'; import { test, expect } from '@playwright/experimental-ct-react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { WindowProvider } from 'wagmi';
import type { Address } from 'types/api/address'; import type { Address } from 'types/api/address';
...@@ -74,7 +75,7 @@ test('token', async({ mount, page }) => { ...@@ -74,7 +75,7 @@ test('token', async({ mount, page }) => {
await page.evaluate(() => { await page.evaluate(() => {
window.ethereum = { window.ethereum = {
providers: [ { isMetaMask: true } ], providers: [ { isMetaMask: true } ],
}; }as WindowProvider;
}); });
const component = await mount( const component = await mount(
......
...@@ -7,7 +7,6 @@ import { useForm } from 'react-hook-form'; ...@@ -7,7 +7,6 @@ import { useForm } from 'react-hook-form';
import type { MethodFormFields, ContractMethodCallResult } from './types'; import type { MethodFormFields, ContractMethodCallResult } from './types';
import type { SmartContractMethodInput, SmartContractMethod } from 'types/api/contract'; import type { SmartContractMethodInput, SmartContractMethod } from 'types/api/contract';
import appConfig from 'configs/app/config';
import arrowIcon from 'icons/arrows/down-right.svg'; import arrowIcon from 'icons/arrows/down-right.svg';
import ContractMethodField from './ContractMethodField'; import ContractMethodField from './ContractMethodField';
...@@ -25,7 +24,7 @@ interface Props<T extends SmartContractMethod> { ...@@ -25,7 +24,7 @@ interface Props<T extends SmartContractMethod> {
isWrite?: boolean; isWrite?: boolean;
} }
const getFieldName = (name: string, index: number): string => name || String(index); const getFieldName = (name: string | undefined, index: number): string => name || String(index);
const sortFields = (data: Array<SmartContractMethodInput>) => ([ a ]: [string, string], [ b ]: [string, string]): 1 | -1 | 0 => { const sortFields = (data: Array<SmartContractMethodInput>) => ([ a ]: [string, string], [ b ]: [string, string]): 1 | -1 | 0 => {
const fieldNames = data.map(({ name }, index) => getFieldName(name, index)); const fieldNames = data.map(({ name }, index) => getFieldName(name, index));
...@@ -67,14 +66,14 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit, ...@@ -67,14 +66,14 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit,
const [ result, setResult ] = React.useState<ContractMethodCallResult<T>>(); const [ result, setResult ] = React.useState<ContractMethodCallResult<T>>();
const [ isLoading, setLoading ] = React.useState(false); const [ isLoading, setLoading ] = React.useState(false);
const inputs = React.useMemo(() => { const inputs: Array<SmartContractMethodInput> = React.useMemo(() => {
return [ return [
...('inputs' in data ? data.inputs : []), ...('inputs' in data ? data.inputs : []),
...(data.stateMutability === 'payable' ? [ { ...('stateMutability' in data && data.stateMutability === 'payable' ? [ {
name: 'value', name: 'value',
type: appConfig.network.currency.symbol, type: 'uint256' as const,
internalType: appConfig.network.currency.symbol, internalType: 'uint256' as const,
} as SmartContractMethodInput ] : []), } ] : []),
]; ];
}, [ data ]); }, [ data ]);
......
import React from 'react'; import React from 'react';
import { useAccount, useSigner, useNetwork, useSwitchNetwork } from 'wagmi'; import { useAccount, useWalletClient, useNetwork, useSwitchNetwork } from 'wagmi';
import type { SmartContractWriteMethod } from 'types/api/contract'; import type { SmartContractWriteMethod } from 'types/api/contract';
...@@ -24,7 +24,7 @@ interface Props { ...@@ -24,7 +24,7 @@ interface Props {
} }
const ContractWrite = ({ addressHash, isProxy, isCustomAbi }: Props) => { const ContractWrite = ({ addressHash, isProxy, isCustomAbi }: Props) => {
const { data: signer } = useSigner(); const { data: walletClient } = useWalletClient();
const { isConnected } = useAccount(); const { isConnected } = useAccount();
const { chain } = useNetwork(); const { chain } = useNetwork();
const { switchNetworkAsync } = useSwitchNetwork(); const { switchNetworkAsync } = useSwitchNetwork();
...@@ -39,17 +39,17 @@ const ContractWrite = ({ addressHash, isProxy, isCustomAbi }: Props) => { ...@@ -39,17 +39,17 @@ const ContractWrite = ({ addressHash, isProxy, isCustomAbi }: Props) => {
}, },
}); });
const { contract, proxy, custom } = useContractContext(); const { contractInfo, customInfo, proxyInfo } = useContractContext();
const _contract = (() => { const abi = (() => {
if (isProxy) { if (isProxy) {
return proxy; return proxyInfo?.abi;
} }
if (isCustomAbi) { if (isCustomAbi) {
return custom; return customInfo?.abi;
} }
return contract; return contractInfo?.abi;
})(); })();
const handleMethodFormSubmit = React.useCallback(async(item: SmartContractWriteMethod, args: Array<string | Array<unknown>>) => { const handleMethodFormSubmit = React.useCallback(async(item: SmartContractWriteMethod, args: Array<string | Array<unknown>>) => {
...@@ -61,30 +61,37 @@ const ContractWrite = ({ addressHash, isProxy, isCustomAbi }: Props) => { ...@@ -61,30 +61,37 @@ const ContractWrite = ({ addressHash, isProxy, isCustomAbi }: Props) => {
await switchNetworkAsync?.(Number(config.network.id)); await switchNetworkAsync?.(Number(config.network.id));
} }
if (!_contract) { if (!abi) {
throw new Error('Something went wrong. Try again later.'); throw new Error('Something went wrong. Try again later.');
} }
if (item.type === 'receive') { if (item.type === 'receive' || item.type === 'fallback') {
const value = args[0] ? getNativeCoinValue(args[0]) : '0'; const value = getNativeCoinValue(args[0]);
const result = await signer?.sendTransaction({ const hash = await walletClient?.sendTransaction({
to: addressHash, to: addressHash as `0x${ string }` | undefined,
value, value,
}); });
return { hash: result?.hash as string }; return { hash };
} }
const _args = item.stateMutability === 'payable' ? args.slice(0, -1) : args; const _args = 'stateMutability' in item && item.stateMutability === 'payable' ? args.slice(0, -1) : args;
const value = item.stateMutability === 'payable' ? getNativeCoinValue(args[args.length - 1]) : undefined; const value = 'stateMutability' in item && item.stateMutability === 'payable' ? getNativeCoinValue(args[args.length - 1]) : undefined;
const methodName = item.type === 'fallback' ? 'fallback' : item.name; const methodName = item.name;
const result = await _contract[methodName](..._args, { if (!methodName) {
gasLimit: 100_000, throw new Error('Method name is not defined');
value, }
const hash = await walletClient?.writeContract({
args: _args,
abi: abi,
functionName: methodName,
address: addressHash as `0x${ string }`,
value: value as undefined,
}); });
return { hash: result.hash as string }; return { hash };
}, [ _contract, addressHash, chain, isConnected, signer, switchNetworkAsync ]); }, [ isConnected, chain, abi, walletClient, addressHash, switchNetworkAsync ]);
const renderContent = React.useCallback((item: SmartContractWriteMethod, index: number, id: number) => { const renderContent = React.useCallback((item: SmartContractWriteMethod, index: number, id: number) => {
return ( return (
......
...@@ -12,7 +12,7 @@ test('loading', async({ mount }) => { ...@@ -12,7 +12,7 @@ test('loading', async({ mount }) => {
error: null, error: null,
}, },
result: { result: {
hash: '0x363574E6C5C71c343d7348093D84320c76d5Dd29', hash: '0x363574E6C5C71c343d7348093D84320c76d5Dd29' as `0x${ string }`,
}, },
onSettle: () => {}, onSettle: () => {},
}; };
...@@ -33,7 +33,7 @@ test('success', async({ mount }) => { ...@@ -33,7 +33,7 @@ test('success', async({ mount }) => {
error: null, error: null,
}, },
result: { result: {
hash: '0x363574E6C5C71c343d7348093D84320c76d5Dd29', hash: '0x363574E6C5C71c343d7348093D84320c76d5Dd29' as `0x${ string }`,
}, },
onSettle: () => {}, onSettle: () => {},
}; };
...@@ -57,7 +57,7 @@ test('error +@mobile', async({ mount }) => { ...@@ -57,7 +57,7 @@ test('error +@mobile', async({ mount }) => {
} as Error, } as Error,
}, },
result: { result: {
hash: '0x363574E6C5C71c343d7348093D84320c76d5Dd29', hash: '0x363574E6C5C71c343d7348093D84320c76d5Dd29' as `0x${ string }`,
}, },
onSettle: () => {}, onSettle: () => {},
}; };
......
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import type { Contract } from 'ethers';
import React from 'react'; import React from 'react';
import { useContract, useProvider, useSigner } from 'wagmi';
import type { Address } from 'types/api/address'; import type { Address } from 'types/api/address';
import type { SmartContract } from 'types/api/contract';
import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery'; import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
...@@ -13,20 +12,18 @@ type ProviderProps = { ...@@ -13,20 +12,18 @@ type ProviderProps = {
} }
type TContractContext = { type TContractContext = {
contract: Contract | null; contractInfo: SmartContract | undefined;
proxy: Contract | null; proxyInfo: SmartContract | undefined;
custom: Contract | null; customInfo: SmartContract | undefined;
}; };
const ContractContext = React.createContext<TContractContext>({ const ContractContext = React.createContext<TContractContext>({
contract: null, proxyInfo: undefined,
proxy: null, contractInfo: undefined,
custom: null, customInfo: undefined,
}); });
export function ContractContextProvider({ addressHash, children }: ProviderProps) { export function ContractContextProvider({ addressHash, children }: ProviderProps) {
const provider = useProvider();
const { data: signer } = useSigner();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { data: contractInfo } = useApiQuery('contract', { const { data: contractInfo } = useApiQuery('contract', {
...@@ -58,27 +55,11 @@ export function ContractContextProvider({ addressHash, children }: ProviderProps ...@@ -58,27 +55,11 @@ export function ContractContextProvider({ addressHash, children }: ProviderProps
}, },
}); });
const contract = useContract({
address: addressHash,
abi: contractInfo?.abi ?? undefined,
signerOrProvider: signer ?? provider,
});
const proxy = useContract({
address: addressInfo?.implementation_address ?? undefined,
abi: proxyInfo?.abi ?? undefined,
signerOrProvider: signer ?? provider,
});
const custom = useContract({
address: addressHash,
abi: customInfo ?? undefined,
signerOrProvider: signer ?? provider,
});
const value = React.useMemo(() => ({ const value = React.useMemo(() => ({
contract, proxyInfo,
proxy, contractInfo,
custom, customInfo,
}), [ contract, proxy, custom ]); } as TContractContext), [ proxyInfo, contractInfo, customInfo ]);
return ( return (
<ContractContext.Provider value={ value }> <ContractContext.Provider value={ value }>
......
...@@ -6,7 +6,7 @@ export type MethodFormFields = Record<string, string>; ...@@ -6,7 +6,7 @@ export type MethodFormFields = Record<string, string>;
export type ContractMethodReadResult = SmartContractQueryMethodRead | ResourceError; export type ContractMethodReadResult = SmartContractQueryMethodRead | ResourceError;
export type ContractMethodWriteResult = Error | { hash: string } | undefined; export type ContractMethodWriteResult = Error | { hash: `0x${ string }` | undefined } | undefined;
export type ContractMethodCallResult<T extends SmartContractMethod> = export type ContractMethodCallResult<T extends SmartContractMethod> =
T extends { method_id: string } ? ContractMethodReadResult : ContractMethodWriteResult; T extends { method_id: string } ? ContractMethodReadResult : ContractMethodWriteResult;
import BigNumber from 'bignumber.js';
import config from 'configs/app/config'; import config from 'configs/app/config';
export const getNativeCoinValue = (value: string | Array<unknown>) => { export const getNativeCoinValue = (value: string | Array<unknown>) => {
const _value = Array.isArray(value) ? value[0] : value; const _value = Array.isArray(value) ? value[0] : value;
if (typeof _value !== 'string') { if (typeof _value !== 'string') {
return '0'; return BigInt(0);
} }
return BigNumber(_value).times(10 ** config.network.currency.decimals).toString(); return BigInt(Number(_value) * 10 ** config.network.currency.decimals);
}; };
export const addZeroesAllowed = (valueType: string) => { export const addZeroesAllowed = (valueType: string) => {
......
...@@ -30,7 +30,9 @@ const NetworkAddToWallet = ({ className }: Props) => { ...@@ -30,7 +30,9 @@ const NetworkAddToWallet = ({ className }: Props) => {
rpcUrls: [ appConfig.network.rpcUrl ], rpcUrls: [ appConfig.network.rpcUrl ],
blockExplorerUrls: [ appConfig.baseUrl ], blockExplorerUrls: [ appConfig.baseUrl ],
} ], } ],
}; // in wagmi types for wallet_addEthereumChain method is not provided
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any;
await provider?.request?.(config); await provider?.request?.(config);
toast({ toast({
position: 'top-right', position: 'top-right',
......
import { useColorModeValue, useToken } from '@chakra-ui/react'; import { useColorModeValue, useToken } from '@chakra-ui/react';
import { import { EthereumClient, w3mConnectors, w3mProvider } from '@web3modal/ethereum';
EthereumClient,
modalConnectors,
walletConnectProvider,
} from '@web3modal/ethereum';
import { Web3Modal } from '@web3modal/react'; import { Web3Modal } from '@web3modal/react';
import React from 'react'; import React from 'react';
import type { Chain } from 'wagmi'; import type { Chain } from 'wagmi';
import { configureChains, createClient, WagmiConfig } from 'wagmi'; import { configureChains, createConfig, WagmiConfig } from 'wagmi';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
const { wagmiClient, ethereumClient } = (() => { const getConfig = () => {
try { try {
if (!appConfig.walletConnect.projectId) {
throw new Error('WalletConnect Project ID is not set');
}
const currentChain: Chain = { const currentChain: Chain = {
id: Number(appConfig.network.id), id: Number(appConfig.network.id),
name: appConfig.network.name || '', name: appConfig.network.name || '',
...@@ -23,6 +23,9 @@ const { wagmiClient, ethereumClient } = (() => { ...@@ -23,6 +23,9 @@ const { wagmiClient, ethereumClient } = (() => {
symbol: appConfig.network.currency.symbol || '', symbol: appConfig.network.currency.symbol || '',
}, },
rpcUrls: { rpcUrls: {
'public': {
http: [ appConfig.network.rpcUrl || '' ],
},
'default': { 'default': {
http: [ appConfig.network.rpcUrl || '' ], http: [ appConfig.network.rpcUrl || '' ],
}, },
...@@ -37,21 +40,23 @@ const { wagmiClient, ethereumClient } = (() => { ...@@ -37,21 +40,23 @@ const { wagmiClient, ethereumClient } = (() => {
const chains = [ currentChain ]; const chains = [ currentChain ];
const { provider } = configureChains(chains, [ const { publicClient } = configureChains(chains, [
walletConnectProvider({ projectId: appConfig.walletConnect.projectId || '' }), w3mProvider({ projectId: appConfig.walletConnect.projectId || '' }),
]); ]);
const wagmiClient = createClient({ const wagmiConfig = createConfig({
autoConnect: true, autoConnect: true,
connectors: modalConnectors({ appName: 'web3Modal', chains }), connectors: w3mConnectors({ projectId: appConfig.walletConnect.projectId, chains, version: 2 }),
provider, publicClient,
}); });
const ethereumClient = new EthereumClient(wagmiClient, chains); const ethereumClient = new EthereumClient(wagmiConfig, chains);
return { wagmiClient, ethereumClient }; return { wagmiConfig, ethereumClient };
} catch (error) { } catch (error) {
return { wagmiClient: undefined, ethereumClient: undefined }; return { wagmiConfig: undefined, ethereumClient: undefined };
} }
})(); };
const { wagmiConfig, ethereumClient } = getConfig();
interface Props { interface Props {
children: React.ReactNode; children: React.ReactNode;
...@@ -62,21 +67,24 @@ const Web3ModalProvider = ({ children, fallback }: Props) => { ...@@ -62,21 +67,24 @@ const Web3ModalProvider = ({ children, fallback }: Props) => {
const modalZIndex = useToken<string>('zIndices', 'modal'); const modalZIndex = useToken<string>('zIndices', 'modal');
const web3ModalTheme = useColorModeValue('light', 'dark'); const web3ModalTheme = useColorModeValue('light', 'dark');
if (!wagmiClient || !ethereumClient) { if (!wagmiConfig || !ethereumClient || !appConfig.walletConnect.projectId) {
return typeof fallback === 'function' ? fallback() : (fallback || null); return typeof fallback === 'function' ? fallback() : (fallback || null);
} }
return ( return (
<WagmiConfig client={ wagmiClient }> <>
{ children } <WagmiConfig config={ wagmiConfig }>
{ children }
</WagmiConfig>
<Web3Modal <Web3Modal
projectId={ appConfig.walletConnect.projectId } projectId={ appConfig.walletConnect.projectId }
ethereumClient={ ethereumClient } ethereumClient={ ethereumClient }
themeZIndex={ Number(modalZIndex) }
themeMode={ web3ModalTheme } themeMode={ web3ModalTheme }
themeBackground="themeColor" themeVariables={{
'--w3m-z-index': modalZIndex,
}}
/> />
</WagmiConfig> </>
); );
}; };
......
...@@ -26,7 +26,7 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => { ...@@ -26,7 +26,7 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => {
type: 'ERC20', // Initially only supports ERC20, but eventually more! type: 'ERC20', // Initially only supports ERC20, but eventually more!
options: { options: {
address: token.address, address: token.address,
symbol: token.symbol, symbol: token.symbol || '',
decimals: Number(token.decimals) || 18, decimals: Number(token.decimals) || 18,
// TODO: add token image when we have it in API // TODO: add token image when we have it in API
// image: '' // image: ''
......
import { test as base, expect } from '@playwright/experimental-ct-react'; import { test as base, expect } from '@playwright/experimental-ct-react';
import React from 'react'; import React from 'react';
import type { WindowProvider } from 'wagmi';
import { FOOTER_LINKS } from 'mocks/config/footerLinks'; import { FOOTER_LINKS } from 'mocks/config/footerLinks';
import contextWithEnvs from 'playwright/fixtures/contextWithEnvs'; import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
...@@ -64,7 +65,7 @@ base.describe('without custom links', () => { ...@@ -64,7 +65,7 @@ base.describe('without custom links', () => {
await page.evaluate(() => { await page.evaluate(() => {
window.ethereum = { window.ethereum = {
providers: [ { isMetaMask: true } ], providers: [ { isMetaMask: true } ],
}; } as WindowProvider;
}); });
await mount( await mount(
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment