FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

306
node_modules/viem/clients/createClient.ts generated vendored Normal file
View File

@@ -0,0 +1,306 @@
import type { Address } from 'abitype'
import type { JsonRpcAccount } from '../accounts/types.js'
import {
type ParseAccountErrorType,
parseAccount,
} from '../accounts/utils/parseAccount.js'
import type { ErrorType } from '../errors/utils.js'
import type { Account } from '../types/account.js'
import type { BlockTag } from '../types/block.js'
import type { Chain } from '../types/chain.js'
import type { DataSuffix } from '../types/dataSuffix.js'
import type {
EIP1193RequestFn,
EIP1474Methods,
RpcSchema,
} from '../types/eip1193.js'
import type { ExactPartial, Prettify } from '../types/utils.js'
import type {
CcipRequestParameters,
CcipRequestReturnType,
} from '../utils/ccip.js'
import { uid } from '../utils/uid.js'
import type { PublicActions } from './decorators/public.js'
import type { WalletActions } from './decorators/wallet.js'
import type { Transport } from './transports/createTransport.js'
export type ClientConfig<
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
accountOrAddress extends Account | Address | undefined =
| Account
| Address
| undefined,
rpcSchema extends RpcSchema | undefined = undefined,
> = {
/** The Account to use for the Client. This will be used for Actions that require an account as an argument. */
account?: accountOrAddress | Account | Address | undefined
/** Flags for batch settings. */
batch?:
| {
/** Toggle to enable `eth_call` multicall aggregation. */
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined
}
| undefined
/**
* Default block tag to use for RPC requests.
*
* If the chain supports a pre-confirmation mechanism
* (set via `chain.experimental_preconfirmationTime`), defaults to `'pending'`.
*
* @default 'latest'
*/
experimental_blockTag?: BlockTag | undefined
/**
* Time (in ms) that cached data will remain in memory.
* @default chain.blockTime / 3
*/
cacheTime?: number | undefined
/**
* [CCIP Read](https://eips.ethereum.org/EIPS/eip-3668) configuration.
* If `false`, the client will not support offchain CCIP lookups.
*/
ccipRead?:
| {
/**
* A function that will be called to make the offchain CCIP lookup request.
* @see https://eips.ethereum.org/EIPS/eip-3668#client-lookup-protocol
*/
request?: (
parameters: CcipRequestParameters,
) => Promise<CcipRequestReturnType>
}
| false
| undefined
/** Chain for the client. */
chain?: Chain | undefined | chain
/** Data suffix to append to transaction data. */
dataSuffix?: DataSuffix | undefined
/** A key for the client. */
key?: string | undefined
/** A name for the client. */
name?: string | undefined
/**
* Frequency (in ms) for polling enabled actions & events.
* @default chain.blockTime / 3
*/
pollingInterval?: number | undefined
/**
* Typed JSON-RPC schema for the client.
*/
rpcSchema?: rpcSchema | undefined
/** The RPC transport */
transport: transport
/** The type of client. */
type?: string | undefined
}
// Actions that are used internally by other Actions (ie. `call` is used by `readContract`).
// They are allowed to be extended, but must conform to their parameter & return type interfaces.
// Example: an extended `call` action must accept `CallParameters` as parameters,
// and conform to the `CallReturnType` return type.
type ExtendableProtectedActions<
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
> = Pick<
PublicActions<transport, chain, account>,
| 'call'
| 'createContractEventFilter'
| 'createEventFilter'
| 'estimateContractGas'
| 'estimateGas'
| 'getBlock'
| 'getBlockNumber'
| 'getChainId'
| 'getContractEvents'
| 'getEnsText'
| 'getFilterChanges'
| 'getGasPrice'
| 'getLogs'
| 'getTransaction'
| 'getTransactionCount'
| 'getTransactionReceipt'
| 'prepareTransactionRequest'
| 'readContract'
| 'sendRawTransaction'
| 'simulateContract'
| 'uninstallFilter'
| 'watchBlockNumber'
| 'watchContractEvent'
> &
Pick<WalletActions<chain, account>, 'sendTransaction' | 'writeContract'>
// TODO: Move `transport` to slot index 2 since `chain` and `account` used more frequently.
// Otherwise, we end up with a lot of `Client<Transport, chain, account>` in actions.
export type Client<
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
rpcSchema extends RpcSchema | undefined = undefined,
extended extends Extended | undefined = Extended | undefined,
> = Client_Base<transport, chain, account, rpcSchema> &
(extended extends Extended ? extended : unknown) & {
extend: <
const client extends Extended &
ExactPartial<ExtendableProtectedActions<transport, chain, account>>,
>(
fn: (
client: Client<transport, chain, account, rpcSchema, extended>,
) => client,
) => Client<
transport,
chain,
account,
rpcSchema,
Prettify<client> & (extended extends Extended ? extended : unknown)
>
}
type Client_Base<
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
rpcSchema extends RpcSchema | undefined = undefined,
> = {
/** The Account of the Client. */
account: account
/** Flags for batch settings. */
batch?: ClientConfig['batch'] | undefined
/** Time (in ms) that cached data will remain in memory. */
cacheTime: number
/** [CCIP Read](https://eips.ethereum.org/EIPS/eip-3668) configuration. */
ccipRead?: ClientConfig['ccipRead'] | undefined
/** Chain for the client. */
chain: chain
/** Data suffix to append to transaction data. */
dataSuffix?: DataSuffix | undefined
/** Default block tag to use for RPC requests. */
experimental_blockTag?: BlockTag | undefined
/** A key for the client. */
key: string
/** A name for the client. */
name: string
/** Frequency (in ms) for polling enabled actions & events. Defaults to 4_000 milliseconds. */
pollingInterval: number
/** Request function wrapped with friendly error handling */
request: EIP1193RequestFn<
rpcSchema extends undefined ? EIP1474Methods : rpcSchema
>
/** The RPC transport */
transport: ReturnType<transport>['config'] & ReturnType<transport>['value']
/** The type of client. */
type: string
/** A unique ID for the client. */
uid: string
}
type Extended = Prettify<
// disallow redefining base properties
{ [_ in keyof Client_Base]?: undefined } & {
[key: string]: unknown
}
>
export type MulticallBatchOptions = {
/** The maximum size (in bytes) for each calldata chunk. @default 1_024 */
batchSize?: number | undefined
/** Enable deployless multicall. */
deployless?: boolean | undefined
/** The maximum number of milliseconds to wait before sending a batch. @default 0 */
wait?: number | undefined
}
export type CreateClientErrorType = ParseAccountErrorType | ErrorType
export function createClient<
transport extends Transport,
chain extends Chain | undefined = undefined,
accountOrAddress extends Account | Address | undefined = undefined,
rpcSchema extends RpcSchema | undefined = undefined,
>(
parameters: ClientConfig<transport, chain, accountOrAddress, rpcSchema>,
): Prettify<
Client<
transport,
chain,
accountOrAddress extends Address
? Prettify<JsonRpcAccount<accountOrAddress>>
: accountOrAddress,
rpcSchema
>
>
export function createClient(parameters: ClientConfig): Client {
const {
batch,
chain,
ccipRead,
dataSuffix,
key = 'base',
name = 'Base Client',
type = 'base',
} = parameters
const experimental_blockTag =
parameters.experimental_blockTag ??
(typeof chain?.experimental_preconfirmationTime === 'number'
? 'pending'
: undefined)
const blockTime = chain?.blockTime ?? 12_000
const defaultPollingInterval = Math.min(
Math.max(Math.floor(blockTime / 2), 500),
4_000,
)
const pollingInterval = parameters.pollingInterval ?? defaultPollingInterval
const cacheTime = parameters.cacheTime ?? pollingInterval
const account = parameters.account
? parseAccount(parameters.account)
: undefined
const { config, request, value } = parameters.transport({
account,
chain,
pollingInterval,
})
const transport = { ...config, ...value }
const client = {
account,
batch,
cacheTime,
ccipRead,
chain,
dataSuffix,
key,
name,
pollingInterval,
request,
transport,
type,
uid: uid(),
...(experimental_blockTag ? { experimental_blockTag } : {}),
}
function extend(base: typeof client) {
type ExtendFn = (base: typeof client) => unknown
return (extendFn: ExtendFn) => {
const extended = extendFn(base) as Extended
for (const key in client) delete extended[key]
const combined = { ...base, ...extended }
return Object.assign(combined, { extend: extend(combined as any) })
}
}
return Object.assign(client, { extend: extend(client) as any })
}
/**
* Defines a typed JSON-RPC schema for the client.
* Note: This is a runtime noop function.
*/
export function rpcSchema<rpcSchema extends RpcSchema>(): rpcSchema {
return null as any
}

