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

480
node_modules/viem/actions/public/call.ts generated vendored Normal file
View File

@@ -0,0 +1,480 @@
import { type Address, parseAbi } from 'abitype'
import * as BlockOverrides from 'ox/BlockOverrides'
import type { Account } from '../../accounts/types.js'
import {
type ParseAccountErrorType,
parseAccount,
} from '../../accounts/utils/parseAccount.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { multicall3Abi } from '../../constants/abis.js'
import { aggregate3Signature } from '../../constants/contract.js'
import {
deploylessCallViaBytecodeBytecode,
deploylessCallViaFactoryBytecode,
multicall3Bytecode,
} from '../../constants/contracts.js'
import { BaseError } from '../../errors/base.js'
import {
ChainDoesNotSupportContract,
ClientChainNotConfiguredError,
} from '../../errors/chain.js'
import {
CounterfactualDeploymentFailedError,
RawContractError,
type RawContractErrorType,
} from '../../errors/contract.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { Hex } from '../../types/misc.js'
import type { RpcTransactionRequest } from '../../types/rpc.js'
import type { StateOverride } from '../../types/stateOverride.js'
import type { TransactionRequest } from '../../types/transaction.js'
import type { ExactPartial, UnionOmit } from '../../types/utils.js'
import {
type DecodeFunctionResultErrorType,
decodeFunctionResult,
} from '../../utils/abi/decodeFunctionResult.js'
import {
type EncodeDeployDataErrorType,
encodeDeployData,
} from '../../utils/abi/encodeDeployData.js'
import {
type EncodeFunctionDataErrorType,
encodeFunctionData,
} from '../../utils/abi/encodeFunctionData.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type GetChainContractAddressErrorType,
getChainContractAddress,
} from '../../utils/chain/getChainContractAddress.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import {
type GetCallErrorReturnType,
getCallError,
} from '../../utils/errors/getCallError.js'
import { extract } from '../../utils/formatters/extract.js'
import {
type FormatTransactionRequestErrorType,
type FormattedTransactionRequest,
formatTransactionRequest,
} from '../../utils/formatters/transactionRequest.js'
import {
type CreateBatchSchedulerErrorType,
createBatchScheduler,
} from '../../utils/promise/createBatchScheduler.js'
import {
type SerializeStateOverrideErrorType,
serializeStateOverride,
} from '../../utils/stateOverride.js'
import type {
AssertRequestErrorType,
AssertRequestParameters,
} from '../../utils/transaction/assertRequest.js'
import { assertRequest } from '../../utils/transaction/assertRequest.js'
export type CallParameters<
chain extends Chain | undefined = Chain | undefined,
> = UnionOmit<FormattedCall<chain>, 'from'> & {
/** Account attached to the call (msg.sender). */
account?: Account | Address | undefined
/** Whether or not to enable multicall batching on this call. */
batch?: boolean | undefined
/** Block overrides for the call. */
blockOverrides?: BlockOverrides.BlockOverrides | undefined
/** Bytecode to perform the call on. */
code?: Hex | undefined
/** Contract deployment factory address (ie. Create2 factory, Smart Account factory, etc). */
factory?: Address | undefined
/** Calldata to execute on the factory to deploy the contract. */
factoryData?: Hex | undefined
/** State overrides for the call. */
stateOverride?: StateOverride | undefined
} & (
| {
/** The balance of the account at a block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockNumber?: undefined
/**
* The balance of the account at a block tag.
* @default 'latest'
*/
blockTag?: BlockTag | undefined
}
)
type FormattedCall<chain extends Chain | undefined = Chain | undefined> =
FormattedTransactionRequest<chain>
export type CallReturnType = { data: Hex | undefined }
export type CallErrorType = GetCallErrorReturnType<
| ParseAccountErrorType
| SerializeStateOverrideErrorType
| AssertRequestErrorType
| NumberToHexErrorType
| FormatTransactionRequestErrorType
| ScheduleMulticallErrorType
| RequestErrorType
| ToDeploylessCallViaBytecodeDataErrorType
| ToDeploylessCallViaFactoryDataErrorType
>
/**
* Executes a new message call immediately without submitting a transaction to the network.
*
* - Docs: https://viem.sh/docs/actions/public/call
* - JSON-RPC Methods: [`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call)
*
* @param client - Client to use
* @param parameters - {@link CallParameters}
* @returns The call data. {@link CallReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { call } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const data = await call(client, {
* account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
* data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* })
*/
export async function call<chain extends Chain | undefined>(
client: Client<Transport, chain>,
args: CallParameters<chain>,
): Promise<CallReturnType> {
const {
account: account_ = client.account,
authorizationList,
batch = Boolean(client.batch?.multicall),
blockNumber,
blockTag = client.experimental_blockTag ?? 'latest',
accessList,
blobs,
blockOverrides,
code,
data: data_,
factory,
factoryData,
gas,
gasPrice,
maxFeePerBlobGas,
maxFeePerGas,
maxPriorityFeePerGas,
nonce,
to,
value,
stateOverride,
...rest
} = args
const account = account_ ? parseAccount(account_) : undefined
if (code && (factory || factoryData))
throw new BaseError(
'Cannot provide both `code` & `factory`/`factoryData` as parameters.',
)
if (code && to)
throw new BaseError('Cannot provide both `code` & `to` as parameters.')
// Check if the call is deployless via bytecode.
const deploylessCallViaBytecode = code && data_
// Check if the call is deployless via a factory.
const deploylessCallViaFactory = factory && factoryData && to && data_
const deploylessCall = deploylessCallViaBytecode || deploylessCallViaFactory
const data = (() => {
if (deploylessCallViaBytecode)
return toDeploylessCallViaBytecodeData({
code,
data: data_,
})
if (deploylessCallViaFactory)
return toDeploylessCallViaFactoryData({
data: data_,
factory,
factoryData,
to,
})
return data_
})()
try {
assertRequest(args as AssertRequestParameters)
const blockNumberHex =
typeof blockNumber === 'bigint' ? numberToHex(blockNumber) : undefined
const block = blockNumberHex || blockTag
const rpcBlockOverrides = blockOverrides
? BlockOverrides.toRpc(blockOverrides)
: undefined
const rpcStateOverride = serializeStateOverride(stateOverride)
const chainFormat = client.chain?.formatters?.transactionRequest?.format
const format = chainFormat || formatTransactionRequest
const request = format(
{
// Pick out extra data that might exist on the chain's transaction request type.
...extract(rest, { format: chainFormat }),
accessList,
account,
authorizationList,
blobs,
data,
gas,
gasPrice,
maxFeePerBlobGas,
maxFeePerGas,
maxPriorityFeePerGas,
nonce,
to: deploylessCall ? undefined : to,
value,
} as TransactionRequest,
'call',
) as TransactionRequest
if (
batch &&
shouldPerformMulticall({ request }) &&
!rpcStateOverride &&
!rpcBlockOverrides
) {
try {
return await scheduleMulticall(client, {
...request,
blockNumber,
blockTag,
} as unknown as ScheduleMulticallParameters<chain>)
} catch (err) {
if (
!(err instanceof ClientChainNotConfiguredError) &&
!(err instanceof ChainDoesNotSupportContract)
)
throw err
}
}
const params = (() => {
const base = [
request as ExactPartial<RpcTransactionRequest>,
block,
] as const
if (rpcStateOverride && rpcBlockOverrides)
return [...base, rpcStateOverride, rpcBlockOverrides] as const
if (rpcStateOverride) return [...base, rpcStateOverride] as const
if (rpcBlockOverrides) return [...base, {}, rpcBlockOverrides] as const
return base
})()
const response = await client.request({
method: 'eth_call',
params,
})
if (response === '0x') return { data: undefined }
return { data: response }
} catch (err) {
const data = getRevertErrorData(err)
// Check for CCIP-Read offchain lookup signature.
const { offchainLookup, offchainLookupSignature } = await import(
'../../utils/ccip.js'
)
if (
client.ccipRead !== false &&
data?.slice(0, 10) === offchainLookupSignature &&
to
)
return { data: await offchainLookup(client, { data, to }) }
// Check for counterfactual deployment error.
if (deploylessCall && data?.slice(0, 10) === '0x101bb98d')
throw new CounterfactualDeploymentFailedError({ factory })
throw getCallError(err as ErrorType, {
...args,
account,
chain: client.chain,
})
}
}
// We only want to perform a scheduled multicall if:
// - The request has calldata,
// - The request has a target address,
// - The target address is not already the aggregate3 signature,
// - The request has no other properties (`nonce`, `gas`, etc cannot be sent with a multicall).
function shouldPerformMulticall({ request }: { request: TransactionRequest }) {
const { data, to, ...request_ } = request
if (!data) return false
if (data.startsWith(aggregate3Signature)) return false
if (!to) return false
if (
Object.values(request_).filter((x) => typeof x !== 'undefined').length > 0
)
return false
return true
}
type ScheduleMulticallParameters<chain extends Chain | undefined> = Pick<
CallParameters<chain>,
'blockNumber' | 'blockTag'
> & {
data: Hex
multicallAddress?: Address | undefined
to: Address
}
type ScheduleMulticallErrorType =
| GetChainContractAddressErrorType
| NumberToHexErrorType
| CreateBatchSchedulerErrorType
| EncodeFunctionDataErrorType
| DecodeFunctionResultErrorType
| RawContractErrorType
| ErrorType
async function scheduleMulticall<chain extends Chain | undefined>(
client: Client<Transport>,
args: ScheduleMulticallParameters<chain>,
) {
const {
batchSize = 1024,
deployless = false,
wait = 0,
} = typeof client.batch?.multicall === 'object' ? client.batch.multicall : {}
const {
blockNumber,
blockTag = client.experimental_blockTag ?? 'latest',
data,
to,
} = args
const multicallAddress = (() => {
if (deployless) return null
if (args.multicallAddress) return args.multicallAddress
if (client.chain) {
return getChainContractAddress({
blockNumber,
chain: client.chain,
contract: 'multicall3',
})
}
throw new ClientChainNotConfiguredError()
})()
const blockNumberHex =
typeof blockNumber === 'bigint' ? numberToHex(blockNumber) : undefined
const block = blockNumberHex || blockTag
const { schedule } = createBatchScheduler({
id: `${client.uid}.${block}`,
wait,
shouldSplitBatch(args) {
const size = args.reduce((size, { data }) => size + (data.length - 2), 0)
return size > batchSize * 2
},
fn: async (
requests: {
data: Hex
to: Address
}[],
) => {
const calls = requests.map((request) => ({
allowFailure: true,
callData: request.data,
target: request.to,
}))
const calldata = encodeFunctionData({
abi: multicall3Abi,
args: [calls],
functionName: 'aggregate3',
})
const data = await client.request({
method: 'eth_call',
params: [
{
...(multicallAddress === null
? {
data: toDeploylessCallViaBytecodeData({
code: multicall3Bytecode,
data: calldata,
}),
}
: { to: multicallAddress, data: calldata }),
},
block,
],
})
return decodeFunctionResult({
abi: multicall3Abi,
args: [calls],
functionName: 'aggregate3',
data: data || '0x',
})
},
})
const [{ returnData, success }] = await schedule({ data, to })
if (!success) throw new RawContractError({ data: returnData })
if (returnData === '0x') return { data: undefined }
return { data: returnData }
}
type ToDeploylessCallViaBytecodeDataErrorType =
| EncodeDeployDataErrorType
| ErrorType
function toDeploylessCallViaBytecodeData(parameters: { code: Hex; data: Hex }) {
const { code, data } = parameters
return encodeDeployData({
abi: parseAbi(['constructor(bytes, bytes)']),
bytecode: deploylessCallViaBytecodeBytecode,
args: [code, data],
})
}
type ToDeploylessCallViaFactoryDataErrorType =
| EncodeDeployDataErrorType
| ErrorType
function toDeploylessCallViaFactoryData(parameters: {
data: Hex
factory: Address
factoryData: Hex
to: Address
}) {
const { data, factory, factoryData, to } = parameters
return encodeDeployData({
abi: parseAbi(['constructor(address, bytes, address, bytes)']),
bytecode: deploylessCallViaFactoryBytecode,
args: [to, data, factory, factoryData],
})
}
/** @internal */
export type GetRevertErrorDataErrorType = ErrorType
/** @internal */
export function getRevertErrorData(err: unknown) {
if (!(err instanceof BaseError)) return undefined
const error = err.walk() as RawContractError
return typeof error?.data === 'object' ? error.data?.data : error.data
}

163
node_modules/viem/actions/public/createAccessList.ts generated vendored Normal file
View File

@@ -0,0 +1,163 @@
import type { Address } from 'abitype'
import type { Account } from '../../accounts/types.js'
import {
type ParseAccountErrorType,
parseAccount,
} from '../../accounts/utils/parseAccount.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { RpcTransactionRequest } from '../../types/rpc.js'
import type { AccessList, TransactionRequest } from '../../types/transaction.js'
import type { ExactPartial, Prettify, UnionOmit } from '../../types/utils.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import {
type GetCallErrorReturnType,
getCallError,
} from '../../utils/errors/getCallError.js'
import { extract } from '../../utils/formatters/extract.js'
import {
type FormatTransactionRequestErrorType,
type FormattedTransactionRequest,
formatTransactionRequest,
} from '../../utils/formatters/transactionRequest.js'
import type {
AssertRequestErrorType,
AssertRequestParameters,
} from '../../utils/transaction/assertRequest.js'
import { assertRequest } from '../../utils/transaction/assertRequest.js'
export type CreateAccessListParameters<
chain extends Chain | undefined = Chain | undefined,
> = UnionOmit<
FormattedTransactionRequest<chain>,
'from' | 'nonce' | 'accessList'
> & {
/** Account attached to the call (msg.sender). */
account?: Account | Address | undefined
} & (
| {
/** The balance of the account at a block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockNumber?: undefined
/**
* The balance of the account at a block tag.
* @default 'latest'
*/
blockTag?: BlockTag | undefined
}
)
export type CreateAccessListReturnType = Prettify<{
accessList: AccessList
gasUsed: bigint
}>
export type CreateAccessListErrorType = GetCallErrorReturnType<
| ParseAccountErrorType
| AssertRequestErrorType
| NumberToHexErrorType
| FormatTransactionRequestErrorType
| RequestErrorType
>
/**
* Creates an EIP-2930 access list.
*
* - Docs: https://viem.sh/docs/actions/public/createAccessList
* - JSON-RPC Methods: `eth_createAccessList`
*
* @param client - Client to use
* @param parameters - {@link CreateAccessListParameters}
* @returns The access list. {@link CreateAccessListReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createAccessList } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const data = await createAccessList(client, {
* account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
* data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* })
*/
export async function createAccessList<chain extends Chain | undefined>(
client: Client<Transport, chain>,
args: CreateAccessListParameters<chain>,
): Promise<CreateAccessListReturnType> {
const {
account: account_ = client.account,
blockNumber,
blockTag = 'latest',
blobs,
data,
gas,
gasPrice,
maxFeePerBlobGas,
maxFeePerGas,
maxPriorityFeePerGas,
to,
value,
...rest
} = args
const account = account_ ? parseAccount(account_) : undefined
try {
assertRequest(args as AssertRequestParameters)
const blockNumberHex =
typeof blockNumber === 'bigint' ? numberToHex(blockNumber) : undefined
const block = blockNumberHex || blockTag
const chainFormat = client.chain?.formatters?.transactionRequest?.format
const format = chainFormat || formatTransactionRequest
const request = format(
{
// Pick out extra data that might exist on the chain's transaction request type.
...extract(rest, { format: chainFormat }),
account,
blobs,
data,
gas,
gasPrice,
maxFeePerBlobGas,
maxFeePerGas,
maxPriorityFeePerGas,
to,
value,
} as TransactionRequest,
'createAccessList',
) as TransactionRequest
const response = await client.request({
method: 'eth_createAccessList',
params: [request as ExactPartial<RpcTransactionRequest>, block],
})
return {
accessList: response.accessList,
gasUsed: BigInt(response.gasUsed),
}
} catch (err) {
throw getCallError(err as ErrorType, {
...args,
account,
chain: client.chain,
})
}
}

44
node_modules/viem/actions/public/createBlockFilter.ts generated vendored Normal file
View File

@@ -0,0 +1,44 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { Filter } from '../../types/filter.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import { createFilterRequestScope } from '../../utils/filters/createFilterRequestScope.js'
export type CreateBlockFilterReturnType = Filter<'block'>
export type CreateBlockFilterErrorType = RequestErrorType | ErrorType
/**
* Creates a [`Filter`](https://viem.sh/docs/glossary/types#filter) to listen for new block hashes that can be used with [`getFilterChanges`](https://viem.sh/docs/actions/public/getFilterChanges).
*
* - Docs: https://viem.sh/docs/actions/public/createBlockFilter
* - JSON-RPC Methods: [`eth_newBlockFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newBlockFilter)
*
* @param client - Client to use
* @returns [`Filter`](https://viem.sh/docs/glossary/types#filter). {@link CreateBlockFilterReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createBlockFilter } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const filter = await createBlockFilter(client)
* // { id: "0x345a6572337856574a76364e457a4366", type: 'block' }
*/
export async function createBlockFilter<chain extends Chain | undefined>(
client: Client<Transport, chain>,
): Promise<CreateBlockFilterReturnType> {
const getRequest = createFilterRequestScope(client, {
method: 'eth_newBlockFilter',
})
const id = await client.request({
method: 'eth_newBlockFilter',
})
return { id, request: getRequest(id), type: 'block' }
}

View File

