Wagmi SolidJS useWriteContractSync 详解:执行合约写操作并同步等待确认回执
2026/9/17 11:58:01 网站建设 项目流程

Wagmi SolidJS useWriteContractSync 详解:执行合约写操作并同步等待确认回执

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

本篇指南围绕 Wagmi 的 SolidJS 适配包@wagmi/solid中的useWriteContractSync原语展开:它是用于执行合约写函数并等待交易被打包进区块的响应式原语,成功后返回完整的TransactionReceipt而非单纯的交易哈希。读完本文,你将掌握它的导入与完整用法、mutation全部可选参数、返回类型的每一项含义,以及它在 Solid 响应式体系下的底层实现链路(从原语到@wagmi/core的 mutation 选项与 action 实现),并能据此在 SolidJS 应用里可靠地发起、确认和回滚合约写操作。

一、useWriteContractSync 是什么

useWriteContractSync是一个用于在 SolidJS 组件中执行合约写函数的 primitive,与useWriteContract的关键区别在于:

  • 同步语义:它会等待交易被包含进区块(in-block)之后才 resolve;
  • 返回值不同:成功时data是一个TransactionReceipt(包含statusblockNumbergasUsed等完整回执信息),而useWriteContract只返回交易哈希。

这意味着如果你需要"写完立刻知道结果"的场景——例如确认 mint 是否成功、读取status判断回滚——useWriteContractSync是更合适的选择。

二、导入与基础用法

导入

import { useWriteContractSync } from '@wagmi/solid'

使用示例