91
node_modules/viem/clients/createPublicClient.ts generated vendored Normal file
View File

@@ -0,0 +1,91 @@
import type { Address } from 'abitype'
import type { ErrorType } from '../errors/utils.js'
import type { Account, ParseAccount } from '../types/account.js'
import type { Chain } from '../types/chain.js'
import type { PublicRpcSchema, RpcSchema } from '../types/eip1193.js'
import type { Prettify } from '../types/utils.js'
import {
type Client,
type ClientConfig,
type CreateClientErrorType,
createClient,
} from './createClient.js'
import { type PublicActions, publicActions } from './decorators/public.js'
import type { Transport } from './transports/createTransport.js'
export type PublicClientConfig<
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
accountOrAddress extends Account | Address | undefined = undefined,
rpcSchema extends RpcSchema | undefined = undefined,
> = Prettify<
Pick<
ClientConfig<transport, chain, accountOrAddress, rpcSchema>,
| 'batch'
| 'cacheTime'
| 'ccipRead'
| 'chain'
| 'experimental_blockTag'
| 'key'
| 'name'
| 'pollingInterval'
| 'rpcSchema'
| 'transport'
>
>
export type PublicClient<
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
accountOrAddress extends Account | undefined = undefined,
rpcSchema extends RpcSchema | undefined = undefined,
> = Prettify<
Client<
transport,
chain,
accountOrAddress,
rpcSchema extends RpcSchema
? [...PublicRpcSchema, ...rpcSchema]
: PublicRpcSchema,
PublicActions<transport, chain>
>
>
export type CreatePublicClientErrorType = CreateClientErrorType | ErrorType
/**
* Creates a Public Client with a given [Transport](https://viem.sh/docs/clients/intro) configured for a [Chain](https://viem.sh/docs/clients/chains).
*
* - Docs: https://viem.sh/docs/clients/public
*
* A Public Client is an interface to "public" [JSON-RPC API](https://ethereum.org/en/developers/docs/apis/json-rpc/) methods such as retrieving block numbers, transactions, reading from smart contracts, etc through [Public Actions](/docs/actions/public/introduction).
*
* @param config - {@link PublicClientConfig}
* @returns A Public Client. {@link PublicClient}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
*/
export function createPublicClient<
transport extends Transport,
chain extends Chain | undefined = undefined,
accountOrAddress extends Account | Address | undefined = undefined,
rpcSchema extends RpcSchema | undefined = undefined,
>(
parameters: PublicClientConfig<transport, chain, accountOrAddress, rpcSchema>,
): PublicClient<transport, chain, ParseAccount<accountOrAddress>, rpcSchema> {
const { key = 'public', name = 'Public Client' } = parameters
const client = createClient({
...parameters,
key,
name,
type: 'publicClient',
})
return client.extend(publicActions) as any
}

127
node_modules/viem/clients/createTestClient.ts generated vendored Normal file
View File

@@ -0,0 +1,127 @@
import type { Address } from 'abitype'
import type { Account } from '../accounts/types.js'
import type { ErrorType } from '../errors/utils.js'
import type { ParseAccount } from '../types/account.js'
import type { Chain } from '../types/chain.js'
import type { RpcSchema, TestRpcSchema } from '../types/eip1193.js'
import type { Prettify } from '../types/utils.js'
import {
type Client,
type ClientConfig,
type CreateClientErrorType,
createClient,
} from './createClient.js'
import { type TestActions, testActions } from './decorators/test.js'
import type { Transport } from './transports/createTransport.js'
export type TestClientMode = 'anvil' | 'hardhat' | 'ganache'
export type TestClientConfig<
mode extends TestClientMode = TestClientMode,
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
accountOrAddress extends Account | Address | undefined =
| Account
| Address
| undefined,
rpcSchema extends RpcSchema | undefined = undefined,
> = Prettify<
Pick<
ClientConfig<transport, chain, accountOrAddress, rpcSchema>,
| 'account'
| 'cacheTime'
| 'chain'
| 'key'
| 'name'
| 'pollingInterval'
| 'rpcSchema'
| 'transport'
> & {
/** Mode of the test client. */
mode: mode | ('anvil' | 'hardhat' | 'ganache') // TODO: Type utility that expands `TestClientMode`
}
>
export type TestClient<
mode extends TestClientMode = TestClientMode,
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
includeActions extends boolean = true,
rpcSchema extends RpcSchema | undefined = undefined,
> = Prettify<
{ mode: mode } & Client<
transport,
chain,
account,
rpcSchema extends RpcSchema
? [...TestRpcSchema<mode>, ...rpcSchema]
: TestRpcSchema<mode>,
{ mode: mode } & (includeActions extends true
? TestActions
: Record<string, unknown>)
>
>
export type CreateTestClientErrorType = CreateClientErrorType | ErrorType
/**
* @description Creates a test client with a given transport.
*/
/**
* Creates a Test Client with a given [Transport](https://viem.sh/docs/clients/intro) configured for a [Chain](https://viem.sh/docs/clients/chains).
*
* - Docs: https://viem.sh/docs/clients/test
*
* A Test Client is an interface to "test" JSON-RPC API methods accessible through a local Ethereum test node such as [Anvil](https://book.getfoundry.sh/anvil/) or [Hardhat](https://hardhat.org/) such as mining blocks, impersonating accounts, setting fees, etc through [Test Actions](https://viem.sh/docs/actions/test/introduction).
*
* @param config - {@link TestClientConfig}
* @returns A Test Client. {@link TestClient}
*
* @example
* import { createTestClient, custom } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: foundry,
* transport: http(),
* })
*/
export function createTestClient<
mode extends 'anvil' | 'hardhat' | 'ganache', // TODO: Type utility that expands `TestClientMode`
transport extends Transport,
chain extends Chain | undefined = undefined,
accountOrAddress extends Account | Address | undefined = undefined,
rpcSchema extends RpcSchema | undefined = undefined,
>(
parameters: TestClientConfig<
mode,
transport,
chain,
accountOrAddress,
rpcSchema
>,
): TestClient<
mode,
transport,
chain,
ParseAccount<accountOrAddress>,
true,
rpcSchema
>
export function createTestClient(parameters: TestClientConfig): TestClient {
const { key = 'test', name = 'Test Client', mode } = parameters
const client = createClient({
...parameters,
key,
name,
type: 'testClient',
})
return client.extend((config) => ({
mode,
...testActions({ mode })(config),
}))
}

118
node_modules/viem/clients/createWalletClient.ts generated vendored Normal file
View File