@@ -0,0 +1,171 @@
import type { Abi, Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockNumber, BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type {
ContractEventName,
MaybeExtractEventArgsFromAbi,
} from '../../types/contract.js'
import type { Filter } from '../../types/filter.js'
import type { Hex } from '../../types/misc.js'
import {
type EncodeEventTopicsErrorType,
type EncodeEventTopicsParameters,
encodeEventTopics,
} from '../../utils/abi/encodeEventTopics.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import { createFilterRequestScope } from '../../utils/filters/createFilterRequestScope.js'
export type CreateContractEventFilterParameters<
abi extends Abi | readonly unknown[] = Abi,
eventName extends ContractEventName<abi> | undefined = undefined,
args extends
| MaybeExtractEventArgsFromAbi<abi, eventName>
| undefined = undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
> = {
address?: Address | Address[] | undefined
abi: abi
eventName?: eventName | ContractEventName<abi> | undefined
fromBlock?: fromBlock | BlockNumber | BlockTag | undefined
/**
* Whether or not the logs must match the indexed/non-indexed arguments in the event ABI item.
* @default false
*/
strict?: strict | boolean | undefined
toBlock?: toBlock | BlockNumber | BlockTag | undefined
} & (undefined extends eventName
? {
args?: undefined
}
: MaybeExtractEventArgsFromAbi<abi, eventName> extends infer eventFilterArgs
? {
args?:
| eventFilterArgs
| (args extends eventFilterArgs ? args : never)
| undefined
}
: {
args?: undefined
})
export type CreateContractEventFilterReturnType<
abi extends Abi | readonly unknown[] = Abi,
eventName extends ContractEventName<abi> | undefined = undefined,
args extends
| MaybeExtractEventArgsFromAbi<abi, eventName>
| undefined = undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
> = Filter<'event', abi, eventName, args, strict, fromBlock, toBlock>
export type CreateContractEventFilterErrorType =
| EncodeEventTopicsErrorType
| RequestErrorType
| NumberToHexErrorType
| ErrorType
/**
* Creates a Filter to retrieve event logs that can be used with [`getFilterChanges`](https://viem.sh/docs/actions/public/getFilterChanges) or [`getFilterLogs`](https://viem.sh/docs/actions/public/getFilterLogs).
*
* - Docs: https://viem.sh/docs/contract/createContractEventFilter
*
* @param client - Client to use
* @param parameters - {@link CreateContractEventFilterParameters}
* @returns [`Filter`](https://viem.sh/docs/glossary/types#filter). {@link CreateContractEventFilterReturnType}
*
* @example
* import { createPublicClient, http, parseAbi } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createContractEventFilter } from 'viem/contract'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const filter = await createContractEventFilter(client, {
* abi: parseAbi(['event Transfer(address indexed, address indexed, uint256)']),
* })
*/
export async function createContractEventFilter<
chain extends Chain | undefined,
const abi extends Abi | readonly unknown[],
eventName extends ContractEventName<abi> | undefined,
args extends MaybeExtractEventArgsFromAbi<abi, eventName> | undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
>(
client: Client<Transport, chain>,
parameters: CreateContractEventFilterParameters<
abi,
eventName,
args,
strict,
fromBlock,
toBlock
>,
): Promise<
CreateContractEventFilterReturnType<
abi,
eventName,
args,
strict,
fromBlock,
toBlock
>
> {
const { address, abi, args, eventName, fromBlock, strict, toBlock } =
parameters as CreateContractEventFilterParameters
const getRequest = createFilterRequestScope(client, {
method: 'eth_newFilter',
})
const topics = eventName
? encodeEventTopics({
abi,
args,
eventName,
} as unknown as EncodeEventTopicsParameters)
: undefined
const id: Hex = await client.request({
method: 'eth_newFilter',
params: [
{
address,
fromBlock:
typeof fromBlock === 'bigint' ? numberToHex(fromBlock) : fromBlock,
toBlock: typeof toBlock === 'bigint' ? numberToHex(toBlock) : toBlock,
topics,
},
],
})
return {
abi,
args,
eventName,
id,
request: getRequest(id),
strict: Boolean(strict),
type: 'event',
} as unknown as CreateContractEventFilterReturnType<
abi,
eventName,
args,
strict,
fromBlock,
toBlock
>
}

237
node_modules/viem/actions/public/createEventFilter.ts generated vendored Normal file
View File

@@ -0,0 +1,237 @@
import type { AbiEvent, Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockNumber, BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type {
MaybeAbiEventName,
MaybeExtractEventArgsFromAbi,
} from '../../types/contract.js'
import type { Filter } from '../../types/filter.js'
import type { Hex, LogTopic } from '../../types/misc.js'
import type { Prettify } from '../../types/utils.js'
import {
type EncodeEventTopicsErrorType,
type EncodeEventTopicsParameters,
encodeEventTopics,
} from '../../utils/abi/encodeEventTopics.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import { createFilterRequestScope } from '../../utils/filters/createFilterRequestScope.js'
export type CreateEventFilterParameters<
abiEvent extends AbiEvent | undefined = undefined,
abiEvents extends
| readonly AbiEvent[]
| readonly unknown[]
| undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
//
_eventName extends string | undefined = MaybeAbiEventName<abiEvent>,
_args extends
| MaybeExtractEventArgsFromAbi<abiEvents, _eventName>
| undefined = undefined,
> = {
address?: Address | Address[] | undefined
fromBlock?: fromBlock | BlockNumber | BlockTag | undefined
toBlock?: toBlock | BlockNumber | BlockTag | undefined
} & (MaybeExtractEventArgsFromAbi<
abiEvents,
_eventName
> extends infer eventFilterArgs
?
| {
args:
| eventFilterArgs
| (_args extends eventFilterArgs ? _args : never)
event: abiEvent
events?: undefined
/**
* Whether or not the logs must match the indexed/non-indexed arguments on `event`.
* @default false
*/
strict?: strict | undefined
}
| {
args?: undefined
event?: abiEvent | undefined
events?: undefined
/**
* Whether or not the logs must match the indexed/non-indexed arguments on `event`.
* @default false
*/
strict?: strict | undefined
}
| {
args?: undefined
event?: undefined
events: abiEvents | undefined
/**
* Whether or not the logs must match the indexed/non-indexed arguments on `event`.
* @default false
*/
strict?: strict | undefined
}
| {
args?: undefined
event?: undefined
events?: undefined
strict?: undefined
}
: {
args?: undefined
event?: undefined
events?: undefined
strict?: undefined
})
export type CreateEventFilterReturnType<
abiEvent extends AbiEvent | undefined = undefined,
abiEvents extends
| readonly AbiEvent[]
| readonly unknown[]
| undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
_eventName extends string | undefined = MaybeAbiEventName<abiEvent>,
_args extends
| MaybeExtractEventArgsFromAbi<abiEvents, _eventName>
| undefined = undefined,
> = Prettify<
Filter<'event', abiEvents, _eventName, _args, strict, fromBlock, toBlock>
>
export type CreateEventFilterErrorType =
| EncodeEventTopicsErrorType
| RequestErrorType
| NumberToHexErrorType
| ErrorType
/**
* Creates a [`Filter`](https://viem.sh/docs/glossary/types#filter) to listen for new events that can be used with [`getFilterChanges`](https://viem.sh/docs/actions/public/getFilterChanges).
*
* - Docs: https://viem.sh/docs/actions/public/createEventFilter
* - JSON-RPC Methods: [`eth_newFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newfilter)
*
* @param client - Client to use
* @param parameters - {@link CreateEventFilterParameters}
* @returns [`Filter`](https://viem.sh/docs/glossary/types#filter). {@link CreateEventFilterReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createEventFilter } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const filter = await createEventFilter(client, {
* address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
* })
*/
export async function createEventFilter<
chain extends Chain | undefined,
const abiEvent extends AbiEvent | undefined = undefined,
const abiEvents extends
| readonly AbiEvent[]
| readonly unknown[]
| undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber<bigint> | BlockTag | undefined = undefined,
toBlock extends BlockNumber<bigint> | BlockTag | undefined = undefined,
_eventName extends string | undefined = MaybeAbiEventName<abiEvent>,
_args extends
| MaybeExtractEventArgsFromAbi<abiEvents, _eventName>
| undefined = undefined,
>(
client: Client<Transport, chain>,
{
address,
args,
event,
events: events_,
fromBlock,
strict,
toBlock,
}: CreateEventFilterParameters<
abiEvent,
abiEvents,
strict,
fromBlock,
toBlock,
_eventName,
_args
> = {} as any,
): Promise<
CreateEventFilterReturnType<
abiEvent,
abiEvents,
strict,
fromBlock,
toBlock,
_eventName,
_args
>
> {
const events = events_ ?? (event ? [event] : undefined)
const getRequest = createFilterRequestScope(client, {
method: 'eth_newFilter',
})
let topics: LogTopic[] = []
if (events) {
const encoded = (events as AbiEvent[]).flatMap((event) =>
encodeEventTopics({
abi: [event],
eventName: (event as AbiEvent).name,
args,
} as EncodeEventTopicsParameters),
)
// TODO: Clean up type casting
topics = [encoded as LogTopic]
if (event) topics = topics[0] as LogTopic[]
}
const id: Hex = await client.request({
method: 'eth_newFilter',
params: [
{
address,
fromBlock:
typeof fromBlock === 'bigint' ? numberToHex(fromBlock) : fromBlock,
toBlock: typeof toBlock === 'bigint' ? numberToHex(toBlock) : toBlock,
...(topics.length ? { topics } : {}),
},
],
})
return {
abi: events,
args,
eventName: event ? (event as AbiEvent).name : undefined,
fromBlock,
id,
request: getRequest(id),
strict: Boolean(strict),
toBlock,
type: 'event',
} as unknown as CreateEventFilterReturnType<
abiEvent,
abiEvents,
strict,
fromBlock,
toBlock,
_eventName,
_args
>
}

View File

@@ -0,0 +1,49 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { Filter } from '../../types/filter.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import { createFilterRequestScope } from '../../utils/filters/createFilterRequestScope.js'
export type CreatePendingTransactionFilterReturnType = Filter<'transaction'>
export type CreatePendingTransactionFilterErrorType =
| RequestErrorType
| ErrorType
/**
* Creates a Filter to listen for new pending transaction hashes that can be used with [`getFilterChanges`](https://viem.sh/docs/actions/public/getFilterChanges).
*
* - Docs: https://viem.sh/docs/actions/public/createPendingTransactionFilter
* - JSON-RPC Methods: [`eth_newPendingTransactionFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newpendingtransactionfilter)
*
* @param client - Client to use
* @returns [`Filter`](https://viem.sh/docs/glossary/types#filter). {@link CreateBlockFilterReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createPendingTransactionFilter } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const filter = await createPendingTransactionFilter(client)
* // { id: "0x345a6572337856574a76364e457a4366", type: 'transaction' }
*/
export async function createPendingTransactionFilter<
transport extends Transport,
chain extends Chain | undefined,
>(
client: Client<transport, chain>,
): Promise<CreatePendingTransactionFilterReturnType> {
const getRequest = createFilterRequestScope(client, {
method: 'eth_newPendingTransactionFilter',
})
const id = await client.request({
method: 'eth_newPendingTransactionFilter',
})
return { id, request: getRequest(id), type: 'transaction' }
}

147
node_modules/viem/actions/public/estimateContractGas.ts generated vendored Normal file
View File

@@ -0,0 +1,147 @@
import type { Abi } from 'abitype'
import type { Account } from '../../accounts/types.js'
import {
type ParseAccountErrorType,
parseAccount,
} from '../../accounts/utils/parseAccount.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { BaseError } from '../../errors/base.js'
import type { Chain } from '../../types/chain.js'
import type {
ContractFunctionArgs,
ContractFunctionName,
ContractFunctionParameters,
GetValue,
} from '../../types/contract.js'
import type { Hex } from '../../types/misc.js'
import type { UnionOmit } from '../../types/utils.js'
import {
type EncodeFunctionDataErrorType,
type EncodeFunctionDataParameters,
encodeFunctionData,
} from '../../utils/abi/encodeFunctionData.js'
import {
type GetContractErrorReturnType,
getContractError,
} from '../../utils/errors/getContractError.js'
import { getAction } from '../../utils/getAction.js'
import {
type EstimateGasErrorType,
type EstimateGasParameters,
estimateGas,
} from './estimateGas.js'
export type EstimateContractGasParameters<
abi extends Abi | readonly unknown[] = Abi,
functionName extends ContractFunctionName<
abi,
'nonpayable' | 'payable'
> = ContractFunctionName<abi, 'nonpayable' | 'payable'>,
args extends ContractFunctionArgs<
abi,
'nonpayable' | 'payable',
functionName
> = ContractFunctionArgs<abi, 'nonpayable' | 'payable', functionName>,
chain extends Chain | undefined = Chain | undefined,
> = ContractFunctionParameters<
abi,
'nonpayable' | 'payable',
functionName,
args
> &
UnionOmit<EstimateGasParameters<chain>, 'data' | 'to' | 'value'> &
GetValue<
abi,
functionName,
EstimateGasParameters<chain> extends EstimateGasParameters
? EstimateGasParameters<chain>['value']
: EstimateGasParameters['value']
> & {
/** Data to append to the end of the calldata. Useful for adding a ["domain" tag](https://opensea.notion.site/opensea/Seaport-Order-Attributions-ec2d69bf455041a5baa490941aad307f). */
dataSuffix?: Hex | undefined
}
export type EstimateContractGasReturnType = bigint
export type EstimateContractGasErrorType = GetContractErrorReturnType<
EncodeFunctionDataErrorType | EstimateGasErrorType | ParseAccountErrorType
>
/**
* Estimates the gas required to successfully execute a contract write function call.
*
* - Docs: https://viem.sh/docs/contract/estimateContractGas
*
* Internally, uses a [Public Client](https://viem.sh/docs/clients/public) to call the [`estimateGas` action](https://viem.sh/docs/actions/public/estimateGas) with [ABI-encoded `data`](https://viem.sh/docs/contract/encodeFunctionData).
*
* @param client - Client to use
* @param parameters - {@link EstimateContractGasParameters}
* @returns The gas estimate (in wei). {@link EstimateContractGasReturnType}
*
* @example
* import { createPublicClient, http, parseAbi } from 'viem'
* import { mainnet } from 'viem/chains'
* import { estimateContractGas } from 'viem/contract'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const gas = await estimateContractGas(client, {
* address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
* abi: parseAbi(['function mint() public']),
* functionName: 'mint',
* account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
* })
*/
export async function estimateContractGas<
const abi extends Abi | readonly unknown[],
functionName extends ContractFunctionName<abi, 'nonpayable' | 'payable'>,
args extends ContractFunctionArgs<abi, 'pure' | 'view', functionName>,
chain extends Chain | undefined,
account extends Account | undefined = undefined,
>(
client: Client<Transport, chain, account>,
parameters: EstimateContractGasParameters<abi, functionName, args, chain>,
): Promise<EstimateContractGasReturnType> {
const {
abi,
address,
args,
functionName,
dataSuffix = typeof client.dataSuffix === 'string'
? client.dataSuffix
: client.dataSuffix?.value,
...request
} = parameters as EstimateContractGasParameters
const data = encodeFunctionData({
abi,
args,
functionName,
} as EncodeFunctionDataParameters)
try {
const gas = await getAction(
client,
estimateGas,
'estimateGas',
)({
data: `${data}${dataSuffix ? dataSuffix.replace('0x', '') : ''}`,
to: address,
...request,
} as unknown as EstimateGasParameters)
return gas
} catch (error) {
const account = request.account ? parseAccount(request.account) : undefined
throw getContractError(error as BaseError, {
abi,
address,
args,
docsPath: '/docs/contract/estimateContractGas',
functionName,
sender: account?.address,
})
}
}

178
node_modules/viem/actions/public/estimateFeesPerGas.ts generated vendored Normal file
View File

@@ -0,0 +1,178 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import {
BaseFeeScalarError,
type BaseFeeScalarErrorType,
Eip1559FeesNotSupportedError,
type Eip1559FeesNotSupportedErrorType,
} from '../../errors/fee.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Account } from '../../types/account.js'
import type { Block } from '../../types/block.js'
import type {
Chain,
ChainEstimateFeesPerGasFnParameters,
ChainFeesFnParameters,
GetChainParameter,
} from '../../types/chain.js'
import type {
FeeValuesEIP1559,
FeeValuesLegacy,
FeeValuesType,
} from '../../types/fee.js'
import { getAction } from '../../utils/getAction.js'
import type { PrepareTransactionRequestParameters } from '../wallet/prepareTransactionRequest.js'
import {
type EstimateMaxPriorityFeePerGasErrorType,
internal_estimateMaxPriorityFeePerGas,
} from './estimateMaxPriorityFeePerGas.js'
import { getBlock } from './getBlock.js'
import { type GetGasPriceErrorType, getGasPrice } from './getGasPrice.js'
export type EstimateFeesPerGasParameters<
chain extends Chain | undefined = Chain | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
type extends FeeValuesType = FeeValuesType,
> = {
/**
* The type of fee values to return.
*
* - `legacy`: Returns the legacy gas price.
* - `eip1559`: Returns the max fee per gas and max priority fee per gas.
*
* @default 'eip1559'
*/
type?: type | FeeValuesType | undefined
} & GetChainParameter<chain, chainOverride>
export type EstimateFeesPerGasReturnType<
type extends FeeValuesType = FeeValuesType,
> =
| (type extends 'legacy' ? FeeValuesLegacy : never)
| (type extends 'eip1559' ? FeeValuesEIP1559 : never)
export type EstimateFeesPerGasErrorType =
| BaseFeeScalarErrorType
| EstimateMaxPriorityFeePerGasErrorType
| GetGasPriceErrorType
| Eip1559FeesNotSupportedErrorType
| ErrorType
/**
* Returns an estimate for the fees per gas (in wei) for a
* transaction to be likely included in the next block.
* Defaults to [`chain.fees.estimateFeesPerGas`](/docs/clients/chains#fees-estimatefeespergas) if set.
*
* - Docs: https://viem.sh/docs/actions/public/estimateFeesPerGas
*
* @param client - Client to use
* @param parameters - {@link EstimateFeesPerGasParameters}
* @returns An estimate (in wei) for the fees per gas. {@link EstimateFeesPerGasReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { estimateFeesPerGas } from 'viem/actions'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const maxPriorityFeePerGas = await estimateFeesPerGas(client)
* // { maxFeePerGas: ..., maxPriorityFeePerGas: ... }
*/
export async function estimateFeesPerGas<
chain extends Chain | undefined,
chainOverride extends Chain | undefined,
type extends FeeValuesType = 'eip1559',
>(
client: Client<Transport, chain>,
args?: EstimateFeesPerGasParameters<chain, chainOverride, type> | undefined,
): Promise<EstimateFeesPerGasReturnType<type>> {
return internal_estimateFeesPerGas(client, args as any)
}
export async function internal_estimateFeesPerGas<
chain extends Chain | undefined,
chainOverride extends Chain | undefined,
type extends FeeValuesType = 'eip1559',
>(
client: Client<Transport, chain>,
args: EstimateFeesPerGasParameters<chain, chainOverride, type> & {
block?: Block | undefined
request?: PrepareTransactionRequestParameters<Chain, Account> | undefined
},
): Promise<EstimateFeesPerGasReturnType<type>> {
const {
block: block_,
chain = client.chain,
request,
type = 'eip1559',
} = args || {}
const baseFeeMultiplier = await (async () => {
if (typeof chain?.fees?.baseFeeMultiplier === 'function')
return chain.fees.baseFeeMultiplier({
block: block_ as Block,
client,
request,
} as ChainFeesFnParameters)
return chain?.fees?.baseFeeMultiplier ?? 1.2
})()
if (baseFeeMultiplier < 1) throw new BaseFeeScalarError()
const decimals = baseFeeMultiplier.toString().split('.')[1]?.length ?? 0
const denominator = 10 ** decimals
const multiply = (base: bigint) =>
(base * BigInt(Math.ceil(baseFeeMultiplier * denominator))) /
BigInt(denominator)
const block = block_
? block_
: await getAction(client, getBlock, 'getBlock')({})
if (typeof chain?.fees?.estimateFeesPerGas === 'function') {
const fees = (await chain.fees.estimateFeesPerGas({
block: block_ as Block,
client,
multiply,
request,
type,
} as ChainEstimateFeesPerGasFnParameters)) as unknown as EstimateFeesPerGasReturnType<type>
if (fees !== null) return fees
}
if (type === 'eip1559') {
if (typeof block.baseFeePerGas !== 'bigint')
throw new Eip1559FeesNotSupportedError()
const maxPriorityFeePerGas =
typeof request?.maxPriorityFeePerGas === 'bigint'
? request.maxPriorityFeePerGas
: await internal_estimateMaxPriorityFeePerGas(
client as Client<Transport, Chain>,
{
block: block as Block,
chain,
request,
},
)
const baseFeePerGas = multiply(block.baseFeePerGas)
const maxFeePerGas =
request?.maxFeePerGas ?? baseFeePerGas + maxPriorityFeePerGas
return {
maxFeePerGas,
maxPriorityFeePerGas,
} as EstimateFeesPerGasReturnType<type>
}
const gasPrice =
request?.gasPrice ??
multiply(await getAction(client, getGasPrice, 'getGasPrice')({}))
return {
gasPrice,
} as EstimateFeesPerGasReturnType<type>
}

229
node_modules/viem/actions/public/estimateGas.ts generated vendored Normal file
View File

@@ -0,0 +1,229 @@
import type { Address } from 'abitype'
import type { Account } from '../../accounts/types.js'
import {
type ParseAccountErrorType,
parseAccount,
} from '../../accounts/utils/parseAccount.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { BaseError } from '../../errors/base.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { StateOverride } from '../../types/stateOverride.js'
import type { TransactionRequest } from '../../types/transaction.js'
import type { UnionOmit } from '../../types/utils.js'
import {
type RecoverAuthorizationAddressErrorType,
recoverAuthorizationAddress,
} from '../../utils/authorization/recoverAuthorizationAddress.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import {
type GetEstimateGasErrorReturnType,
getEstimateGasError,
} from '../../utils/errors/getEstimateGasError.js'
import { extract } from '../../utils/formatters/extract.js'
import {
type FormattedTransactionRequest,
formatTransactionRequest,
} from '../../utils/formatters/transactionRequest.js'
import { serializeStateOverride } from '../../utils/stateOverride.js'
import {
type AssertRequestErrorType,
type AssertRequestParameters,
assertRequest,
} from '../../utils/transaction/assertRequest.js'
import {
type PrepareTransactionRequestParameters,
type PrepareTransactionRequestParameterType,
prepareTransactionRequest,
} from '../wallet/prepareTransactionRequest.js'
export type EstimateGasParameters<
chain extends Chain | undefined = Chain | undefined,
> = UnionOmit<FormattedEstimateGas<chain>, 'from'> & {
account?: Account | Address | undefined
prepare?:
| boolean
| readonly PrepareTransactionRequestParameterType[]
| undefined
stateOverride?: StateOverride | undefined
} & (
| {
/** The balance of the account at a block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockNumber?: undefined
/**
* The balance of the account at a block tag.
* @default 'latest'
*/
blockTag?: BlockTag | undefined
}
)
type FormattedEstimateGas<chain extends Chain | undefined = Chain | undefined> =
FormattedTransactionRequest<chain>
export type EstimateGasReturnType = bigint
export type EstimateGasErrorType = GetEstimateGasErrorReturnType<
| ParseAccountErrorType
| NumberToHexErrorType
| RequestErrorType
| RecoverAuthorizationAddressErrorType
| AssertRequestErrorType
>
/**
* Estimates the gas necessary to complete a transaction without submitting it to the network.
*
* - Docs: https://viem.sh/docs/actions/public/estimateGas
* - JSON-RPC Methods: [`eth_estimateGas`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas)
*
* @param client - Client to use
* @param parameters - {@link EstimateGasParameters}
* @returns The gas estimate (in gas units). {@link EstimateGasReturnType}
*
* @example
* import { createPublicClient, http, parseEther } from 'viem'
* import { mainnet } from 'viem/chains'
* import { estimateGas } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const gasEstimate = await estimateGas(client, {
* account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: parseEther('1'),
* })
*/
export async function estimateGas<
chain extends Chain | undefined,
account extends Account | undefined = undefined,
>(
client: Client<Transport, chain, account>,
args: EstimateGasParameters<chain>,
): Promise<EstimateGasReturnType> {
const { account: account_ = client.account, prepare = true } = args
const account = account_ ? parseAccount(account_) : undefined
const parameters = (() => {
if (Array.isArray(prepare)) return prepare
// Some RPC Providers do not compute versioned hashes from blobs. We will need
// to compute them.
if (account?.type !== 'local') return ['blobVersionedHashes']
return undefined
})()
try {
const to = await (async () => {
// If `to` exists on the parameters, use that.
if (args.to) return args.to
// If no `to` exists, and we are sending a EIP-7702 transaction, use the
// address of the first authorization in the list.
if (args.authorizationList && args.authorizationList.length > 0)
return await recoverAuthorizationAddress({
authorization: args.authorizationList[0],
}).catch(() => {
throw new BaseError(
'`to` is required. Could not infer from `authorizationList`',
)
})
// Otherwise, we are sending a deployment transaction.
return undefined
})()
const {
accessList,
authorizationList,
blobs,
blobVersionedHashes,
blockNumber,
blockTag,
data,
gas,
gasPrice,
maxFeePerBlobGas,
maxFeePerGas,
maxPriorityFeePerGas,
nonce,
value,
stateOverride,
...rest
} = prepare
? ((await prepareTransactionRequest(client, {
...args,
parameters,
to,
} as PrepareTransactionRequestParameters)) as EstimateGasParameters)
: args
// If we get `gas` back from the prepared transaction request, which is
// different from the `gas` we provided, it was likely filled by other means
// during request preparation (e.g. `eth_fillTransaction` or `chain.transactionRequest.prepare`).
// (e.g. `eth_fillTransaction` or `chain.transactionRequest.prepare`).
if (gas && args.gas !== gas) return gas
const blockNumberHex =
typeof blockNumber === 'bigint' ? numberToHex(blockNumber) : undefined
const block = blockNumberHex || blockTag
const rpcStateOverride = serializeStateOverride(stateOverride)
assertRequest(args as AssertRequestParameters)
const chainFormat = client.chain?.formatters?.transactionRequest?.format
const format = chainFormat || formatTransactionRequest
const request = format(
{
// Pick out extra data that might exist on the chain's transaction request type.
...extract(rest, { format: chainFormat }),
account,
accessList,
authorizationList,
blobs,
blobVersionedHashes,
data,
gasPrice,
maxFeePerBlobGas,
maxFeePerGas,
maxPriorityFeePerGas,
nonce,
to,
value,
} as TransactionRequest,
'estimateGas',
)
return BigInt(
await client.request({
method: 'eth_estimateGas',
params: rpcStateOverride
? [
request,
block ?? client.experimental_blockTag ?? 'latest',
rpcStateOverride,
]
: block
? [request, block]
: [request],
}),
)
} catch (err) {
throw getEstimateGasError(err as BaseError, {
...args,
account,
chain: client.chain,
})
}
}

View File

@@ -0,0 +1,134 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import {
Eip1559FeesNotSupportedError,
type Eip1559FeesNotSupportedErrorType,
} from '../../errors/fee.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Account } from '../../types/account.js'
import type { Block } from '../../types/block.js'
import type {
Chain,
ChainFeesFnParameters,
GetChainParameter,
} from '../../types/chain.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type HexToBigIntErrorType,
hexToBigInt,
} from '../../utils/encoding/fromHex.js'
import { getAction } from '../../utils/getAction.js'
import type { PrepareTransactionRequestParameters } from '../wallet/prepareTransactionRequest.js'
import { type GetBlockErrorType, getBlock } from './getBlock.js'
import { type GetGasPriceErrorType, getGasPrice } from './getGasPrice.js'
export type EstimateMaxPriorityFeePerGasParameters<
chain extends Chain | undefined = Chain | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
> = GetChainParameter<chain, chainOverride>
export type EstimateMaxPriorityFeePerGasReturnType = bigint
export type EstimateMaxPriorityFeePerGasErrorType =
| GetBlockErrorType
| HexToBigIntErrorType
| RequestErrorType
| GetBlockErrorType
| GetGasPriceErrorType
| Eip1559FeesNotSupportedErrorType
| ErrorType
/**
* Returns an estimate for the max priority fee per gas (in wei) for a
* transaction to be likely included in the next block.
* Defaults to [`chain.fees.defaultPriorityFee`](/docs/clients/chains#fees-defaultpriorityfee) if set.
*
* - Docs: https://viem.sh/docs/actions/public/estimateMaxPriorityFeePerGas
*
* @param client - Client to use
* @returns An estimate (in wei) for the max priority fee per gas. {@link EstimateMaxPriorityFeePerGasReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { estimateMaxPriorityFeePerGas } from 'viem/actions'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const maxPriorityFeePerGas = await estimateMaxPriorityFeePerGas(client)
* // 10000000n
*/
export async function estimateMaxPriorityFeePerGas<
chain extends Chain | undefined,
chainOverride extends Chain | undefined,
>(
client: Client<Transport, chain>,
args?:
| EstimateMaxPriorityFeePerGasParameters<chain, chainOverride>
| undefined,
): Promise<EstimateMaxPriorityFeePerGasReturnType> {
return internal_estimateMaxPriorityFeePerGas(client, args as any)
}
export async function internal_estimateMaxPriorityFeePerGas<
chain extends Chain | undefined,
chainOverride extends Chain | undefined,
>(
client: Client<Transport, chain>,
args: EstimateMaxPriorityFeePerGasParameters<chain, chainOverride> & {
block?: Block | undefined
request?:
| PrepareTransactionRequestParameters<
chain,
Account | undefined,
chainOverride
>
| undefined
},
): Promise<EstimateMaxPriorityFeePerGasReturnType> {
const { block: block_, chain = client.chain, request } = args || {}
try {
const maxPriorityFeePerGas =
chain?.fees?.maxPriorityFeePerGas ?? chain?.fees?.defaultPriorityFee
if (typeof maxPriorityFeePerGas === 'function') {
const block =
block_ || (await getAction(client, getBlock, 'getBlock')({}))
const maxPriorityFeePerGas_ = await maxPriorityFeePerGas({
block,
client,
request,
} as ChainFeesFnParameters)
if (maxPriorityFeePerGas_ === null) throw new Error()
return maxPriorityFeePerGas_
}
if (typeof maxPriorityFeePerGas !== 'undefined') return maxPriorityFeePerGas
const maxPriorityFeePerGasHex = await client.request({
method: 'eth_maxPriorityFeePerGas',
})
return hexToBigInt(maxPriorityFeePerGasHex)
} catch {
// If the RPC Provider does not support `eth_maxPriorityFeePerGas`
// fall back to calculating it manually via `gasPrice - baseFeePerGas`.
// See: https://github.com/ethereum/pm/issues/328#:~:text=eth_maxPriorityFeePerGas%20after%20London%20will%20effectively%20return%20eth_gasPrice%20%2D%20baseFee
const [block, gasPrice] = await Promise.all([
block_
? Promise.resolve(block_)
: getAction(client, getBlock, 'getBlock')({}),
getAction(client, getGasPrice, 'getGasPrice')({}),
])
if (typeof block.baseFeePerGas !== 'bigint')
throw new Eip1559FeesNotSupportedError()
const maxPriorityFeePerGas = gasPrice - block.baseFeePerGas
if (maxPriorityFeePerGas < 0n) return 0n
return maxPriorityFeePerGas
}
}

258
node_modules/viem/actions/public/fillTransaction.ts generated vendored Normal file
View File

@@ -0,0 +1,258 @@
import type { Address } from 'abitype'
import { parseAccount } from '../../accounts/utils/parseAccount.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { BaseError } from '../../errors/base.js'
import { BaseFeeScalarError } from '../../errors/fee.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Account, GetAccountParameter } from '../../types/account.js'
import type { ExtractCapabilities } from '../../types/capabilities.js'
import type {
Chain,
ChainFeesFnParameters,
DeriveChain,
GetChainParameter,
} from '../../types/chain.js'
import type { Hex } from '../../types/misc.js'
import type { TransactionRequest } from '../../types/transaction.js'
import type { UnionOmit } from '../../types/utils.js'
import {
type GetTransactionErrorReturnType,
getTransactionError,
} from '../../utils/errors/getTransactionError.js'
import { extract } from '../../utils/formatters/extract.js'
import {
type FormattedTransaction,
formatTransaction,
} from '../../utils/formatters/transaction.js'
import {
type FormattedTransactionRequest,
formatTransactionRequest,
} from '../../utils/formatters/transactionRequest.js'
import { getAction } from '../../utils/getAction.js'
import type { NonceManager } from '../../utils/nonceManager.js'
import { assertRequest } from '../../utils/transaction/assertRequest.js'
import { getBlock } from './getBlock.js'
import { getChainId as getChainId_ } from './getChainId.js'
export type FillTransactionParameters<
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
accountOverride extends Account | Address | undefined =
| Account
| Address
| undefined,
///
_derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
> = UnionOmit<FormattedTransactionRequest<_derivedChain>, 'from'> &
GetAccountParameter<account, accountOverride, false, true> &
GetChainParameter<chain, chainOverride> & {
/**
* Nonce manager to use for the transaction request.
*/
nonceManager?: NonceManager | undefined
}
export type FillTransactionReturnType<
chain extends Chain | undefined = Chain | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
///
_derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
> = {
capabilities?:
| ExtractCapabilities<'fillTransaction', 'ReturnType'>
| undefined
raw: Hex
transaction: FormattedTransaction<_derivedChain>
}
export type FillTransactionErrorType =
| GetTransactionErrorReturnType<ErrorType>
| ErrorType
/**
* Fills a transaction request with the necessary fields to be signed over.
*
* - Docs: https://viem.sh/docs/actions/public/fillTransaction
*
* @param client - Client to use
* @param parameters - {@link FillTransactionParameters}
* @returns The filled transaction. {@link FillTransactionReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { fillTransaction } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const result = await fillTransaction(client, {
* account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: parseEther('1'),
* })
*/
export async function fillTransaction<
chain extends Chain | undefined,
account extends Account | undefined,
chainOverride extends Chain | undefined = undefined,
accountOverride extends Account | Address | undefined = undefined,
>(
client: Client<Transport, chain, account>,
parameters: FillTransactionParameters<
chain,
account,
chainOverride,
accountOverride
>,
): Promise<FillTransactionReturnType<chain, chainOverride>> {
const {
account = client.account,
accessList,
authorizationList,
chain = client.chain,
blobVersionedHashes,
blobs,
data,
gas,
gasPrice,
maxFeePerBlobGas,
maxFeePerGas,
maxPriorityFeePerGas,
nonce: nonce_,
nonceManager,
to,
type,
value,
...rest
} = parameters
const nonce = await (async () => {
if (!account) return nonce_
if (!nonceManager) return nonce_
if (typeof nonce_ !== 'undefined') return nonce_
const account_ = parseAccount(account)
const chainId = chain
? chain.id
: await getAction(client, getChainId_, 'getChainId')({})
return await nonceManager.consume({
address: account_.address,
chainId,
client,
})
})()
assertRequest(parameters)
const chainFormat = chain?.formatters?.transactionRequest?.format
const format = chainFormat || formatTransactionRequest
const request = format(
{
// Pick out extra data that might exist on the chain's transaction request type.
...extract(rest, { format: chainFormat }),
account: account ? parseAccount(account) : undefined,
accessList,
authorizationList,
blobs,
blobVersionedHashes,
data,
gas,
gasPrice,
maxFeePerBlobGas,
maxFeePerGas,
maxPriorityFeePerGas,
nonce,
to,
type,
value,
} as TransactionRequest,
'fillTransaction',
)
try {
const response = await client.request({
method: 'eth_fillTransaction',
params: [request],
})
const format = chain?.formatters?.transaction?.format || formatTransaction
const transaction = format(response.tx)
// Remove unnecessary fields.
delete transaction.blockHash
delete transaction.blockNumber
delete transaction.r
delete transaction.s
delete transaction.transactionIndex
delete transaction.v
delete transaction.yParity
// Rewrite fields.
transaction.data = transaction.input
// Preference supplied fees (some nodes do not take these preferences).
if (transaction.gas) transaction.gas = parameters.gas ?? transaction.gas
if (transaction.gasPrice)
transaction.gasPrice = parameters.gasPrice ?? transaction.gasPrice
if (transaction.maxFeePerBlobGas)
transaction.maxFeePerBlobGas =
parameters.maxFeePerBlobGas ?? transaction.maxFeePerBlobGas
if (transaction.maxFeePerGas)
transaction.maxFeePerGas =
parameters.maxFeePerGas ?? transaction.maxFeePerGas
if (transaction.maxPriorityFeePerGas)
transaction.maxPriorityFeePerGas =
parameters.maxPriorityFeePerGas ?? transaction.maxPriorityFeePerGas
if (typeof transaction.nonce !== 'undefined')
transaction.nonce = parameters.nonce ?? transaction.nonce
// Build fee multiplier function.
const feeMultiplier = await (async () => {
if (typeof chain?.fees?.baseFeeMultiplier === 'function') {
const block = await getAction(client, getBlock, 'getBlock')({})
return chain.fees.baseFeeMultiplier({
block,
client,
request: parameters,
} as ChainFeesFnParameters)
}
return chain?.fees?.baseFeeMultiplier ?? 1.2
})()
if (feeMultiplier < 1) throw new BaseFeeScalarError()
const decimals = feeMultiplier.toString().split('.')[1]?.length ?? 0
const denominator = 10 ** decimals
const multiplyFee = (base: bigint) =>
(base * BigInt(Math.ceil(feeMultiplier * denominator))) /
BigInt(denominator)
// Apply fee multiplier.
if (!transaction.feePayerSignature) {
if (transaction.maxFeePerGas && !parameters.maxFeePerGas)
transaction.maxFeePerGas = multiplyFee(transaction.maxFeePerGas)
if (transaction.gasPrice && !parameters.gasPrice)
transaction.gasPrice = multiplyFee(transaction.gasPrice)
}
return {
raw: response.raw,
transaction: {
from: request.from,
...transaction,
},
...(response.capabilities ? { capabilities: response.capabilities } : {}),
}
} catch (err) {
throw getTransactionError(
err as BaseError,
{
...parameters,
chain: client.chain,
} as never,
)
}
}

