wagmi 核心 Action 详解:prepareTransactionRequest 交易请求预处理器
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
prepareTransactionRequest是@wagmi/core提供的核心 Action,用于在交易签名前自动补齐一笔交易请求所需的全部必要字段——包括 nonce(交易序号)、gas limit(Gas 上限)、手续费参数(gasPrice/maxFeePerGas/maxPriorityFeePerGas)以及交易类型(如eip1559)。本指南将围绕该 Action 的完整参数体系、返回类型、错误处理,并结合仓库源码与测试用例,讲解其在 wagmi 应用中为转账、合约调用、批量调用(calls)等场景准备交易请求的实战方法,读完即可在自己的项目中安全、准确地使用该能力。
一、Action 概述:为什么要“预处理”交易请求
在以太坊上发起一笔交易(转账或合约调用)时,除了to、value、data等业务字段外,交易还依赖链上状态才能被矿工接受,例如:
- nonce:从链上读取的账户交易计数,防止交易重放;
- gas limit:交易执行所需的 Gas 上限;
- 手续费:Legacy 交易的
gasPrice,或 EIP-1559 交易的maxFeePerGas/maxPriorityFeePerGas; - 交易类型:根据链与账户状态自动选择(如
eip1559、legacy)。
prepareTransactionRequest正是负责“补齐”这些链上依赖字段的 Action。它本质上是对 viem 同名 Action 的 wagmi 封装,但额外集成了 wagmi 的Config、链选择与连接器(Connector)体系,并返回带chainId的交易请求。在发送交易(sendTransaction)之前先经过它,是构建健壮 dApp 的常见做法。
二、安装与导入
该 Action 由@wagmi/core包导出,无需额外安装依赖:
import { prepareTransactionRequest } from '@wagmi/core'同时可导入配套的类型定义:
import { type PrepareTransactionRequestParameters, type PrepareTransactionRequestReturnType, type PrepareTransactionRequestErrorType, } from '@wagmi/core'其导出位置见 actions 导出文件,类型定义与实现均位于 prepareTransactionRequest 源码。
三、基本用法
在调用前,需要先通过createConfig创建 wagmi 配置(chains与transports是必填项),示例配置如下(摘自 配置片段):
import { createConfig, http } from '@wagmi/core' import { mainnet, sepolia } from '@wagmi/core/chains' export const config = createConfig({ chains: [mainnet, sepolia], transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, })之后即可准备一笔向指定地址转账 1 ETH 的交易请求:
import { prepareTransactionRequest } from '@wagmi/core' import { parseEther } from 'viem' import { config } from './config' await prepareTransactionRequest(config, { to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })函数签名(见 源码)为:
prepareTransactionRequest<config, chainId, request>( config: config, parameters: PrepareTransactionRequestParameters<config, chainId, request>, ): Promise<PrepareTransactionRequestReturnType<config, chainId, request>>其中config为第一步创建的 wagmi 配置,parameters是交易请求参数,下面逐一展开。
四、参数详解(PrepareTransactionRequestParameters)
所有参数均为可选(由 TypeScript 类型系统按场景约束),导入类型:
import { type PrepareTransactionRequestParameters } from '@wagmi/core'从源码看,该参数类型通过UnionStrictOmit移除了 viem 的chain字段,并混入ChainIdParameter(链 ID)与ConnectorParameter(连接器),最终以按链展开的联合类型([key in keyof chains])形式提供精确的类型推导。
4.1 account
- 类型:
Account | Address | undefined - 作用:发送交易的账户(Account 对象或地址字符串)。不传时使用当前已连接账户。
await prepareTransactionRequest(config, { account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })源码行为提示:从 实现 可见,当account是type === 'local'的本地账户对象时,直接通过config.getClient({ chainId })取客户端;否则通过getConnectorClient获取连接器客户端,并传入account(可能为undefined,此时使用连接器当前账户)。
4.2 to
- 类型:
`0x${string}` | undefined - 作用:交易接收方或合约地址。
await prepareTransactionRequest(config, { account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })注意:如果使用calls(批量调用)而非to,则to可省略(见 类型定义 中calls与to的互斥联合)。
4.3 accessList
- 类型:
AccessList | undefined - 作用:访问列表(Access List),用于预先声明交易将访问的合约地址与存储槽,可优化 Gas 费用。
await prepareTransactionRequest(config, { accessList: [ { address: '0x1', storageKeys: ['0x1'], }, ], account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })4.4 chainId
- 类型:
config['chains'][number]['id'] | undefined - 作用:为指定链准备交易请求。不传时使用当前活动链。
import { mainnet } from '@wagmi/core/chains' await prepareTransactionRequest(config, { chainId: mainnet.id, account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })类型推导亮点:由于chainId被限定为config['chains'][number]['id'],@wagmi/core会根据config中配置的链集合(如mainnet、sepolia)做字面量类型推导,传入未配置的链 ID 会在编译期报错。
4.5 data
- 类型:
`0x${string}` | undefined - 作用:合约哈希方法调用(method call)与编码后的参数(即合约 calldata)。可用于构造合约交互交易。
await prepareTransactionRequest(config, { data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })4.6 gasPrice
- 类型:
bigint | undefined - 作用:每单位 Gas 支付的价格(以 wei 为单位)。仅适用于 Legacy 交易(即非 EIP-1559 链或 EIP-1559 不可用时的回退场景)。
import { parseEther, parseGwei } from 'viem' await prepareTransactionRequest(config, { account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', gasPrice: parseGwei('20'), to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })parseGwei('20')返回20000000000n,即以 20 Gwei 作为 Gas 单价。
4.7 maxFeePerGas
- 类型:
bigint | undefined - 作用:每单位 Gas 的总费用上限(以 wei 为单位),已包含
maxPriorityFeePerGas。仅适用于 EIP-1559 交易。
await prepareTransactionRequest(config, { account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', maxFeePerGas: parseGwei('20'), to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })4.8 maxPriorityFeePerGas
- 类型:
bigint | undefined - 作用:每单位 Gas 的矿工优先小费上限(以 wei 为单位)。仅适用于 EIP-1559 交易。通常与
maxFeePerGas搭配使用,且应满足maxFeePerGas >= maxPriorityFeePerGas。
await prepareTransactionRequest(config, { account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', maxFeePerGas: parseGwei('20'), maxPriorityFeePerGas: parseGwei('2'), to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })4.9 nonce
- 类型:
number | undefined - 作用:标识该交易的唯一序号。通常由链上账户交易计数自动填充,手动指定可用于覆盖(replace)pending 交易等高级场景。
await prepareTransactionRequest(config, { account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), nonce: 5, })4.10 parameters
- 类型:
("fees" | "gas" | "nonce" | "type")[] | undefined - 作用:指定需要预处理的参数子集。例如传入
["gas", "nonce"]时,仅补齐gas与nonce,其余字段(如type、手续费)保持用户传入的值不变。
await prepareTransactionRequest(config, { account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', parameters: ['gas', 'nonce'], to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })该参数在精细化控制“哪些字段由链上补齐、哪些字段保持自定义”时非常有用,例如在需要严格自定义手续费但希望自动填充 nonce 与 gas 上限的场景。
4.11 value
- 类型:
bigint | undefined - 作用:交易转账金额(以 wei 为单位)。文档中原文描述为“the transaction recipient or contract address”,结合源码与常规语义,其实际含义为转账金额,可用
parseEther等工具转换:
await prepareTransactionRequest(config, { account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })4.12 calls(批量调用)
除上述参数外,从 源码类型定义 可以看到,PrepareTransactionRequestParameters还支持calls: Calls<readonly unknown[]>形式的批量调用参数,此时to变为可选。这使该 Action 同样可以服务于 EIP-7702 / 批量调用等场景,适合构造复杂的多操作交易请求。
五、返回类型(PrepareTransactionRequestReturnType)
import { type PrepareTransactionRequestReturnType } from '@wagmi/core'返回值为一个完整的TransactionRequest交易请求对象,包含补齐后的字段,例如account、from、to、value、nonce、gas、gasPrice/maxFeePerGas/maxPriorityFeePerGas、type等。
从 类型定义 看,返回值在 viem 的PrepareTransactionRequestReturnType基础上额外固定携带chainId字段(& { chainId: chains[key]['id'] }),并按链展开为联合类型,便于下游sendTransaction等 Action 直接消费。
参考仓库测试 prepareTransactionRequest.test.ts,一次默认调用的返回快照大致为:
{ account: { address: '0x95132632579b073D12a6673e18Ab05777a6B86f8', type: 'json-rpc' }, chainId: 1, from: '0x95132632579b073D12a6673e18Ab05777a6B86f8', to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', type: 'eip1559', value: 1000000000000000000n, // 以及被测试解构忽略的 gas / gasPrice / maxFeePerGas / maxPriorityFeePerGas / nonce 等字段 }可以看到在连接器(json-rpc 账户)场景下,返回的交易类型被自动确定为eip1559,chainId为1(mainnet),value为1 ETH对应的1000000000000000000n。
六、错误处理(PrepareTransactionRequestErrorType)
import { type PrepareTransactionRequestErrorType } from '@wagmi/core'该类型直接复用 viem 的PrepareTransactionRequestErrorType(见 源码),覆盖如账户不存在、链未配置、RPC 请求失败、Gas 估算失败等异常场景。实践中建议配合 try/catch 或错误边界处理,并可结合 wagmi 的错误体系(errors 文档)统一展示。
七、与 TanStack Query 集成(/query 子路径)
@wagmi/core为便于缓存与响应式刷新,还导出了 TanStack Query 相关的工具函数,导入方式:
import { type PrepareTransactionRequestData, type PrepareTransactionRequestOptions, type PrepareTransactionRequestQueryFnData, type PrepareTransactionRequestQueryKey, prepareTransactionRequestQueryKey, prepareTransactionRequestQueryOptions, } from '@wagmi/core/query'实现在 query/prepareTransactionRequest.ts:
prepareTransactionRequestQueryOptions(config, options):构造 query 配置。其enabled逻辑要求to或非空calls存在时才启用查询(L52-L57);queryFn内部在缺少to且无calls时抛出'to or calls is required'错误。prepareTransactionRequestQueryKey(options):生成查询键['prepareTransactionRequest', { ...过滤后的参数 }],参数变化会自动触发重新查询。- 配套类型
PrepareTransactionRequestData、PrepareTransactionRequestOptions等用于类型安全的 query 使用。
八、React 框架下的 Hook 封装
在@wagmi/react中,该能力被封装为usePrepareTransactionRequestHook(实现见 usePrepareTransactionRequest.ts):
import { usePrepareTransactionRequest } from 'wagmi' const result = usePrepareTransactionRequest({ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: parseEther('1'), })Hook 内部通过useConfig获取配置、useChainId获取当前链,并在未显式传入chainId时自动回退到当前链(L71-L77)。其返回值是基于 TanStack Query 的UseQueryReturnType,因此天然具备 loading、error、data 等状态管理能力。
九、底层调用链与实现原理
从 核心实现 可以梳理出完整的调用链:
- 账户分支判断:若
account为type === 'local'的本地账户(如privateKeyToAccount创建的账户),直接通过config.getClient({ chainId })获取客户端,跳过连接器;否则进入连接器路径。 - 获取连接器客户端:通过
getConnectorClient(config, { account, assertChainId: false, chainId, connector })获取与连接器绑定的 viem 客户端。assertChainId: false意味着允许在目标链与当前连接链不一致时继续处理。 - Action 分发:使用
getAction工具将 viem 的prepareTransactionRequest绑定到客户端上调用(避免重复实例化)。 - 参数透传:将
account(若提供)与原参数一并透传给 viem 实现,由 viem 负责 RPC 读取(nonce、gas、手续费建议值)并组装最终请求。
测试用例(prepareTransactionRequest.test.ts)覆盖了三种典型场景,可作为行为依据:
- 默认场景(连接器 json-rpc 账户):
to+value,返回补齐后的请求; - 显式 account 场景:传入地址字符串时,返回的
account为地址、from为该地址; - 本地账户场景:
privateKeyToAccount(privateKey)构造的本地账户,account返回完整的本地账户对象(含publicKey、sign等),验证了“本地账户不走连接器”的分支逻辑。
十、典型使用流程总结
在实际 dApp 中,建议按以下流程使用:
- 通过
createConfig配置好chains与transports(见配置片段); - 用户连接钱包后,调用
prepareTransactionRequest(config, { to, value, ... })或usePrepareTransactionRequest获取补齐字段的交易请求; - 将返回值交给
sendTransaction等发送类 Action 完成签名与广播; - 如需精细控制,使用
parameters限定补齐的字段子集;如需为特定链准备请求,显式传入chainId。
该 Action 的完整行为还可参考 TanStack Query 集成文档 与 发送交易指南 等仓库内文档,结合使用可获得更完整的交易构建体验。
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考