@@ -0,0 +1,118 @@
import type { Address } from 'abitype'
import type { Account } from '../accounts/types.js'
import type { ErrorType } from '../errors/utils.js'
import type { ParseAccount } from '../types/account.js'
import type { Chain } from '../types/chain.js'
import type { RpcSchema, WalletRpcSchema } from '../types/eip1193.js'
import type { Prettify } from '../types/utils.js'
import {
type Client,
type ClientConfig,
type CreateClientErrorType,
createClient,
} from './createClient.js'
import { type WalletActions, walletActions } from './decorators/wallet.js'
import type { Transport } from './transports/createTransport.js'
export type WalletClientConfig<
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
accountOrAddress extends Account | Address | undefined =
| Account
| Address
| undefined,
rpcSchema extends RpcSchema | undefined = undefined,
> = Prettify<
Pick<
ClientConfig<transport, chain, accountOrAddress, rpcSchema>,
| 'account'
| 'cacheTime'
| 'ccipRead'
| 'chain'
| 'dataSuffix'
| 'key'
| 'name'
| 'pollingInterval'
| 'rpcSchema'
| 'transport'
>
>
export type WalletClient<
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
rpcSchema extends RpcSchema | undefined = undefined,
> = Prettify<
Client<
transport,
chain,
account,
rpcSchema extends RpcSchema
? [...WalletRpcSchema, ...rpcSchema]
: WalletRpcSchema,
WalletActions<chain, account>
>
>
export type CreateWalletClientErrorType = CreateClientErrorType | ErrorType
/**
* Creates a Wallet Client with a given [Transport](https://viem.sh/docs/clients/intro) configured for a [Chain](https://viem.sh/docs/clients/chains).
*
* - Docs: https://viem.sh/docs/clients/wallet
*
* A Wallet Client is an interface to interact with [Ethereum Account(s)](https://ethereum.org/en/glossary/#account) and provides the ability to retrieve accounts, execute transactions, sign messages, etc. through [Wallet Actions](https://viem.sh/docs/actions/wallet/introduction).
*
* The Wallet Client supports signing over:
* - [JSON-RPC Accounts](https://viem.sh/docs/clients/wallet#json-rpc-accounts) (e.g. Browser Extension Wallets, WalletConnect, etc).
* - [Local Accounts](https://viem.sh/docs/clients/wallet#local-accounts-private-key-mnemonic-etc) (e.g. private key/mnemonic wallets).
*
* @param config - {@link WalletClientConfig}
* @returns A Wallet Client. {@link WalletClient}
*
* @example
* // JSON-RPC Account
* import { createWalletClient, custom } from 'viem'
* import { mainnet } from 'viem/chains'
*
* const client = createWalletClient({
* chain: mainnet,
* transport: custom(window.ethereum),
* })
*
* @example
* // Local Account
* import { createWalletClient, custom } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { mainnet } from 'viem/chains'
*
* const client = createWalletClient({
* account: privateKeyToAccount('0x…')
* chain: mainnet,
* transport: http(),
* })
*/
export function createWalletClient<
transport extends Transport,
chain extends Chain | undefined = undefined,
accountOrAddress extends Account | Address | undefined = undefined,
rpcSchema extends RpcSchema | undefined = undefined,
>(
parameters: WalletClientConfig<transport, chain, accountOrAddress, rpcSchema>,
): WalletClient<transport, chain, ParseAccount<accountOrAddress>, rpcSchema>
export function createWalletClient(
parameters: WalletClientConfig,
): WalletClient {
const { key = 'wallet', name = 'Wallet Client', transport } = parameters
const client = createClient({
...parameters,
key,
name,
transport,
type: 'walletClient',
})
return client.extend(walletActions)
}

2140
node_modules/viem/clients/decorators/public.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

777
node_modules/viem/clients/decorators/test.ts generated vendored Normal file
View File