121
node_modules/viem/actions/public/getBalance.ts generated vendored Normal file
View File

@@ -0,0 +1,121 @@
import type { Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { multicall3Abi } from '../../constants/abis.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import { decodeFunctionResult } from '../../utils/abi/decodeFunctionResult.js'
import { encodeFunctionData } from '../../utils/abi/encodeFunctionData.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import { getAction } from '../../utils/getAction.js'
import { type CallParameters, call } from './call.js'
export type GetBalanceParameters = {
/** The address of the account. */
address: Address
} & (
| {
/** The balance of the account at a block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockNumber?: undefined
/** The balance of the account at a block tag. */
blockTag?: BlockTag | undefined
}
)
export type GetBalanceReturnType = bigint
export type GetBalanceErrorType =
| NumberToHexErrorType
| RequestErrorType
| ErrorType
/**
* Returns the balance of an address in wei.
*
* - Docs: https://viem.sh/docs/actions/public/getBalance
* - JSON-RPC Methods: [`eth_getBalance`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getbalance)
*
* You can convert the balance to ether units with [`formatEther`](https://viem.sh/docs/utilities/formatEther).
*
* ```ts
* const balance = await getBalance(client, {
* address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* blockTag: 'safe'
* })
* const balanceAsEther = formatEther(balance)
* // "6.942"
* ```
*
* @param client - Client to use
* @param parameters - {@link GetBalanceParameters}
* @returns The balance of the address in wei. {@link GetBalanceReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getBalance } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const balance = await getBalance(client, {
* address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* })
* // 10000000000000000000000n (wei)
*/
export async function getBalance<chain extends Chain | undefined>(
client: Client<Transport, chain>,
{
address,
blockNumber,
blockTag = client.experimental_blockTag ?? 'latest',
}: GetBalanceParameters,
): Promise<GetBalanceReturnType> {
if (client.batch?.multicall && client.chain?.contracts?.multicall3) {
const multicall3Address = client.chain.contracts.multicall3.address
const calldata = encodeFunctionData({
abi: multicall3Abi,
functionName: 'getEthBalance',
args: [address],
})
const { data } = await getAction(
client,
call,
'call',
)({
to: multicall3Address,
data: calldata,
blockNumber,
blockTag,
} as unknown as CallParameters<chain>)
return decodeFunctionResult({
abi: multicall3Abi,
functionName: 'getEthBalance',
args: [address],
data: data || '0x',
})
}
const blockNumberHex =
typeof blockNumber === 'bigint' ? numberToHex(blockNumber) : undefined
const balance = await client.request({
method: 'eth_getBalance',
params: [address, blockNumberHex || blockTag],
})
return BigInt(balance)
}

42
node_modules/viem/actions/public/getBlobBaseFee.ts generated vendored Normal file
View File

@@ -0,0 +1,42 @@
import type { Account } from '../../accounts/types.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
export type GetBlobBaseFeeReturnType = bigint
export type GetBlobBaseFeeErrorType = RequestErrorType | ErrorType
/**
* Returns the base fee per blob gas in wei.
*
* - Docs: https://viem.sh/docs/actions/public/getBlobBaseFee
* - JSON-RPC Methods: [`eth_blobBaseFee`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blobBaseFee)
*
* @param client - Client to use
* @returns The blob base fee (in wei). {@link GetBlobBaseFeeReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getBlobBaseFee } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const blobBaseFee = await getBlobBaseFee(client)
*/
export async function getBlobBaseFee<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
): Promise<GetBlobBaseFeeReturnType> {
const baseFee = await client.request({
method: 'eth_blobBaseFee',
})
return BigInt(baseFee)
}

132
node_modules/viem/actions/public/getBlock.ts generated vendored Normal file
View File

@@ -0,0 +1,132 @@
import type { Account } from '../../accounts/types.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import {
BlockNotFoundError,
type BlockNotFoundErrorType,
} from '../../errors/block.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { Hash } from '../../types/misc.js'
import type { RpcBlock } from '../../types/rpc.js'
import type { Prettify } from '../../types/utils.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import {
type FormattedBlock,
formatBlock,
} from '../../utils/formatters/block.js'
export type GetBlockParameters<
includeTransactions extends boolean = false,
blockTag extends BlockTag = 'latest',
> = {
/** Whether or not to include transaction data in the response. */
includeTransactions?: includeTransactions | undefined
} & (
| {
/** Hash of the block. */
blockHash?: Hash | undefined
blockNumber?: undefined
blockTag?: undefined
}
| {
blockHash?: undefined
/** The block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockHash?: undefined
blockNumber?: undefined
/**
* The block tag.
* @default 'latest'
*/
blockTag?: blockTag | BlockTag | undefined
}
)
export type GetBlockReturnType<
chain extends Chain | undefined = undefined,
includeTransactions extends boolean = false,
blockTag extends BlockTag = 'latest',
> = Prettify<FormattedBlock<chain, includeTransactions, blockTag>>
export type GetBlockErrorType =
| BlockNotFoundErrorType
| NumberToHexErrorType
| RequestErrorType
| ErrorType
/**
* Returns information about a block at a block number, hash, or tag.
*
* - Docs: https://viem.sh/docs/actions/public/getBlock
* - Examples: https://stackblitz.com/github/wevm/viem/tree/main/examples/blocks_fetching-blocks
* - JSON-RPC Methods:
* - Calls [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) for `blockNumber` & `blockTag`.
* - Calls [`eth_getBlockByHash`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbyhash) for `blockHash`.
*
* @param client - Client to use
* @param parameters - {@link GetBlockParameters}
* @returns Information about the block. {@link GetBlockReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getBlock } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const block = await getBlock(client)
*/
export async function getBlock<
chain extends Chain | undefined,
account extends Account | undefined,
includeTransactions extends boolean = false,
blockTag extends BlockTag = 'latest',
>(
client: Client<Transport, chain, account>,
{
blockHash,
blockNumber,
blockTag = client.experimental_blockTag ?? 'latest',
includeTransactions: includeTransactions_,
}: GetBlockParameters<includeTransactions, blockTag> = {},
): Promise<GetBlockReturnType<chain, includeTransactions, blockTag>> {
const includeTransactions = includeTransactions_ ?? false
const blockNumberHex =
blockNumber !== undefined ? numberToHex(blockNumber) : undefined
let block: RpcBlock | null = null
if (blockHash) {
block = await client.request(
{
method: 'eth_getBlockByHash',
params: [blockHash, includeTransactions],
},
{ dedupe: true },
)
} else {
block = await client.request(
{
method: 'eth_getBlockByNumber',
params: [blockNumberHex || blockTag, includeTransactions],
},
{ dedupe: Boolean(blockNumberHex) },
)
}
if (!block) throw new BlockNotFoundError({ blockHash, blockNumber })
const format = client.chain?.formatters?.block?.format || formatBlock
return format(block, 'getBlock')
}

66
node_modules/viem/actions/public/getBlockNumber.ts generated vendored Normal file
View File

@@ -0,0 +1,66 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type GetCacheErrorType,
getCache,
withCache,
} from '../../utils/promise/withCache.js'
export type GetBlockNumberParameters = {
/** Time (in ms) that cached block number will remain in memory. */
cacheTime?: number | undefined
}
export type GetBlockNumberReturnType = bigint
export type GetBlockNumberErrorType = RequestErrorType | ErrorType
const cacheKey = (id: string) => `blockNumber.${id}`
/** @internal */
export type GetBlockNumberCacheErrorType = GetCacheErrorType | ErrorType
/** @internal */
export function getBlockNumberCache(id: string) {
return getCache(cacheKey(id))
}
/**
* Returns the number of the most recent block seen.
*
* - Docs: https://viem.sh/docs/actions/public/getBlockNumber
* - Examples: https://stackblitz.com/github/wevm/viem/tree/main/examples/blocks_fetching-blocks
* - JSON-RPC Methods: [`eth_blockNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blocknumber)
*
* @param client - Client to use
* @param parameters - {@link GetBlockNumberParameters}
* @returns The number of the block. {@link GetBlockNumberReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getBlockNumber } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const blockNumber = await getBlockNumber(client)
* // 69420n
*/
export async function getBlockNumber<chain extends Chain | undefined>(
client: Client<Transport, chain>,
{ cacheTime = client.cacheTime }: GetBlockNumberParameters = {},
): Promise<GetBlockNumberReturnType> {
const blockNumberHex = await withCache(
() =>
client.request({
method: 'eth_blockNumber',
}),
{ cacheKey: cacheKey(client.uid), cacheTime },
)
return BigInt(blockNumberHex)
}

View File

@@ -0,0 +1,100 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { Hash } from '../../types/misc.js'
import type { Quantity } from '../../types/rpc.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type HexToNumberErrorType,
hexToNumber,
} from '../../utils/encoding/fromHex.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
export type GetBlockTransactionCountParameters =
| {
/** Hash of the block. */
blockHash?: Hash | undefined
blockNumber?: undefined
blockTag?: undefined
}
| {
blockHash?: undefined
/** The block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockHash?: undefined
blockNumber?: undefined
/** The block tag. Defaults to 'latest'. */
blockTag?: BlockTag | undefined
}
export type GetBlockTransactionCountReturnType = number
export type GetBlockTransactionCountErrorType =
| NumberToHexErrorType
| HexToNumberErrorType
| RequestErrorType
| ErrorType
/**
* Returns the number of Transactions at a block number, hash, or tag.
*
* - Docs: https://viem.sh/docs/actions/public/getBlockTransactionCount
* - JSON-RPC Methods:
* - Calls [`eth_getBlockTransactionCountByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbynumber) for `blockNumber` & `blockTag`.
* - Calls [`eth_getBlockTransactionCountByHash`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbyhash) for `blockHash`.
*
* @param client - Client to use
* @param parameters - {@link GetBlockTransactionCountParameters}
* @returns The block transaction count. {@link GetBlockTransactionCountReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getBlockTransactionCount } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const count = await getBlockTransactionCount(client)
*/
export async function getBlockTransactionCount<chain extends Chain | undefined>(
client: Client<Transport, chain>,
{
blockHash,
blockNumber,
blockTag = 'latest',
}: GetBlockTransactionCountParameters = {},
): Promise<GetBlockTransactionCountReturnType> {
const blockNumberHex =
blockNumber !== undefined ? numberToHex(blockNumber) : undefined
let count: Quantity
if (blockHash) {
count = await client.request(
{
method: 'eth_getBlockTransactionCountByHash',
params: [blockHash],
},
{ dedupe: true },
)
} else {
count = await client.request(
{
method: 'eth_getBlockTransactionCountByNumber',
params: [blockNumberHex || blockTag],
},
{ dedupe: Boolean(blockNumberHex) },
)
}
return hexToNumber(count)
}

51
node_modules/viem/actions/public/getChainId.ts generated vendored Normal file
View File

@@ -0,0 +1,51 @@
import type { Account } from '../../accounts/types.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type HexToNumberErrorType,
hexToNumber,
} from '../../utils/encoding/fromHex.js'
export type GetChainIdReturnType = number
export type GetChainIdErrorType =
| HexToNumberErrorType
| RequestErrorType
| ErrorType
/**
* Returns the chain ID associated with the current network.
*
* - Docs: https://viem.sh/docs/actions/public/getChainId
* - JSON-RPC Methods: [`eth_chainId`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_chainid)
*
* @param client - Client to use
* @returns The current chain ID. {@link GetChainIdReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getChainId } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const chainId = await getChainId(client)
* // 1
*/
export async function getChainId<
chain extends Chain | undefined,
account extends Account | undefined,
>(client: Client<Transport, chain, account>): Promise<GetChainIdReturnType> {
const chainIdHex = await client.request(
{
method: 'eth_chainId',
},
{ dedupe: true },
)
return hexToNumber(chainIdHex)
}

73
node_modules/viem/actions/public/getCode.ts generated vendored Normal file
View File

