wagmi Vue 组合式函数 useWriteContract 实战:在 Vue 3 中安全地执行合约写交易

发布时间:2026/9/18 23:23:08

wagmi Vue 组合式函数 useWriteContract 实战:在 Vue 3 中安全地执行合约写交易 wagmi Vue 组合式函数 useWriteContract 实战在 Vue 3 中安全地执行合约写交易【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmiuseWriteContract是wagmi/vue提供的核心组合式函数Composable用于在 Vue 3 应用中调用 Solidity 合约的「写」函数write function并广播交易。本文以 useWriteContract 官方文档 为主线结合仓库源码useWriteContract.ts、writeContract.ts 等逐层拆解它的用法、参数、返回值与底层实现帮助你写出类型安全、可处理状态与错误、可复用的链上写入逻辑。什么是「写函数」为什么需要广播交易Solidity 合约中的函数分为两类view/pure等「读」函数不改变链上状态调用后直接返回结果而「写」函数如transferFrom、approve、mint会修改区块链状态。因为状态变更需要全网共识与矿工打包这类调用必须消耗 Gas并以广播一笔交易的方式执行。useWriteContract正是为这类场景设计它接收合约 ABI、合约地址、函数名与参数通过已连接的账户签名并广播交易最终返回交易哈希Hash——交易被确认打包还需要额外等待详见下文「等待交易上链」。安装与导入useWriteContract属于wagmi/vue包直接导入即可import { useWriteContract } from wagmi/vue使用它之前应用需要先完成两件准备工作使用 createConfig 创建链配置chains 与 transports将配置通过 WagmiPlugin 注入应用例如// config.ts import { createConfig, http } from wagmi/vue import { mainnet, sepolia } from wagmi/vue/chains export const config createConfig({ chains: [mainnet, sepolia], transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, })// main.ts import { WagmiPlugin } from wagmi/vue import { createApp } from vue import { config } from ./config import App from ./App.vue createApp(App).use(WagmiPlugin, { config }).mount(#app)基本用法在组件中触发一笔合约写交易以下示例调用 ERC-20 合约的transferFrom授权转账完整的 abi.ts 与 config.ts 可在仓库中找到!-- index.vue -- script setup langts import { useWriteContract } from wagmi/vue import { abi } from ./abi const writeContract useWriteContract() /script template button clickwriteContract.mutate({ abi, address: 0x6b175474e89094c44da98b954eedeac495271d0f, functionName: transferFrom, args: [ 0xd2135CfB216b74109775236E36d4b433F1DF507B, 0xA0Cf798816D4b9b9866b5330EEa46a18382f251e, 123n, ], }) Transfer /button /template其中 abi.ts 定义了approve与transferFrom两个函数的签名注意使用as const断言以保证类型推断详见「类型推断」一节export const abi [ { type: function, name: approve, stateMutability: nonpayable, inputs: [ { name: spender, type: address }, { name: amount, type: uint256 }, ], outputs: [{ type: bool }], }, { type: function, name: transferFrom, stateMutability: nonpayable, inputs: [ { name: sender, type: address }, { name: recipient, type: address }, { name: amount, type: uint256 }, ], outputs: [{ type: bool }], }, ] as const几个关键点金额使用bigint字面量示例中123n是123 wei避免 JavaScriptnumber的精度丢失大额 ETH 可配合 viem 的parseEther(0.01)转换mutate(variables)触发交易把合约调用参数传给mutate后组合式函数内部会完成「获取连接器客户端 → 签名 → 广播」的完整流程返回的是交易哈希而非回执data中是0x...形式的哈希区块确认结果需配合waitForTransactionReceipt获取见下文。参数详解useWriteContract接受一个UseWriteContractParameters对象import { type UseWriteContractParameters } from wagmi/vue从源码看其类型定义为ConfigParameterconfig WriteContractOptionsconfig, context见 useWriteContract.ts即「config 参数 合约调用参数 TanStack Query 的 mutation 参数」。configConfig | undefined指定要使用的 Config 实例覆盖从 WagmiPlugin 中检索到的默认配置。适合测试、多配置并存或需要在组合式函数外部控制配置的场景script setup langts import { useWriteContract } from wagmi/vue import { config } from ./config // [!code focus] const writeContract useWriteContract({ config, // [!code focus] }) /script若不传则通过useConfig从插件上下文自动获取——这是 useWriteContract 内部的第一步。mutationTanStack Query 参数组合式函数内部基于tanstack/vue-query的useMutation实现因此大部分 TanStack Query 的 mutation 参数都可用类型为WriteContractOptions见 query/writeContract.ts注意mutationFn与mutationKey被 Wagmi 内部占用分别绑定writeContractaction 与[writeContract]键不可覆盖其余参数均支持参见 utils/query.ts 中OmitmutationFn | mutationKey | throwOnError的定义。参数类型说明gcTimenumber \| Infinity \| undefined未使用/非活跃缓存数据的存活毫秒数到期后被垃圾回收设为Infinity禁用回收metaRecordstring, unknown \| undefined附加到 mutation 缓存条目的元信息可在onError/onSuccess等回调中读取networkModeonline \| always \| offlineFirst \| undefined网络模式默认onlineonError(error, variables, context?) ...mutation 出错时触发接收错误对象onMutate(variables) ...mutation 函数执行前触发可用于乐观更新返回值会传给onError/onSettled以便回滚onSuccess(data, variables, context?) ...mutation 成功时触发接收结果onSettled(data, error, variables, context?) ...mutation 无论成功或失败都会触发queryClientQueryClient自定义QueryClient否则使用最近上下文中的实例retryboolean \| number \| ((failureCount, error) boolean) \| undefined失败重试次数默认0true无限重试数字表示最多重试次数retryDelaynumber \| ((retryAttempt, error) number) \| undefined重试前等待毫秒数可用attempt Math.min(2 ** attempt * 1000, 30_000)实现指数退避完整说明见共享文档 mutation-options.md。合约调用参数action 层除config与 mutation 参数外mutate的变量对象WriteContractVariables还包含完整的合约调用参数它们与wagmi/core的 writeContract action 参数一一对应此处先列出最常用的一组完整参考见下文「交易参数完整参考」参数类型说明abiAbi合约 ABIas const声明可获得最强类型推断addressAddress合约地址functionNamestring要调用的合约函数名由abi推断argsreadonly unknown[] \| undefined传给函数的参数由abi与functionName推断chainIdconfig[chains][number][id] \| undefined发送交易前校验的链 IDvaluebigint \| undefined随交易发送的 wei 金额如parseEther(0.01)返回值详解import { type UseWriteContractReturnType } from wagmi/vue返回对象是 TanStack QueryuseMutation结果的增强版本并额外提供两个已废弃别名见「底层原理」包含属性类型说明mutate(variables, options?) void触发 mutation可传onSuccess/onError/onSettled回调mutateAsync(variables, options?) PromiseTData与mutate类似但返回可await的 PromisedataTData \| undefined最近一次成功的结果即交易哈希0x...errorTError \| nullmutation 的错误对象failureCountnumber失败计数每次失败 1成功归零failureReasonTError \| null失败重试的原因成功时重置为nullisError/isIdle/isPending/isSuccessboolean由status派生的布尔状态isPausedbooleanmutation 是否被网络模式暂停reset() void重置 mutation 内部状态statusidle \| pending \| error \| success核心状态idle初始 →pending执行中 →error/successsubmittedAtnumbermutation 提交时间戳默认0variablesTVariables \| undefined最近一次传给mutate的变量对象完整说明见共享文档 mutation-result.md。在实际组件中常用isPending控制按钮 loading、error展示失败信息template div button :disabledwriteContract.isPending.value clickonTransfer {{ writeContract.isPending.value ? 确认中… : Transfer }} /button p v-ifwriteContract.error.value {{ writeContract.error.value.shortMessage }} /p p v-ifwriteContract.data.value Hash: {{ writeContract.data.value }} /p /div /template注意在 Vue 模板中tanstack/vue-query返回的是ref 包裹的响应式值模板中直接访问会被自动解包在script setup中则需通过.value读取。TypeScript 类型推断让编译器替你把关只要abi以as const正确声明参考 abi-write.tsTypeScript 就会自动推断出functionName只能是 ABI 中存在的函数名args数量、顺序、类型与所选函数签名严格一致例如transferFrom要求[address, address, uint256]value等参数的合法性校验。这意味着拼错函数名、传错参数类型都会在编译期直接报错。data的类型同样可通过abifunctionNameargs的组合推断出来详见 TypeScript 文档。此外若需要显式引用类型可以从wagmi/vue/query导入参考 mutation-imports.md 的模板模式import { type WriteContractData, type WriteContractVariables, type WriteContractMutate, type WriteContractMutateAsync, WriteContractMutationOptions, } from wagmi/vue/query底层原理从组合式函数到链上交易useWriteContract的整个实现非常精简useWriteContract.tsexport function useWriteContractconfig extends Config, context unknown( parameters: UseWriteContractParametersconfig, context {}, ): UseWriteContractReturnTypeconfig, context { const config useConfig(parameters) // 1. 取配置默认来自插件 const options writeContractMutationOptions(config, parameters) // 2. 组装 mutation 选项 const mutation useMutation(options) // 3. 交给 TanStack Vue Query return { ...(mutation as Return), writeContract: mutation.mutate, // 4. 兼容别名已废弃 writeContractAsync: mutation.mutateAsync, // 4. 兼容别名已废弃 } }对应的writeContractMutationOptionsquery/writeContract.ts把变量直接桥接到 core actionreturn { ...(options.mutation as any), mutationFn(variables) { return writeContract(config, variables) // 调用 wagmi/core 的 writeContract }, mutationKey: [writeContract], }而 core 层的writeContractactionactions/writeContract.ts核心调用链为判断account是否为local类型账户是则直接config.getClient({ chainId })否则通过getConnectorClient获取当前连接器MetaMask、WalletConnect 等对应的 viemClient校验chainId若传入与当前链是否一致构造chain上下文通过getAction(client, viem_writeContract, writeContract)复用 viem 的writeContract完成编码 calldata、估算 Gas、签名并广播返回交易哈希。因此整个调用链为Vue 组件 →useWriteContract→writeContractMutationOptions→wagmi/core的writeContract→ viem 的writeContract→ 连接器签名广播。两个值得注意的实现细节返回对象中额外暴露了writeContract与writeContractAsync两个别名源码中已标注deprecated请统一使用mutate/mutateAsyncWriteContractMutate泛型用functionName收窄了变量联合类型确保mutate调用时 args 精确匹配所选函数见 query/writeContract.ts 的注释说明。交易参数完整参考以下参数均可在mutate的变量对象中传入与 writeContract action 对齐参数类型说明abiAbi合约 ABI类型推断的核心addressAddress合约地址functionNamestring要调用的函数名nonpayable/payable由abi推断argsreadonly unknown[] \| undefined调用参数由abi与functionName推断chainIdnumber \| undefined发送前校验的链 IDconnectorConnector \| undefined用于签名的连接器默认取当前连接可用getConnection(config)获取accountAddress \| Account \| undefined签名账户若指定了本地账户则走本地客户端路径gasbigint \| undefined交易执行提供的 Gas 上限如parseGwei(20)gasPricebigint \| undefined每单位 Gas 价格仅 Legacy 交易maxFeePerGasbigint \| undefined总费用上限含优先费仅 EIP-1559 交易maxPriorityFeePerGasbigint \| undefined最大优先费仅 EIP-1559 交易noncenumber标识该交易的唯一序号typelegacy \| eip1559 \| eip2930 \| undefined可选的交易类型用于收窄参数valuebigint \| undefined随交易发送的 wei 金额accessListAccessList \| undefinedEIP-2930 访问列表dataSuffix0x${string} \| undefined附加到 calldata 末尾的数据如 Seaport 的 domain tag实战组合模拟 → 写入 → 等待确认官方建议将simulateContract与writeContract配对使用先用simulateContract在本地验证交易是否会成功不消耗 Gas成功后再真正广播。结合等待交易确认一个完整的 Vue 组合式示例为script setup langts import { useSimulateContract, useWriteContract } from wagmi/vue import { waitForTransactionReceipt } from wagmi/vue/actions import { abi } from ./abi import { config } from ./config const { data } useSimulateContract({ abi, address: 0x6b175474e89094c44da98b954eedeac495271d0f, functionName: transferFrom, args: [ 0xd2135CfB216b74109775236E36d4b433F1DF507B, 0xA0Cf798816D4b9b9866b5330EEa46a18382f251e, 123n, ], }) const { writeContractAsync } useWriteContract() async function onTransfer() { try { // 1. 模拟确认交易会成功 const { request } data.value! // 2. 广播交易得到哈希 const hash await writeContractAsync(request) // 3. 等待交易上链拿到回执 const receipt await waitForTransactionReceipt(config, { hash }) console.log(Transaction confirmed:, receipt.transactionHash) } catch (error) { console.error(Transaction failed:, error) } } /scriptsimulateContract返回的request可直接透传给writeContract这是官方推荐的稳健模式相关用法详见 core actions 文档。延伸阅读组合式函数源码useWriteContract.tscore action 实现与完整参数actions/writeContract.ts 与 writeContract action 文档mutation 桥接层query/writeContract.ts共享文档mutation-options.md、mutation-result.md、mutation-imports.md示例代码片段abi-write.ts、vue/config.ts类型安全配置指南TypeScript 文档【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/18 23:18:08