@@ -0,0 +1,777 @@
import {
type DropTransactionParameters,
dropTransaction,
} from '../../actions/test/dropTransaction.js'
import {
type DumpStateReturnType,
dumpState,
} from '../../actions/test/dumpState.js'
import {
type GetAutomineReturnType,
getAutomine,
} from '../../actions/test/getAutomine.js'
import {
type GetTxpoolContentReturnType,
getTxpoolContent,
} from '../../actions/test/getTxpoolContent.js'
import {
type GetTxpoolStatusReturnType,
getTxpoolStatus,
} from '../../actions/test/getTxpoolStatus.js'
import {
type ImpersonateAccountParameters,
impersonateAccount,
} from '../../actions/test/impersonateAccount.js'
import {
type IncreaseTimeParameters,
increaseTime,
} from '../../actions/test/increaseTime.js'
import {
type InspectTxpoolReturnType,
inspectTxpool,
} from '../../actions/test/inspectTxpool.js'
import {
type LoadStateParameters,
type LoadStateReturnType,
loadState,
} from '../../actions/test/loadState.js'
import { type MineParameters, mine } from '../../actions/test/mine.js'
import { removeBlockTimestampInterval } from '../../actions/test/removeBlockTimestampInterval.js'
import { type ResetParameters, reset } from '../../actions/test/reset.js'
import { type RevertParameters, revert } from '../../actions/test/revert.js'
import {
type SendUnsignedTransactionParameters,
type SendUnsignedTransactionReturnType,
sendUnsignedTransaction,
} from '../../actions/test/sendUnsignedTransaction.js'
import { setAutomine } from '../../actions/test/setAutomine.js'
import {
type SetBalanceParameters,
setBalance,
} from '../../actions/test/setBalance.js'
import {
type SetBlockGasLimitParameters,
setBlockGasLimit,
} from '../../actions/test/setBlockGasLimit.js'
import {
type SetBlockTimestampIntervalParameters,
setBlockTimestampInterval,
} from '../../actions/test/setBlockTimestampInterval.js'
import { type SetCodeParameters, setCode } from '../../actions/test/setCode.js'
import {
type SetCoinbaseParameters,
setCoinbase,
} from '../../actions/test/setCoinbase.js'
import {
type SetIntervalMiningParameters,
setIntervalMining,
} from '../../actions/test/setIntervalMining.js'
import { setLoggingEnabled } from '../../actions/test/setLoggingEnabled.js'
import {
type SetMinGasPriceParameters,
setMinGasPrice,
} from '../../actions/test/setMinGasPrice.js'
import {
type SetNextBlockBaseFeePerGasParameters,
setNextBlockBaseFeePerGas,
} from '../../actions/test/setNextBlockBaseFeePerGas.js'
import {
type SetNextBlockTimestampParameters,
setNextBlockTimestamp,
} from '../../actions/test/setNextBlockTimestamp.js'
import {
type SetNonceParameters,
setNonce,
} from '../../actions/test/setNonce.js'
import { setRpcUrl } from '../../actions/test/setRpcUrl.js'
import {
type SetStorageAtParameters,
setStorageAt,
} from '../../actions/test/setStorageAt.js'
import { snapshot } from '../../actions/test/snapshot.js'
import {
type StopImpersonatingAccountParameters,
stopImpersonatingAccount,
} from '../../actions/test/stopImpersonatingAccount.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { Quantity } from '../../types/rpc.js'
import type { Client } from '../createClient.js'
import type { TestClientMode } from '../createTestClient.js'
import type { Transport } from '../transports/createTransport.js'
export type TestActions = {
/**
* Removes a transaction from the mempool.
*
* - Docs: https://viem.sh/docs/actions/test/dropTransaction
*
* @param args - {@link DropTransactionParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.dropTransaction({
* hash: '0xe58dceb6b20b03965bb678e27d141e151d7d4efc2334c2d6a49b9fac523f7364'
* })
*/
dropTransaction: (args: DropTransactionParameters) => Promise<void>
/**
* Serializes the current state (including contracts code, contract's storage,
* accounts properties, etc.) into a savable data blob.
*
* - Docs: https://viem.sh/docs/actions/test/dumpState
*
* @param client - Client to use
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.dumpState()
*/
dumpState: () => Promise<DumpStateReturnType>
/**
* Returns the automatic mining status of the node.
*
* - Docs: https://viem.sh/docs/actions/test/getAutomine
*
* @returns Whether or not the node is auto mining. {@link GetAutomineReturnType}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* const isAutomining = await client.getAutomine()
*/
getAutomine: () => Promise<GetAutomineReturnType>
/**
* Returns the details of all transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only.
*
* - Docs: https://viem.sh/docs/actions/test/getTxpoolContent
*
* @returns Transaction pool content. {@link GetTxpoolContentReturnType}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* const content = await client.getTxpoolContent()
*/
getTxpoolContent: () => Promise<GetTxpoolContentReturnType>
/**
* Returns a summary of all the transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only.
*
* - Docs: https://viem.sh/docs/actions/test/getTxpoolStatus
*
* @returns Transaction pool status. {@link GetTxpoolStatusReturnType}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* const status = await client.getTxpoolStatus()
*/
getTxpoolStatus: () => Promise<GetTxpoolStatusReturnType>
/**
* Impersonate an account or contract address. This lets you send transactions from that account even if you don't have access to its private key.
*
* - Docs: https://viem.sh/docs/actions/test/impersonateAccount
*
* @param args - {@link ImpersonateAccountParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.impersonateAccount({
* address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* })
*/
impersonateAccount: (args: ImpersonateAccountParameters) => Promise<void>
/**
* Jump forward in time by the given amount of time, in seconds.
*
* - Docs: https://viem.sh/docs/actions/test/increaseTime
*
* @param args {@link IncreaseTimeParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.increaseTime({
* seconds: 420,
* })
*/
increaseTime: (args: IncreaseTimeParameters) => Promise<Quantity>
/**
* Returns a summary of all the transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only.
*
* - Docs: https://viem.sh/docs/actions/test/inspectTxpool
*
* @returns Transaction pool inspection data. {@link InspectTxpoolReturnType}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* const data = await client.inspectTxpool()
*/
inspectTxpool: () => Promise<InspectTxpoolReturnType>
/**
* Adds state previously dumped with `dumpState` to the current chain.
*
* - Docs: https://viem.sh/docs/actions/test/loadState
*
* @param client - Client to use
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.loadState({ state: '0x...' })
*/
loadState: (args: LoadStateParameters) => Promise<LoadStateReturnType>
/**
* Mine a specified number of blocks.
*
* - Docs: https://viem.sh/docs/actions/test/mine
*
* @param client - Client to use
* @param args {@link MineParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.mine({ blocks: 1 })
*/
mine: (args: MineParameters) => Promise<void>
/**
* Removes [`setBlockTimestampInterval`](https://viem.sh/docs/actions/test/setBlockTimestampInterval) if it exists.
*
* - Docs: https://viem.sh/docs/actions/test/removeBlockTimestampInterval
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
* import { removeBlockTimestampInterval } from 'viem/test'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.removeBlockTimestampInterval()
*/
removeBlockTimestampInterval: () => Promise<void>
/**
* Resets fork back to its original state.
*
* - Docs: https://viem.sh/docs/actions/test/reset
*
* @param args {@link ResetParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.reset({ blockNumber: 69420n })
*/
reset: (args?: ResetParameters | undefined) => Promise<void>
/**
* Revert the state of the blockchain at the current block.
*
* - Docs: https://viem.sh/docs/actions/test/revert
*
* @param args {@link RevertParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.revert({ id: '0x…' })
*/
revert: (args: RevertParameters) => Promise<void>
/**
* Executes a transaction regardless of the signature.
*
* - Docs: https://viem.sh/docs/actions/test/sendUnsignedTransaction
*
* @param args {@link SendUnsignedTransactionParameters}
* @returns The transaction hash. {@link SendUnsignedTransactionReturnType}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* const hash = await client.sendUnsignedTransaction({
* from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*/
sendUnsignedTransaction: <chain extends Chain | undefined>(
args: SendUnsignedTransactionParameters<chain>,
) => Promise<SendUnsignedTransactionReturnType>
/**
* Enables or disables the automatic mining of new blocks with each new transaction submitted to the network.
*
* - Docs: https://viem.sh/docs/actions/test/setAutomine
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setAutomine()
*/
setAutomine: (args: boolean) => Promise<void>
/**
* Modifies the balance of an account.
*
* - Docs: https://viem.sh/docs/actions/test/setBalance
*
* @param args {@link SetBalanceParameters}
*
* @example
* import { createTestClient, http, parseEther } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setBalance({
* address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
* value: parseEther('1'),
* })
*/
setBalance: (args: SetBalanceParameters) => Promise<void>
/**
* Sets the block's gas limit.
*
* - Docs: https://viem.sh/docs/actions/test/setBlockGasLimit
*
* @param args {@link SetBlockGasLimitParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setBlockGasLimit({ gasLimit: 420_000n })
*/
setBlockGasLimit: (args: SetBlockGasLimitParameters) => Promise<void>
/**
* Similar to [`increaseTime`](https://viem.sh/docs/actions/test/increaseTime), but sets a block timestamp `interval`. The timestamp of future blocks will be computed as `lastBlock_timestamp` + `interval`.
*
* - Docs: https://viem.sh/docs/actions/test/setBlockTimestampInterval
*
* @param args {@link SetBlockTimestampIntervalParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setBlockTimestampInterval({ interval: 5 })
*/
setBlockTimestampInterval: (
args: SetBlockTimestampIntervalParameters,
) => Promise<void>
/**
* Modifies the bytecode stored at an account's address.
*
* - Docs: https://viem.sh/docs/actions/test/setCode
*
* @param args {@link SetCodeParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setCode({
* address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79',
* bytecode: '0x60806040526000600355600019600955600c80546001600160a01b031916737a250d5630b4cf539739df…',
* })
*/
setCode: (args: SetCodeParameters) => Promise<void>
/**
* Sets the coinbase address to be used in new blocks.
*
* - Docs: https://viem.sh/docs/actions/test/setCoinbase
*
* @param args {@link SetCoinbaseParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setCoinbase({
* address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79',
* })
*/
setCoinbase: (args: SetCoinbaseParameters) => Promise<void>
/**
* Sets the automatic mining interval (in seconds) of blocks. Setting the interval to 0 will disable automatic mining.
*
* - Docs: https://viem.sh/docs/actions/test/setIntervalMining
*
* @param args {@link SetIntervalMiningParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setIntervalMining({ interval: 5 })
*/
setIntervalMining: (args: SetIntervalMiningParameters) => Promise<void>
/**
* Enable or disable logging on the test node network.
*
* - Docs: https://viem.sh/docs/actions/test/setLoggingEnabled
*
* @param client - Client to use
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setLoggingEnabled()
*/
setLoggingEnabled: (args: boolean) => Promise<void>
/**
* Change the minimum gas price accepted by the network (in wei).
*
* - Docs: https://viem.sh/docs/actions/test/setMinGasPrice
*
* Note: `setMinGasPrice` can only be used on clients that do not have EIP-1559 enabled.
*
* @param args {@link SetBlockGasLimitParameters}
*
* @example
* import { createTestClient, http, parseGwei } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setMinGasPrice({
* gasPrice: parseGwei('20'),
* })
*/
setMinGasPrice: (args: SetMinGasPriceParameters) => Promise<void>
/**
* Sets the next block's base fee per gas.
*
* - Docs: https://viem.sh/docs/actions/test/setNextBlockBaseFeePerGas
*
* @param args {@link SetNextBlockBaseFeePerGasParameters}
*
* @example
* import { createTestClient, http, parseGwei } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setNextBlockBaseFeePerGas({
* baseFeePerGas: parseGwei('20'),
* })
*/
setNextBlockBaseFeePerGas: (
args: SetNextBlockBaseFeePerGasParameters,
) => Promise<void>
/**
* Sets the next block's timestamp.
*
* - Docs: https://viem.sh/docs/actions/test/setNextBlockTimestamp
*
* @param args {@link SetNextBlockTimestampParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setNextBlockTimestamp({ timestamp: 1671744314n })
*/
setNextBlockTimestamp: (
args: SetNextBlockTimestampParameters,
) => Promise<void>
/**
* Modifies (overrides) the nonce of an account.
*
* - Docs: https://viem.sh/docs/actions/test/setNonce
*
* @param args {@link SetNonceParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setNonce({
* address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
* nonce: 420,
* })
*/
setNonce: (args: SetNonceParameters) => Promise<void>
/**
* Sets the backend RPC URL.
*
* - Docs: https://viem.sh/docs/actions/test/setRpcUrl
*
* @param jsonRpcUrl RPC URL
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setRpcUrl('https://eth-mainnet.g.alchemy.com/v2')
*/
setRpcUrl: (args: string) => Promise<void>
/**
* Writes to a slot of an account's storage.
*
* - Docs: https://viem.sh/docs/actions/test/setStorageAt
*
* @param args {@link SetStorageAtParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.setStorageAt({
* address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79',
* index: 2,
* value: '0x0000000000000000000000000000000000000000000000000000000000000069',
* })
*/
setStorageAt: (args: SetStorageAtParameters) => Promise<void>
/**
* Snapshot the state of the blockchain at the current block.
*
* - Docs: https://viem.sh/docs/actions/test/snapshot
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
* import { snapshot } from 'viem/test'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.snapshot()
*/
snapshot: () => Promise<Quantity>
/**
* Stop impersonating an account after having previously used [`impersonateAccount`](https://viem.sh/docs/actions/test/impersonateAccount).
*
* - Docs: https://viem.sh/docs/actions/test/stopImpersonatingAccount
*
* @param args {@link StopImpersonatingAccountParameters}
*
* @example
* import { createTestClient, http } from 'viem'
* import { foundry } from 'viem/chains'
* import { stopImpersonatingAccount } from 'viem/test'
*
* const client = createTestClient({
* mode: 'anvil',
* chain: 'foundry',
* transport: http(),
* })
* await client.stopImpersonatingAccount({
* address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
* })
*/
stopImpersonatingAccount: (
args: StopImpersonatingAccountParameters,
) => Promise<void>
}
export function testActions<mode extends TestClientMode>({
mode,
}: {
mode: mode
}): <
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
>(
client: Client<transport, chain, account>,
) => TestActions {
return <
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
>(
client_: Client<transport, chain, account>,
): TestActions => {
const client = client_.extend(() => ({
mode,
}))
return {
dropTransaction: (args) => dropTransaction(client, args),
dumpState: () => dumpState(client),
getAutomine: () => getAutomine(client),
getTxpoolContent: () => getTxpoolContent(client),
getTxpoolStatus: () => getTxpoolStatus(client),
impersonateAccount: (args) => impersonateAccount(client, args),
increaseTime: (args) => increaseTime(client, args),
inspectTxpool: () => inspectTxpool(client),
loadState: (args) => loadState(client, args),
mine: (args) => mine(client, args),
removeBlockTimestampInterval: () => removeBlockTimestampInterval(client),
reset: (args) => reset(client, args),
revert: (args) => revert(client, args),
sendUnsignedTransaction: (args) =>
sendUnsignedTransaction(client, args as any),
setAutomine: (args) => setAutomine(client, args),
setBalance: (args) => setBalance(client, args),
setBlockGasLimit: (args) => setBlockGasLimit(client, args),
setBlockTimestampInterval: (args) =>
setBlockTimestampInterval(client, args),
setCode: (args) => setCode(client, args),
setCoinbase: (args) => setCoinbase(client, args),
setIntervalMining: (args) => setIntervalMining(client, args),
setLoggingEnabled: (args) => setLoggingEnabled(client, args),
setMinGasPrice: (args) => setMinGasPrice(client, args),
setNextBlockBaseFeePerGas: (args) =>
setNextBlockBaseFeePerGas(client, args),
setNextBlockTimestamp: (args) => setNextBlockTimestamp(client, args),
setNonce: (args) => setNonce(client, args),
setRpcUrl: (args) => setRpcUrl(client, args),
setStorageAt: (args) => setStorageAt(client, args),
snapshot: () => snapshot(client),
stopImpersonatingAccount: (args) =>
stopImpersonatingAccount(client, args),
}
}
}