@@ -0,0 +1,73 @@
import type { Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { Hex } from '../../types/misc.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
export type GetCodeParameters = {
address: Address
} & (
| {
blockNumber?: undefined
blockTag?: BlockTag | undefined
}
| {
blockNumber?: bigint | undefined
blockTag?: undefined
}
)
export type GetCodeReturnType = Hex | undefined
export type GetCodeErrorType =
| NumberToHexErrorType
| RequestErrorType
| ErrorType
/**
* Retrieves the bytecode at an address.
*
* - Docs: https://viem.sh/docs/contract/getCode
* - JSON-RPC Methods: [`eth_getCode`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getcode)
*
* @param client - Client to use
* @param parameters - {@link GetCodeParameters}
* @returns The contract's bytecode. {@link GetCodeReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getCode } from 'viem/contract'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const code = await getCode(client, {
* address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
* })
*/
export async function getCode<chain extends Chain | undefined>(
client: Client<Transport, chain>,
{ address, blockNumber, blockTag = 'latest' }: GetCodeParameters,
): Promise<GetCodeReturnType> {
const blockNumberHex =
blockNumber !== undefined ? numberToHex(blockNumber) : undefined
const hex = await client.request(
{
method: 'eth_getCode',
params: [address, blockNumberHex || blockTag],
},
{ dedupe: Boolean(blockNumberHex) },
)
if (hex === '0x') return undefined
return hex
}

170
node_modules/viem/actions/public/getContractEvents.ts generated vendored Normal file
View File

@@ -0,0 +1,170 @@
import type { Abi, Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockNumber, BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type {
ContractEventArgs,
ContractEventName,
} from '../../types/contract.js'
import type { Log } from '../../types/log.js'
import type { Hash } from '../../types/misc.js'
import {
type GetAbiItemErrorType,
type GetAbiItemParameters,
getAbiItem,
} from '../../utils/abi/getAbiItem.js'
import { getAction } from '../../utils/getAction.js'
import {
type GetLogsErrorType,
type GetLogsParameters,
getLogs,
} from './getLogs.js'
export type GetContractEventsParameters<
abi extends Abi | readonly unknown[] = Abi,
eventName extends ContractEventName<abi> | undefined =
| ContractEventName<abi>
| undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
> = {
/** The address of the contract. */
address?: Address | Address[] | undefined
/** Contract ABI. */
abi: abi
args?:
| ContractEventArgs<
abi,
eventName extends ContractEventName<abi>
? eventName
: ContractEventName<abi>
>
| undefined
/** Contract event. */
eventName?: eventName | ContractEventName<abi> | undefined
/**
* Whether or not the logs must match the indexed/non-indexed arguments on `event`.
* @default false
*/
strict?: strict | boolean | undefined
} & (
| {
/** Block number or tag after which to include logs */
fromBlock?: fromBlock | BlockNumber | BlockTag | undefined
/** Block number or tag before which to include logs */
toBlock?: toBlock | BlockNumber | BlockTag | undefined
blockHash?: undefined
}
| {
fromBlock?: undefined
toBlock?: undefined
/** Hash of block to include logs from */
blockHash?: Hash | undefined
}
)
export type GetContractEventsReturnType<
abi extends Abi | readonly unknown[] = readonly unknown[],
eventName extends ContractEventName<abi> | undefined =
| ContractEventName<abi>
| undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
///
isPending extends boolean =
| (fromBlock extends 'pending' ? true : false)
| (toBlock extends 'pending' ? true : false),
> = Log<bigint, number, isPending, undefined, strict, abi, eventName>[]
export type GetContractEventsErrorType =
| GetAbiItemErrorType
| GetLogsErrorType
| ErrorType
/**
* Returns a list of event logs emitted by a contract.
*
* - Docs: https://viem.sh/docs/contract/getContractEvents#getcontractevents
* - JSON-RPC Methods: [`eth_getLogs`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs)
*
* @param client - Client to use
* @param parameters - {@link GetContractEventsParameters}
* @returns A list of event logs. {@link GetContractEventsReturnType}
*
* @example
* import { createClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getContractEvents } from 'viem/public'
* import { wagmiAbi } from './abi'
*
* const client = createClient({
* chain: mainnet,
* transport: http(),
* })
* const logs = await getContractEvents(client, {
* address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
* abi: wagmiAbi,
* eventName: 'Transfer'
* })
*/
export async function getContractEvents<
chain extends Chain | undefined,
const abi extends Abi | readonly unknown[],
eventName extends ContractEventName<abi> | undefined = undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
>(
client: Client<Transport, chain>,
parameters: GetContractEventsParameters<
abi,
eventName,
strict,
fromBlock,
toBlock
>,
): Promise<
GetContractEventsReturnType<abi, eventName, strict, fromBlock, toBlock>
> {
const {
abi,
address,
args,
blockHash,
eventName,
fromBlock,
toBlock,
strict,
} = parameters
const event = eventName
? getAbiItem({ abi, name: eventName } as GetAbiItemParameters)
: undefined
const events = !event
? (abi as Abi).filter((x) => x.type === 'event')
: undefined
return getAction(
client,
getLogs,
'getLogs',
)({
address,
args,
blockHash,
event,
events,
fromBlock,
toBlock,
strict,
} as {} as GetLogsParameters) as unknown as GetContractEventsReturnType<
abi,
eventName,
strict,
fromBlock,
toBlock
>
}

80
node_modules/viem/actions/public/getDelegation.ts generated vendored Normal file
View File

@@ -0,0 +1,80 @@
import type { Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import {
type GetAddressErrorType,
getAddress,
} from '../../utils/address/getAddress.js'
import { type SizeErrorType, size } from '../../utils/data/size.js'
import { type SliceErrorType, slice } from '../../utils/data/slice.js'
import { type GetCodeErrorType, getCode } from './getCode.js'
export type GetDelegationParameters = {
/** The address to check for delegation. */
address: Address
} & (
| {
blockNumber?: undefined
blockTag?: BlockTag | undefined
}
| {
blockNumber?: bigint | undefined
blockTag?: undefined
}
)
export type GetDelegationReturnType = Address | undefined
export type GetDelegationErrorType =
| GetAddressErrorType
| GetCodeErrorType
| SliceErrorType
| SizeErrorType
| ErrorType
/**
* Returns the address that an account has delegated to via EIP-7702.
*
* - Docs: https://viem.sh/docs/actions/public/getDelegation
*
* @param client - Client to use
* @param parameters - {@link GetDelegationParameters}
* @returns The delegated address, or undefined if not delegated. {@link GetDelegationReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getDelegation } from 'viem/actions'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const delegation = await getDelegation(client, {
* address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* })
*/
export async function getDelegation<chain extends Chain | undefined>(
client: Client<Transport, chain>,
{ address, blockNumber, blockTag = 'latest' }: GetDelegationParameters,
): Promise<GetDelegationReturnType> {
const code = await getCode(client, {
address,
...(blockNumber !== undefined ? { blockNumber } : { blockTag }),
} as GetDelegationParameters)
if (!code) return undefined
// EIP-7702 delegation designator: 0xef0100 prefix (3 bytes) + address (20 bytes) = 23 bytes
if (size(code) !== 23) return undefined
// Check for EIP-7702 delegation designator prefix
if (!code.startsWith('0xef0100')) return undefined
// Extract the delegated address (bytes 3-23) and checksum it
return getAddress(slice(code, 3, 23))
}

134
node_modules/viem/actions/public/getEip712Domain.ts generated vendored Normal file
View File

@@ -0,0 +1,134 @@
import type { Address, TypedDataDomain } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import {
Eip712DomainNotFoundError,
type Eip712DomainNotFoundErrorType,
} from '../../errors/eip712.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Hex } from '../../types/misc.js'
import type { RequiredBy } from '../../types/utils.js'
import { getAction } from '../../utils/getAction.js'
import {
type ReadContractErrorType,
type ReadContractParameters,
readContract,
} from './readContract.js'
export type GetEip712DomainParameters = {
address: Address
} & Pick<ReadContractParameters, 'factory' | 'factoryData'>
export type GetEip712DomainReturnType = {
domain: RequiredBy<
TypedDataDomain,
'chainId' | 'name' | 'verifyingContract' | 'salt' | 'version'
>
fields: Hex
extensions: readonly bigint[]
}
export type GetEip712DomainErrorType =
| Eip712DomainNotFoundErrorType
| ReadContractErrorType
| ErrorType
/**
* Reads the EIP-712 domain from a contract, based on the ERC-5267 specification.
*
* @param client - A {@link Client} instance.
* @param parameters - The parameters of the action. {@link GetEip712DomainParameters}
* @returns The EIP-712 domain, fields, and extensions. {@link GetEip712DomainReturnType}
*
* @example
* ```ts
* import { createPublicClient, http, getEip712Domain } from 'viem'
* import { mainnet } from 'viem/chains'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
*
* const domain = await getEip712Domain(client, {
* address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
* })
* // {
* // domain: {
* // name: 'ExampleContract',
* // version: '1',
* // chainId: 1,
* // verifyingContract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
* // },
* // fields: '0x0f',
* // extensions: [],
* // }
* ```
*/
export async function getEip712Domain(
client: Client<Transport>,
parameters: GetEip712DomainParameters,
): Promise<GetEip712DomainReturnType> {
const { address, factory, factoryData } = parameters
try {
const [
fields,
name,
version,
chainId,
verifyingContract,
salt,
extensions,
] = await getAction(
client,
readContract,
'readContract',
)({
abi,
address,
functionName: 'eip712Domain',
factory,
factoryData,
})
return {
domain: {
name,
version,
chainId: Number(chainId),
verifyingContract,
salt,
},
extensions,
fields,
}
} catch (e) {
const error = e as ReadContractErrorType
if (
error.name === 'ContractFunctionExecutionError' &&
error.cause.name === 'ContractFunctionZeroDataError'
) {
throw new Eip712DomainNotFoundError({ address })
}
throw error
}
}
const abi = [
{
inputs: [],
name: 'eip712Domain',
outputs: [
{ name: 'fields', type: 'bytes1' },
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
{ name: 'salt', type: 'bytes32' },
{ name: 'extensions', type: 'uint256[]' },
],
stateMutability: 'view',
type: 'function',
},
] as const

94
node_modules/viem/actions/public/getFeeHistory.ts generated vendored Normal file
View File

@@ -0,0 +1,94 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { FeeHistory } from '../../types/fee.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import {
type FormatFeeHistoryErrorType,
formatFeeHistory,
} from '../../utils/formatters/feeHistory.js'
export type GetFeeHistoryParameters = {
/**
* Number of blocks in the requested range. Between 1 and 1024 blocks can be requested in a single query. Less than requested may be returned if not all blocks are available.
*/
blockCount: number
/**
* A monotonically increasing list of percentile values to sample from each block's effective priority fees per gas in ascending order, weighted by gas used.
*/
rewardPercentiles: number[]
} & (
| {
blockNumber?: undefined
/**
* Highest number block of the requested range.
* @default 'latest'
*/
blockTag?: BlockTag | undefined
}
| {
/** Highest number block of the requested range. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
)
export type GetFeeHistoryReturnType = FeeHistory
export type GetFeeHistoryErrorType =
| NumberToHexErrorType
| RequestErrorType
| FormatFeeHistoryErrorType
/**
* Returns a collection of historical gas information.
*
* - Docs: https://viem.sh/docs/actions/public/getFeeHistory
* - JSON-RPC Methods: [`eth_feeHistory`](https://docs.alchemy.com/reference/eth-feehistory)
*
* @param client - Client to use
* @param parameters - {@link GetFeeHistoryParameters}
* @returns The gas estimate (in wei). {@link GetFeeHistoryReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getFeeHistory } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const feeHistory = await getFeeHistory(client, {
* blockCount: 4,
* rewardPercentiles: [25, 75],
* })
*/
export async function getFeeHistory<chain extends Chain | undefined>(
client: Client<Transport, chain>,
{
blockCount,
blockNumber,
blockTag = 'latest',
rewardPercentiles,
}: GetFeeHistoryParameters,
): Promise<GetFeeHistoryReturnType> {
const blockNumberHex =
typeof blockNumber === 'bigint' ? numberToHex(blockNumber) : undefined
const feeHistory = await client.request(
{
method: 'eth_feeHistory',
params: [
numberToHex(blockCount),
blockNumberHex || blockTag,
rewardPercentiles,
],
},
{ dedupe: Boolean(blockNumberHex) },
)
return formatFeeHistory(feeHistory)
}

208
node_modules/viem/actions/public/getFilterChanges.ts generated vendored Normal file
View File

@@ -0,0 +1,208 @@
import type { Abi, AbiEvent, ExtractAbiEvent } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { RpcLog } from '../../index.js'
import type { BlockNumber, BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { Filter, FilterType } from '../../types/filter.js'
import type { Log } from '../../types/log.js'
import type { Hash } from '../../types/misc.js'
import type { DecodeEventLogErrorType } from '../../utils/abi/decodeEventLog.js'
import { parseEventLogs } from '../../utils/abi/parseEventLogs.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type FormatLogErrorType,
formatLog,
} from '../../utils/formatters/log.js'
export type GetFilterChangesParameters<
filterType extends FilterType = FilterType,
abi extends Abi | readonly unknown[] | undefined = undefined,
eventName extends string | undefined = undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
> = {
filter: Filter<filterType, abi, eventName, any, strict, fromBlock, toBlock>
}
export type GetFilterChangesReturnType<
filterType extends FilterType = FilterType,
abi extends Abi | readonly unknown[] | undefined = undefined,
eventName extends string | undefined = undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
_AbiEvent extends AbiEvent | undefined = abi extends Abi
? eventName extends string
? ExtractAbiEvent<abi, eventName>
: undefined
: undefined,
_Pending extends boolean =
| (fromBlock extends 'pending' ? true : false)
| (toBlock extends 'pending' ? true : false),
> = filterType extends 'event'
? Log<bigint, number, _Pending, _AbiEvent, strict, abi, eventName>[]
: Hash[]
export type GetFilterChangesErrorType =
| RequestErrorType
| DecodeEventLogErrorType
| FormatLogErrorType
| ErrorType
/**
* Returns a list of logs or hashes based on a [Filter](/docs/glossary/terms#filter) since the last time it was called.
*
* - Docs: https://viem.sh/docs/actions/public/getFilterChanges
* - JSON-RPC Methods: [`eth_getFilterChanges`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterchanges)
*
* A Filter can be created from the following actions:
*
* - [`createBlockFilter`](https://viem.sh/docs/actions/public/createBlockFilter)
* - [`createContractEventFilter`](https://viem.sh/docs/contract/createContractEventFilter)
* - [`createEventFilter`](https://viem.sh/docs/actions/public/createEventFilter)
* - [`createPendingTransactionFilter`](https://viem.sh/docs/actions/public/createPendingTransactionFilter)
*
* Depending on the type of filter, the return value will be different:
*
* - If the filter was created with `createContractEventFilter` or `createEventFilter`, it returns a list of logs.
* - If the filter was created with `createPendingTransactionFilter`, it returns a list of transaction hashes.
* - If the filter was created with `createBlockFilter`, it returns a list of block hashes.
*
* @param client - Client to use
* @param parameters - {@link GetFilterChangesParameters}
* @returns Logs or hashes. {@link GetFilterChangesReturnType}
*
* @example
* // Blocks
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createBlockFilter, getFilterChanges } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const filter = await createBlockFilter(client)
* const hashes = await getFilterChanges(client, { filter })
*
* @example
* // Contract Events
* import { createPublicClient, http, parseAbi } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createContractEventFilter, getFilterChanges } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const filter = await createContractEventFilter(client, {
* address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
* abi: parseAbi(['event Transfer(address indexed, address indexed, uint256)']),
* eventName: 'Transfer',
* })
* const logs = await getFilterChanges(client, { filter })
*
* @example
* // Raw Events
* import { createPublicClient, http, parseAbiItem } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createEventFilter, getFilterChanges } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const filter = await createEventFilter(client, {
* address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
* event: parseAbiItem('event Transfer(address indexed, address indexed, uint256)'),
* })
* const logs = await getFilterChanges(client, { filter })
*
* @example
* // Transactions
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createPendingTransactionFilter, getFilterChanges } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const filter = await createPendingTransactionFilter(client)
* const hashes = await getFilterChanges(client, { filter })
*/
export async function getFilterChanges<
transport extends Transport,
chain extends Chain | undefined,
filterType extends FilterType,
const abi extends Abi | readonly unknown[] | undefined,
eventName extends string | undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
>(
_client: Client<transport, chain>,
{
filter,
}: GetFilterChangesParameters<
filterType,
abi,
eventName,
strict,
fromBlock,
toBlock
>,
): Promise<
GetFilterChangesReturnType<
filterType,
abi,
eventName,
strict,
fromBlock,
toBlock
>
> {
const strict = 'strict' in filter && filter.strict
const logs = await filter.request({
method: 'eth_getFilterChanges',
params: [filter.id],
})
if (typeof logs[0] === 'string')
return logs as GetFilterChangesReturnType<
filterType,
abi,
eventName,
strict,
fromBlock,
toBlock
>
const formattedLogs = logs.map((log) => formatLog(log as RpcLog))
if (!('abi' in filter) || !filter.abi)
return formattedLogs as GetFilterChangesReturnType<
filterType,
abi,
eventName,
strict,
fromBlock,
toBlock
>
return parseEventLogs({
abi: filter.abi,
logs: formattedLogs,
strict,
}) as unknown as GetFilterChangesReturnType<
filterType,
abi,
eventName,
strict,
fromBlock,
toBlock
>
}

119
node_modules/viem/actions/public/getFilterLogs.ts generated vendored Normal file
View File

@@ -0,0 +1,119 @@
import type { Abi, AbiEvent, ExtractAbiEvent } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockNumber, BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { Filter } from '../../types/filter.js'
import type { Log } from '../../types/log.js'
import type { DecodeEventLogErrorType } from '../../utils/abi/decodeEventLog.js'
import { parseEventLogs } from '../../utils/abi/parseEventLogs.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type FormatLogErrorType,
formatLog,
} from '../../utils/formatters/log.js'
export type GetFilterLogsParameters<
abi extends Abi | readonly unknown[] | undefined = undefined,
eventName extends string | undefined = undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
> = {
filter: Filter<'event', abi, eventName, any, strict, fromBlock, toBlock>
}
export type GetFilterLogsReturnType<
abi extends Abi | readonly unknown[] | undefined = undefined,
eventName extends string | undefined = undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
_AbiEvent extends AbiEvent | undefined = abi extends Abi
? eventName extends string
? ExtractAbiEvent<abi, eventName>
: undefined
: undefined,
_Pending extends boolean =
| (fromBlock extends 'pending' ? true : false)
| (toBlock extends 'pending' ? true : false),
> = Log<bigint, number, _Pending, _AbiEvent, strict, abi, eventName>[]
export type GetFilterLogsErrorType =
| RequestErrorType
| DecodeEventLogErrorType
| FormatLogErrorType
| ErrorType
/**
* Returns a list of event logs since the filter was created.
*
* - Docs: https://viem.sh/docs/actions/public/getFilterLogs
* - JSON-RPC Methods: [`eth_getFilterLogs`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterlogs)
*
* `getFilterLogs` is only compatible with **event filters**.
*
* @param client - Client to use
* @param parameters - {@link GetFilterLogsParameters}
* @returns A list of event logs. {@link GetFilterLogsReturnType}
*
* @example
* import { createPublicClient, http, parseAbiItem } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createEventFilter, getFilterLogs } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const filter = await createEventFilter(client, {
* address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
* event: parseAbiItem('event Transfer(address indexed, address indexed, uint256)'),
* })
* const logs = await getFilterLogs(client, { filter })
*/
export async function getFilterLogs<
chain extends Chain | undefined,
const abi extends Abi | readonly unknown[] | undefined,
eventName extends string | undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
>(
_client: Client<Transport, chain>,
{
filter,
}: GetFilterLogsParameters<abi, eventName, strict, fromBlock, toBlock>,
): Promise<
GetFilterLogsReturnType<abi, eventName, strict, fromBlock, toBlock>
> {
const strict = filter.strict ?? false
const logs = await filter.request({
method: 'eth_getFilterLogs',
params: [filter.id],
})
const formattedLogs = logs.map((log) => formatLog(log))
if (!filter.abi)
return formattedLogs as GetFilterLogsReturnType<
abi,
eventName,
strict,
fromBlock,
toBlock
>
return parseEventLogs({
abi: filter.abi,
logs: formattedLogs,
strict,
}) as unknown as GetFilterLogsReturnType<
abi,
eventName,
strict,
fromBlock,
toBlock
>
}

40
node_modules/viem/actions/public/getGasPrice.ts generated vendored Normal file
View File

@@ -0,0 +1,40 @@
import type { Account } from '../../accounts/types.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
export type GetGasPriceReturnType = bigint
export type GetGasPriceErrorType = RequestErrorType | ErrorType
/**
* Returns the current price of gas (in wei).
*
* - Docs: https://viem.sh/docs/actions/public/getGasPrice
* - JSON-RPC Methods: [`eth_gasPrice`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice)
*
* @param client - Client to use
* @returns The gas price (in wei). {@link GetGasPriceReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getGasPrice } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const gasPrice = await getGasPrice(client)
*/
export async function getGasPrice<
chain extends Chain | undefined,
account extends Account | undefined,
>(client: Client<Transport, chain, account>): Promise<GetGasPriceReturnType> {
const gasPrice = await client.request({
method: 'eth_gasPrice',
})
return BigInt(gasPrice)
}

218
node_modules/viem/actions/public/getLogs.ts generated vendored Normal file
View File

@@ -0,0 +1,218 @@
import type { AbiEvent, Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockNumber, BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type {
MaybeAbiEventName,
MaybeExtractEventArgsFromAbi,
} from '../../types/contract.js'
import type { Log } from '../../types/log.js'
import type { Hash, LogTopic } from '../../types/misc.js'
import type { RpcLog } from '../../types/rpc.js'
import type { DecodeEventLogErrorType } from '../../utils/abi/decodeEventLog.js'
import {
type EncodeEventTopicsErrorType,
type EncodeEventTopicsParameters,
encodeEventTopics,
} from '../../utils/abi/encodeEventTopics.js'
import { parseEventLogs } from '../../utils/abi/parseEventLogs.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import {
type FormatLogErrorType,
formatLog,
} from '../../utils/formatters/log.js'
export type GetLogsParameters<
abiEvent extends AbiEvent | undefined = undefined,
abiEvents extends
| readonly AbiEvent[]
| readonly unknown[]
| undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
//
_eventName extends string | undefined = MaybeAbiEventName<abiEvent>,
> = {
/** Address or list of addresses from which logs originated */
address?: Address | Address[] | undefined
} & (
| {
event: abiEvent
events?: undefined
args?: MaybeExtractEventArgsFromAbi<abiEvents, _eventName> | undefined
/**
* Whether or not the logs must match the indexed/non-indexed arguments on `event`.
* @default false
*/
strict?: strict | undefined
}
| {
event?: undefined
events: abiEvents
args?: undefined
/**
* Whether or not the logs must match the indexed/non-indexed arguments on `event`.
* @default false
*/
strict?: strict | undefined
}
| {
event?: undefined
events?: undefined
args?: undefined
strict?: undefined
}
) &
(
| {
/** Block number or tag after which to include logs */
fromBlock?: fromBlock | BlockNumber | BlockTag | undefined
/** Block number or tag before which to include logs */
toBlock?: toBlock | BlockNumber | BlockTag | undefined
blockHash?: undefined
}
| {
fromBlock?: undefined
toBlock?: undefined
/** Hash of block to include logs from */
blockHash?: Hash | undefined
}
)
export type GetLogsReturnType<
abiEvent extends AbiEvent | undefined = undefined,
abiEvents extends
| readonly AbiEvent[]
| readonly unknown[]
| undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
//
_eventName extends string | undefined = MaybeAbiEventName<abiEvent>,
_pending extends boolean =
| (fromBlock extends 'pending' ? true : false)
| (toBlock extends 'pending' ? true : false),
> = Log<bigint, number, _pending, abiEvent, strict, abiEvents, _eventName>[]
export type GetLogsErrorType =
| DecodeEventLogErrorType
| EncodeEventTopicsErrorType
| FormatLogErrorType
| NumberToHexErrorType
| RequestErrorType
| ErrorType
/**
* Returns a list of event logs matching the provided parameters.
*
* - Docs: https://viem.sh/docs/actions/public/getLogs
* - Examples: https://stackblitz.com/github/wevm/viem/tree/main/examples/logs_event-logs
* - JSON-RPC Methods: [`eth_getLogs`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs)
*
* @param client - Client to use
* @param parameters - {@link GetLogsParameters}
* @returns A list of event logs. {@link GetLogsReturnType}
*
* @example
* import { createPublicClient, http, parseAbiItem } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getLogs } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const logs = await getLogs(client)
*/
export async function getLogs<
chain extends Chain | undefined,
const abiEvent extends AbiEvent | undefined = undefined,
const abiEvents extends
| readonly AbiEvent[]
| readonly unknown[]
| undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,
strict extends boolean | undefined = undefined,
fromBlock extends BlockNumber | BlockTag | undefined = undefined,
toBlock extends BlockNumber | BlockTag | undefined = undefined,
>(
client: Client<Transport, chain>,
{
address,
blockHash,
fromBlock,
toBlock,
event,
events: events_,
args,
strict: strict_,
}: GetLogsParameters<abiEvent, abiEvents, strict, fromBlock, toBlock> = {},
): Promise<GetLogsReturnType<abiEvent, abiEvents, strict, fromBlock, toBlock>> {
const strict = strict_ ?? false
const events = events_ ?? (event ? [event] : undefined)
let topics: LogTopic[] = []
if (events) {
const encoded = (events as AbiEvent[]).flatMap((event) =>
encodeEventTopics({
abi: [event],
eventName: (event as AbiEvent).name,
args: events_ ? undefined : args,
} as EncodeEventTopicsParameters),
)
// TODO: Clean up type casting
topics = [encoded as LogTopic]
if (event) topics = topics[0] as LogTopic[]
}
let logs: RpcLog[]
if (blockHash) {
logs = await client.request({
method: 'eth_getLogs',
params: [{ address, topics, blockHash }],
})
} else {
logs = await client.request({
method: 'eth_getLogs',
params: [
{
address,
topics,
fromBlock:
typeof fromBlock === 'bigint' ? numberToHex(fromBlock) : fromBlock,
toBlock: typeof toBlock === 'bigint' ? numberToHex(toBlock) : toBlock,
},
],
})
}
const formattedLogs = logs.map((log) => formatLog(log))
if (!events)
return formattedLogs as GetLogsReturnType<
abiEvent,
abiEvents,
strict,
fromBlock,
toBlock
>
return parseEventLogs({
abi: events,
args: args as any,
logs: formattedLogs,
strict,
}) as unknown as GetLogsReturnType<
abiEvent,
abiEvents,
strict,
fromBlock,
toBlock
>
}

93
node_modules/viem/actions/public/getProof.ts generated vendored Normal file
View File

@@ -0,0 +1,93 @@
import type { Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { Hash } from '../../types/misc.js'
import type { Proof } from '../../types/proof.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import {
type FormatProofErrorType,
formatProof,
} from '../../utils/formatters/proof.js'
export type GetProofParameters = {
/** Account address. */
address: Address
/** Array of storage-keys that should be proofed and included. */
storageKeys: Hash[]
} & (
| {
/** The block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockNumber?: undefined
/**
* The block tag.
* @default 'latest'
*/
blockTag?: BlockTag | undefined
}
)
export type GetProofReturnType = Proof
export type GetProofErrorType =
| NumberToHexErrorType
| FormatProofErrorType
| RequestErrorType
| ErrorType
/**
* Returns the account and storage values of the specified account including the Merkle-proof.
*
* - Docs: https://viem.sh/docs/actions/public/getProof
* - JSON-RPC Methods:
* - Calls [`eth_getProof`](https://eips.ethereum.org/EIPS/eip-1186)
*
* @param client - Client to use
* @param parameters - {@link GetProofParameters}
* @returns Proof data. {@link GetProofReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getProof } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const block = await getProof(client, {
* address: '0x...',
* storageKeys: ['0x...'],
* })
*/
export async function getProof<chain extends Chain | undefined>(
client: Client<Transport, chain>,
{
address,
blockNumber,
blockTag: blockTag_,
storageKeys,
}: GetProofParameters,
): Promise<GetProofReturnType> {
const blockTag = blockTag_ ?? 'latest'
const blockNumberHex =
blockNumber !== undefined ? numberToHex(blockNumber) : undefined
const proof = await client.request({
method: 'eth_getProof',
params: [address, storageKeys, blockNumberHex || blockTag],
})
return formatProof(proof)
}

71
node_modules/viem/actions/public/getStorageAt.ts generated vendored Normal file
View File

@@ -0,0 +1,71 @@
import type { Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { Hex } from '../../types/misc.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
export type GetStorageAtParameters = {
address: Address
slot: Hex
} & (
| {
blockNumber?: undefined
blockTag?: BlockTag | undefined
}
| {
blockNumber?: bigint | undefined
blockTag?: undefined
}
)
export type GetStorageAtReturnType = Hex | undefined
export type GetStorageAtErrorType =
| NumberToHexErrorType
| RequestErrorType
| ErrorType
/**
* Returns the value from a storage slot at a given address.
*
* - Docs: https://viem.sh/docs/contract/getStorageAt
* - JSON-RPC Methods: [`eth_getStorageAt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getstorageat)
*
* @param client - Client to use
* @param parameters - {@link GetStorageAtParameters}
* @returns The value of the storage slot. {@link GetStorageAtReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getStorageAt } from 'viem/contract'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const code = await getStorageAt(client, {
* address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
* slot: toHex(0),
* })
*/
export async function getStorageAt<chain extends Chain | undefined>(
client: Client<Transport, chain>,
{ address, blockNumber, blockTag = 'latest', slot }: GetStorageAtParameters,
): Promise<GetStorageAtReturnType> {
const blockNumberHex =
blockNumber !== undefined ? numberToHex(blockNumber) : undefined
const data = await client.request({
method: 'eth_getStorageAt',
params: [address, slot, blockNumberHex || blockTag],
})
return data
}

163
node_modules/viem/actions/public/getTransaction.ts generated vendored Normal file
View File

@@ -0,0 +1,163 @@
import type { Address } from '../../accounts/index.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import {
TransactionNotFoundError,
type TransactionNotFoundErrorType,
} from '../../errors/transaction.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { Hash } from '../../types/misc.js'
import type { RpcTransaction } from '../../types/rpc.js'
import type { OneOf, Prettify } from '../../types/utils.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import {
type FormattedTransaction,
formatTransaction,
} from '../../utils/formatters/transaction.js'
export type GetTransactionParameters<blockTag extends BlockTag = 'latest'> =
OneOf<
// eth_getTransactionByBlockHashAndIndex
| {
/** The block hash */
blockHash: Hash
/** The index of the transaction on the block. */
index: number
}
// eth_getTransactionByBlockNumberAndIndex
| {
/** The block number */
blockNumber: bigint
/** The index of the transaction on the block. */
index: number
}
// eth_getTransactionByBlockNumberAndIndex
| {
/** The block tag. */
blockTag: blockTag | BlockTag
/** The index of the transaction on the block. */
index: number
}
// eth_getTransactionByHash
| {
/** The hash of the transaction. */
hash: Hash
}
// eth_getTransactionBySenderAndNonce
| {
/** The sender of the transaction. */
sender: Address
/** The nonce of the transaction on the sender. */
nonce: number
}
>
export type GetTransactionReturnType<
chain extends Chain | undefined = undefined,
blockTag extends BlockTag = 'latest',
> = Prettify<FormattedTransaction<chain, blockTag>>
export type GetTransactionErrorType =
| TransactionNotFoundErrorType
| NumberToHexErrorType
| RequestErrorType
| ErrorType
/**
* Returns information about a [Transaction](https://viem.sh/docs/glossary/terms#transaction) given a hash or block identifier.
*
* - Docs: https://viem.sh/docs/actions/public/getTransaction
* - Example: https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_fetching-transactions
* - JSON-RPC Methods: [`eth_getTransactionByHash`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionByHash)
*
* @param client - Client to use
* @param parameters - {@link GetTransactionParameters}
* @returns The transaction information. {@link GetTransactionReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getTransaction } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const transaction = await getTransaction(client, {
* hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
* })
*/
export async function getTransaction<
chain extends Chain | undefined,
blockTag extends BlockTag = 'latest',
>(
client: Client<Transport, chain>,
{
blockHash,
blockNumber,
blockTag: blockTag_,
hash,
index,
sender,
nonce,
}: GetTransactionParameters<blockTag>,
): Promise<GetTransactionReturnType<chain, blockTag>> {
const blockTag = blockTag_ || 'latest'
const blockNumberHex =
blockNumber !== undefined ? numberToHex(blockNumber) : undefined
let transaction: RpcTransaction | null = null
if (hash) {
transaction = await client.request(
{
method: 'eth_getTransactionByHash',
params: [hash],
},
{ dedupe: true },
)
} else if (blockHash) {
transaction = await client.request(
{
method: 'eth_getTransactionByBlockHashAndIndex',
params: [blockHash, numberToHex(index)],
},
{ dedupe: true },
)
} else if ((blockNumberHex || blockTag) && typeof index === 'number') {
transaction = await client.request(
{
method: 'eth_getTransactionByBlockNumberAndIndex',
params: [blockNumberHex || blockTag, numberToHex(index)],
},
{ dedupe: Boolean(blockNumberHex) },
)
} else if (sender && typeof nonce === 'number') {
transaction = await client.request(
{
method: 'eth_getTransactionBySenderAndNonce',
params: [sender, numberToHex(nonce)],
},
{ dedupe: true },
)
}
if (!transaction)
throw new TransactionNotFoundError({
blockHash,
blockNumber,
blockTag,
hash,
index,
})
const format =
client.chain?.formatters?.transaction?.format || formatTransaction
return format(transaction, 'getTransaction')
}

View File

@@ -0,0 +1,79 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { Hash } from '../../types/misc.js'
import type { FormattedTransactionReceipt } from '../../utils/formatters/transactionReceipt.js'
import { getAction } from '../../utils/getAction.js'
import {
type GetBlockNumberErrorType,
getBlockNumber,
} from './getBlockNumber.js'
import {
type GetTransactionErrorType,
getTransaction,
} from './getTransaction.js'
export type GetTransactionConfirmationsParameters<
chain extends Chain | undefined = Chain,
> =
| {
/** The transaction hash. */
hash: Hash
transactionReceipt?: undefined
}
| {
hash?: undefined
/** The transaction receipt. */
transactionReceipt: FormattedTransactionReceipt<chain>
}
export type GetTransactionConfirmationsReturnType = bigint
export type GetTransactionConfirmationsErrorType =
| GetBlockNumberErrorType
| GetTransactionErrorType
| ErrorType
/**
* Returns the number of blocks passed (confirmations) since the transaction was processed on a block.
*
* - Docs: https://viem.sh/docs/actions/public/getTransactionConfirmations
* - Example: https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_fetching-transactions
* - JSON-RPC Methods: [`eth_getTransactionConfirmations`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionConfirmations)
*
* @param client - Client to use
* @param parameters - {@link GetTransactionConfirmationsParameters}
* @returns The number of blocks passed since the transaction was processed. If confirmations is 0, then the Transaction has not been confirmed & processed yet. {@link GetTransactionConfirmationsReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getTransactionConfirmations } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const confirmations = await getTransactionConfirmations(client, {
* hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
* })
*/
export async function getTransactionConfirmations<
chain extends Chain | undefined,
>(
client: Client<Transport, chain>,
{ hash, transactionReceipt }: GetTransactionConfirmationsParameters<chain>,
): Promise<GetTransactionConfirmationsReturnType> {
const [blockNumber, transaction] = await Promise.all([
getAction(client, getBlockNumber, 'getBlockNumber')({}),
hash
? getAction(client, getTransaction, 'getTransaction')({ hash })
: undefined,
])
const transactionBlockNumber =
transactionReceipt?.blockNumber || transaction?.blockNumber
if (!transactionBlockNumber) return 0n
return blockNumber - transactionBlockNumber! + 1n
}

View File

@@ -0,0 +1,85 @@
import type { Address } from 'abitype'
import type { Account } from '../../accounts/types.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type HexToNumberErrorType,
hexToNumber,
} from '../../utils/encoding/fromHex.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
export type GetTransactionCountParameters = {
/** The account address. */
address: Address
} & (
| {
/** The block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockNumber?: undefined
/** The block tag. Defaults to 'latest'. */
blockTag?: BlockTag | undefined
}
)
export type GetTransactionCountReturnType = number
export type GetTransactionCountErrorType =
| RequestErrorType
| NumberToHexErrorType
| HexToNumberErrorType
| ErrorType
/**
* Returns the number of [Transactions](https://viem.sh/docs/glossary/terms#transaction) an Account has sent.
*
* - Docs: https://viem.sh/docs/actions/public/getTransactionCount
* - JSON-RPC Methods: [`eth_getTransactionCount`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactioncount)
*
* @param client - Client to use
* @param parameters - {@link GetTransactionCountParameters}
* @returns The number of transactions an account has sent. {@link GetTransactionCountReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getTransactionCount } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const transactionCount = await getTransactionCount(client, {
* address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* })
*/
export async function getTransactionCount<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
{ address, blockTag = 'latest', blockNumber }: GetTransactionCountParameters,
): Promise<GetTransactionCountReturnType> {
const count = await client.request(
{
method: 'eth_getTransactionCount',
params: [
address,
typeof blockNumber === 'bigint' ? numberToHex(blockNumber) : blockTag,
],
},
{
dedupe: Boolean(blockNumber),
},
)
return hexToNumber(count)
}

View File