import { useWriteContractSync } from '@wagmi/solid' import { abi } from './abi' function App() { const writeContractSync = useWriteContractSync() const handleMint = () => { writeContractSync.mutate({ abi, address: '0x6b175474e89094c44da98b954eedeac495271d0f', functionName: 'mint', }) } // writeContractSync.data contains the TransactionReceipt when successful }

配套的WagmiProvider需要一个config(参见仓库中的示例 config.ts):

import { createConfig, http } from '@wagmi/solid' import { mainnet, sepolia } from '@wagmi/solid/chains' export const config = createConfig({ chains: [mainnet, sepolia], transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, })

注意:mutate的 variables 中,abiaddressfunctionNameargs等具体参数的取值规则与校验方式与 core 层的writeContractSyncaction 保持一致(abifunctionNameargsvalue等字段的完整说明见该文档)。

三、Parameters(参数)

import { useWriteContractSync } from '@wagmi/solid' useWriteContractSync.Parameters useWriteContractSync.SolidParameters

参数以getter 函数(accessor)的形式传入,以维持 Solid 的响应式追踪——组件内parameters()依赖的响应式源变化时,mutation 选项会被重新计算。

config

Config | undefined

用于替代从最近的WagmiProvider中获取的Config

mutation

TanStack Query mutation 参数。注意:Wagmi 不支持传入全部 TanStack Query 参数——mutationFnmutationKey等由 Wagmi 内部接管(内部固定为mutationKey: ['writeContractSync'],见 writeContractSyncMutationOptions),不可覆盖。以下列出的参数均受支持:

参数类型说明
gcTimenumber \| Infinity \| undefined未使用/失活的 mutation 缓存数据在内存中保留的毫秒数;缓存失活后超过该时长即被回收,多处指定时取最长值;设为Infinity可禁用垃圾回收
metaRecord<string, unknown> \| undefined若设置,会在 mutation 缓存条目上附加额外信息,可在所有mutate可用处(如onErroronSuccess)访问
networkMode'online' \| 'always' \| 'offlineFirst' \| undefined默认'online',控制 mutation 的网络执行模式
onError(error, variables, context?) => unknown \| Promise<unknown>mutation 出错时触发,接收错误对象
onMutate(variables) => context \| voidmutation 执行前触发,适合做乐观更新;返回值会传递给onErroronSettled,便于回滚
onSuccess(data, variables, context?) => unknown \| Promise<unknown>mutation 成功时触发,接收 mutation 结果(本例中即TransactionReceipt
onSettled(data, error, variables, context?) => unknown \| Promise<unknown>无论成功还是出错都会触发
queryClientQueryClient指定自定义QueryClient,否则使用最近上下文中的实例
retryboolean \| number \| ((failureCount, error) => boolean)默认0false不重试,true无限重试,数字则重试至失败次数达到该值
retryDelaynumber \| ((retryAttempt, error) => number)返回下一次重试前的延迟毫秒数,可实现指数/线性退避

mutate 的 variables

mutate/mutateAsync的第一参对象即WriteContractSyncVariables,其类型定义见 WriteContractSyncVariables,继承自 core action 的WriteContractSyncParameters(见 writeContractSync.ts)。除了上述示例中的abiaddressfunctionNameargs外,还支持:

  • chainId:指定目标链,默认为当前连接的链;
  • connector:指定使用哪个 connector 发起交易;
  • account:指定签名账户(local account 时直接走 config 的 client);
  • value:调用 payable 函数时随交易附带的 ETH 数量。

四、Return Type(返回类型)

import { useWriteContractSync } from '@wagmi/solid' useWriteContractSync.ReturnType

返回类型的data属性是TransactionReceipt,包含已确认交易的完整回执(statusblockNumberblockHashlogs等)。其余字段为标准 TanStack Query mutation 结果,且均为 Solid 响应式信号,可在组件模板中直接绑定:

成员类型说明
mutate(variables, { onSuccess, onSettled, onError }) => void触发 mutation,可附带一次性回调
mutateAsync(variables, { onSuccess, onSettled, onError }) => Promise<TData>mutate相同但返回可 await 的 Promise
dataTransactionReceipt \| undefined最近一次成功 resolve 的数据,默认undefined
errorWriteContractSyncErrorType \| null最近一次错误的对象
failureCountnumber失败次数,成功时重置为0
failureReasonWriteContractSyncErrorType \| null失败原因,成功时重置为null
isError/isIdle/isPending/isSuccessbooleanstatus派生的布尔信号
isPausedbooleanmutation 处于paused状态时为true
reset() => void将 mutation 内部状态重置为初始状态
status'idle' \| 'pending' \| 'error' \| 'success'当前状态:初始 / 执行中 / 上次失败 / 上次成功
submittedAtnumber提交时间戳,默认0
variablesTVariables \| undefined最近一次传给mutate的 variables

此外,返回对象上还保留了两个已弃用的便捷别名(源码中标注@deprecated,见 useWriteContractSync.ts):writeContractSync(等价mutate)与writeContractSyncAsync(等价mutateAsync),新代码请统一使用mutate/mutateAsync

五、类型推断

abi设置正确时,TypeScript 会针对mutate/mutateAsync自动推断出functionNameargsvalue的精确类型——例如functionName只能是 ABI 中nonpayable | payable的函数名,args会按函数签名给出元组类型。mutate的类型签名定义在 WriteContractSyncMutate,其中abi使用了const泛型修饰符以保证字面量 ABI 不被拓宽。更多细节见 Wagmi TypeScript 文档。

错误类型同样有完整推断:WriteContractSyncErrorType覆盖getConnectorClient()错误、base 错误与 viem 层错误三类(见 WriteContractSyncErrorType)。

六、源码实现链路:从 Solid 原语到 viem

结合仓库源码,可以完整还原这条调用链:

1. Solid 原语层

useWriteContractSync.ts 的实现非常简洁:

export function useWriteContractSync(parameters = () => ({})) { const config = useConfig(parameters) const mutation = useMutation(() => writeContractSyncMutationOptions(config(), parameters()), ) return mergeProps(mutation, { /* 弃用别名 writeContractSync / writeContractSyncAsync */ }) }
  • 参数默认值是() => ({})这样的 accessor,配合useConfig(parameters)writeContractSyncMutationOptions(config(), parameters()),使得 config 与 mutation 选项都保持响应式;
  • 最终通过 Solid 的mergeProps把 mutation 结果铺平成对象返回,让调用方拿到一组可直接在模板中使用的响应式属性。

2. Core mutation 选项层

writeContractSyncMutationOptions 负责组装 TanStack Query 的 mutation 配置:

return { ...(options.mutation as any), mutationFn(variables) { return writeContractSync(config, variables) }, mutationKey: ['writeContractSync'], }

用户的mutation回调(onSuccessretry等)通过展开合并进来,而mutationFnmutationKey被固定为调用 core 的writeContractSyncaction——这也解释了文档中"不支持覆盖全部 TanStack Query 参数"的说明。

3. Core action 层:客户端选择与"同步等待"

writeContractSync 是真正执行写操作的 action,核心逻辑分三步:

  1. 选择 client:若显式传入的account是 local 账户(account.type === 'local'),直接用config.getClient({ chainId });否则走getConnectorClient,即要求存在已连接的 connector——这是使用写操作的前提:
    if (typeof account === 'object' && account?.type === 'local') client = config.getClient({ chainId }) else client = await getConnectorClient(config, { account, assertChainId: false, chainId, connector })
  2. 对齐 chain:当chainId与 client 链不一致时,构造仅含id的最小 chain 对象,并设置assertChainId: !!chainId,避免跨链断言失败;
  3. 委托 viem:通过getAction(client, viem_writeContractSync, 'writeContractSync')调用 viem 的同名 action。viem 的writeContractSync内部会发送交易后轮询等待回执(等待交易被打包),因此返回值WriteContractSyncReturnTypeTransactionReceipt
    export type WriteContractSyncReturnType = viem_WriteContractSyncReturnType

这正是文档中"等待交易被包含进区块后才 resolve,返回TransactionReceipt而非交易哈希"这一行为差异的底层来源。

七、测试用例中的行为验证

仓库中的运行时测试 useWriteContractSync.test.ts 完整覆盖了"等待回执"这一语义:

  1. connect(config, { connector })建立连接(验证写操作依赖连接态);
  2. renderPrimitive(() => useWriteContractSync())渲染原语后调用result.mutate({ abi, address, functionName: 'mint' })
  3. testClient.mainnet.mine({ blocks: 1 })主动产出一个区块,随后vi.waitUntil(() => result.isSuccess)等待成功;
  4. 断言result.data?.status === 'success'result.data?.blockNumber有定义——直接证明了data是完整回执而非哈希。

类型层测试 useWriteContractSync.test-d.ts 则逐一锁定了各回调的类型:onSuccessdataTransactionReceiptonErrorerrorWriteContractSyncErrorTypeonMutate返回的context会正确流转给onError/onSettled,与上文参数表的描述一一对应。

八、可用的 TanStack Query 类型

如需在回调中显式标注类型,可从@wagmi/solid/query导入(该模块由 query 导出 统一提供,测试 query.test.ts 确认了writeContractSyncMutationOptions在导出列表中):

import { type WriteContractSyncData, type WriteContractSyncVariables, type WriteContractSyncMutate, type WriteContractSyncMutateAsync, writeContractSyncMutationOptions, } from '@wagmi/solid/query'

九、使用注意事项与适用限制

  • 必须已连接:非 local 账户场景下交易经由getConnectorClient发起,未连接 wallet 时会抛出GetConnectorClientErrorType错误,UI 中应先用useConnect/useConnection处理连接状态;
  • useWriteContract的取舍:只关心"交易已发送"用useWriteContract(更快返回 hash);需要确认执行结果、读取回执日志或status时用useWriteContractSync
  • retry的谨慎使用:写操作天然不幂等,retry: true或较大的重试次数可能造成重复提交,建议配合onMutate乐观更新 +onError回滚的模式管理状态;
  • 弃用别名writeContractSync/writeContractSyncAsync属性已标记弃用,升级代码时替换为mutate/mutateAsync即可。

小结

useWriteContractSync以 Solid accessor 参数 + TanStack Query mutation 的形态,把 core 层"发送交易并等待回执"的能力封装成了响应式原语:mutate发起写调用,isPending/isSuccess驱动 UI 状态,data直接提供可断言的TransactionReceipt。从 solid 原语实现、到 core mutation 选项、再到 core action 的 client 选择与 viem 委托,整条链路在仓库源码中均有清晰对应,便于按需深入排查连接、跨链或类型推断相关问题。

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

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

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

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

立即咨询