1216
node_modules/viem/clients/decorators/wallet.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

6
node_modules/viem/clients/package.json generated vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"type": "module",
"types": "../_types/clients/index.d.ts",
"module": "../_esm/clients/index.js",
"main": "../_cjs/clients/index.js"
}

View File

@@ -0,0 +1,95 @@
import type { ErrorType } from '../../errors/utils.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { EIP1193RequestFn } from '../../types/eip1193.js'
import type { OneOf } from '../../types/utils.js'
import { buildRequest } from '../../utils/buildRequest.js'
import { uid as uid_ } from '../../utils/uid.js'
import type { ClientConfig } from '../createClient.js'
export type TransportConfig<
type extends string = string,
eip1193RequestFn extends EIP1193RequestFn = EIP1193RequestFn,
> = {
/** The name of the transport. */
name: string
/** The key of the transport. */
key: string
/** Methods to include or exclude from executing RPC requests. */
methods?:
| OneOf<
| {
include?: string[] | undefined
}
| {
exclude?: string[] | undefined
}
>
| undefined
/** The JSON-RPC request function that matches the EIP-1193 request spec. */
request: eip1193RequestFn
/** The base delay (in ms) between retries. */
retryDelay?: number | undefined
/** The max number of times to retry. */
retryCount?: number | undefined
/** The timeout (in ms) for requests. */
timeout?: number | undefined
/** The type of the transport. */
type: type
}
export type Transport<
type extends string = string,
rpcAttributes = Record<string, any>,
eip1193RequestFn extends EIP1193RequestFn = EIP1193RequestFn,
> = <chain extends Chain | undefined = Chain>({
chain,
}: {
account?: Account | undefined
chain?: chain | undefined
pollingInterval?: ClientConfig['pollingInterval'] | undefined
retryCount?: TransportConfig['retryCount'] | undefined
timeout?: TransportConfig['timeout'] | undefined
}) => {
config: TransportConfig<type>
request: eip1193RequestFn
value?: rpcAttributes | undefined
}
export type CreateTransportErrorType = ErrorType
/**
* @description Creates an transport intended to be used with a client.
*/
export function createTransport<
type extends string,
rpcAttributes extends Record<string, any>,
>(
{
key,
methods,
name,
request,
retryCount = 3,
retryDelay = 150,
timeout,
type,
}: TransportConfig<type>,
value?: rpcAttributes | undefined,
): ReturnType<Transport<type, rpcAttributes>> {
const uid = uid_()
return {
config: {
key,
methods,
name,
request,
retryCount,
retryDelay,
timeout,
type,
},
request: buildRequest(request, { methods, retryCount, retryDelay, uid }),
value,
}
}

55
node_modules/viem/clients/transports/custom.ts generated vendored Normal file
View File