@@ -0,0 +1,75 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import {
TransactionReceiptNotFoundError,
type TransactionReceiptNotFoundErrorType,
} from '../../errors/transaction.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { Hash } from '../../types/misc.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type FormattedTransactionReceipt,
formatTransactionReceipt,
} from '../../utils/formatters/transactionReceipt.js'
export type GetTransactionReceiptParameters = {
/** The hash of the transaction. */
hash: Hash
}
export type GetTransactionReceiptReturnType<
chain extends Chain | undefined = undefined,
> = FormattedTransactionReceipt<chain>
export type GetTransactionReceiptErrorType =
| RequestErrorType
| TransactionReceiptNotFoundErrorType
| ErrorType
/**
* Returns the [Transaction Receipt](https://viem.sh/docs/glossary/terms#transaction-receipt) given a [Transaction](https://viem.sh/docs/glossary/terms#transaction) hash.
*
* - Docs: https://viem.sh/docs/actions/public/getTransactionReceipt
* - Example: https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_fetching-transactions
* - JSON-RPC Methods: [`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionreceipt)
*
* @param client - Client to use
* @param parameters - {@link GetTransactionReceiptParameters}
* @returns The transaction receipt. {@link GetTransactionReceiptReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { getTransactionReceipt } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const transactionReceipt = await getTransactionReceipt(client, {
* hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
* })
*/
export async function getTransactionReceipt<chain extends Chain | undefined>(
client: Client<Transport, chain>,
{ hash }: GetTransactionReceiptParameters,
) {
const receipt = await client.request(
{
method: 'eth_getTransactionReceipt',
params: [hash],
},
{ dedupe: true },
)
if (!receipt) throw new TransactionReceiptNotFoundError({ hash })
const format =
client.chain?.formatters?.transactionReceipt?.format ||
formatTransactionReceipt
return format(
receipt,
'getTransactionReceipt',
) as GetTransactionReceiptReturnType<chain>
}

309
node_modules/viem/actions/public/multicall.ts generated vendored Normal file
View File

@@ -0,0 +1,309 @@
import type { AbiStateMutability, Address, Narrow } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { multicall3Abi } from '../../constants/abis.js'
import { multicall3Bytecode } from '../../constants/contracts.js'
import { AbiDecodingZeroDataError } from '../../errors/abi.js'
import { BaseError } from '../../errors/base.js'
import { RawContractError } from '../../errors/contract.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { ContractFunctionParameters } from '../../types/contract.js'
import type { Hex } from '../../types/misc.js'
import type {
MulticallContracts,
MulticallResults,
} from '../../types/multicall.js'
import {
type DecodeFunctionResultErrorType,
decodeFunctionResult,
} from '../../utils/abi/decodeFunctionResult.js'
import {
type EncodeFunctionDataErrorType,
encodeFunctionData,
} from '../../utils/abi/encodeFunctionData.js'
import {
type GetChainContractAddressErrorType,
getChainContractAddress,
} from '../../utils/chain/getChainContractAddress.js'
import {
type GetContractErrorReturnType,
getContractError,
} from '../../utils/errors/getContractError.js'
import { getAction } from '../../utils/getAction.js'
import type { CallParameters } from './call.js'
import { type ReadContractErrorType, readContract } from './readContract.js'
export type MulticallParameters<
contracts extends readonly unknown[] = readonly ContractFunctionParameters[],
allowFailure extends boolean = true,
options extends {
optional?: boolean
properties?: Record<string, any>
} = {},
> = Pick<
CallParameters,
| 'authorizationList'
| 'blockNumber'
| 'blockOverrides'
| 'blockTag'
| 'stateOverride'
> & {
/** The account to use for the multicall. */
account?: Address | undefined
/** Whether to allow failures. */
allowFailure?: allowFailure | boolean | undefined
/** The size of each batch of calls. */
batchSize?: number | undefined
/** Enable deployless multicall. */
deployless?: boolean | undefined
/** The contracts to call. */
contracts: MulticallContracts<
Narrow<contracts>,
{ mutability: AbiStateMutability } & options
>
/** The address of the multicall3 contract to use. */
multicallAddress?: Address | undefined
}
export type MulticallReturnType<
contracts extends readonly unknown[] = readonly ContractFunctionParameters[],
allowFailure extends boolean = true,
options extends {
error?: Error
} = { error: Error },
> = MulticallResults<
Narrow<contracts>,
allowFailure,
{ mutability: AbiStateMutability } & options
>
export type MulticallErrorType =
| GetChainContractAddressErrorType
| ReadContractErrorType
| GetContractErrorReturnType<
EncodeFunctionDataErrorType | DecodeFunctionResultErrorType
>
| ErrorType
/**
* Similar to [`readContract`](https://viem.sh/docs/contract/readContract), but batches up multiple functions on a contract in a single RPC call via the [`multicall3` contract](https://github.com/mds1/multicall).
*
* - Docs: https://viem.sh/docs/contract/multicall
*
* @param client - Client to use
* @param parameters - {@link MulticallParameters}
* @returns An array of results with accompanying status. {@link MulticallReturnType}
*
* @example
* import { createPublicClient, http, parseAbi } from 'viem'
* import { mainnet } from 'viem/chains'
* import { multicall } from 'viem/contract'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const abi = parseAbi([
* 'function balanceOf(address) view returns (uint256)',
* 'function totalSupply() view returns (uint256)',
* ])
* const results = await multicall(client, {
* contracts: [
* {
* address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
* abi,
* functionName: 'balanceOf',
* args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'],
* },
* {
* address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
* abi,
* functionName: 'totalSupply',
* },
* ],
* })
* // [{ result: 424122n, status: 'success' }, { result: 1000000n, status: 'success' }]
*/
export async function multicall<
const contracts extends readonly unknown[],
chain extends Chain | undefined,
allowFailure extends boolean = true,
>(
client: Client<Transport, chain>,
parameters: MulticallParameters<contracts, allowFailure>,
): Promise<MulticallReturnType<contracts, allowFailure>> {
const {
account,
authorizationList,
allowFailure = true,
blockNumber,
blockOverrides,
blockTag,
stateOverride,
} = parameters
const contracts = parameters.contracts as ContractFunctionParameters[]
const {
batchSize = parameters.batchSize ?? 1024,
deployless = parameters.deployless ?? false,
} = typeof client.batch?.multicall === 'object' ? client.batch.multicall : {}
const multicallAddress = (() => {
if (parameters.multicallAddress) return parameters.multicallAddress
if (deployless) return null
if (client.chain) {
return getChainContractAddress({
blockNumber,
chain: client.chain,
contract: 'multicall3',
})
}
throw new Error(
'client chain not configured. multicallAddress is required.',
)
})()
type Aggregate3Calls = {
allowFailure: boolean
callData: Hex
target: Address
}[]
const chunkedCalls: Aggregate3Calls[] = [[]]
let currentChunk = 0
let currentChunkSize = 0
for (let i = 0; i < contracts.length; i++) {
const { abi, address, args, functionName } = contracts[i]
try {
const callData = encodeFunctionData({ abi, args, functionName })
currentChunkSize += (callData.length - 2) / 2
// Check to see if we need to create a new chunk.
if (
// Check if batching is enabled.
batchSize > 0 &&
// Check if the current size of the batch exceeds the size limit.
currentChunkSize > batchSize &&
// Check if the current chunk is not already empty.
chunkedCalls[currentChunk].length > 0
) {
currentChunk++
currentChunkSize = (callData.length - 2) / 2
chunkedCalls[currentChunk] = []
}
chunkedCalls[currentChunk] = [
...chunkedCalls[currentChunk],
{
allowFailure: true,
callData,
target: address,
},
]
} catch (err) {
const error = getContractError(err as BaseError, {
abi,
address,
args,
docsPath: '/docs/contract/multicall',
functionName,
sender: account,
})
if (!allowFailure) throw error
chunkedCalls[currentChunk] = [
...chunkedCalls[currentChunk],
{
allowFailure: true,
callData: '0x' as Hex,
target: address,
},
]
}
}
const aggregate3Results = await Promise.allSettled(
chunkedCalls.map((calls) =>
getAction(
client,
readContract,
'readContract',
)({
...(multicallAddress === null
? { code: multicall3Bytecode }
: { address: multicallAddress }),
abi: multicall3Abi,
account,
args: [calls],
authorizationList,
blockNumber,
blockOverrides,
blockTag,
functionName: 'aggregate3',
stateOverride,
}),
),
)
const results = []
for (let i = 0; i < aggregate3Results.length; i++) {
const result = aggregate3Results[i]
// If an error occurred in a `readContract` invocation (ie. network error),
// then append the failure reason to each contract result.
if (result.status === 'rejected') {
if (!allowFailure) throw result.reason
for (let j = 0; j < chunkedCalls[i].length; j++) {
results.push({
status: 'failure',
error: result.reason,
result: undefined,
})
}
continue
}
// If the `readContract` call was successful, then decode the results.
const aggregate3Result = result.value
for (let j = 0; j < aggregate3Result.length; j++) {
// Extract the response from `readContract`
const { returnData, success } = aggregate3Result[j]
// Extract the request call data from the original call.
const { callData } = chunkedCalls[i][j]
// Extract the contract config for this call from the `contracts` argument
// for decoding.
const { abi, address, functionName, args } = contracts[
results.length
] as ContractFunctionParameters
try {
if (callData === '0x') throw new AbiDecodingZeroDataError()
if (!success) throw new RawContractError({ data: returnData })
const result = decodeFunctionResult({
abi,
args,
data: returnData,
functionName,
})
results.push(allowFailure ? { result, status: 'success' } : result)
} catch (err) {
const error = getContractError(err as BaseError, {
abi,
address,
args,
docsPath: '/docs/contract/multicall',
functionName,
})
if (!allowFailure) throw error
results.push({ error, result: undefined, status: 'failure' })
}
}
}
if (results.length !== contracts.length)
throw new BaseError('multicall results mismatch')
return results as MulticallReturnType<contracts, allowFailure>
}

146
node_modules/viem/actions/public/readContract.ts generated vendored Normal file
View File

@@ -0,0 +1,146 @@
import type { Abi } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { BaseError } from '../../errors/base.js'
import type { Chain } from '../../types/chain.js'
import type {
ContractFunctionArgs,
ContractFunctionName,
ContractFunctionParameters,
ContractFunctionReturnType,
} from '../../types/contract.js'
import type { UnionEvaluate } from '../../types/utils.js'
import {
type DecodeFunctionResultErrorType,
decodeFunctionResult,
} from '../../utils/abi/decodeFunctionResult.js'
import {
type EncodeFunctionDataErrorType,
type EncodeFunctionDataParameters,
encodeFunctionData,
} from '../../utils/abi/encodeFunctionData.js'
import {
type GetContractErrorReturnType,
getContractError,
} from '../../utils/errors/getContractError.js'
import { getAction } from '../../utils/getAction.js'
import { type CallErrorType, type CallParameters, call } from './call.js'
export type ReadContractParameters<
abi extends Abi | readonly unknown[] = Abi,
functionName extends ContractFunctionName<
abi,
'pure' | 'view'
> = ContractFunctionName<abi, 'pure' | 'view'>,
args extends ContractFunctionArgs<
abi,
'pure' | 'view',
functionName
> = ContractFunctionArgs<abi, 'pure' | 'view', functionName>,
> = UnionEvaluate<
Pick<
CallParameters,
| 'account'
| 'authorizationList'
| 'blockNumber'
| 'blockOverrides'
| 'blockTag'
| 'factory'
| 'factoryData'
| 'stateOverride'
>
> &
ContractFunctionParameters<abi, 'pure' | 'view', functionName, args, boolean>
export type ReadContractReturnType<
abi extends Abi | readonly unknown[] = Abi,
functionName extends ContractFunctionName<
abi,
'pure' | 'view'
> = ContractFunctionName<abi, 'pure' | 'view'>,
args extends ContractFunctionArgs<
abi,
'pure' | 'view',
functionName
> = ContractFunctionArgs<abi, 'pure' | 'view', functionName>,
> = ContractFunctionReturnType<abi, 'pure' | 'view', functionName, args>
export type ReadContractErrorType = GetContractErrorReturnType<
CallErrorType | EncodeFunctionDataErrorType | DecodeFunctionResultErrorType
>
/**
* Calls a read-only function on a contract, and returns the response.
*
* - Docs: https://viem.sh/docs/contract/readContract
* - Examples: https://stackblitz.com/github/wevm/viem/tree/main/examples/contracts_reading-contracts
*
* A "read-only" function (constant function) on a Solidity contract is denoted by a `view` or `pure` keyword. They can only read the state of the contract, and cannot make any changes to it. Since read-only methods do not change the state of the contract, they do not require any gas to be executed, and can be called by any user without the need to pay for gas.
*
* Internally, uses a [Public Client](https://viem.sh/docs/clients/public) to call the [`call` action](https://viem.sh/docs/actions/public/call) with [ABI-encoded `data`](https://viem.sh/docs/contract/encodeFunctionData).
*
* @param client - Client to use
* @param parameters - {@link ReadContractParameters}
* @returns The response from the contract. Type is inferred. {@link ReadContractReturnType}
*
* @example
* import { createPublicClient, http, parseAbi } from 'viem'
* import { mainnet } from 'viem/chains'
* import { readContract } from 'viem/contract'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const result = await readContract(client, {
* address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
* abi: parseAbi(['function balanceOf(address) view returns (uint256)']),
* functionName: 'balanceOf',
* args: ['0xA0Cf798816D4b9b9866b5330EEa46a18382f251e'],
* })
* // 424122n
*/
export async function readContract<
chain extends Chain | undefined,
const abi extends Abi | readonly unknown[],
functionName extends ContractFunctionName<abi, 'pure' | 'view'>,
const args extends ContractFunctionArgs<abi, 'pure' | 'view', functionName>,
>(
client: Client<Transport, chain>,
parameters: ReadContractParameters<abi, functionName, args>,
): Promise<ReadContractReturnType<abi, functionName, args>> {
const { abi, address, args, functionName, ...rest } =
parameters as ReadContractParameters
const calldata = encodeFunctionData({
abi,
args,
functionName,
} as EncodeFunctionDataParameters)
try {
const { data } = await getAction(
client,
call,
'call',
)({
...(rest as CallParameters),
data: calldata,
to: address!,
})
return decodeFunctionResult({
abi,
args,
functionName,
data: data || '0x',
}) as ReadContractReturnType<abi, functionName>
} catch (error) {
throw getContractError(error as BaseError, {
abi,
address,
args,
docsPath: '/docs/contract/readContract',
functionName,
})
}
}

299
node_modules/viem/actions/public/simulateBlocks.ts generated vendored Normal file
View File

@@ -0,0 +1,299 @@
import type { Abi, AbiStateMutability, Address, Narrow } from 'abitype'
import * as BlockOverrides from 'ox/BlockOverrides'
import {
type ParseAccountErrorType,
parseAccount,
} from '../../accounts/utils/parseAccount.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { AbiDecodingZeroDataError } from '../../errors/abi.js'
import type { BaseError } from '../../errors/base.js'
import { RawContractError } from '../../errors/contract.js'
import { UnknownNodeError } from '../../errors/node.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Account } from '../../types/account.js'
import type { Block, BlockTag } from '../../types/block.js'
import type { Call, Calls } from '../../types/calls.js'
import type { Chain } from '../../types/chain.js'
import type { Log } from '../../types/log.js'
import type { Hex } from '../../types/misc.js'
import type { MulticallResults } from '../../types/multicall.js'
import type { StateOverride } from '../../types/stateOverride.js'
import type { TransactionRequest } from '../../types/transaction.js'
import type { ExactPartial, UnionOmit } from '../../types/utils.js'
import {
type DecodeFunctionResultErrorType,
decodeFunctionResult,
} from '../../utils/abi/decodeFunctionResult.js'
import {
type EncodeFunctionDataErrorType,
encodeFunctionData,
} from '../../utils/abi/encodeFunctionData.js'
import { concat } from '../../utils/data/concat.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import { getContractError } from '../../utils/errors/getContractError.js'
import {
type GetNodeErrorReturnType,
getNodeError,
} from '../../utils/errors/getNodeError.js'
import {
type FormatBlockErrorType,
formatBlock,
} from '../../utils/formatters/block.js'
import { formatLog } from '../../utils/formatters/log.js'
import {
type FormatTransactionRequestErrorType,
formatTransactionRequest,
} from '../../utils/formatters/transactionRequest.js'
import {
type SerializeStateOverrideErrorType,
serializeStateOverride,
} from '../../utils/stateOverride.js'
import {
type AssertRequestErrorType,
assertRequest,
} from '../../utils/transaction/assertRequest.js'
type CallExtraProperties = ExactPartial<
UnionOmit<
TransactionRequest,
'blobs' | 'data' | 'kzg' | 'to' | 'sidecars' | 'value'
>
> & {
/** Account attached to the call (msg.sender). */
account?: Account | Address | undefined
/** Recipient. `null` if contract deployment. */
to?: Address | null | undefined
}
export type SimulateBlocksParameters<
calls extends readonly unknown[] = readonly unknown[],
> = {
/** Blocks to simulate. */
blocks: readonly {
/** Block overrides. */
blockOverrides?: BlockOverrides.BlockOverrides | undefined
/** Calls to execute. */
calls: Calls<Narrow<calls>, CallExtraProperties>
/** State overrides. */
stateOverrides?: StateOverride | undefined
}[]
/** Whether to return the full transactions. */
returnFullTransactions?: boolean | undefined
/** Whether to trace transfers. */
traceTransfers?: boolean | undefined
/** Whether to enable validation mode. */
validation?: boolean | undefined
} & (
| {
/** The balance of the account at a block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockNumber?: undefined
/**
* The balance of the account at a block tag.
* @default 'latest'
*/
blockTag?: BlockTag | undefined
}
)
export type SimulateBlocksReturnType<
calls extends readonly unknown[] = readonly unknown[],
> = readonly (Block & {
calls: MulticallResults<
Narrow<calls>,
true,
{
extraProperties: {
data: Hex
gasUsed: bigint
logs?: Log[] | undefined
}
error: Error
mutability: AbiStateMutability
}
>
})[]
export type SimulateBlocksErrorType =
| AssertRequestErrorType
| DecodeFunctionResultErrorType
| EncodeFunctionDataErrorType
| FormatBlockErrorType
| FormatTransactionRequestErrorType
| GetNodeErrorReturnType
| ParseAccountErrorType
| SerializeStateOverrideErrorType
| NumberToHexErrorType
| ErrorType
/**
* Simulates a set of calls on block(s) with optional block and state overrides.
*
* @example
* ```ts
* import { createClient, http, parseEther } from 'viem'
* import { simulate } from 'viem/actions'
* import { mainnet } from 'viem/chains'
*
* const client = createClient({
* chain: mainnet,
* transport: http(),
* })
*
* const result = await simulate(client, {
* blocks: [{
* blockOverrides: {
* number: 69420n,
* },
* calls: [{
* {
* account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
* data: '0xdeadbeef',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* },
* {
* account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: parseEther('1'),
* },
* }],
* stateOverrides: [{
* address: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
* balance: parseEther('10'),
* }],
* }]
* })
* ```
*
* @param client - Client to use.
* @param parameters - {@link SimulateBlocksParameters}
* @returns Simulated blocks. {@link SimulateBlocksReturnType}
*/
export async function simulateBlocks<
chain extends Chain | undefined,
const calls extends readonly unknown[],
>(
client: Client<Transport, chain>,
parameters: SimulateBlocksParameters<calls>,
): Promise<SimulateBlocksReturnType<calls>> {
const {
blockNumber,
blockTag = client.experimental_blockTag ?? 'latest',
blocks,
returnFullTransactions,
traceTransfers,
validation,
} = parameters
try {
const blockStateCalls = []
for (const block of blocks) {
const blockOverrides = block.blockOverrides
? BlockOverrides.toRpc(block.blockOverrides)
: undefined
const calls = block.calls.map((call_) => {
const call = call_ as Call<unknown, CallExtraProperties>
const account = call.account ? parseAccount(call.account) : undefined
const data = call.abi ? encodeFunctionData(call) : call.data
const request = {
...call,
account,
data: call.dataSuffix
? concat([data || '0x', call.dataSuffix])
: data,
from: call.from ?? account?.address,
} as const
assertRequest(request)
return formatTransactionRequest(request)
})
const stateOverrides = block.stateOverrides
? serializeStateOverride(block.stateOverrides)
: undefined
blockStateCalls.push({
blockOverrides,
calls,
stateOverrides,
})
}
const blockNumberHex =
typeof blockNumber === 'bigint' ? numberToHex(blockNumber) : undefined
const block = blockNumberHex || blockTag
const result = await client.request({
method: 'eth_simulateV1',
params: [
{ blockStateCalls, returnFullTransactions, traceTransfers, validation },
block,
],
})
return result.map((block, i) => ({
...formatBlock(block),
calls: block.calls.map((call, j) => {
const { abi, args, functionName, to } = blocks[i].calls[j] as Call<
unknown,
CallExtraProperties
>
const data = call.error?.data ?? call.returnData
const gasUsed = BigInt(call.gasUsed)
const logs = call.logs?.map((log) => formatLog(log))
const status = call.status === '0x1' ? 'success' : 'failure'
const result =
abi && status === 'success' && data !== '0x'
? decodeFunctionResult({
abi,
data,
functionName,
})
: null
const error = (() => {
if (status === 'success') return undefined
let error: Error | undefined
if (data === '0x') error = new AbiDecodingZeroDataError()
else if (data) error = new RawContractError({ data })
if (!error) return undefined
return getContractError(error, {
abi: (abi ?? []) as Abi,
address: to ?? '0x',
args,
functionName: functionName ?? '<unknown>',
})
})()
return {
data,
gasUsed,
logs,
status,
...(status === 'success'
? {
result,
}
: {
error,
}),
}
}),
})) as unknown as SimulateBlocksReturnType<calls>
} catch (e) {
const cause = e as BaseError
const error = getNodeError(cause, {})
if (error instanceof UnknownNodeError) throw cause
throw error
}
}

404
node_modules/viem/actions/public/simulateCalls.ts generated vendored Normal file
View File