oh-my-hermes:统一 Hermes 配置管理,让 React Native 性能优化更简单

1. 项目缘起:为什么我会折腾一套 Hermes 配置管理方案先交代一下背景。我一直在做 React Native 相关的性能优化工作,接触 Hermes 引擎其实比大多数人要早。Hermes 是 Facebook 专门为 React Native 打造的那套 JavaScript 引擎,它在 Android…

2026/9/18 23:18:08

UE高级运动系统实战:数据流、动画融合与性能优化

1. 先把"高级运动系统"的边界划清楚1.1 高级运动系统究竟在解决什么问题刚接触 UE高级运动系统 的人,十有八九是被那种"转身会甩腿、跑动会压身、上下坡脚步能贴地"的角色手感吸引过来的。但真把工程拖进编辑器跑起来,往往第一反应是…

2026/9/19 0:08:11

Docker Desktop 设置转圈?WSL 后端与配置清理排查指南

点开 Docker Desktop 的齿轮图标,转圈转到你以为电脑死机——这事我遇到过不止一次。第一次碰上的时候我还在赶一个交付,容器跑得好好的,就是想改个镜像源,结果 Settings 页面那个加载动画转了整整八分钟没停。后来查日志、翻 iss…

2026/9/19 0:08:10

Docker Compose编排PostgreSQL、Chat2DB与监控栈