@@ -0,0 +1,55 @@
import type { ErrorType } from '../../errors/utils.js'
import {
type CreateTransportErrorType,
createTransport,
type Transport,
type TransportConfig,
} from './createTransport.js'
type EthereumProvider = { request(...args: any): Promise<any> }
export type CustomTransportConfig = {
/** The key of the transport. */
key?: TransportConfig['key'] | undefined
/** Methods to include or exclude from executing RPC requests. */
methods?: TransportConfig['methods'] | undefined
/** The name of the transport. */
name?: TransportConfig['name'] | undefined
/** The max number of times to retry. */
retryCount?: TransportConfig['retryCount'] | undefined
/** The base delay (in ms) between retries. */
retryDelay?: TransportConfig['retryDelay'] | undefined
}
export type CustomTransport = Transport<
'custom',
{},
EthereumProvider['request']
>
export type CustomTransportErrorType = CreateTransportErrorType | ErrorType
/**
* @description Creates a custom transport given an EIP-1193 compliant `request` attribute.
*/
export function custom<provider extends EthereumProvider>(
provider: provider,
config: CustomTransportConfig = {},
): CustomTransport {
const {
key = 'custom',
methods,
name = 'Custom Provider',
retryDelay,
} = config
return ({ retryCount: defaultRetryCount }) =>
createTransport({
key,
methods,
name,
request: provider.request.bind(provider),
retryCount: config.retryCount ?? defaultRetryCount,
retryDelay,
type: 'custom',
})
}

317
node_modules/viem/clients/transports/fallback.ts generated vendored Normal file
View File

@@ -0,0 +1,317 @@
import { ExecutionRevertedError } from '../../errors/node.js'
import {
TransactionRejectedRpcError,
UserRejectedRequestError,
WalletConnectSessionSettlementError,
} from '../../errors/rpc.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import { wait } from '../../utils/wait.js'
import {
type CreateTransportErrorType,
createTransport,
type Transport,
type TransportConfig,
} from './createTransport.js'
// TODO: Narrow `method` & `params` types.
export type OnResponseFn = (
args: {
method: string
params: unknown[]
transport: ReturnType<Transport>
} & (
| {
error?: undefined
response: unknown
status: 'success'
}
| {
error: Error
response?: undefined
status: 'error'
}
),
) => void
type RankOptions = {
/**
* The polling interval (in ms) at which the ranker should ping the RPC URL.
* @default client.pollingInterval
*/
interval?: number | undefined
/**
* Ping method to determine latency.
*/
ping?: (parameters: {
transport: ReturnType<Transport>
}) => Promise<unknown> | undefined
/**
* The number of previous samples to perform ranking on.
* @default 10
*/
sampleCount?: number | undefined
/**
* Timeout when sampling transports.
* @default 1_000
*/
timeout?: number | undefined
/**
* Weights to apply to the scores. Weight values are proportional.
*/
weights?:
| {
/**
* The weight to apply to the latency score.
* @default 0.3
*/
latency?: number | undefined
/**
* The weight to apply to the stability score.
* @default 0.7
*/
stability?: number | undefined
}
| undefined
}
export type FallbackTransportConfig = {
/** The key of the Fallback transport. */
key?: TransportConfig['key'] | undefined
/** The name of the Fallback transport. */
name?: TransportConfig['name'] | undefined
/** Toggle to enable ranking, or rank options. */
rank?: boolean | RankOptions | undefined
/** The max number of times to retry. */
retryCount?: TransportConfig['retryCount'] | undefined
/** The base delay (in ms) between retries. */
retryDelay?: TransportConfig['retryDelay'] | undefined
/** Callback on whether an error should throw or try the next transport in the fallback. */
shouldThrow?: (error: Error) => boolean | undefined
}
export type FallbackTransport<
transports extends readonly Transport[] = readonly Transport[],
> = Transport<
'fallback',
{
onResponse: (fn: OnResponseFn) => void
transports: {
[key in keyof transports]: ReturnType<transports[key]>
}
}
>
export type FallbackTransportErrorType = CreateTransportErrorType | ErrorType
export function fallback<const transports extends readonly Transport[]>(
transports_: transports,
config: FallbackTransportConfig = {},
): FallbackTransport<transports> {
const {
key = 'fallback',
name = 'Fallback',
rank = false,
shouldThrow: shouldThrow_ = shouldThrow,
retryCount,
retryDelay,
} = config
return (({ chain, pollingInterval = 4_000, timeout, ...rest }) => {
let transports = transports_
let onResponse: OnResponseFn = () => {}
const transport = createTransport(
{
key,
name,
async request({ method, params }) {
let includes: boolean | undefined
const fetch = async (i = 0): Promise<any> => {
const transport = transports[i]({
...rest,
chain,
retryCount: 0,
timeout,
})
try {
const response = await transport.request({
method,
params,
} as any)
onResponse({
method,
params: params as unknown[],
response,
transport,
status: 'success',
})
return response
} catch (err) {
onResponse({
error: err as Error,
method,
params: params as unknown[],
transport,
status: 'error',
})
if (shouldThrow_(err as Error)) throw err
// If we've reached the end of the fallbacks, throw the error.
if (i === transports.length - 1) throw err
// Check if at least one other transport includes the method
includes ??= transports.slice(i + 1).some((transport) => {
const { include, exclude } =
transport({ chain }).config.methods || {}
if (include) return include.includes(method)
if (exclude) return !exclude.includes(method)
return true
})
if (!includes) throw err
// Otherwise, try the next fallback.
return fetch(i + 1)
}
}
return fetch()
},
retryCount,
retryDelay,
type: 'fallback',
},
{
onResponse: (fn: OnResponseFn) => (onResponse = fn),
transports: transports.map((fn) => fn({ chain, retryCount: 0 })),
},
)
if (rank) {
const rankOptions = (typeof rank === 'object' ? rank : {}) as RankOptions
rankTransports({
chain,
interval: rankOptions.interval ?? pollingInterval,
onTransports: (transports_) => (transports = transports_ as transports),
ping: rankOptions.ping,
sampleCount: rankOptions.sampleCount,
timeout: rankOptions.timeout,
transports,
weights: rankOptions.weights,
})
}
return transport
}) as FallbackTransport<transports>
}
export function shouldThrow(error: Error) {
if ('code' in error && typeof error.code === 'number') {
if (
error.code === TransactionRejectedRpcError.code ||
error.code === UserRejectedRequestError.code ||
error.code === WalletConnectSessionSettlementError.code ||
ExecutionRevertedError.nodeMessage.test(error.message) ||
error.code === 5000 // CAIP UserRejectedRequestError
)
return true
}
return false
}
/** @internal */
export function rankTransports({
chain,
interval = 4_000,
onTransports,
ping,
sampleCount = 10,
timeout = 1_000,
transports,
weights = {},
}: {
chain?: Chain | undefined
interval: RankOptions['interval']
onTransports: (transports: readonly Transport[]) => void
ping?: RankOptions['ping'] | undefined
sampleCount?: RankOptions['sampleCount'] | undefined
timeout?: RankOptions['timeout'] | undefined
transports: readonly Transport[]
weights?: RankOptions['weights'] | undefined
}) {
const { stability: stabilityWeight = 0.7, latency: latencyWeight = 0.3 } =
weights
type SampleData = { latency: number; success: number }
type Sample = SampleData[]
const samples: Sample[] = []
const rankTransports_ = async () => {
// 1. Take a sample from each Transport.
const sample: Sample = await Promise.all(
transports.map(async (transport) => {
const transport_ = transport({ chain, retryCount: 0, timeout })
const start = Date.now()
let end: number
let success: number
try {
await (ping
? ping({ transport: transport_ })
: transport_.request({ method: 'net_listening' }))
success = 1
} catch {
success = 0
} finally {
end = Date.now()
}
const latency = end - start
return { latency, success }
}),
)
// 2. Store the sample. If we have more than `sampleCount` samples, remove
// the oldest sample.
samples.push(sample)
if (samples.length > sampleCount) samples.shift()
// 3. Calculate the max latency from samples.
const maxLatency = Math.max(
...samples.map((sample) =>
Math.max(...sample.map(({ latency }) => latency)),
),
)
// 4. Calculate the score for each Transport.
const scores = transports
.map((_, i) => {
const latencies = samples.map((sample) => sample[i].latency)
const meanLatency =
latencies.reduce((acc, latency) => acc + latency, 0) /
latencies.length
const latencyScore = 1 - meanLatency / maxLatency
const successes = samples.map((sample) => sample[i].success)
const stabilityScore =
successes.reduce((acc, success) => acc + success, 0) /
successes.length
if (stabilityScore === 0) return [0, i]
return [
latencyWeight * latencyScore + stabilityWeight * stabilityScore,
i,
]
})
.sort((a, b) => b[0] - a[0])
// 5. Sort the Transports by score.
onTransports(scores.map(([, i]) => transports[i]))
// 6. Wait, and then rank again.
await wait(interval)
rankTransports_()
}
rankTransports_()
}