@@ -0,0 +1,404 @@
import type { AbiStateMutability, Address, Narrow } from 'abitype'
import * as AbiConstructor from 'ox/AbiConstructor'
import * as AbiFunction from 'ox/AbiFunction'
import { parseAccount } from '../../accounts/utils/parseAccount.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { ethAddress, zeroAddress } from '../../constants/address.js'
import { deploylessCallViaBytecodeBytecode } from '../../constants/contracts.js'
import { BaseError } from '../../errors/base.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Account } from '../../types/account.js'
import type { Block } from '../../types/block.js'
import type { Call, Calls } from '../../types/calls.js'
import type { Chain } from '../../types/chain.js'
import type { Log } from '../../types/log.js'
import type { Hex } from '../../types/misc.js'
import type { MulticallResults } from '../../types/multicall.js'
import type { StateOverride } from '../../types/stateOverride.js'
import type { Mutable } from '../../types/utils.js'
import {
type EncodeFunctionDataErrorType,
encodeFunctionData,
} from '../../utils/abi/encodeFunctionData.js'
import { hexToBigInt } from '../../utils/index.js'
import {
type CreateAccessListErrorType,
createAccessList,
} from './createAccessList.js'
import {
type SimulateBlocksErrorType,
type SimulateBlocksParameters,
simulateBlocks,
} from './simulateBlocks.js'
const getBalanceCode =
'0x6080604052348015600e575f80fd5b5061016d8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063f8b2cb4f1461002d575b5f80fd5b610047600480360381019061004291906100db565b61005d565b604051610054919061011e565b60405180910390f35b5f8173ffffffffffffffffffffffffffffffffffffffff16319050919050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100aa82610081565b9050919050565b6100ba816100a0565b81146100c4575f80fd5b50565b5f813590506100d5816100b1565b92915050565b5f602082840312156100f0576100ef61007d565b5b5f6100fd848285016100c7565b91505092915050565b5f819050919050565b61011881610106565b82525050565b5f6020820190506101315f83018461010f565b9291505056fea26469706673582212203b9fe929fe995c7cf9887f0bdba8a36dd78e8b73f149b17d2d9ad7cd09d2dc6264736f6c634300081a0033'
export type SimulateCallsParameters<
calls extends readonly unknown[] = readonly unknown[],
account extends Account | Address | undefined = Account | Address | undefined,
> = Omit<SimulateBlocksParameters, 'blocks' | 'returnFullTransactions'> & {
/** Account attached to the calls (msg.sender). */
account?: account | undefined
/** Calls to simulate. */
calls: Calls<Narrow<calls>>
/** State overrides. */
stateOverrides?: StateOverride | undefined
/** Whether to trace asset changes. */
traceAssetChanges?: boolean | undefined
}
export type SimulateCallsReturnType<
calls extends readonly unknown[] = readonly unknown[],
> = {
/** Asset changes. */
assetChanges: readonly {
token: {
address: Address
decimals?: number | undefined
symbol?: string | undefined
}
value: { pre: bigint; post: bigint; diff: bigint }
}[]
/** Block results. */
block: Block
/** Call results. */
results: MulticallResults<
Narrow<calls>,
true,
{
extraProperties: {
data: Hex
gasUsed: bigint
logs?: Log[] | undefined
}
error: Error
mutability: AbiStateMutability
}
>
}
export type SimulateCallsErrorType =
| AbiFunction.encodeData.ErrorType
| AbiFunction.from.ErrorType
| CreateAccessListErrorType
| EncodeFunctionDataErrorType
| SimulateBlocksErrorType
| ErrorType
/**
* Simulates execution of a batch of calls.
*
* @param client - Client to use
* @param parameters - {@link SimulateCallsParameters}
* @returns Results. {@link SimulateCallsReturnType}
*
* @example
* ```ts
* import { createPublicClient, http, parseEther } from 'viem'
* import { mainnet } from 'viem/chains'
* import { simulateCalls } from 'viem/actions'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
*
* const result = await simulateCalls(client, {
* account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
* calls: [{
* {
* data: '0xdeadbeef',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* },
* {
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: parseEther('1'),
* },
* ]
* })
* ```
*/
export async function simulateCalls<
const calls extends readonly unknown[],
chain extends Chain | undefined,
account extends Account | Address | undefined = undefined,
>(
client: Client<Transport, chain>,
parameters: SimulateCallsParameters<calls, account>,
): Promise<SimulateCallsReturnType<calls>> {
const {
blockNumber,
blockTag,
calls,
stateOverrides,
traceAssetChanges,
traceTransfers,
validation,
} = parameters
const account = parameters.account
? parseAccount(parameters.account)
: undefined
if (traceAssetChanges && !account)
throw new BaseError(
'`account` is required when `traceAssetChanges` is true',
)
// Derive bytecode to extract ETH balance via a contract call.
const getBalanceData = account
? AbiConstructor.encode(AbiConstructor.from('constructor(bytes, bytes)'), {
bytecode: deploylessCallViaBytecodeBytecode,
args: [
getBalanceCode,
AbiFunction.encodeData(
AbiFunction.from('function getBalance(address)'),
[account.address],
),
],
})
: undefined
// Fetch ERC20/721 addresses that were "touched" from the calls.
const assetAddresses = traceAssetChanges
? await Promise.all(
parameters.calls.map(async (call: any) => {
if (!call.data && !call.abi) return
const { accessList } = await createAccessList(client, {
account: account!.address,
...call,
data: call.abi ? encodeFunctionData(call) : call.data,
})
return accessList.map(({ address, storageKeys }) =>
storageKeys.length > 0 ? address : null,
)
}),
).then((x) => x.flat().filter(Boolean))
: []
const blocks = await simulateBlocks(client, {
blockNumber,
blockTag: blockTag as undefined,
blocks: [
...(traceAssetChanges
? [
// ETH pre balances
{
calls: [{ data: getBalanceData }],
stateOverrides,
},
// Asset pre balances
{
calls: assetAddresses.map((address, i) => ({
abi: [
AbiFunction.from(
'function balanceOf(address) returns (uint256)',
),
],
functionName: 'balanceOf',
args: [account!.address],
to: address,
from: zeroAddress,
nonce: i,
})),
stateOverrides: [
{
address: zeroAddress,
nonce: 0,
},
],
},
]
: []),
{
calls: [...calls, { to: zeroAddress }].map((call) => ({
...(call as Call),
from: account?.address,
})) as any,
stateOverrides,
},
...(traceAssetChanges
? [
// ETH post balances
{
calls: [{ data: getBalanceData }],
},
// Asset post balances
{
calls: assetAddresses.map((address, i) => ({
abi: [
AbiFunction.from(
'function balanceOf(address) returns (uint256)',
),
],
functionName: 'balanceOf',
args: [account!.address],
to: address,
from: zeroAddress,
nonce: i,
})),
stateOverrides: [
{
address: zeroAddress,
nonce: 0,
},
],
},
// Decimals
{
calls: assetAddresses.map((address, i) => ({
to: address,
abi: [
AbiFunction.from('function decimals() returns (uint256)'),
],
functionName: 'decimals',
from: zeroAddress,
nonce: i,
})),
stateOverrides: [
{
address: zeroAddress,
nonce: 0,
},
],
},
// Token URI
{
calls: assetAddresses.map((address, i) => ({
to: address,
abi: [
AbiFunction.from(
'function tokenURI(uint256) returns (string)',
),
],
functionName: 'tokenURI',
args: [0n],
from: zeroAddress,
nonce: i,
})),
stateOverrides: [
{
address: zeroAddress,
nonce: 0,
},
],
},
// Symbols
{
calls: assetAddresses.map((address, i) => ({
to: address,
abi: [AbiFunction.from('function symbol() returns (string)')],
functionName: 'symbol',
from: zeroAddress,
nonce: i,
})),
stateOverrides: [
{
address: zeroAddress,
nonce: 0,
},
],
},
]
: []),
],
traceTransfers,
validation,
})
const block_results = traceAssetChanges ? blocks[2] : blocks[0]
const [
block_ethPre,
block_assetsPre,
,
block_ethPost,
block_assetsPost,
block_decimals,
block_tokenURI,
block_symbols,
] = traceAssetChanges ? blocks : []
// Extract call results from the simulation.
const { calls: block_calls, ...block } = block_results
const results = block_calls.slice(0, -1) ?? []
// Extract pre-execution ETH and asset balances.
const ethPre = block_ethPre?.calls ?? []
const assetsPre = block_assetsPre?.calls ?? []
const balancesPre = [...ethPre, ...assetsPre].map((call) =>
call.status === 'success' ? hexToBigInt(call.data) : null,
)
// Extract post-execution ETH and asset balances.
const ethPost = block_ethPost?.calls ?? []
const assetsPost = block_assetsPost?.calls ?? []
const balancesPost = [...ethPost, ...assetsPost].map((call) =>
call.status === 'success' ? hexToBigInt(call.data) : null,
)
// Extract asset symbols & decimals.
const decimals = (block_decimals?.calls ?? []).map((x) =>
x.status === 'success' ? x.result : null,
) as (number | null)[]
const symbols = (block_symbols?.calls ?? []).map((x) =>
x.status === 'success' ? x.result : null,
) as (string | null)[]
const tokenURI = (block_tokenURI?.calls ?? []).map((x) =>
x.status === 'success' ? x.result : null,
) as (string | null)[]
const changes: Mutable<SimulateCallsReturnType<calls>['assetChanges']> = []
for (const [i, balancePost] of balancesPost.entries()) {
const balancePre = balancesPre[i]
if (typeof balancePost !== 'bigint') continue
if (typeof balancePre !== 'bigint') continue
const decimals_ = decimals[i - 1]
const symbol_ = symbols[i - 1]
const tokenURI_ = tokenURI[i - 1]
const token = (() => {
if (i === 0)
return {
address: ethAddress,
decimals: 18,
symbol: 'ETH',
}
return {
address: assetAddresses[i - 1]! as Address,
decimals: tokenURI_ || decimals_ ? Number(decimals_ ?? 1) : undefined,
symbol: symbol_ ?? undefined,
}
})()
if (changes.some((change) => change.token.address === token.address))
continue
changes.push({
token,
value: {
pre: balancePre,
post: balancePost,
diff: balancePost - balancePre,
},
})
}
return {
assetChanges: changes,
block,
results,
} as unknown as SimulateCallsReturnType<calls>
}

325
node_modules/viem/actions/public/simulateContract.ts generated vendored Normal file
View File

@@ -0,0 +1,325 @@
import type { Abi, AbiFunction, AbiStateMutability, Address } from 'abitype'
import {
type ParseAccountErrorType,
parseAccount,
} from '../../accounts/utils/parseAccount.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { BaseError } from '../../errors/base.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Account, ParseAccount } from '../../types/account.js'
import type { Chain, DeriveChain } from '../../types/chain.js'
import type {
ContractFunctionArgs,
ContractFunctionName,
ContractFunctionParameters,
ContractFunctionReturnType,
ExtractAbiFunctionForArgs,
} from '../../types/contract.js'
import type { Hex } from '../../types/misc.js'
import type { TransactionRequest } from '../../types/transaction.js'
import type {
IsNarrowable,
NoInfer,
Prettify,
UnionEvaluate,
UnionOmit,
} from '../../types/utils.js'
import {
type DecodeFunctionResultErrorType,
decodeFunctionResult,
} from '../../utils/abi/decodeFunctionResult.js'
import {
type EncodeFunctionDataErrorType,
encodeFunctionData,
} from '../../utils/abi/encodeFunctionData.js'
import {
type GetContractErrorReturnType,
getContractError,
} from '../../utils/errors/getContractError.js'
import { getAction } from '../../utils/getAction.js'
import type { WriteContractParameters } from '../wallet/writeContract.js'
import { type CallErrorType, type CallParameters, call } from './call.js'
export type GetMutabilityAwareValue<
abi extends Abi | readonly unknown[],
mutability extends AbiStateMutability = AbiStateMutability,
functionName extends ContractFunctionName<
abi,
mutability
> = ContractFunctionName<abi, mutability>,
valueType = TransactionRequest['value'],
args extends ContractFunctionArgs<
abi,
mutability,
functionName
> = ContractFunctionArgs<abi, mutability, functionName>,
abiFunction extends AbiFunction = abi extends Abi
? ExtractAbiFunctionForArgs<abi, mutability, functionName, args>
: AbiFunction,
_Narrowable extends boolean = IsNarrowable<abi, Abi>,
> = _Narrowable extends true
? abiFunction['stateMutability'] extends 'payable'
? { value?: NoInfer<valueType> | undefined }
: abiFunction['payable'] extends true
? { value?: NoInfer<valueType> | undefined }
: { value?: undefined }
: { value?: NoInfer<valueType> | undefined }
export type SimulateContractParameters<
abi extends Abi | readonly unknown[] = Abi,
functionName extends ContractFunctionName<
abi,
'nonpayable' | 'payable'
> = ContractFunctionName<abi, 'nonpayable' | 'payable'>,
args extends ContractFunctionArgs<
abi,
'nonpayable' | 'payable',
functionName
> = ContractFunctionArgs<abi, 'nonpayable' | 'payable', functionName>,
chain extends Chain | undefined = Chain | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
accountOverride extends Account | Address | null | undefined = undefined,
///
derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
callParameters extends
CallParameters<derivedChain> = CallParameters<derivedChain>,
> = {
account?: accountOverride | null | undefined
chain?: chainOverride | undefined
/** Data to append to the end of the calldata. Useful for adding a ["domain" tag](https://opensea.notion.site/opensea/Seaport-Order-Attributions-ec2d69bf455041a5baa490941aad307f). */
dataSuffix?: Hex | undefined
} & ContractFunctionParameters<
abi,
'nonpayable' | 'payable',
functionName,
args
> &
UnionOmit<
callParameters,
| 'account'
| 'batch'
| 'code'
| 'to'
| 'data'
| 'factory'
| 'factoryData'
| 'value'
> &
GetMutabilityAwareValue<
abi,
'nonpayable' | 'payable',
functionName,
callParameters['value'],
args
>
export type SimulateContractReturnType<
out abi extends Abi | readonly unknown[] = Abi,
in out functionName extends ContractFunctionName<
abi,
'nonpayable' | 'payable'
> = ContractFunctionName<abi, 'nonpayable' | 'payable'>,
in out args extends ContractFunctionArgs<
abi,
'nonpayable' | 'payable',
functionName
> = ContractFunctionArgs<abi, 'nonpayable' | 'payable', functionName>,
/** @ts-expect-error cast variance */
out chain extends Chain | undefined = Chain | undefined,
out account extends Account | undefined = Account | undefined,
out chainOverride extends Chain | undefined = Chain | undefined,
out accountOverride extends Account | Address | null | undefined =
| Account
| Address
| null
| undefined,
///
in out minimizedAbi extends Abi = readonly [
ExtractAbiFunctionForArgs<
abi extends Abi ? abi : Abi,
'nonpayable' | 'payable',
functionName,
args
>,
],
out resolvedAccount extends
| Account
| null
| undefined = accountOverride extends Account | Address | null
? ParseAccount<accountOverride>
: account,
> = {
result: ContractFunctionReturnType<
minimizedAbi,
'nonpayable' | 'payable',
functionName,
args
>
request: Prettify<
UnionEvaluate<
UnionOmit<
WriteContractParameters<
minimizedAbi,
functionName,
args,
chain,
undefined,
chainOverride
>,
'account' | 'abi' | 'args' | 'chain' | 'functionName'
>
> &
ContractFunctionParameters<
minimizedAbi,
'nonpayable' | 'payable',
functionName,
args
> & {
chain: DeriveChain<chain, chainOverride>
} & (resolvedAccount extends Account | null
? { account: resolvedAccount }
: { account?: undefined })
>
}
export type SimulateContractErrorType =
| ParseAccountErrorType
| EncodeFunctionDataErrorType
| GetContractErrorReturnType<CallErrorType | DecodeFunctionResultErrorType>
| ErrorType
/**
* Simulates/validates a contract interaction. This is useful for retrieving **return data** and **revert reasons** of contract write functions.
*
* - Docs: https://viem.sh/docs/contract/simulateContract
* - Examples: https://stackblitz.com/github/wevm/viem/tree/main/examples/contracts_writing-to-contracts
*
* This function does not require gas to execute and _**does not**_ change the state of the blockchain. It is almost identical to [`readContract`](https://viem.sh/docs/contract/readContract), but also supports contract write functions.
*
* Internally, uses a [Public Client](https://viem.sh/docs/clients/public) to call the [`call` action](https://viem.sh/docs/actions/public/call) with [ABI-encoded `data`](https://viem.sh/docs/contract/encodeFunctionData).
*
* @param client - Client to use
* @param parameters - {@link SimulateContractParameters}
* @returns The simulation result and write request. {@link SimulateContractReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { simulateContract } from 'viem/contract'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const result = await simulateContract(client, {
* address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
* abi: parseAbi(['function mint(uint32) view returns (uint32)']),
* functionName: 'mint',
* args: ['69420'],
* account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* })
*/
export async function simulateContract<
chain extends Chain | undefined,
account extends Account | undefined,
const abi extends Abi | readonly unknown[],
functionName extends ContractFunctionName<abi, 'nonpayable' | 'payable'>,
const args extends ContractFunctionArgs<
abi,
'nonpayable' | 'payable',
functionName
>,
chainOverride extends Chain | undefined = undefined,
accountOverride extends Account | Address | null | undefined = undefined,
>(
client: Client<Transport, chain, account>,
parameters: SimulateContractParameters<
abi,
functionName,
args,
chain,
chainOverride,
accountOverride
>,
): Promise<
SimulateContractReturnType<
abi,
functionName,
args,
chain,
account,
chainOverride,
accountOverride
>
> {
const {
abi,
address,
args,
functionName,
dataSuffix = typeof client.dataSuffix === 'string'
? client.dataSuffix
: client.dataSuffix?.value,
...callRequest
} = parameters as SimulateContractParameters
const account = callRequest.account
? parseAccount(callRequest.account)
: client.account
const calldata = encodeFunctionData({ abi, args, functionName })
try {
const { data } = await getAction(
client,
call,
'call',
)({
batch: false,
data: `${calldata}${dataSuffix ? dataSuffix.replace('0x', '') : ''}`,
to: address,
...callRequest,
account,
})
const result = decodeFunctionResult({
abi,
args,
functionName,
data: data || '0x',
})
const minimizedAbi = abi.filter(
(abiItem) =>
'name' in abiItem && abiItem.name === parameters.functionName,
)
return {
result,
request: {
abi: minimizedAbi,
address,
args,
dataSuffix,
functionName,
...callRequest,
account,
},
} as unknown as SimulateContractReturnType<
abi,
functionName,
args,
chain,
account,
chainOverride,
accountOverride
>
} catch (error) {
throw getContractError(error as BaseError, {
abi,
address,
args,
docsPath: '/docs/contract/simulateContract',
functionName,
sender: account?.address,
})
}
}

50
node_modules/viem/actions/public/uninstallFilter.ts generated vendored Normal file
View File

@@ -0,0 +1,50 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { Filter } from '../../types/filter.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
export type UninstallFilterParameters = {
filter: Filter<any>
}
export type UninstallFilterReturnType = boolean
export type UninstallFilterErrorType = RequestErrorType | ErrorType
/**
* Destroys a [`Filter`](https://viem.sh/docs/glossary/types#filter).
*
* - Docs: https://viem.sh/docs/actions/public/uninstallFilter
* - JSON-RPC Methods: [`eth_uninstallFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_uninstallFilter)
*
* Destroys a Filter that was created from one of the following Actions:
* - [`createBlockFilter`](https://viem.sh/docs/actions/public/createBlockFilter)
* - [`createEventFilter`](https://viem.sh/docs/actions/public/createEventFilter)
* - [`createPendingTransactionFilter`](https://viem.sh/docs/actions/public/createPendingTransactionFilter)
*
* @param client - Client to use
* @param parameters - {@link UninstallFilterParameters}
* @returns A boolean indicating if the Filter was successfully uninstalled. {@link UninstallFilterReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createPendingTransactionFilter, uninstallFilter } from 'viem/public'
*
* const filter = await createPendingTransactionFilter(client)
* const uninstalled = await uninstallFilter(client, { filter })
* // true
*/
export async function uninstallFilter<
transport extends Transport,
chain extends Chain | undefined,
>(
_client: Client<transport, chain>,
{ filter }: UninstallFilterParameters,
): Promise<UninstallFilterReturnType> {
return filter.request({
method: 'eth_uninstallFilter',
params: [filter.id],
})
}

402
node_modules/viem/actions/public/verifyHash.ts generated vendored Normal file
View File

