wagmi Core 交易签名实战:signTransaction Action 完整参数指南与源码解析
2026/9/17 15:18:50 网站建设 项目流程

wagmi Core 交易签名实战:signTransaction Action 完整参数指南与源码解析

【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi

本文面向使用 wagmi 构建以太坊应用的开发者,系统讲解@wagmi/coresignTransactionAction 的完整用法。signTransaction用于创建并签名一笔发往目标网络的交易——注意它只负责签名,并不会把交易广播到链上。读完本文,你将掌握该 Action 的导入方式、全部 13 个参数的语义与类型约束、返回值与错误处理,并能结合源码理解其内部调用链,进而在 React/Vue 等框架中通过 TanStack Query 变体(mutation)落地实际场景。

什么是 signTransaction

signTransaction是 wagmi Core 提供的 Action(action),定义于 packages/core/src/actions/signTransaction.ts,官方定位是 "Action for creating and signing transactions to networks"(创建并签名发往网络的交易)。

它与sendTransaction的核心区别在于:sendTransaction签名后会继续广播交易,而signTransaction在拿到序列化签名结果后即返回,交易是否上链由你自行决定。因此它常用于"离线签名"、待签名交易的批量收集、或者交给第三方 Relay/中继服务广播等场景。

Import(导入方式)

import { signTransaction } from '@wagmi/core'

同时可按需导入配套类型:

import { type SignTransactionParameters, type SignTransactionReturnType, type SignTransactionErrorType, } from '@wagmi/core'

从源码看,这些类型均从 packages/core/src/actions/signTransaction.ts 导出,并通过 packages/core/src/exports/actions.ts 暴露到@wagmi/core顶层入口。

Usage(基本用法)

import { signTransaction } from '@wagmi/core' import { parseEther } from 'viem' import { config } from './config' const result = await signTransaction(config, { to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

其中configcreateConfig创建的配置实例,可参考仓库中站点使用的示例配置 site/snippets/core/config.ts:

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(), }, })

调用时第一个参数始终是config,第二个参数是交易请求参数(SignTransactionParameters)。函数返回一个 Promise,resolve 为序列化(即签名完成)后的交易哈希字符串。

内部执行流程(源码级解析)

signTransaction的实现核心位于 packages/core/src/actions/signTransaction.ts,其流程可分为三步:

  1. 客户端选择:解构出accountchainIdconnector与其余交易参数后,若account是对象且type === 'local'(即本地私钥账户),直接使用config.getClient({ chainId });否则调用getConnectorClient获取连接器客户端。
  2. 链上下文组装:当未传chainId或客户端链 ID 与chainId一致时沿用客户端当前链,否则构造{ id: chainId }占位链对象;随后通过getAction(client, viem_signTransaction, 'signTransaction')取得 viem 的底层 action。
  3. 委托 viem 执行:将参数透传给 viem 的signTransaction,并注入assertChainId: !!chainIdchaingas等字段,最终返回序列化交易字符串。

值得注意的是getConnectorClient阶段(见 packages/core/src/actions/getConnectorClient.ts)会执行多重校验:未找到连接抛ConnectorNotConnectedError;连接器链与目标链不一致抛ConnectorChainMismatchError;指定账户不在连接器账户列表内抛ConnectorAccountNotFoundError;重连期间连接器不可用抛ConnectorUnavailableReconnectingError。这些错误类型共同组成了SignTransactionErrorType

Parameters(参数详解)

以下参数均属于SignTransactionParameters,类型定义见 packages/core/src/actions/signTransaction.ts。需要说明:参数类型会随config的链集合与chainId收窄,这意味着不同链上会暴露该链特有的交易字段(例如 Celo 链的feeCurrency),类型层面即得到保障。

accessList

AccessList | undefined

访问列表(Access List),用于 EIP-2930 类型的交易,可预先声明交易将访问的合约地址与存储槽,帮助降低 gas 成本。