175
node_modules/viem/clients/transports/http.ts generated vendored Normal file
View File

@@ -0,0 +1,175 @@
import { RpcRequestError } from '../../errors/request.js'
import {
UrlRequiredError,
type UrlRequiredErrorType,
} from '../../errors/transport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { EIP1193RequestFn, RpcSchema } from '../../types/eip1193.js'
import type { RpcRequest } from '../../types/rpc.js'
import { createBatchScheduler } from '../../utils/promise/createBatchScheduler.js'
import {
getHttpRpcClient,
type HttpRpcClientOptions,
} from '../../utils/rpc/http.js'
import {
type CreateTransportErrorType,
createTransport,
type Transport,
type TransportConfig,
} from './createTransport.js'
export type HttpTransportConfig<
rpcSchema extends RpcSchema | undefined = undefined,
raw extends boolean = false,
> = {
/**
* Whether to enable Batch JSON-RPC.
* @link https://www.jsonrpc.org/specification#batch
*/
batch?:
| boolean
| {
/** The maximum number of JSON-RPC requests to send in a batch. @default 1_000 */
batchSize?: number | undefined
/** The maximum number of milliseconds to wait before sending a batch. @default 0 */
wait?: number | undefined
}
| undefined
fetchFn?: HttpRpcClientOptions['fetchFn'] | undefined
/**
* Request configuration to pass to `fetch`.
* @link https://developer.mozilla.org/en-US/docs/Web/API/fetch
*/
fetchOptions?: HttpRpcClientOptions['fetchOptions'] | undefined
/** A callback to handle the response from `fetch`. */
onFetchRequest?: HttpRpcClientOptions['onRequest'] | undefined
/** A callback to handle the response from `fetch`. */
onFetchResponse?: HttpRpcClientOptions['onResponse'] | undefined
/** The key of the HTTP transport. */
key?: TransportConfig['key'] | undefined
/** Methods to include or exclude from executing RPC requests. */
methods?: TransportConfig['methods'] | undefined
/** The name of the HTTP transport. */
name?: TransportConfig['name'] | undefined
/** Whether to return JSON RPC errors as responses instead of throwing. */
raw?: raw | boolean | undefined
/** The max number of times to retry. */
retryCount?: TransportConfig['retryCount'] | undefined
/** The base delay (in ms) between retries. */
retryDelay?: TransportConfig['retryDelay'] | undefined
/** Typed JSON-RPC schema for the transport. */
rpcSchema?: rpcSchema | RpcSchema | undefined
/** The timeout (in ms) for the HTTP request. Default: 10_000 */
timeout?: TransportConfig['timeout'] | undefined
}
export type HttpTransport<
rpcSchema extends RpcSchema | undefined = undefined,
raw extends boolean = false,
> = Transport<
'http',
{
fetchOptions?: HttpTransportConfig['fetchOptions'] | undefined
url?: string | undefined
},
EIP1193RequestFn<rpcSchema, raw>
>
export type HttpTransportErrorType =
| CreateTransportErrorType
| UrlRequiredErrorType
| ErrorType
/**
* @description Creates a HTTP transport that connects to a JSON-RPC API.
*/
export function http<
rpcSchema extends RpcSchema | undefined = undefined,
raw extends boolean = false,
>(
/** URL of the JSON-RPC API. Defaults to the chain's public RPC URL. */
url?: string | undefined,
config: HttpTransportConfig<rpcSchema, raw> = {},
): HttpTransport<rpcSchema, raw> {
const {
batch,
fetchFn,
fetchOptions,
key = 'http',
methods,
name = 'HTTP JSON-RPC',
onFetchRequest,
onFetchResponse,
retryDelay,
raw,
} = config
return ({ chain, retryCount: retryCount_, timeout: timeout_ }) => {
const { batchSize = 1000, wait = 0 } =
typeof batch === 'object' ? batch : {}
const retryCount = config.retryCount ?? retryCount_
const timeout = timeout_ ?? config.timeout ?? 10_000
const url_ = url || chain?.rpcUrls.default.http[0]
if (!url_) throw new UrlRequiredError()
const rpcClient = getHttpRpcClient(url_, {
fetchFn,
fetchOptions,
onRequest: onFetchRequest,
onResponse: onFetchResponse,
timeout,
})
return createTransport(
{
key,
methods,
name,
async request({ method, params }) {
const body = { method, params }
const { schedule } = createBatchScheduler({
id: url_,
wait,
shouldSplitBatch(requests) {
return requests.length > batchSize
},
fn: (body: RpcRequest[]) =>
rpcClient.request({
body,
}),
sort: (a, b) => a.id - b.id,
})
const fn = async (body: RpcRequest) =>
batch
? schedule(body)
: [
await rpcClient.request({
body,
}),
]
const [{ error, result }] = await fn(body)
if (raw) return { error, result }
if (error)
throw new RpcRequestError({
body,
error,
url: url_,
})
return result
},
retryCount,
retryDelay,
timeout,
type: 'http',
},
{
fetchOptions,
url: url_,
},
)
}
}

177
node_modules/viem/clients/transports/ipc.ts generated vendored Normal file
View File