@@ -0,0 +1,402 @@
import type { Address } from 'abitype'
import { SignatureErc6492 } from 'ox/erc6492'
import { SignatureErc8010 } from 'ox/erc8010'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import {
erc1271Abi,
erc6492SignatureValidatorAbi,
multicall3Abi,
} from '../../constants/abis.js'
import {
erc6492SignatureValidatorByteCode,
multicall3Bytecode,
} from '../../constants/contracts.js'
import {
CallExecutionError,
ContractFunctionExecutionError,
} from '../../errors/contract.js'
import type { InvalidHexBooleanError } from '../../errors/encoding.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { ByteArray, Hex, Signature } from '../../types/misc.js'
import type { OneOf } from '../../types/utils.js'
import {
type EncodeDeployDataErrorType,
encodeDeployData,
} from '../../utils/abi/encodeDeployData.js'
import {
type EncodeFunctionDataErrorType,
encodeFunctionData,
} from '../../utils/abi/encodeFunctionData.js'
import {
type GetAddressErrorType,
getAddress,
} from '../../utils/address/getAddress.js'
import {
type IsAddressEqualErrorType,
isAddressEqual,
} from '../../utils/address/isAddressEqual.js'
import { verifyAuthorization } from '../../utils/authorization/verifyAuthorization.js'
import { type ConcatHexErrorType, concatHex } from '../../utils/data/concat.js'
import { type IsHexErrorType, isHex } from '../../utils/data/isHex.js'
import { hexToBool } from '../../utils/encoding/fromHex.js'
import {
type BytesToHexErrorType,
bytesToHex,
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import { getAction } from '../../utils/getAction.js'
import {
type RecoverAddressErrorType,
recoverAddress,
} from '../../utils/signature/recoverAddress.js'
import {
type SerializeSignatureErrorType,
serializeSignature,
} from '../../utils/signature/serializeSignature.js'
import { type CallErrorType, type CallParameters, call } from './call.js'
import { type GetCodeErrorType, getCode } from './getCode.js'
import { type ReadContractErrorType, readContract } from './readContract.js'
export type VerifyHashParameters = Pick<
CallParameters,
'blockNumber' | 'blockTag'
> & {
/** The address that signed the original message. */
address: Address
/** The chain to use. */
chain?: Chain | null | undefined
/** The address of the ERC-6492 signature verifier contract. */
erc6492VerifierAddress?: Address | undefined
/** The hash to be verified. */
hash: Hex
/** Multicall3 address for ERC-8010 verification. */
multicallAddress?: Address | undefined
/** The signature that was generated by signing the message with the address's private key. */
signature: Hex | ByteArray | Signature
/** @deprecated use `erc6492VerifierAddress` instead. */
universalSignatureVerifierAddress?: Address | undefined
/** Chooses which verification path to try first before falling back. */
mode?: 'auto' | 'eoa' | (string & {}) | undefined
} & OneOf<{ factory: Address; factoryData: Hex } | {}>
export type VerifyHashReturnType = boolean
export type VerifyHashErrorType =
| BytesToHexErrorType
| CallErrorType
| ConcatHexErrorType
| EncodeDeployDataErrorType
| EncodeFunctionDataErrorType
| ErrorType
| GetAddressErrorType
| GetCodeErrorType
| InvalidHexBooleanError
| IsAddressEqualErrorType
| IsHexErrorType
| NumberToHexErrorType
| ReadContractErrorType
| RecoverAddressErrorType
| SerializeSignatureErrorType
/**
* Verifies a message hash onchain using ERC-6492.
*
* @param client - Client to use.
* @param parameters - {@link VerifyHashParameters}
* @returns Whether or not the signature is valid. {@link VerifyHashReturnType}
*/
export async function verifyHash<chain extends Chain | undefined>(
client: Client<Transport, chain>,
parameters: VerifyHashParameters,
): Promise<VerifyHashReturnType> {
const {
address,
chain = client.chain,
hash,
erc6492VerifierAddress:
verifierAddress = parameters.universalSignatureVerifierAddress ??
chain?.contracts?.erc6492Verifier?.address,
multicallAddress = parameters.multicallAddress ??
chain?.contracts?.multicall3?.address,
mode = 'auto',
} = parameters
if (chain?.verifyHash) return await chain.verifyHash(client, parameters)
const signature = (() => {
const signature = parameters.signature
if (isHex(signature)) return signature
if (typeof signature === 'object' && 'r' in signature && 's' in signature)
return serializeSignature(signature)
return bytesToHex(signature)
})()
try {
if (mode === 'eoa') {
try {
const verified = isAddressEqual(
getAddress(address),
await recoverAddress({ hash, signature }),
)
if (verified) return true
} catch {}
}
if (SignatureErc8010.validate(signature))
return await verifyErc8010(client, {
...parameters,
multicallAddress,
signature,
})
return await verifyErc6492(client, {
...parameters,
verifierAddress,
signature,
})
} catch (error) {
if (mode !== 'eoa') {
// Fallback attempt to verify the signature via ECDSA recovery.
try {
const verified = isAddressEqual(
getAddress(address),
await recoverAddress({ hash, signature }),
)
if (verified) return true
} catch {}
}
if (error instanceof VerificationError) {
// if the execution fails, the signature was not valid and an internal method inside of the validator reverted
// this can happen for many reasons, for example if signer can not be recovered from the signature
// or if the signature has no valid format
return false
}
throw error
}
}
/** @internal */
export async function verifyErc8010(
client: Client,
parameters: verifyErc8010.Parameters,
) {
const { address, blockNumber, blockTag, hash, multicallAddress } = parameters
const {
authorization: authorization_ox,
data: initData,
signature,
to,
} = SignatureErc8010.unwrap(parameters.signature)
// Check if already delegated
const code = await getCode(client, {
address,
blockNumber,
blockTag,
} as never)
// If already delegated, perform standard ERC-1271 verification.
if (code === concatHex(['0xef0100', authorization_ox.address]))
return await verifyErc1271(client, {
address,
blockNumber,
blockTag,
hash,
signature,
})
const authorization = {
address: authorization_ox.address,
chainId: Number(authorization_ox.chainId),
nonce: Number(authorization_ox.nonce),
r: numberToHex(authorization_ox.r, { size: 32 }),
s: numberToHex(authorization_ox.s, { size: 32 }),
yParity: authorization_ox.yParity,
} as const
const valid = await verifyAuthorization({
address,
authorization,
})
if (!valid) throw new VerificationError()
// Deployless verification.
const results = await getAction(
client,
readContract,
'readContract',
)({
...(multicallAddress
? { address: multicallAddress }
: { code: multicall3Bytecode }),
authorizationList: [authorization],
abi: multicall3Abi,
blockNumber,
blockTag: 'pending',
functionName: 'aggregate3',
args: [
[
...(initData
? ([
{
allowFailure: true,
target: to ?? address,
callData: initData,
},
] as const)
: []),
{
allowFailure: true,
target: address,
callData: encodeFunctionData({
abi: erc1271Abi,
functionName: 'isValidSignature',
args: [hash, signature],
}),
},
],
],
})
const data = results[results.length - 1]?.returnData
if (data?.startsWith('0x1626ba7e')) return true
throw new VerificationError()
}
export namespace verifyErc8010 {
export type Parameters = Pick<CallParameters, 'blockNumber' | 'blockTag'> & {
/** The address that signed the original message. */
address: Address
/** The hash to be verified. */
hash: Hex
/** Multicall3 address for ERC-8010 verification. */
multicallAddress?: Address | undefined
/** The signature that was generated by signing the message with the address's private key. */
signature: Hex
}
}
/** @internal */
// biome-ignore lint/correctness/noUnusedVariables: _
async function verifyErc6492(
client: Client,
parameters: verifyErc6492.Parameters,
) {
const {
address,
factory,
factoryData,
hash,
signature,
verifierAddress,
...rest
} = parameters
const wrappedSignature = await (async () => {
// If no `factory` or `factoryData` is provided, it is assumed that the
// address is not a Smart Account, or the Smart Account is already deployed.
if (!factory && !factoryData) return signature
// If the signature is already wrapped, return the signature.
if (SignatureErc6492.validate(signature)) return signature
// If the Smart Account is not deployed, wrap the signature with a 6492 wrapper
// to perform counterfactual validation.
return SignatureErc6492.wrap({
data: factoryData!,
signature,
to: factory!,
})
})()
const args = verifierAddress
? ({
to: verifierAddress,
data: encodeFunctionData({
abi: erc6492SignatureValidatorAbi,
functionName: 'isValidSig',
args: [address, hash, wrappedSignature],
}),
...rest,
} as unknown as CallParameters)
: ({
data: encodeDeployData({
abi: erc6492SignatureValidatorAbi,
args: [address, hash, wrappedSignature],
bytecode: erc6492SignatureValidatorByteCode,
}),
...rest,
} as unknown as CallParameters)
const { data } = await getAction(
client,
call,
'call',
)(args).catch((error) => {
if (error instanceof CallExecutionError) throw new VerificationError()
throw error
})
if (hexToBool(data ?? '0x0')) return true
throw new VerificationError()
}
export namespace verifyErc6492 {
export type Parameters = Pick<CallParameters, 'blockNumber' | 'blockTag'> & {
/** The address that signed the original message. */
address: Address
/** The hash to be verified. */
hash: Hex
/** The signature that was generated by signing the message with the address's private key. */
signature: Hex
/** The address of the ERC-6492 signature verifier contract. */
verifierAddress?: Address | undefined
} & OneOf<{ factory: Address; factoryData: Hex } | {}>
}
/** @internal */
export async function verifyErc1271(
client: Client,
parameters: verifyErc1271.Parameters,
) {
const { address, blockNumber, blockTag, hash, signature } = parameters
const result = await getAction(
client,
readContract,
'readContract',
)({
address,
abi: erc1271Abi,
args: [hash, signature],
blockNumber,
blockTag,
functionName: 'isValidSignature',
}).catch((error) => {
if (error instanceof ContractFunctionExecutionError)
throw new VerificationError()
throw error
})
if (result.startsWith('0x1626ba7e')) return true
throw new VerificationError()
}
export namespace verifyErc1271 {
export type Parameters = Pick<CallParameters, 'blockNumber' | 'blockTag'> & {
/** The address that signed the original message. */
address: Address
/** The hash to be verified. */
hash: Hex
/** The signature that was generated by signing the message with the address's private key. */
signature: Hex
}
}
class VerificationError extends Error {}

76
node_modules/viem/actions/public/verifyMessage.ts generated vendored Normal file
View File

@@ -0,0 +1,76 @@
import type { Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type {
ByteArray,
Hex,
SignableMessage,
Signature,
} from '../../types/misc.js'
import type { Prettify } from '../../types/utils.js'
import { getAction } from '../../utils/getAction.js'
import type { HashMessageErrorType } from '../../utils/signature/hashMessage.js'
import { hashMessage } from '../../utils/signature/hashMessage.js'
import {
type VerifyHashErrorType,
type VerifyHashParameters,
verifyHash,
} from './verifyHash.js'
export type VerifyMessageParameters = Prettify<
Omit<VerifyHashParameters, 'hash'> & {
/** The address that signed the original message. */
address: Address
/** The message to be verified. */
message: SignableMessage
/** The signature that was generated by signing the message with the address's private key. */
signature: Hex | ByteArray | Signature
}
>
export type VerifyMessageReturnType = boolean
export type VerifyMessageErrorType =
| HashMessageErrorType
| VerifyHashErrorType
| ErrorType
/**
* Verify that a message was signed by the provided address.
*
* Compatible with Smart Contract Accounts & Externally Owned Accounts via [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492).
*
* - Docs {@link https://viem.sh/docs/actions/public/verifyMessage}
*
* @param client - Client to use.
* @param parameters - {@link VerifyMessageParameters}
* @returns Whether or not the signature is valid. {@link VerifyMessageReturnType}
*/
export async function verifyMessage<chain extends Chain | undefined>(
client: Client<Transport, chain>,
{
address,
message,
factory,
factoryData,
signature,
...callRequest
}: VerifyMessageParameters,
): Promise<VerifyMessageReturnType> {
const hash = hashMessage(message)
return getAction(
client,
verifyHash,
'verifyHash',
)({
address,
factory: factory!,
factoryData: factoryData!,
hash,
signature,
...callRequest,
})
}

79
node_modules/viem/actions/public/verifyTypedData.ts generated vendored Normal file
View File

@@ -0,0 +1,79 @@
import type { Address, TypedData } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { ByteArray, Hex, Signature } from '../../types/misc.js'
import type { TypedDataDefinition } from '../../types/typedData.js'
import { getAction } from '../../utils/getAction.js'
import {
type HashTypedDataErrorType,
hashTypedData,
} from '../../utils/signature/hashTypedData.js'
import {
type VerifyHashErrorType,
type VerifyHashParameters,
verifyHash,
} from './verifyHash.js'
export type VerifyTypedDataParameters<
typedData extends TypedData | Record<string, unknown> = TypedData,
primaryType extends keyof typedData | 'EIP712Domain' = keyof typedData,
> = Omit<VerifyHashParameters, 'hash'> &
TypedDataDefinition<typedData, primaryType> & {
/** The address to verify the typed data for. */
address: Address
/** The signature to verify */
signature: Hex | ByteArray | Signature
}
export type VerifyTypedDataReturnType = boolean
export type VerifyTypedDataErrorType =
| HashTypedDataErrorType
| VerifyHashErrorType
| ErrorType
/**
* Verify that typed data was signed by the provided address.
*
* - Docs {@link https://viem.sh/docs/actions/public/verifyTypedData}
*
* @param client - Client to use.
* @param parameters - {@link VerifyTypedDataParameters}
* @returns Whether or not the signature is valid. {@link VerifyTypedDataReturnType}
*/
export async function verifyTypedData<
const typedData extends TypedData | Record<string, unknown>,
primaryType extends keyof typedData | 'EIP712Domain',
chain extends Chain | undefined,
>(
client: Client<Transport, chain>,
parameters: VerifyTypedDataParameters<typedData, primaryType>,
): Promise<VerifyTypedDataReturnType> {
const {
address,
factory,
factoryData,
signature,
message,
primaryType,
types,
domain,
...callRequest
} = parameters as VerifyTypedDataParameters
const hash = hashTypedData({ message, primaryType, types, domain })
return getAction(
client,
verifyHash,
'verifyHash',
)({
address,
factory: factory!,
factoryData: factoryData!,
hash,
signature,
...callRequest,
})
}

View File

@@ -0,0 +1,377 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { BlockNotFoundError } from '../../errors/block.js'
import {
TransactionNotFoundError,
TransactionReceiptNotFoundError,
WaitForTransactionReceiptTimeoutError,
type WaitForTransactionReceiptTimeoutErrorType,
} from '../../errors/transaction.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { Hash } from '../../types/misc.js'
import type { Transaction } from '../../types/transaction.js'
import { getAction } from '../../utils/getAction.js'
import { type ObserveErrorType, observe } from '../../utils/observe.js'
import { withResolvers } from '../../utils/promise/withResolvers.js'
import {
type WithRetryParameters,
withRetry,
} from '../../utils/promise/withRetry.js'
import { stringify } from '../../utils/stringify.js'
import { type GetBlockErrorType, getBlock } from './getBlock.js'
import {
type GetTransactionErrorType,
type GetTransactionReturnType,
getTransaction,
} from './getTransaction.js'
import {
type GetTransactionReceiptErrorType,
type GetTransactionReceiptReturnType,
getTransactionReceipt,
} from './getTransactionReceipt.js'
import {
type WatchBlockNumberErrorType,
watchBlockNumber,
} from './watchBlockNumber.js'
export type ReplacementReason = 'cancelled' | 'replaced' | 'repriced'
export type ReplacementReturnType<
chain extends Chain | undefined = Chain | undefined,
> = {
reason: ReplacementReason
replacedTransaction: Transaction
transaction: Transaction
transactionReceipt: GetTransactionReceiptReturnType<chain>
}
export type WaitForTransactionReceiptReturnType<
chain extends Chain | undefined = Chain | undefined,
> = GetTransactionReceiptReturnType<chain>
export type WaitForTransactionReceiptParameters<
chain extends Chain | undefined = Chain | undefined,
> = {
/**
* Whether to check for transaction replacements.
* @default true
*/
checkReplacement?: boolean | undefined
/**
* The number of confirmations (blocks that have passed) to wait before resolving.
* @default 1
*/
confirmations?: number | undefined
/** The hash of the transaction. */
hash: Hash
/** Optional callback to emit if the transaction has been replaced. */
onReplaced?: ((response: ReplacementReturnType<chain>) => void) | undefined
/**
* Polling frequency (in ms). Defaults to the client's pollingInterval config.
* @default client.pollingInterval
*/
pollingInterval?: number | undefined
/**
* Number of times to retry if the transaction or block is not found.
* @default 6 (exponential backoff)
*/
retryCount?: WithRetryParameters['retryCount'] | undefined
/**
* Time to wait (in ms) between retries.
* @default `({ count }) => ~~(1 << count) * 200` (exponential backoff)
*/
retryDelay?: WithRetryParameters['delay'] | undefined
/**
* Optional timeout (in milliseconds) to wait before stopping polling.
* @default 180_000
*/
timeout?: number | undefined
}
export type WaitForTransactionReceiptErrorType =
| ObserveErrorType
| GetBlockErrorType
| GetTransactionErrorType
| GetTransactionReceiptErrorType
| WatchBlockNumberErrorType
| WaitForTransactionReceiptTimeoutErrorType
| ErrorType
/**
* Waits for the [Transaction](https://viem.sh/docs/glossary/terms#transaction) to be included on a [Block](https://viem.sh/docs/glossary/terms#block) (one confirmation), and then returns the [Transaction Receipt](https://viem.sh/docs/glossary/terms#transaction-receipt).
*
* - Docs: https://viem.sh/docs/actions/public/waitForTransactionReceipt
* - Example: https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_sending-transactions
* - JSON-RPC Methods:
* - Polls [`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionReceipt) on each block until it has been processed.
* - If a Transaction has been replaced:
* - Calls [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) and extracts the transactions
* - Checks if one of the Transactions is a replacement
* - If so, calls [`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionReceipt).
*
* The `waitForTransactionReceipt` action additionally supports Replacement detection (e.g. sped up Transactions).
*
* Transactions can be replaced when a user modifies their transaction in their wallet (to speed up or cancel). Transactions are replaced when they are sent from the same nonce.
*
* There are 3 types of Transaction Replacement reasons:
*
* - `repriced`: The gas price has been modified (e.g. different `maxFeePerGas`)
* - `cancelled`: The Transaction has been cancelled (e.g. `value === 0n`)
* - `replaced`: The Transaction has been replaced (e.g. different `value` or `data`)
*
* @param client - Client to use
* @param parameters - {@link WaitForTransactionReceiptParameters}
* @returns The transaction receipt. {@link WaitForTransactionReceiptReturnType}
*
* @example
* import { createPublicClient, waitForTransactionReceipt, http } from 'viem'
* import { mainnet } from 'viem/chains'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const transactionReceipt = await waitForTransactionReceipt(client, {
* hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
* })
*/
export async function waitForTransactionReceipt<
chain extends Chain | undefined,
>(
client: Client<Transport, chain>,
parameters: WaitForTransactionReceiptParameters<chain>,
): Promise<WaitForTransactionReceiptReturnType<chain>> {
const {
checkReplacement = true,
confirmations = 1,
hash,
onReplaced,
retryCount = 6,
retryDelay = ({ count }) => ~~(1 << count) * 200, // exponential backoff
timeout = 180_000,
} = parameters
const observerId = stringify(['waitForTransactionReceipt', client.uid, hash])
const pollingInterval = (() => {
if (parameters.pollingInterval) return parameters.pollingInterval
if (client.chain?.experimental_preconfirmationTime)
return client.chain.experimental_preconfirmationTime
return client.pollingInterval
})()
let transaction: GetTransactionReturnType<chain> | undefined
let replacedTransaction: GetTransactionReturnType<chain> | undefined
let receipt: GetTransactionReceiptReturnType<chain> | undefined
let retrying = false
let _unobserve: () => void
let _unwatch: () => void
const { promise, resolve, reject } =
withResolvers<WaitForTransactionReceiptReturnType<chain>>()
const timer = timeout
? setTimeout(() => {
_unwatch?.()
_unobserve?.()
reject(new WaitForTransactionReceiptTimeoutError({ hash }))
}, timeout)
: undefined
_unobserve = observe(
observerId,
{ onReplaced, resolve, reject },
async (emit) => {
receipt = await getAction(
client,
getTransactionReceipt,
'getTransactionReceipt',
)({ hash }).catch(() => undefined)
if (receipt && confirmations <= 1) {
clearTimeout(timer)
emit.resolve(receipt)
_unobserve?.()
return
}
_unwatch = getAction(
client,
watchBlockNumber,
'watchBlockNumber',
)({
emitMissed: true,
emitOnBegin: true,
poll: true,
pollingInterval,
async onBlockNumber(blockNumber_) {
const done = (fn: () => void) => {
clearTimeout(timer)
_unwatch?.()
fn()
_unobserve?.()
}
let blockNumber = blockNumber_
if (retrying) return
try {
// If we already have a valid receipt, let's check if we have enough
// confirmations. If we do, then we can resolve.
if (receipt) {
if (
confirmations > 1 &&
(!receipt.blockNumber ||
blockNumber - receipt.blockNumber + 1n < confirmations)
)
return
done(() => emit.resolve(receipt!))
return
}
// Get the transaction to check if it's been replaced.
// We need to retry as some RPC Providers may be slow to sync
// up mined transactions.
if (checkReplacement && !transaction) {
retrying = true
await withRetry(
async () => {
transaction = (await getAction(
client,
getTransaction,
'getTransaction',
)({ hash })) as GetTransactionReturnType<chain>
if (transaction.blockNumber)
blockNumber = transaction.blockNumber
},
{
delay: retryDelay,
retryCount,
},
)
retrying = false
}
// Get the receipt to check if it's been processed.
receipt = await getAction(
client,
getTransactionReceipt,
'getTransactionReceipt',
)({ hash })
// Check if we have enough confirmations. If not, continue polling.
if (
confirmations > 1 &&
(!receipt.blockNumber ||
blockNumber - receipt.blockNumber + 1n < confirmations)
)
return
done(() => emit.resolve(receipt!))
} catch (err) {
// If the receipt is not found, the transaction will be pending.
// We need to check if it has potentially been replaced.
if (
err instanceof TransactionNotFoundError ||
err instanceof TransactionReceiptNotFoundError
) {
if (!transaction) {
retrying = false
return
}
try {
replacedTransaction = transaction
// Let's retrieve the transactions from the current block.
// We need to retry as some RPC Providers may be slow to sync
// up mined blocks.
retrying = true
const block = await withRetry(
() =>
getAction(
client,
getBlock,
'getBlock',
)({
blockNumber,
includeTransactions: true,
}),
{
delay: retryDelay,
retryCount,
shouldRetry: ({ error }) =>
error instanceof BlockNotFoundError,
},
)
retrying = false
const replacementTransaction = (
block.transactions as {} as Transaction[]
).find(
({ from, nonce }) =>
from === replacedTransaction!.from &&
nonce === replacedTransaction!.nonce,
)
// If we couldn't find a replacement transaction, continue polling.
if (!replacementTransaction) return
// If we found a replacement transaction, return it's receipt.
receipt = await getAction(
client,
getTransactionReceipt,
'getTransactionReceipt',
)({
hash: replacementTransaction.hash,
})
// Check if we have enough confirmations. If not, continue polling.
if (
confirmations > 1 &&
(!receipt.blockNumber ||
blockNumber - receipt.blockNumber + 1n < confirmations)
)
return
let reason: ReplacementReason = 'replaced'
if (
replacementTransaction.to === replacedTransaction.to &&
replacementTransaction.value === replacedTransaction.value &&
replacementTransaction.input === replacedTransaction.input
) {
reason = 'repriced'
} else if (
replacementTransaction.from === replacementTransaction.to &&
replacementTransaction.value === 0n
) {
reason = 'cancelled'
}
done(() => {
emit.onReplaced?.({
reason,
replacedTransaction: replacedTransaction! as any,
transaction: replacementTransaction,
transactionReceipt: receipt!,
})
emit.resolve(receipt!)
})
} catch (err_) {
done(() => emit.reject(err_))
}
} else {
done(() => emit.reject(err))
}
}
},
})
},
)
return promise
}

216
node_modules/viem/actions/public/watchBlockNumber.ts generated vendored Normal file
View File

@@ -0,0 +1,216 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { HasTransportType } from '../../types/transport.js'
import { hexToBigInt } from '../../utils/encoding/fromHex.js'
import { getAction } from '../../utils/getAction.js'
import { observe } from '../../utils/observe.js'
import { type PollErrorType, poll } from '../../utils/poll.js'
import { stringify } from '../../utils/stringify.js'
import {
type GetBlockNumberReturnType,
getBlockNumber,
} from './getBlockNumber.js'
export type OnBlockNumberParameter = GetBlockNumberReturnType
export type OnBlockNumberFn = (
blockNumber: OnBlockNumberParameter,
prevBlockNumber: OnBlockNumberParameter | undefined,
) => void
export type WatchBlockNumberParameters<
transport extends Transport = Transport,
> = {
/** The callback to call when a new block number is received. */
onBlockNumber: OnBlockNumberFn
/** The callback to call when an error occurred when trying to get for a new block. */
onError?: ((error: Error) => void) | undefined
} & (
| (HasTransportType<transport, 'webSocket' | 'ipc'> extends true
? {
emitMissed?: undefined
emitOnBegin?: undefined
/** Whether or not the WebSocket Transport should poll the JSON-RPC, rather than using `eth_subscribe`. */
poll?: false | undefined
pollingInterval?: undefined
}
: never)
| {
/** Whether or not to emit the missed block numbers to the callback. */
emitMissed?: boolean | undefined
/** Whether or not to emit the latest block number to the callback when the subscription opens. */
emitOnBegin?: boolean | undefined
poll?: true | undefined
/** Polling frequency (in ms). Defaults to Client's pollingInterval config. */
pollingInterval?: number | undefined
}
)
export type WatchBlockNumberReturnType = () => void
export type WatchBlockNumberErrorType = PollErrorType | ErrorType
/**
* Watches and returns incoming block numbers.
*
* - Docs: https://viem.sh/docs/actions/public/watchBlockNumber
* - Examples: https://stackblitz.com/github/wevm/viem/tree/main/examples/blocks_watching-blocks
* - JSON-RPC Methods:
* - When `poll: true`, calls [`eth_blockNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blocknumber) on a polling interval.
* - When `poll: false` & WebSocket Transport, uses a WebSocket subscription via [`eth_subscribe`](https://docs.alchemy.com/reference/eth-subscribe-polygon) and the `"newHeads"` event.
*
* @param client - Client to use
* @param parameters - {@link WatchBlockNumberParameters}
* @returns A function that can be invoked to stop watching for new block numbers. {@link WatchBlockNumberReturnType}
*
* @example
* import { createPublicClient, watchBlockNumber, http } from 'viem'
* import { mainnet } from 'viem/chains'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const unwatch = watchBlockNumber(client, {
* onBlockNumber: (blockNumber) => console.log(blockNumber),
* })
*/
export function watchBlockNumber<
chain extends Chain | undefined,
transport extends Transport,
>(
client: Client<transport, chain>,
{
emitOnBegin = false,
emitMissed = false,
onBlockNumber,
onError,
poll: poll_,
pollingInterval = client.pollingInterval,
}: WatchBlockNumberParameters<transport>,
): WatchBlockNumberReturnType {
const enablePolling = (() => {
if (typeof poll_ !== 'undefined') return poll_
if (
client.transport.type === 'webSocket' ||
client.transport.type === 'ipc'
)
return false
if (
client.transport.type === 'fallback' &&
(client.transport.transports[0].config.type === 'webSocket' ||
client.transport.transports[0].config.type === 'ipc')
)
return false
return true
})()
let prevBlockNumber: GetBlockNumberReturnType | undefined
const pollBlockNumber = () => {
const observerId = stringify([
'watchBlockNumber',
client.uid,
emitOnBegin,
emitMissed,
pollingInterval,
])
return observe(observerId, { onBlockNumber, onError }, (emit) =>
poll(
async () => {
try {
const blockNumber = await getAction(
client,
getBlockNumber,
'getBlockNumber',
)({ cacheTime: 0 })
if (prevBlockNumber !== undefined) {
// If the current block number is the same as the previous,
// we can skip.
if (blockNumber === prevBlockNumber) return
// If we have missed out on some previous blocks, and the
// `emitMissed` flag is truthy, let's emit those blocks.
if (blockNumber - prevBlockNumber > 1 && emitMissed) {
for (let i = prevBlockNumber + 1n; i < blockNumber; i++) {
emit.onBlockNumber(i, prevBlockNumber)
prevBlockNumber = i
}
}
}
// If the next block number is greater than the previous,
// it is not in the past, and we can emit the new block number.
if (
prevBlockNumber === undefined ||
blockNumber > prevBlockNumber
) {
emit.onBlockNumber(blockNumber, prevBlockNumber)
prevBlockNumber = blockNumber
}
} catch (err) {
emit.onError?.(err as Error)
}
},
{
emitOnBegin,
interval: pollingInterval,
},
),
)
}
const subscribeBlockNumber = () => {
const observerId = stringify([
'watchBlockNumber',
client.uid,
emitOnBegin,
emitMissed,
])
return observe(observerId, { onBlockNumber, onError }, (emit) => {
let active = true
let unsubscribe = () => (active = false)
;(async () => {
try {
const transport = (() => {
if (client.transport.type === 'fallback') {
const transport = client.transport.transports.find(
(transport: ReturnType<Transport>) =>
transport.config.type === 'webSocket' ||
transport.config.type === 'ipc',
)
if (!transport) return client.transport
return transport.value
}
return client.transport
})()
const { unsubscribe: unsubscribe_ } = await transport.subscribe({
params: ['newHeads'],
onData(data: any) {
if (!active) return
const blockNumber = hexToBigInt(data.result?.number)
emit.onBlockNumber(blockNumber, prevBlockNumber)
prevBlockNumber = blockNumber
},
onError(error: Error) {
emit.onError?.(error)
},
})
unsubscribe = unsubscribe_
if (!active) unsubscribe()
} catch (err) {
onError?.(err as Error)
}
})()
return () => unsubscribe()
})
}
return enablePolling ? pollBlockNumber() : subscribeBlockNumber()
}

275
node_modules/viem/actions/public/watchBlocks.ts generated vendored Normal file
View File

@@ -0,0 +1,275 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { HasTransportType } from '../../types/transport.js'
import { getAction } from '../../utils/getAction.js'
import { observe } from '../../utils/observe.js'
import { type PollErrorType, poll } from '../../utils/poll.js'
import { type StringifyErrorType, stringify } from '../../utils/stringify.js'
import { type GetBlockReturnType, getBlock } from './getBlock.js'
export type OnBlockParameter<
chain extends Chain | undefined = Chain,
includeTransactions extends boolean = false,
blockTag extends BlockTag = 'latest',
> = GetBlockReturnType<chain, includeTransactions, blockTag>
export type OnBlock<
chain extends Chain | undefined = Chain,
includeTransactions extends boolean = false,
blockTag extends BlockTag = 'latest',
> = (
block: OnBlockParameter<chain, includeTransactions, blockTag>,
prevBlock: OnBlockParameter<chain, includeTransactions, blockTag> | undefined,
) => void
export type WatchBlocksParameters<
transport extends Transport = Transport,
chain extends Chain | undefined = Chain,
includeTransactions extends boolean = false,
blockTag extends BlockTag = 'latest',
> = {
/** The callback to call when a new block is received. */
onBlock: OnBlock<chain, includeTransactions, blockTag>
/** The callback to call when an error occurred when trying to get for a new block. */
onError?: ((error: Error) => void) | undefined
} & (
| (HasTransportType<transport, 'webSocket' | 'ipc'> extends true
? {
blockTag?: undefined
emitMissed?: undefined
emitOnBegin?: undefined
includeTransactions?: undefined
/** Whether or not the WebSocket Transport should poll the JSON-RPC, rather than using `eth_subscribe`. */
poll?: false | undefined
pollingInterval?: undefined
}
: never)
| {
/** The block tag. Defaults to "latest". */
blockTag?: blockTag | BlockTag | undefined
/** Whether or not to emit the missed blocks to the callback. */
emitMissed?: boolean | undefined
/** Whether or not to emit the block to the callback when the subscription opens. */
emitOnBegin?: boolean | undefined
/** Whether or not to include transaction data in the response. */
includeTransactions?: includeTransactions | undefined
poll?: true | undefined
/** Polling frequency (in ms). Defaults to the client's pollingInterval config. */
pollingInterval?: number | undefined
}
)
export type WatchBlocksReturnType = () => void
export type WatchBlocksErrorType =
| StringifyErrorType
| PollErrorType
| ErrorType
/**
* Watches and returns information for incoming blocks.
*
* - Docs: https://viem.sh/docs/actions/public/watchBlocks
* - Examples: https://stackblitz.com/github/wevm/viem/tree/main/examples/blocks_watching-blocks
* - JSON-RPC Methods:
* - When `poll: true`, calls [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getBlockByNumber) on a polling interval.
* - When `poll: false` & WebSocket Transport, uses a WebSocket subscription via [`eth_subscribe`](https://docs.alchemy.com/reference/eth-subscribe-polygon) and the `"newHeads"` event.
*
* @param client - Client to use
* @param parameters - {@link WatchBlocksParameters}
* @returns A function that can be invoked to stop watching for new block numbers. {@link WatchBlocksReturnType}
*
* @example
* import { createPublicClient, watchBlocks, http } from 'viem'
* import { mainnet } from 'viem/chains'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const unwatch = watchBlocks(client, {
* onBlock: (block) => console.log(block),
* })
*/
export function watchBlocks<
transport extends Transport,
chain extends Chain | undefined,
includeTransactions extends boolean = false,
blockTag extends BlockTag = 'latest',
>(
client: Client<transport, chain>,
{
blockTag = client.experimental_blockTag ?? 'latest',
emitMissed = false,
emitOnBegin = false,
onBlock,
onError,
includeTransactions: includeTransactions_,
poll: poll_,
pollingInterval = client.pollingInterval,
}: WatchBlocksParameters<transport, chain, includeTransactions, blockTag>,
): WatchBlocksReturnType {
const enablePolling = (() => {
if (typeof poll_ !== 'undefined') return poll_
if (
client.transport.type === 'webSocket' ||
client.transport.type === 'ipc'
)
return false
if (
client.transport.type === 'fallback' &&
(client.transport.transports[0].config.type === 'webSocket' ||
client.transport.transports[0].config.type === 'ipc')
)
return false
return true
})()
const includeTransactions = includeTransactions_ ?? false
let prevBlock:
| GetBlockReturnType<chain, false | includeTransactions, 'latest'>
| undefined
const pollBlocks = () => {
const observerId = stringify([
'watchBlocks',
client.uid,
blockTag,
emitMissed,
emitOnBegin,
includeTransactions,
pollingInterval,
])
return observe(observerId, { onBlock, onError }, (emit) =>
poll(
async () => {
try {
const block = await getAction(
client,
getBlock,
'getBlock',
)({
blockTag,
includeTransactions,
})
if (block.number !== null && prevBlock?.number != null) {
// If the current block number is the same as the previous,
// we can skip.
if (block.number === prevBlock.number) return
// If we have missed out on some previous blocks, and the
// `emitMissed` flag is truthy, let's emit those blocks.
if (block.number - prevBlock.number > 1 && emitMissed) {
for (let i = prevBlock?.number + 1n; i < block.number; i++) {
const block = (await getAction(
client,
getBlock,
'getBlock',
)({
blockNumber: i,
includeTransactions,
})) as GetBlockReturnType<chain>
emit.onBlock(block as any, prevBlock as any)
prevBlock = block
}
}
}
if (
// If no previous block exists, emit.
prevBlock?.number == null ||
// If the block tag is "pending" with no block number, emit.
(blockTag === 'pending' && block?.number == null) ||
// If the next block number is greater than the previous block number, emit.
// We don't want to emit blocks in the past.
(block.number !== null && block.number > prevBlock.number)
) {
emit.onBlock(block as any, prevBlock as any)
prevBlock = block as any
}
} catch (err) {
emit.onError?.(err as Error)
}
},
{
emitOnBegin,
interval: pollingInterval,
},
),
)
}
const subscribeBlocks = () => {
let active = true
let emitFetched = true
let unsubscribe = () => (active = false)
;(async () => {
try {
if (emitOnBegin) {
getAction(
client,
getBlock,
'getBlock',
)({
blockTag,
includeTransactions,
})
.then((block) => {
if (!active) return
if (!emitFetched) return
onBlock(block as any, undefined)
emitFetched = false
})
.catch(onError)
}
const transport = (() => {
if (client.transport.type === 'fallback') {
const transport = client.transport.transports.find(
(transport: ReturnType<Transport>) =>
transport.config.type === 'webSocket' ||
transport.config.type === 'ipc',
)
if (!transport) return client.transport
return transport.value
}
return client.transport
})()
const { unsubscribe: unsubscribe_ } = await transport.subscribe({
params: ['newHeads'],
async onData(data: any) {
if (!active) return
const block = (await getAction(
client,
getBlock,
'getBlock',
)({
blockNumber: data.result?.number,
includeTransactions,
}).catch(() => {})) as GetBlockReturnType<chain>
if (!active) return
onBlock(block as any, prevBlock as any)
emitFetched = false
prevBlock = block
},
onError(error: Error) {
onError?.(error)
},
})
unsubscribe = unsubscribe_
if (!active) unsubscribe()
} catch (err) {
onError?.(err as Error)
}
})()
return () => unsubscribe()
}
return enablePolling ? pollBlocks() : subscribeBlocks()
}

379
node_modules/viem/actions/public/watchContractEvent.ts generated vendored Normal file
View File

@@ -0,0 +1,379 @@
import type { Abi, Address, ExtractAbiEvent } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import {
DecodeLogDataMismatch,
DecodeLogTopicsMismatch,
} from '../../errors/abi.js'
import { InvalidInputRpcError } from '../../errors/rpc.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockNumber } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type {
ContractEventArgs,
ContractEventName,
} from '../../types/contract.js'
import type { Filter } from '../../types/filter.js'
import type { Log } from '../../types/log.js'
import type { LogTopic } from '../../types/misc.js'
import type { GetPollOptions } from '../../types/transport.js'
import { decodeEventLog } from '../../utils/abi/decodeEventLog.js'
import {
type EncodeEventTopicsParameters,
encodeEventTopics,
} from '../../utils/abi/encodeEventTopics.js'
import { formatLog } from '../../utils/formatters/log.js'
import { getAction } from '../../utils/getAction.js'
import { type ObserveErrorType, observe } from '../../utils/observe.js'
import { poll } from '../../utils/poll.js'
import { type StringifyErrorType, stringify } from '../../utils/stringify.js'
import { createContractEventFilter } from './createContractEventFilter.js'
import { getBlockNumber } from './getBlockNumber.js'
import {
type GetContractEventsParameters,
getContractEvents,
} from './getContractEvents.js'
import { getFilterChanges } from './getFilterChanges.js'
import { uninstallFilter } from './uninstallFilter.js'
export type WatchContractEventOnLogsParameter<
abi extends Abi | readonly unknown[] = Abi,
eventName extends ContractEventName<abi> = ContractEventName<abi>,
strict extends boolean | undefined = undefined,
> = abi extends Abi
? Abi extends abi
? Log[]
: Log<bigint, number, false, ExtractAbiEvent<abi, eventName>, strict>[]
: Log[]
export type WatchContractEventOnLogsFn<
abi extends Abi | readonly unknown[] = Abi,
eventName extends ContractEventName<abi> = ContractEventName<abi>,
strict extends boolean | undefined = undefined,
> = (logs: WatchContractEventOnLogsParameter<abi, eventName, strict>) => void
export type WatchContractEventParameters<
abi extends Abi | readonly unknown[] = Abi,
eventName extends ContractEventName<abi> | undefined = ContractEventName<abi>,
strict extends boolean | undefined = undefined,
transport extends Transport = Transport,
> = {
/** The address of the contract. */
address?: Address | Address[] | undefined
/** Contract ABI. */
abi: abi
args?:
| ContractEventArgs<
abi,
eventName extends ContractEventName<abi>
? eventName
: ContractEventName<abi>
>
| undefined
/** Contract event. */
eventName?: eventName | ContractEventName<abi> | undefined
/** Block to start listening from. */
fromBlock?: BlockNumber<bigint> | undefined
/** The callback to call when an error occurred when trying to get for a new block. */
onError?: ((error: Error) => void) | undefined
/** The callback to call when new event logs are received. */
onLogs: WatchContractEventOnLogsFn<
abi,
eventName extends ContractEventName<abi>
? eventName
: ContractEventName<abi>,
strict
>
/**
* Whether or not the logs must match the indexed/non-indexed arguments on `event`.
* @default false
*/
strict?: strict | boolean | undefined
} & GetPollOptions<transport>
export type WatchContractEventReturnType = () => void
export type WatchContractEventErrorType =
| StringifyErrorType
| ObserveErrorType
| ErrorType
/**
* Watches and returns emitted contract event logs.
*
* - Docs: https://viem.sh/docs/contract/watchContractEvent
*
* This Action will batch up all the event logs found within the [`pollingInterval`](https://viem.sh/docs/contract/watchContractEvent#pollinginterval-optional), and invoke them via [`onLogs`](https://viem.sh/docs/contract/watchContractEvent#onLogs).
*
* `watchContractEvent` will attempt to create an [Event Filter](https://viem.sh/docs/contract/createContractEventFilter) and listen to changes to the Filter per polling interval, however, if the RPC Provider does not support Filters (e.g. `eth_newFilter`), then `watchContractEvent` will fall back to using [`getLogs`](https://viem.sh/docs/actions/public/getLogs) instead.
*
* @param client - Client to use
* @param parameters - {@link WatchContractEventParameters}
* @returns A function that can be invoked to stop watching for new event logs. {@link WatchContractEventReturnType}
*
* @example
* import { createPublicClient, http, parseAbi } from 'viem'
* import { mainnet } from 'viem/chains'
* import { watchContractEvent } from 'viem/contract'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const unwatch = watchContractEvent(client, {
* address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
* abi: parseAbi(['event Transfer(address indexed from, address indexed to, uint256 value)']),
* eventName: 'Transfer',
* args: { from: '0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b' },
* onLogs: (logs) => console.log(logs),
* })
*/
export function watchContractEvent<
chain extends Chain | undefined,
const abi extends Abi | readonly unknown[],
eventName extends ContractEventName<abi> | undefined = undefined,
strict extends boolean | undefined = undefined,
transport extends Transport = Transport,
>(
client: Client<transport, chain>,
parameters: WatchContractEventParameters<abi, eventName, strict, transport>,
): WatchContractEventReturnType {
const {
abi,
address,
args,
batch = true,
eventName,
fromBlock,
onError,
onLogs,
poll: poll_,
pollingInterval = client.pollingInterval,
strict: strict_,
} = parameters
const enablePolling = (() => {
if (typeof poll_ !== 'undefined') return poll_
if (typeof fromBlock === 'bigint') return true
if (
client.transport.type === 'webSocket' ||
client.transport.type === 'ipc'
)
return false
if (
client.transport.type === 'fallback' &&
(client.transport.transports[0].config.type === 'webSocket' ||
client.transport.transports[0].config.type === 'ipc')
)
return false
return true
})()
const pollContractEvent = () => {
const strict = strict_ ?? false
const observerId = stringify([
'watchContractEvent',
address,
args,
batch,
client.uid,
eventName,
pollingInterval,
strict,
fromBlock,
])
return observe(observerId, { onLogs, onError }, (emit) => {
let previousBlockNumber: bigint
if (fromBlock !== undefined) previousBlockNumber = fromBlock - 1n
let filter: Filter<'event', abi, eventName> | undefined
let initialized = false
const unwatch = poll(
async () => {
if (!initialized) {
try {
filter = (await getAction(
client,
createContractEventFilter,
'createContractEventFilter',
)({
abi,
address,
args: args as any,
eventName: eventName as any,
strict: strict as any,
fromBlock,
})) as Filter<'event', abi, eventName>
} catch {}
initialized = true
return
}
try {
let logs: Log[]
if (filter) {
logs = await getAction(
client,
getFilterChanges,
'getFilterChanges',
)({ filter })
} else {
// If the filter doesn't exist, we will fall back to use `getLogs`.
// The fall back exists because some RPC Providers do not support filters.
// Fetch the block number to use for `getLogs`.
const blockNumber = await getAction(
client,
getBlockNumber,
'getBlockNumber',
)({})
// If the block number has changed, we will need to fetch the logs.
// If the block number doesn't exist, we are yet to reach the first poll interval,
// so do not emit any logs.
if (previousBlockNumber && previousBlockNumber < blockNumber) {
logs = await getAction(
client,
getContractEvents,
'getContractEvents',
)({
abi,
address,
args,
eventName,
fromBlock: previousBlockNumber + 1n,
toBlock: blockNumber,
strict,
} as {} as GetContractEventsParameters)
} else {
logs = []
}
previousBlockNumber = blockNumber
}
if (logs.length === 0) return
if (batch) emit.onLogs(logs as any)
else for (const log of logs) emit.onLogs([log] as any)
} catch (err) {
// If a filter has been set and gets uninstalled, providers will throw an InvalidInput error.
// Reinitialize the filter when this occurs
if (filter && err instanceof InvalidInputRpcError)
initialized = false
emit.onError?.(err as Error)
}
},
{
emitOnBegin: true,
interval: pollingInterval,
},
)
return async () => {
if (filter)
await getAction(
client,
uninstallFilter,
'uninstallFilter',
)({ filter })
unwatch()
}
})
}
const subscribeContractEvent = () => {
const strict = strict_ ?? false
const observerId = stringify([
'watchContractEvent',
address,
args,
batch,
client.uid,
eventName,
pollingInterval,
strict,
])
let active = true
let unsubscribe = () => (active = false)
return observe(observerId, { onLogs, onError }, (emit) => {
;(async () => {
try {
const transport = (() => {
if (client.transport.type === 'fallback') {
const transport = client.transport.transports.find(
(transport: ReturnType<Transport>) =>
transport.config.type === 'webSocket' ||
transport.config.type === 'ipc',
)
if (!transport) return client.transport
return transport.value
}
return client.transport
})()
const topics: LogTopic[] = eventName
? encodeEventTopics({
abi: abi,
eventName: eventName,
args,
} as EncodeEventTopicsParameters)
: []
const { unsubscribe: unsubscribe_ } = await transport.subscribe({
params: ['logs', { address, topics }],
onData(data: any) {
if (!active) return
const log = data.result
try {
const { eventName, args } = decodeEventLog({
abi: abi,
data: log.data,
topics: log.topics as any,
strict: strict_,
})
const formatted = formatLog(log, {
args,
eventName: eventName as string,
})
emit.onLogs([formatted] as any)
} catch (err) {
let eventName: string | undefined
let isUnnamed: boolean | undefined
if (
err instanceof DecodeLogDataMismatch ||
err instanceof DecodeLogTopicsMismatch
) {
// If strict mode is on, and log data/topics do not match event definition, skip.
if (strict_) return
eventName = err.abiItem.name
isUnnamed = err.abiItem.inputs?.some(
(x) => !('name' in x && x.name),
)
}
// Set args to empty if there is an error decoding (e.g. indexed/non-indexed params mismatch).
const formatted = formatLog(log, {
args: isUnnamed ? [] : {},
eventName,
})
emit.onLogs([formatted] as any)
}
},
onError(error: Error) {
emit.onError?.(error)
},
})
unsubscribe = unsubscribe_
if (!active) unsubscribe()
} catch (err) {
onError?.(err as Error)
}
})()
return () => unsubscribe()
})
}
return enablePolling ? pollContractEvent() : subscribeContractEvent()
}

391
node_modules/viem/actions/public/watchEvent.ts generated vendored Normal file
View File

@@ -0,0 +1,391 @@
import type { AbiEvent, Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import {
DecodeLogDataMismatch,
DecodeLogTopicsMismatch,
} from '../../errors/abi.js'
import { InvalidInputRpcError } from '../../errors/rpc.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockNumber } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type {
MaybeAbiEventName,
MaybeExtractEventArgsFromAbi,
} from '../../types/contract.js'
import type { Filter } from '../../types/filter.js'
import type { Log } from '../../types/log.js'
import type { LogTopic } from '../../types/misc.js'
import type { GetPollOptions } from '../../types/transport.js'
import { decodeEventLog } from '../../utils/abi/decodeEventLog.js'
import {
type EncodeEventTopicsParameters,
encodeEventTopics,
} from '../../utils/abi/encodeEventTopics.js'
import { formatLog } from '../../utils/formatters/log.js'
import { getAction } from '../../utils/getAction.js'
import { type ObserveErrorType, observe } from '../../utils/observe.js'
import { poll } from '../../utils/poll.js'
import { type StringifyErrorType, stringify } from '../../utils/stringify.js'
import {
type CreateEventFilterParameters,
createEventFilter,
} from './createEventFilter.js'
import { getBlockNumber } from './getBlockNumber.js'
import { getFilterChanges } from './getFilterChanges.js'
import { type GetLogsParameters, getLogs } from './getLogs.js'
import { uninstallFilter } from './uninstallFilter.js'
export type WatchEventOnLogsParameter<
abiEvent extends AbiEvent | undefined = undefined,
abiEvents extends
| readonly AbiEvent[]
| readonly unknown[]
| undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,
strict extends boolean | undefined = undefined,
eventName extends string | undefined = MaybeAbiEventName<abiEvent>,
> = Log<bigint, number, false, abiEvent, strict, abiEvents, eventName>[]
export type WatchEventOnLogsFn<
abiEvent extends AbiEvent | undefined = undefined,
abiEvents extends
| readonly AbiEvent[]
| readonly unknown[]
| undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,
strict extends boolean | undefined = undefined,
//
_eventName extends string | undefined = MaybeAbiEventName<abiEvent>,
> = (
logs: WatchEventOnLogsParameter<abiEvent, abiEvents, strict, _eventName>,
) => void
export type WatchEventParameters<
abiEvent extends AbiEvent | undefined = undefined,
abiEvents extends
| readonly AbiEvent[]
| readonly unknown[]
| undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,
strict extends boolean | undefined = undefined,
transport extends Transport = Transport,
//
_eventName extends string | undefined = MaybeAbiEventName<abiEvent>,
> = {
/** The address of the contract. */
address?: Address | Address[] | undefined
/** Block to start listening from. */
fromBlock?: BlockNumber<bigint> | undefined
/** The callback to call when an error occurred when trying to get for a new block. */
onError?: ((error: Error) => void) | undefined
/** The callback to call when new event logs are received. */
onLogs: WatchEventOnLogsFn<abiEvent, abiEvents, strict, _eventName>
} & GetPollOptions<transport> &
(
| {
event: abiEvent
events?: undefined
args?: MaybeExtractEventArgsFromAbi<abiEvents, _eventName> | undefined
/**
* Whether or not the logs must match the indexed/non-indexed arguments on `event`.
* @default false
*/
strict?: strict | undefined
}
| {
event?: undefined
events?: abiEvents | undefined
args?: undefined
/**
* Whether or not the logs must match the indexed/non-indexed arguments on `event`.
* @default false
*/
strict?: strict | undefined
}
| {
event?: undefined
events?: undefined
args?: undefined
strict?: undefined
}
)
export type WatchEventReturnType = () => void
export type WatchEventErrorType =
| StringifyErrorType
| ObserveErrorType
| ErrorType
/**
* Watches and returns emitted [Event Logs](https://viem.sh/docs/glossary/terms#event-log).
*
* - Docs: https://viem.sh/docs/actions/public/watchEvent
* - JSON-RPC Methods:
* - **RPC Provider supports `eth_newFilter`:**
* - Calls [`eth_newFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newfilter) to create a filter (called on initialize).
* - On a polling interval, it will call [`eth_getFilterChanges`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterchanges).
* - **RPC Provider does not support `eth_newFilter`:**
* - Calls [`eth_getLogs`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs) for each block between the polling interval.
*
* This Action will batch up all the Event Logs found within the [`pollingInterval`](https://viem.sh/docs/actions/public/watchEvent#pollinginterval-optional), and invoke them via [`onLogs`](https://viem.sh/docs/actions/public/watchEvent#onLogs).
*
* `watchEvent` will attempt to create an [Event Filter](https://viem.sh/docs/actions/public/createEventFilter) and listen to changes to the Filter per polling interval, however, if the RPC Provider does not support Filters (e.g. `eth_newFilter`), then `watchEvent` will fall back to using [`getLogs`](https://viem.sh/docs/actions/public/getLogs) instead.
*
* @param client - Client to use
* @param parameters - {@link WatchEventParameters}
* @returns A function that can be invoked to stop watching for new Event Logs. {@link WatchEventReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { watchEvent } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const unwatch = watchEvent(client, {
* onLogs: (logs) => console.log(logs),
* })
*/
export function watchEvent<
chain extends Chain | undefined,
const abiEvent extends AbiEvent | undefined = undefined,
const abiEvents extends
| readonly AbiEvent[]
| readonly unknown[]
| undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,
strict extends boolean | undefined = undefined,
transport extends Transport = Transport,
_eventName extends string | undefined = undefined,
>(
client: Client<transport, chain>,
{
address,
args,
batch = true,
event,
events,
fromBlock,
onError,
onLogs,
poll: poll_,
pollingInterval = client.pollingInterval,
strict: strict_,
}: WatchEventParameters<abiEvent, abiEvents, strict, transport>,
): WatchEventReturnType {
const enablePolling = (() => {
if (typeof poll_ !== 'undefined') return poll_
if (typeof fromBlock === 'bigint') return true
if (
client.transport.type === 'webSocket' ||
client.transport.type === 'ipc'
)
return false
if (
client.transport.type === 'fallback' &&
(client.transport.transports[0].config.type === 'webSocket' ||
client.transport.transports[0].config.type === 'ipc')
)
return false
return true
})()
const strict = strict_ ?? false
const pollEvent = () => {
const observerId = stringify([
'watchEvent',
address,
args,
batch,
client.uid,
event,
pollingInterval,
fromBlock,
])
return observe(observerId, { onLogs, onError }, (emit) => {
let previousBlockNumber: bigint
if (fromBlock !== undefined) previousBlockNumber = fromBlock - 1n
let filter: Filter<'event', abiEvents, _eventName, any>
let initialized = false
const unwatch = poll(
async () => {
if (!initialized) {
try {
filter = (await getAction(
client,
createEventFilter as any,
'createEventFilter',
)({
address,
args,
event: event!,
events,
strict,
fromBlock,
} as unknown as CreateEventFilterParameters)) as unknown as Filter<
'event',
abiEvents,
_eventName
>
} catch {}
initialized = true
return
}
try {
let logs: Log[]
if (filter) {
logs = await getAction(
client,
getFilterChanges,
'getFilterChanges',
)({ filter })
} else {
// If the filter doesn't exist, we will fall back to use `getLogs`.
// The fall back exists because some RPC Providers do not support filters.
// Fetch the block number to use for `getLogs`.
const blockNumber = await getAction(
client,
getBlockNumber,
'getBlockNumber',
)({})
// If the block number has changed, we will need to fetch the logs.
// If the block number doesn't exist, we are yet to reach the first poll interval,
// so do not emit any logs.
if (previousBlockNumber && previousBlockNumber !== blockNumber) {
logs = await getAction(
client,
getLogs,
'getLogs',
)({
address,
args,
event: event!,
events,
fromBlock: previousBlockNumber + 1n,
toBlock: blockNumber,
} as unknown as GetLogsParameters)
} else {
logs = []
}
previousBlockNumber = blockNumber
}
if (logs.length === 0) return
if (batch) emit.onLogs(logs as any)
else for (const log of logs) emit.onLogs([log] as any)
} catch (err) {
// If a filter has been set and gets uninstalled, providers will throw an InvalidInput error.
// Reinitialize the filter when this occurs
if (filter && err instanceof InvalidInputRpcError)
initialized = false
emit.onError?.(err as Error)
}
},
{
emitOnBegin: true,
interval: pollingInterval,
},
)
return async () => {
if (filter)
await getAction(
client,
uninstallFilter,
'uninstallFilter',
)({ filter })
unwatch()
}
})
}
const subscribeEvent = () => {
let active = true
let unsubscribe = () => (active = false)
;(async () => {
try {
const transport = (() => {
if (client.transport.type === 'fallback') {
const transport = client.transport.transports.find(
(transport: ReturnType<Transport>) =>
transport.config.type === 'webSocket' ||
transport.config.type === 'ipc',
)
if (!transport) return client.transport
return transport.value
}
return client.transport
})()
const events_ = events ?? (event ? [event] : undefined)
let topics: LogTopic[] = []
if (events_) {
const encoded = (events_ as AbiEvent[]).flatMap((event) =>
encodeEventTopics({
abi: [event],
eventName: (event as AbiEvent).name,
args,
} as EncodeEventTopicsParameters),
)
// TODO: Clean up type casting
topics = [encoded as LogTopic]
if (event) topics = topics[0] as LogTopic[]
}
const { unsubscribe: unsubscribe_ } = await transport.subscribe({
params: ['logs', { address, topics }],
onData(data: any) {
if (!active) return
const log = data.result
try {
const { eventName, args } = decodeEventLog({
abi: events_ ?? [],
data: log.data,
topics: log.topics,
strict,
})
const formatted = formatLog(log, { args, eventName })
onLogs([formatted] as any)
} catch (err) {
let eventName: string | undefined
let isUnnamed: boolean | undefined
if (
err instanceof DecodeLogDataMismatch ||
err instanceof DecodeLogTopicsMismatch
) {
// If strict mode is on, and log data/topics do not match event definition, skip.
if (strict_) return
eventName = err.abiItem.name
isUnnamed = err.abiItem.inputs?.some(
(x) => !('name' in x && x.name),
)
}
// Set args to empty if there is an error decoding (e.g. indexed/non-indexed params mismatch).
const formatted = formatLog(log, {
args: isUnnamed ? [] : {},
eventName,
})
onLogs([formatted] as any)
}
},
onError(error: Error) {
onError?.(error)
},
})
unsubscribe = unsubscribe_
if (!active) unsubscribe()
} catch (err) {
onError?.(err as Error)
}
})()
return () => unsubscribe()
}
return enablePolling ? pollEvent() : subscribeEvent()
}

View File

@@ -0,0 +1,168 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'
import type { Filter } from '../../types/filter.js'
import type { Hash } from '../../types/misc.js'
import type { GetPollOptions } from '../../types/transport.js'
import { getAction } from '../../utils/getAction.js'
import { type ObserveErrorType, observe } from '../../utils/observe.js'
import { poll } from '../../utils/poll.js'
import { type StringifyErrorType, stringify } from '../../utils/stringify.js'
import { createPendingTransactionFilter } from './createPendingTransactionFilter.js'
import { getFilterChanges } from './getFilterChanges.js'
import { uninstallFilter } from './uninstallFilter.js'
export type OnTransactionsParameter = Hash[]
export type OnTransactionsFn = (transactions: OnTransactionsParameter) => void
export type WatchPendingTransactionsParameters<
transport extends Transport = Transport,
> = {
/** The callback to call when an error occurred when trying to get for a new block. */
onError?: ((error: Error) => void) | undefined
/** The callback to call when new transactions are received. */
onTransactions: OnTransactionsFn
} & GetPollOptions<transport>
export type WatchPendingTransactionsReturnType = () => void
export type WatchPendingTransactionsErrorType =
| StringifyErrorType
| ObserveErrorType
| ErrorType
/**
* Watches and returns pending transaction hashes.
*
* - Docs: https://viem.sh/docs/actions/public/watchPendingTransactions
* - JSON-RPC Methods:
* - When `poll: true`
* - Calls [`eth_newPendingTransactionFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newpendingtransactionfilter) to initialize the filter.
* - Calls [`eth_getFilterChanges`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getFilterChanges) on a polling interval.
* - When `poll: false` & WebSocket Transport, uses a WebSocket subscription via [`eth_subscribe`](https://docs.alchemy.com/reference/eth-subscribe-polygon) and the `"newPendingTransactions"` event.
*
* This Action will batch up all the pending transactions found within the [`pollingInterval`](https://viem.sh/docs/actions/public/watchPendingTransactions#pollinginterval-optional), and invoke them via [`onTransactions`](https://viem.sh/docs/actions/public/watchPendingTransactions#ontransactions).
*
* @param client - Client to use
* @param parameters - {@link WatchPendingTransactionsParameters}
* @returns A function that can be invoked to stop watching for new pending transaction hashes. {@link WatchPendingTransactionsReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { watchPendingTransactions } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const unwatch = await watchPendingTransactions(client, {
* onTransactions: (hashes) => console.log(hashes),
* })
*/
export function watchPendingTransactions<
transport extends Transport,
chain extends Chain | undefined,
>(
client: Client<transport, chain>,
{
batch = true,
onError,
onTransactions,
poll: poll_,
pollingInterval = client.pollingInterval,
}: WatchPendingTransactionsParameters<transport>,
) {
const enablePolling =
typeof poll_ !== 'undefined'
? poll_
: client.transport.type !== 'webSocket' && client.transport.type !== 'ipc'
const pollPendingTransactions = () => {
const observerId = stringify([
'watchPendingTransactions',
client.uid,
batch,
pollingInterval,
])
return observe(observerId, { onTransactions, onError }, (emit) => {
let filter: Filter<'transaction'>
const unwatch = poll(
async () => {
try {
if (!filter) {
try {
filter = await getAction(
client,
createPendingTransactionFilter,
'createPendingTransactionFilter',
)({})
return
} catch (err) {
unwatch()
throw err
}
}
const hashes = await getAction(
client,
getFilterChanges,
'getFilterChanges',
)({ filter })
if (hashes.length === 0) return
if (batch) emit.onTransactions(hashes)
else for (const hash of hashes) emit.onTransactions([hash])
} catch (err) {
emit.onError?.(err as Error)
}
},
{
emitOnBegin: true,
interval: pollingInterval,
},
)
return async () => {
if (filter)
await getAction(
client,
uninstallFilter,
'uninstallFilter',
)({ filter })
unwatch()
}
})
}
const subscribePendingTransactions = () => {
let active = true
let unsubscribe = () => (active = false)
;(async () => {
try {
const { unsubscribe: unsubscribe_ } = await client.transport.subscribe({
params: ['newPendingTransactions'],
onData(data: any) {
if (!active) return
const transaction = data.result
onTransactions([transaction])
},
onError(error: Error) {
onError?.(error)
},
})
unsubscribe = unsubscribe_
if (!active) unsubscribe()
} catch (err) {
onError?.(err as Error)
}
})()
return () => unsubscribe()
}
return enablePolling
? pollPendingTransactions()
: subscribePendingTransactions()
}