import { signTransaction } from '@wagmi/core' import { parseEther } from 'viem' import { config } from './config' const result = await signTransaction(config, { accessList: [{ address: '0x1', storageKeys: ['0x1'], }], to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

account

Address | Account | undefined

用于签名的账户。可以传地址字符串,也可以传 viem 的Account对象(如privateKeyToAccount生成的本地账户)。文档明确说明:若该账户在connector上不存在,会抛出错误。

import { signTransaction } from '@wagmi/core' import { parseEther } from 'viem' import { config } from './config' const result = await signTransaction(config, { account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

源码中对account的处理是分支的关键:当传入的是type === 'local'的对象时跳过连接器,直接走config.getClient的本地签名路径;而传入地址时则会进入getConnectorClient并校验该地址是否存在于连接器账户中,否则抛出ConnectorAccountNotFoundError(测试用例见 packages/core/src/actions/signTransaction.test.ts)。

chainId

config['chains'][number]['id'] | undefined

签名前用于校验的链 ID。传值时会在调用 viem 时设置assertChainId: true,确保连接器当前链与目标链一致,防止跨链误签。

import { signTransaction } from '@wagmi/core' import { mainnet } from '@wagmi/core/chains' import { parseEther } from 'viem' import { config } from './config' const result = await signTransaction(config, { chainId: mainnet.id, to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

connector

Connector | undefined

指定用于签名的连接器。默认使用当前连接器(即config.state.current对应的连接)。

import { getConnections, signTransaction } from '@wagmi/core' import { parseEther } from 'viem' import { config } from './config' const connections = getConnections(config) const result = await signTransaction(config, { connector: connections[0]?.connector, to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

data

`0x${string}` | undefined

合约方法调用数据,即 ABI 编码后的函数选择器与参数(calldata)。典型用法是先通过encodeFunctionData生成,再传给signTransaction做合约交互签名。

import { signTransaction } from '@wagmi/core' import { parseEther } from 'viem' import { config } from './config' const result = await signTransaction(config, { data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

gas

bigint | undefined | null

为交易执行提供的 gas 上限(单位为 wei)。此参数在源码类型中被显式放宽为可传null(见 packages/core/src/actions/signTransaction.ts),并会在转发给 viem 时通过gas: rest.gas ?? undefined归一化处理。

import { signTransaction } from '@wagmi/core' import { parseEther, parseGwei } from 'viem' import { config } from './config' const result = await signTransaction(config, { gas: parseGwei('20'), to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

gasPrice

bigint | undefined

每单位 gas 的价格(wei)。仅适用于 Legacy 交易(type: 'legacy')。注意gasPrice与 EIP-1559 的maxFeePerGas/maxPriorityFeePerGas互斥,同时传入会在类型层面报错(类型测试见 packages/core/src/actions/signTransaction.test-d.ts)。

import { signTransaction } from '@wagmi/core' import { parseEther, parseGwei } from 'viem' import { config } from './config' const result = await signTransaction(config, { gasPrice: parseGwei('20'), to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

maxFeePerGas

bigint | undefined

每单位 gas 的总费用上限(wei),已包含maxPriorityFeePerGas。仅适用于 EIP-1559 交易(type: 'eip1559')。

import { signTransaction } from '@wagmi/core' import { parseEther, parseGwei } from 'viem' import { config } from './config' const result = await signTransaction(config, { maxFeePerGas: parseGwei('20'), to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

maxPriorityFeePerGas

bigint | undefined

每单位 gas 的最大优先费用(小费,wei)。仅适用于 EIP-1559 交易,通常与maxFeePerGas一起传入。

import { signTransaction } from '@wagmi/core' import { parseEther, parseGwei } from 'viem' import { config } from './config' const result = await signTransaction(config, { maxFeePerGas: parseGwei('20'), maxPriorityFeePerGas: parseGwei('2'), to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

nonce

number

标识这笔交易的唯一序号(nonce)。同一账户下 nonce 必须连续且唯一,签名时显式指定 nonce 可用于实现交易队列、替换(replace)或取消(cancel)等高级场景。

import { signTransaction } from '@wagmi/core' import { parseEther } from 'viem' import { config } from './config' const result = await signTransaction(config, { nonce: 123, to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

to

Address

交易接收方或合约地址(必填字段)。

import { signTransaction } from '@wagmi/core' import { parseEther } from 'viem' import { config } from './config' const result = await signTransaction(config, { to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

type

'legacy' | 'eip1559' | 'eip2930' | undefined

可选的交易请求类型,用于收窄参数类型。传入后,TypeScript 会依据类型校验参数组合的合法性(如type: 'legacy'时不允许再传maxFeePerGas)。

import { signTransaction } from '@wagmi/core' import { parseEther } from 'viem' import { config } from './config' const result = await signTransaction(config, { to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', type: 'eip1559', value: parseEther('0.01'), })

值得补充的是:类型系统不仅支持上述三种,还通过请求字段自动推断更现代的交易形态。例如仅传maxFeePerGas/maxPriorityFeePerGas即被推断为 EIP-1559,传accessList推断为 EIP-2930,传blobVersionedHashes/maxFeePerBlobGas推断为 EIP-4844(Blob 交易),传authorizationList推断为 EIP-7702,并分别对应不同的序列化返回类型TransactionSerializedEIP1559TransactionSerializedEIP2930TransactionSerializedEIP4844TransactionSerializedEIP7702TransactionSerializedLegacy(见 packages/core/src/actions/signTransaction.test-d.ts)。

value

bigint | undefined

随交易发送的金额(wei)。习惯上用 viem 的parseEther等工具函数从人类可读单位转换。

import { signTransaction } from '@wagmi/core' import { parseEther } from 'viem' import { config } from './config' const result = await signTransaction(config, { to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), })

Return Type(返回值)

import { type SignTransactionReturnType } from '@wagmi/core'

返回值为Hash类型——即序列化并签名后的交易哈希字符串(0x开头的十六进制)。它不同于交易哈希(tx hash),而是代表"已签名交易"本身的序列化表示,可直接用于后续的广播操作。从类型定义看,SignTransactionReturnType直接复用 viem 的viem_SignTransactionReturnType<request>,因此具体返回类型会随请求参数的交易类型收窄(Legacy/EIP-1559/EIP-2930/EIP-4844/EIP-7702 各有对应的序列化类型)。

Error(错误处理)

import { type SignTransactionErrorType } from '@wagmi/core'

SignTransactionErrorType由三部分组成(见 packages/core/src/actions/signTransaction.ts):

  • GetConnectorClientErrorType:连接器客户端获取阶段可能抛出的错误,包括ConnectorNotConnectedError(未连接)、ConnectorAccountNotFoundError(账户不在连接器上)、ConnectorChainMismatchError(链不匹配)、ConnectorUnavailableReconnectingError(重连期间不可用);
  • BaseErrorTypeErrorType:wagmi 基础错误类型;
  • viem_SignTransactionErrorType:底层 viem 的签名错误。

仓库测试 packages/core/src/actions/signTransaction.test.ts 验证了三个典型错误场景:

  1. 默认成功路径:连接 Mock Connector 后签名成功,结果匹配signedTransactionRegex
  2. 连接器未连接:传入一个未连接的 connector 时抛出ConnectorNotConnectedError
  3. 账户不存在:传入连接器上不存在的账户地址时抛出ConnectorAccountNotFoundError
  4. 本地账户路径:使用privateKeyToAccount(privateKey)生成的本地账户无需连接器即可完成签名。

框架集成:TanStack Query Mutation

在 React/Vue/Solid 等框架中,你通常不会直接调用signTransaction,而是使用其 TanStack Query mutation 变体(如 React 的useSignTransaction,实现见 packages/react/src/hooks/useSignTransaction.ts)。

框架层类型从wagmi/query导入:

import { type SignTransactionData, type SignTransactionVariables, type SignTransactionMutate, type SignTransactionMutateAsync, SignTransactionMutationOptions, } from 'wagmi/query'

其底层实现signTransactionMutationOptions位于 packages/core/src/query/signTransaction.ts,核心逻辑是:

mutationFn(variables) { return signTransaction(config, variables as any) }, mutationKey: ['signTransaction'],

也就是说,所有 mutation 变体最终都会调用本文讲解的signTransactionaction,并固定使用['signTransaction']作为 mutation key。mutation 相关约定(SignTransactionData对应返回值、SignTransactionVariables对应参数、SignTransactionMutate/SignTransactionMutateAsync对应同步/异步触发函数)详见共享文档 site/shared/mutation-imports.md。

与 viem 的关系

signTransaction是对 viem 同名 actionsignTransaction的 wagmi 封装。从源码可见,实现通过getAction(client, viem_signTransaction, 'signTransaction')获取 viem action 并透传参数,同时额外处理了连接器客户端、链 ID 校验与账户解析等 wagmi 层逻辑。因此,两者参数语义保持一致——若你已熟悉 viem 的signTransaction,迁移到 wagmi 只需补充config参数即可。

小结

  • signTransaction(config, parameters)只签名不广播,返回序列化签名交易;
  • 参数覆盖 EIP-1559/2930/4844/7702 与 Legacy 多种交易形态,类型系统会根据type与请求字段自动收窄并校验参数组合;
  • 账户可来自连接器(需已连接且账户存在)或本地Account对象(无需连接器);
  • 错误类型集中于连接器客户端获取阶段,可用SignTransactionErrorType统一处理;
  • 框架层推荐通过 TanStack Query mutation 变体(如useSignTransaction)使用,底层与 action 完全一致。

【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询