1. 单机场景下,为什么我依然离不开 docker-compose刚接触容器那会儿,我也觉得docker run敲一长串参数挺酷,直到某天要在本地拉起一套 PostgreSQL 加 Chat2DB 的数据开发环境,命令写完自己都记不住,第二天重启机器还得翻…

2026/9/19 0:08:10

UEditor在信创环境下导入Word文档的适配方案与踩坑记录

“百度UE”这个叫法我一听就知道,说的是百度开源的 UEditor——也就是那个在很多老后台管理系统里用了十多年的富文本编辑器。最近接了个国产化适配的活儿,客户给的验收清单里白纸黑字写着“支持在信创环境下导入 Word 文档”,第一反应就是拿…

2026/9/19 0:03:10

SYB创业计划书财务逻辑拆解:从销售收入预测到现金流量计划

简介:SYB创业计划书完整版.doc 是一份面向创业者、备赛学生及有开店打算人群的实用模板,以一家社区日用超市为案例,围绕企业概况、创业者个人情况、市场评估、市场营销计划、企业组织结构、固定资产、流动资金、销售收入预测、销售和成本计划…

2026/9/18 14:13:01

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/19 0:03:10

验证 OpenSpec 兼容性,Cursor 的 Token 从 TaoToken 出

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 0:03:10

书桌角落的 Mac mini,OpenClaw 通过 TaoToken 跑任务。

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/19 0:03:10

oh-my-hermes:打造跨工具的命令编排与插件化工作流

1. 项目概述与设计初衷1.1 它到底是什么先说结论:oh-my-hermes 是一个面向开发者日常终端操作的效率工具套件,核心定位是“把分散在各类命令行工具里的高频操作,统一收拢成一套插件化、可编排的工作流”。项目灵感来源很明显——oh-my-zsh 重…

2026/9/18 14:13:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/18 14:13:02

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/18 14:13:02

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码