From e4adf06af522684efbacae613bb954cbac7454a2 Mon Sep 17 00:00:00 2001 From: Enes Date: Fri, 11 Oct 2024 17:19:35 +0300 Subject: [PATCH] refactor: handle custom transport objects for wagmi adapter (#3072) --- .changeset/warm-toes-unite.md | 23 +++++++ packages/adapters/wagmi/src/client.ts | 14 +++- .../adapters/wagmi/src/tests/client.test.ts | 65 +++++++++++++++++++ packages/adapters/wagmi/src/utils/helpers.ts | 28 +------- packages/appkit-utils/package.json | 3 +- packages/appkit-utils/src/CaipNetworkUtil.ts | 24 +++++++ pnpm-lock.yaml | 5 +- 7 files changed, 130 insertions(+), 32 deletions(-) create mode 100644 .changeset/warm-toes-unite.md diff --git a/.changeset/warm-toes-unite.md b/.changeset/warm-toes-unite.md new file mode 100644 index 0000000000..6d733afd3c --- /dev/null +++ b/.changeset/warm-toes-unite.md @@ -0,0 +1,23 @@ +--- +'@reown/appkit-adapter-wagmi': patch +'@reown/appkit-utils': patch +'@apps/demo': patch +'@apps/gallery': patch +'@apps/laboratory': patch +'@reown/appkit-adapter-ethers': patch +'@reown/appkit-adapter-ethers5': patch +'@reown/appkit-adapter-polkadot': patch +'@reown/appkit-adapter-solana': patch +'@reown/appkit': patch +'@reown/appkit-cdn': patch +'@reown/appkit-common': patch +'@reown/appkit-core': patch +'@reown/appkit-experimental': patch +'@reown/appkit-polyfills': patch +'@reown/appkit-scaffold-ui': patch +'@reown/appkit-siwe': patch +'@reown/appkit-ui': patch +'@reown/appkit-wallet': patch +--- + +Refactors wagmi constructor to handle custom transpor objects diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index 8b054c6c10..aa15e81841 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -48,7 +48,7 @@ import type { WriteContractArgs } from '@reown/appkit-core' import { formatUnits, parseUnits } from 'viem' -import type { Hex } from 'viem' +import type { Hex, HttpTransport } from 'viem' import { ConstantsUtil, PresetsUtil, @@ -59,7 +59,6 @@ import { import { isReownName, SafeLocalStorage, SafeLocalStorageKeys } from '@reown/appkit-common' import { getEmailCaipNetworks, - getTransport, getWalletConnectCaipNetworks, parseWalletCapabilities, requireCaipAddress @@ -169,9 +168,18 @@ export class WagmiAdapter implements ChainAdapter { const transportsArr = this.wagmiChains.map(chain => [ chain.id, - getTransport({ chain: chain as Chain, projectId: configParams.projectId }) + CaipNetworksUtil.getViemTransport(chain as CaipNetwork) ]) + Object.entries(configParams.transports ?? {}).forEach(([chainId, transport]) => { + const index = transportsArr.findIndex(([id]) => id === Number(chainId)) + if (index === -1) { + transportsArr.push([Number(chainId), transport as HttpTransport]) + } else { + transportsArr[index] = [Number(chainId), transport as HttpTransport] + } + }) + const transports = Object.fromEntries(transportsArr) const connectors: CreateConnectorFn[] = [...(configParams.connectors ?? [])] diff --git a/packages/adapters/wagmi/src/tests/client.test.ts b/packages/adapters/wagmi/src/tests/client.test.ts index bbf55cf263..1261c1f909 100644 --- a/packages/adapters/wagmi/src/tests/client.test.ts +++ b/packages/adapters/wagmi/src/tests/client.test.ts @@ -11,6 +11,8 @@ import { import { connect, disconnect, getAccount, getChainId, getEnsName, getBalance } from '@wagmi/core' import { CaipNetworksUtil, ConstantsUtil } from '@reown/appkit-utils' import type { CaipNetwork } from '@reown/appkit-common' +import { http } from 'viem' +import { WagmiAdapter } from '../client' const [mainnet, arbitrum] = CaipNetworksUtil.extendCaipNetworks( [AppkitMainnet, AppkitArbitrum, AppkitPolygon, AppkitOptimism, AppkitBsc], @@ -495,4 +497,67 @@ describe('Wagmi Client', () => { expect(mockAppKit.redirect).toHaveBeenCalledWith('ApproveTransaction') }) }) + + describe('Wagmi Client - Transports', () => { + it('should use default transports for networks without custom transports', () => { + const client = new WagmiAdapter({ + projectId: '123', + networks: [mainnet, arbitrum] + }) + + expect(client.wagmiConfig._internal.transports).toBeDefined() + expect(client.wagmiConfig._internal.transports[mainnet.id as number]).toBeDefined() + expect(client.wagmiConfig._internal.transports[arbitrum.id as number]).toBeDefined() + }) + + it('should merge user-provided transports with default transports', () => { + const customTransport = http('https://custom-rpc.example.com') + const client = new WagmiAdapter({ + projectId: '123', + networks: [mainnet, arbitrum], + transports: { + [mainnet.id]: customTransport + } + }) + + expect(client.wagmiConfig._internal.transports).toBeDefined() + expect(client.wagmiConfig._internal.transports[mainnet.id as number]).toBe(customTransport) + expect(client.wagmiConfig._internal.transports[arbitrum.id as number]).toBeDefined() + expect(client.wagmiConfig._internal.transports[arbitrum.id as number]).not.toBe( + customTransport + ) + }) + + it('should prioritize user-provided transports over default ones', () => { + const customTransport1 = http('https://custom-rpc1.example.com') + const customTransport2 = http('https://custom-rpc2.example.com') + const client = new WagmiAdapter({ + projectId: '123', + networks: [mainnet, arbitrum], + transports: { + [mainnet.id]: customTransport1, + [arbitrum.id]: customTransport2 + } + }) + + expect(client.wagmiConfig._internal.transports).toBeDefined() + expect(client.wagmiConfig._internal.transports[mainnet.id as number]).toBe(customTransport1) + expect(client.wagmiConfig._internal.transports[arbitrum.id as number]).toBe(customTransport2) + }) + + it('should handle transports for networks not in the provided networks array', () => { + const customTransport = http('https://custom-rpc.example.com') + const client = new WagmiAdapter({ + projectId: '123', + networks: [mainnet], + transports: { + [arbitrum.id]: customTransport + } + }) + + expect(client.wagmiConfig._internal.transports).toBeDefined() + expect(client.wagmiConfig._internal.transports[mainnet.id as number]).toBeDefined() + expect(client.wagmiConfig._internal.transports[arbitrum.id as number]).toBe(customTransport) + }) + }) }) diff --git a/packages/adapters/wagmi/src/utils/helpers.ts b/packages/adapters/wagmi/src/utils/helpers.ts index 1e4e679cb1..781a4f0848 100644 --- a/packages/adapters/wagmi/src/utils/helpers.ts +++ b/packages/adapters/wagmi/src/utils/helpers.ts @@ -1,11 +1,9 @@ import { type CaipNetworkId } from '@reown/appkit-common' import { ConstantsUtil, PresetsUtil } from '@reown/appkit-utils' import { UniversalProvider } from '@walletconnect/universal-provider' -import { fallback, http, type Hex } from 'viem' +import { type Hex } from 'viem' -import type { Chain } from '@wagmi/core/chains' import type { Connector } from '@wagmi/core' -import { CoreHelperUtil } from '@reown/appkit-core' import { WcHelpersUtil } from '@reown/appkit' export async function getWalletConnectCaipNetworks(connector?: Connector) { @@ -35,30 +33,6 @@ export function getEmailCaipNetworks() { } } -export function getTransport({ chain, projectId }: { chain: Chain; projectId: string }) { - const RPC_URL = CoreHelperUtil.getBlockchainApiUrl() - const chainDefaultUrl = chain.rpcUrls.default.http?.[0] - - if (!PresetsUtil.WalletConnectRpcChainIds.includes(chain.id)) { - return http(chainDefaultUrl) - } - - return fallback([ - http(`${RPC_URL}/v1/?chainId=${ConstantsUtil.EIP155}:${chain.id}&projectId=${projectId}`, { - /* - * The Blockchain API uses "Content-Type: text/plain" to avoid OPTIONS preflight requests - * It will only work for viem >= 2.17.7 - */ - fetchOptions: { - headers: { - 'Content-Type': 'text/plain' - } - } - }), - http(chainDefaultUrl) - ]) -} - export function requireCaipAddress(caipAddress: string) { if (!caipAddress) { throw new Error('No CAIP address provided') diff --git a/packages/appkit-utils/package.json b/packages/appkit-utils/package.json index acfc94fd27..f661b8d817 100644 --- a/packages/appkit-utils/package.json +++ b/packages/appkit-utils/package.json @@ -50,7 +50,8 @@ "@reown/appkit-wallet": "workspace:*", "@walletconnect/logger": "2.1.2", "@walletconnect/universal-provider": "2.17.0", - "valtio": "1.11.2" + "valtio": "1.11.2", + "viem": "2.x" }, "devDependencies": { "@coinbase/wallet-sdk": "4.0.3", diff --git a/packages/appkit-utils/src/CaipNetworkUtil.ts b/packages/appkit-utils/src/CaipNetworkUtil.ts index 9de4a905ac..966bda0991 100644 --- a/packages/appkit-utils/src/CaipNetworkUtil.ts +++ b/packages/appkit-utils/src/CaipNetworkUtil.ts @@ -5,6 +5,7 @@ import { type CaipNetworkId } from '@reown/appkit-common' import { PresetsUtil } from './PresetsUtil.js' +import { fallback, http } from 'viem' const RPC_URL_HOST = 'rpc.walletconnect.org' @@ -170,5 +171,28 @@ export const CaipNetworksUtil = { projectId }) ) as [CaipNetwork, ...CaipNetwork[]] + }, + + getViemTransport(caipNetwork: CaipNetwork) { + const chainDefaultUrl = caipNetwork.rpcUrls.default.http?.[0] + + if (!WC_HTTP_RPC_SUPPORTED_CHAINS.includes(caipNetwork.caipNetworkId)) { + return http(chainDefaultUrl) + } + + return fallback([ + http(chainDefaultUrl, { + /* + * The Blockchain API uses "Content-Type: text/plain" to avoid OPTIONS preflight requests + * It will only work for viem >= 2.17.7 + */ + fetchOptions: { + headers: { + 'Content-Type': 'text/plain' + } + } + }), + http(chainDefaultUrl) + ]) } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c0b91a389f..7d21312f47 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -712,7 +712,7 @@ importers: version: 5.2.11(@types/node@20.11.5)(terser@5.33.0) wagmi: specifier: 2.12.9 - version: 2.12.9(@tanstack/query-core@5.56.2)(@tanstack/react-query@5.24.8(react@18.2.0))(@types/react@18.2.62)(bufferutil@4.0.8)(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.2.62)(bufferutil@4.0.8)(react@18.2.0)(typescript@5.3.3)(utf-8-validate@5.0.10))(react@18.2.0)(rollup@4.22.4)(typescript@5.3.3)(utf-8-validate@5.0.10)(viem@2.21.4(bufferutil@4.0.8)(typescript@5.3.3)(utf-8-validate@5.0.10)(zod@3.22.4))(zod@3.22.4) + version: 2.12.9(@tanstack/query-core@5.56.2)(@tanstack/react-query@5.24.8(react@18.2.0))(@types/react@18.2.62)(bufferutil@4.0.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@4.22.4)(typescript@5.3.3)(utf-8-validate@5.0.10)(viem@2.21.4(bufferutil@4.0.8)(typescript@5.3.3)(utf-8-validate@5.0.10)(zod@3.22.4))(zod@3.22.4) devDependencies: '@types/react': specifier: 18.2.62 @@ -1189,6 +1189,9 @@ importers: valtio: specifier: 1.11.2 version: 1.11.2(@types/react@18.2.62)(react@18.2.0) + viem: + specifier: 2.x + version: 2.21.4(bufferutil@4.0.8)(typescript@5.3.3)(utf-8-validate@5.0.10)(zod@3.22.4) devDependencies: '@coinbase/wallet-sdk': specifier: 4.0.3