@@ -0,0 +1,177 @@
import type { Address } from 'abitype'
import { RpcRequestError } from '../../errors/request.js'
import type { UrlRequiredErrorType } from '../../errors/transport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Hash, LogTopic } from '../../types/misc.js'
import type { RpcResponse } from '../../types/rpc.js'
import {
type GetIpcRpcClientOptions,
getIpcRpcClient,
type IpcRpcClient,
} from '../../utils/rpc/ipc.js'
import {
type CreateTransportErrorType,
createTransport,
type Transport,
type TransportConfig,
} from './createTransport.js'
type IpcTransportSubscribeParameters = {
onData: (data: RpcResponse) => void
onError?: ((error: any) => void) | undefined
}
type IpcTransportSubscribeReturnType = {
subscriptionId: Hash
unsubscribe: () => Promise<RpcResponse<boolean>>
}
type IpcTransportSubscribe = {
subscribe(
args: IpcTransportSubscribeParameters &
(
| {
params: ['newHeads']
}
| {
params: ['newPendingTransactions']
}
| {
params: [
'logs',
{
address?: Address | Address[]
topics?: LogTopic[]
},
]
}
| {
params: ['syncing']
}
),
): Promise<IpcTransportSubscribeReturnType>
}
export type IpcTransportConfig = {
/** The key of the Ipc transport. */
key?: TransportConfig['key'] | undefined
/** Methods to include or exclude from executing RPC requests. */
methods?: TransportConfig['methods'] | undefined
/** The name of the Ipc transport. */
name?: TransportConfig['name'] | undefined
/**
* Whether or not to attempt to reconnect on socket failure.
* @default true
*/
reconnect?: GetIpcRpcClientOptions['reconnect'] | undefined
/** The max number of times to retry. */
retryCount?: TransportConfig['retryCount'] | undefined
/** The base delay (in ms) between retries. */
retryDelay?: TransportConfig['retryDelay'] | undefined
/** The timeout (in ms) for async Ipc requests. Default: 10_000 */
timeout?: TransportConfig['timeout'] | undefined
}
export type IpcTransport = Transport<
'ipc',
{
getRpcClient(): Promise<IpcRpcClient>
subscribe: IpcTransportSubscribe['subscribe']
}
>
export type IpcTransportErrorType =
| CreateTransportErrorType
| UrlRequiredErrorType
| ErrorType
/**
* @description Creates an IPC transport that connects to a JSON-RPC API.
*/
export function ipc(
path: string,
config: IpcTransportConfig = {},
): IpcTransport {
const {
key = 'ipc',
methods,
name = 'IPC JSON-RPC',
reconnect,
retryDelay,
} = config
return ({ retryCount: retryCount_, timeout: timeout_ }) => {
const retryCount = config.retryCount ?? retryCount_
const timeout = timeout_ ?? config.timeout ?? 10_000
return createTransport(
{
key,
methods,
name,
async request({ method, params }) {
const body = { method, params }
const rpcClient = await getIpcRpcClient(path, { reconnect })
const { error, result } = await rpcClient.requestAsync({
body,
timeout,
})
if (error)
throw new RpcRequestError({
body,
error,
url: path,
})
return result
},
retryCount,
retryDelay,
timeout,
type: 'ipc',
},
{
getRpcClient() {
return getIpcRpcClient(path)
},
async subscribe({ params, onData, onError }: any) {
const rpcClient = await getIpcRpcClient(path)
const { result: subscriptionId } = await new Promise<any>(
(resolve, reject) =>
rpcClient.request({
body: {
method: 'eth_subscribe',
params,
},
onResponse(response) {
if (response.error) {
reject(response.error)
onError?.(response.error)
return
}
if (typeof response.id === 'number') {
resolve(response)
return
}
if (response.method !== 'eth_subscription') return
onData(response.params)
},
}),
)
return {
subscriptionId,
async unsubscribe() {
return new Promise<any>((resolve) =>
rpcClient.request({
body: {
method: 'eth_unsubscribe',
params: [subscriptionId],
},
onResponse: resolve,
}),
)
},
}
},
},
)
}
}

203
node_modules/viem/clients/transports/webSocket.ts generated vendored Normal file
View File

@@ -0,0 +1,203 @@
import type { Address } from 'abitype'
import { RpcRequestError } from '../../errors/request.js'
import {
UrlRequiredError,
type UrlRequiredErrorType,
} from '../../errors/transport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Hash, LogTopic } from '../../types/misc.js'
import type { RpcResponse } from '../../types/rpc.js'
import { getSocket } from '../../utils/rpc/compat.js'
import type { SocketRpcClient } from '../../utils/rpc/socket.js'
import {
type GetWebSocketRpcClientOptions,
getWebSocketRpcClient,
} from '../../utils/rpc/webSocket.js'
import {
type CreateTransportErrorType,
createTransport,
type Transport,
type TransportConfig,
} from './createTransport.js'
type WebSocketTransportSubscribeParameters = {
onData: (data: RpcResponse) => void
onError?: ((error: any) => void) | undefined
}
type WebSocketTransportSubscribeReturnType = {
subscriptionId: Hash
unsubscribe: () => Promise<RpcResponse<boolean>>
}
type WebSocketTransportSubscribe = {
subscribe(
args: WebSocketTransportSubscribeParameters &
(
| {
params: ['newHeads']
}
| {
params: ['newPendingTransactions']
}
| {
params: [
'logs',
{
address?: Address | Address[]
topics?: LogTopic[]
},
]
}
| {
params: ['syncing']
}
),
): Promise<WebSocketTransportSubscribeReturnType>
}
export type WebSocketTransportConfig = {
/**
* Whether or not to send keep-alive ping messages.
* @default true
*/
keepAlive?: GetWebSocketRpcClientOptions['keepAlive'] | undefined
/** The key of the WebSocket transport. */
key?: TransportConfig['key'] | undefined
/** Methods to include or exclude from executing RPC requests. */
methods?: TransportConfig['methods'] | undefined
/** The name of the WebSocket transport. */
name?: TransportConfig['name'] | undefined
/**
* Whether or not to attempt to reconnect on socket failure.
* @default true
*/
reconnect?: GetWebSocketRpcClientOptions['reconnect'] | undefined
/** The max number of times to retry. */
retryCount?: TransportConfig['retryCount'] | undefined
/** The base delay (in ms) between retries. */
retryDelay?: TransportConfig['retryDelay'] | undefined
/** The timeout (in ms) for async WebSocket requests. Default: 10_000 */
timeout?: TransportConfig['timeout'] | undefined
}
export type WebSocketTransport = Transport<
'webSocket',
{
/**
* @deprecated use `getRpcClient` instead.
*/
getSocket(): Promise<WebSocket>
getRpcClient(): Promise<SocketRpcClient<WebSocket>>
subscribe: WebSocketTransportSubscribe['subscribe']
}
>
export type WebSocketTransportErrorType =
| CreateTransportErrorType
| UrlRequiredErrorType
| ErrorType
/**
* @description Creates a WebSocket transport that connects to a JSON-RPC API.
*/
export function webSocket(
/** URL of the JSON-RPC API. Defaults to the chain's public RPC URL. */
url?: string,
config: WebSocketTransportConfig = {},
): WebSocketTransport {
const {
keepAlive,
key = 'webSocket',
methods,
name = 'WebSocket JSON-RPC',
reconnect,
retryDelay,
} = config
return ({ chain, retryCount: retryCount_, timeout: timeout_ }) => {
const retryCount = config.retryCount ?? retryCount_
const timeout = timeout_ ?? config.timeout ?? 10_000
const url_ = url || chain?.rpcUrls.default.webSocket?.[0]
const wsRpcClientOpts = { keepAlive, reconnect }
if (!url_) throw new UrlRequiredError()
return createTransport(
{
key,
methods,
name,
async request({ method, params }) {
const body = { method, params }
const rpcClient = await getWebSocketRpcClient(url_, wsRpcClientOpts)
const { error, result } = await rpcClient.requestAsync({
body,
timeout,
})
if (error)
throw new RpcRequestError({
body,
error,
url: url_,
})
return result
},
retryCount,
retryDelay,
timeout,
type: 'webSocket',
},
{
getSocket() {
return getSocket(url_)
},
getRpcClient() {
return getWebSocketRpcClient(url_, wsRpcClientOpts)
},
async subscribe({ params, onData, onError }: any) {
const rpcClient = await getWebSocketRpcClient(url_, wsRpcClientOpts)
const { result: subscriptionId } = await new Promise<any>(
(resolve, reject) =>
rpcClient.request({
body: {
method: 'eth_subscribe',
params,
},
onError(error) {
reject(error)
onError?.(error)
return
},
onResponse(response) {
if (response.error) {
reject(response.error)
onError?.(response.error)
return
}
if (typeof response.id === 'number') {
resolve(response)
return
}
if (response.method !== 'eth_subscription') return
onData(response.params)
},
}),
)
return {
subscriptionId,
async unsubscribe() {
return new Promise<any>((resolve) =>
rpcClient.request({
body: {
method: 'eth_unsubscribe',
params: [subscriptionId],
},
onResponse: resolve,
}),
)
},
}
},
},
)
}
}