From a73a7737b756886b388f120ae423e72cca53e8a0 Mon Sep 17 00:00:00 2001 From: jxom Date: Tue, 23 Jul 2024 15:37:51 +1000 Subject: [PATCH] feat: propagate transport rpc urls to connectors (#4162) * feat: propagate transport rpc urls to connectors * tests: update snaps --- .changeset/real-squids-add.md | 8 ++ packages/connectors/src/metaMask.ts | 12 ++- packages/connectors/src/walletConnect.ts | 12 ++- .../core/src/connectors/createConnector.ts | 2 + packages/core/src/createConfig.ts | 7 +- packages/core/src/exports/index.test.ts | 1 + packages/core/src/exports/index.ts | 2 + .../core/src/utils/extractRpcUrls.test.ts | 73 +++++++++++++++++++ packages/core/src/utils/extractRpcUrls.ts | 19 +++++ 9 files changed, 127 insertions(+), 9 deletions(-) create mode 100644 .changeset/real-squids-add.md create mode 100644 packages/core/src/utils/extractRpcUrls.test.ts create mode 100644 packages/core/src/utils/extractRpcUrls.ts diff --git a/.changeset/real-squids-add.md b/.changeset/real-squids-add.md new file mode 100644 index 0000000000..51e69dd33b --- /dev/null +++ b/.changeset/real-squids-add.md @@ -0,0 +1,8 @@ +--- +"@wagmi/connectors": minor +"@wagmi/core": minor +"wagmi": minor +"@wagmi/vue": minor +--- + +Added functionality for consumer-defined RPC URLs (`config.transports`) to be propagated to the WalletConnect & MetaMask Connectors. diff --git a/packages/connectors/src/metaMask.ts b/packages/connectors/src/metaMask.ts index a54e9b8c45..6d10c98a22 100644 --- a/packages/connectors/src/metaMask.ts +++ b/packages/connectors/src/metaMask.ts @@ -7,6 +7,7 @@ import { ChainNotConfiguredError, type Connector, createConnector, + extractRpcUrls, } from '@wagmi/core' import type { Compute, @@ -175,10 +176,13 @@ export function metaMask(parameters: MetaMaskParameters = {}) { // Workaround cast since MetaMask SDK does not support `'exactOptionalPropertyTypes'` ...(parameters as RemoveUndefined), readonlyRPCMap: Object.fromEntries( - config.chains.map((chain) => [ - chain.id, - chain.rpcUrls.default.http[0]!, - ]), + config.chains.map((chain) => { + const [url] = extractRpcUrls({ + chain, + transports: config.transports, + }) + return [chain.id, url] + }), ), dappMetadata: parameters.dappMetadata ?? {}, useDeeplink: parameters.useDeeplink ?? true, diff --git a/packages/connectors/src/walletConnect.ts b/packages/connectors/src/walletConnect.ts index 4eed9b328c..40f8fb17b5 100644 --- a/packages/connectors/src/walletConnect.ts +++ b/packages/connectors/src/walletConnect.ts @@ -3,6 +3,7 @@ import { type Connector, ProviderNotFoundError, createConnector, + extractRpcUrls, } from '@wagmi/core' import type { Compute, ExactPartial, Omit } from '@wagmi/core/internal' import type { EthereumProvider } from '@walletconnect/ethereum-provider' @@ -249,10 +250,13 @@ export function walletConnect(parameters: WalletConnectParameters) { optionalChains, projectId: parameters.projectId, rpcMap: Object.fromEntries( - config.chains.map((chain) => [ - chain.id, - chain.rpcUrls.default.http[0]!, - ]), + config.chains.map((chain) => { + const [url] = extractRpcUrls({ + chain, + transports: config.transports, + }) + return [chain.id, url] + }), ), showQrModal: parameters.showQrModal ?? true, }) diff --git a/packages/core/src/connectors/createConnector.ts b/packages/core/src/connectors/createConnector.ts index c749f9a41f..75a4ae3fad 100644 --- a/packages/core/src/connectors/createConnector.ts +++ b/packages/core/src/connectors/createConnector.ts @@ -7,6 +7,7 @@ import type { ProviderMessage, } from 'viem' +import type { Transport } from '../createConfig.js' import type { Emitter } from '../createEmitter.js' import type { Storage } from '../createStorage.js' import type { Compute, ExactPartial, StrictOmit } from '../types/utils.js' @@ -30,6 +31,7 @@ export type CreateConnectorFn< chains: readonly [Chain, ...Chain[]] emitter: Emitter storage?: Compute> | null | undefined + transports?: Record | undefined }) => Compute< { readonly icon?: string | undefined diff --git a/packages/core/src/createConfig.ts b/packages/core/src/createConfig.ts index 9d00bdedc3..4429a4c3bb 100644 --- a/packages/core/src/createConfig.ts +++ b/packages/core/src/createConfig.ts @@ -103,7 +103,12 @@ export function createConfig< // Set up emitter with uid and add to connector so they are "linked" together. const emitter = createEmitter(uid()) const connector = { - ...connectorFn({ emitter, chains: chains.getState(), storage }), + ...connectorFn({ + emitter, + chains: chains.getState(), + storage, + transports: rest.transports, + }), emitter, uid: emitter.uid, } diff --git a/packages/core/src/exports/index.test.ts b/packages/core/src/exports/index.test.ts index 985249dc72..34c546e088 100644 --- a/packages/core/src/exports/index.test.ts +++ b/packages/core/src/exports/index.test.ts @@ -102,6 +102,7 @@ test('exports', () => { "parseCookie", "deepEqual", "deserialize", + "extractRpcUrls", "normalizeChainId", "serialize", "version", diff --git a/packages/core/src/exports/index.ts b/packages/core/src/exports/index.ts index a389369aee..6b71048f7d 100644 --- a/packages/core/src/exports/index.ts +++ b/packages/core/src/exports/index.ts @@ -543,6 +543,8 @@ export { deepEqual } from '../utils/deepEqual.js' export { deserialize } from '../utils/deserialize.js' +export { extractRpcUrls } from '../utils/extractRpcUrls.js' + export { normalizeChainId } from '../utils/normalizeChainId.js' export { serialize } from '../utils/serialize.js' diff --git a/packages/core/src/utils/extractRpcUrls.test.ts b/packages/core/src/utils/extractRpcUrls.test.ts new file mode 100644 index 0000000000..84355c1e16 --- /dev/null +++ b/packages/core/src/utils/extractRpcUrls.test.ts @@ -0,0 +1,73 @@ +import { http } from 'viem' +import { mainnet, optimism, sepolia } from 'viem/chains' +import { expect, test } from 'vitest' + +import { fallback } from '../transports/fallback.js' +import { extractRpcUrls } from './extractRpcUrls.js' + +test('default', () => { + expect( + extractRpcUrls({ + chain: mainnet, + transports: { + [mainnet.id]: fallback([ + http('https://wagmi.com'), + http('https://lol.com'), + ]), + [sepolia.id]: http('https://sepoliarocks.com'), + [optimism.id]: http(), + }, + }), + ).toMatchInlineSnapshot(` + [ + "https://wagmi.com", + "https://lol.com", + ] + `) + + expect( + extractRpcUrls({ + chain: sepolia, + transports: { + [mainnet.id]: fallback([ + http('https://wagmi.com'), + http('https://lol.com'), + ]), + [sepolia.id]: http('https://sepoliarocks.com'), + [optimism.id]: http(), + }, + }), + ).toMatchInlineSnapshot(` + [ + "https://sepoliarocks.com", + ] + `) + + expect( + extractRpcUrls({ + chain: optimism, + transports: { + [mainnet.id]: fallback([ + http('https://wagmi.com'), + http('https://lol.com'), + ]), + [sepolia.id]: http('https://sepoliarocks.com'), + [optimism.id]: http(), + }, + }), + ).toMatchInlineSnapshot(` + [ + "https://mainnet.optimism.io", + ] + `) + + expect( + extractRpcUrls({ + chain: mainnet, + }), + ).toMatchInlineSnapshot(` + [ + "https://cloudflare-eth.com", + ] + `) +}) diff --git a/packages/core/src/utils/extractRpcUrls.ts b/packages/core/src/utils/extractRpcUrls.ts new file mode 100644 index 0000000000..2fab6c0657 --- /dev/null +++ b/packages/core/src/utils/extractRpcUrls.ts @@ -0,0 +1,19 @@ +import type { Chain, Transport } from 'viem' + +type ExtractRpcUrlsParameters = { + transports?: Record | undefined + chain: Chain +} + +export function extractRpcUrls(parameters: ExtractRpcUrlsParameters) { + const { chain } = parameters + const fallbackUrl = chain.rpcUrls.default.http[0] + + if (!parameters.transports) return [fallbackUrl] + + const transport = parameters.transports?.[chain.id]?.({ chain }) + const transports = transport?.value?.transports || [transport] + return transports.map( + ({ value }: { value: { url: string } }) => value.url || fallbackUrl, + ) +}