ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Wagmi Vue 合约写入实战:用 useWriteContract 与 useWaitForTransactionReceipt 实现 Mint NFT 表单

Wagmi Vue 合约写入实战:用 useWriteContract 与 useWaitForTransactionReceipt 实现 Mint NFT 表单 Wagmi Vue 合约写入实战用 useWriteContract 与 useWaitForTransactionReceipt 实现 Mint NFT 表单【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi本文是一篇面向 Vue 3 开发者的实战指南讲解如何基于 Wagmi当前仓库中的wagmi/vue包在 DApp 中调用智能合约的写入write函数通过useWriteContract与useWaitForTransactionReceipt两个 Composable 从零构建一个可运行的「Mint NFT」表单完整覆盖表单提交、交易广播、加载状态、交易确认与错误处理。读完本文你将掌握合约写入的完整调用链从 Vue 组件到 viem 底层 Action并理解各 Composable 的返回值与参数语义能够直接迁移到转账、质押、兑换等任意合约写入场景。一、什么是「写入合约」在 Solidity 中合约函数分为两类view / pure读取函数只读取链上状态不消耗 Gas不产生交易nonpayable / payable写入函数修改区块链状态需要消耗 Gas因此会广播一笔交易来改变状态。Wagmi 的useWriteContract正是用来执行这类「写入函数」的 Composable。由于写入最终以交易形式广播它的使用方式与发送交易指南中的useSendTransaction高度相似——两者的底层都是一次交易签名与广播流程。本指南以「Mint NFT」为例用户输入一个tokenIduint32点击 Mint 按钮后调用合约的mint(tokenId)函数。示例建立在连接钱包指南基础之上并使用两个 ComposableComposable职责useWriteContract构建并广播合约写入交易返回交易哈希useWaitForTransactionReceipt根据交易哈希等待链上回执反馈确认状态二、前置准备连接钱包写入合约必须由已连接的钱包账户签名并广播所以请先完成连接钱包指南中的配置创建config.ts通过createConfig声明chains、connectors如injected()、metaMask()、walletConnect({ projectId })与transports在应用入口main.ts中注入WagmiPlugin携带config与VueQueryPluginuseWriteContract基于 TanStack Vue Query 的useMutation实现必须注入编写Connect.vue/Connection.vue通过useConnect、useConnection、useDisconnect完成连接/断开展示。下文所有组件均在「已连接钱包」的前提下使用。三、创建 MintNft 组件先创建MintNft.vue包含一个携带tokenId输入框的表单script setup langts /script template form input nametokenId placeholder69420 required / button typesubmitMint/button /form /template四、添加表单提交处理器给表单绑定submit.preventsubmit在处理器中从FormData中取出用户输入的tokenIdscript setup langts function submit(event: Event) { const formData new FormData(event.target as HTMLFormElement) const tokenId formData.get(tokenId) as string } /script template form submit.preventsubmit input nametokenId placeholder69420 required / button typesubmitMint/button /form /template这一步骤中tokenId仍是以字符串形式从表单读取的真正的「合约调用」在下一步完成。五、接入 useWriteContract 发送交易从wagmi即wagmi/vue导入useWriteContract并在submit中调用它返回的writeContract函数script setup langts import { useWriteContract } from wagmi import { abi } from ./abi const { data: hash, writeContract } useWriteContract() function submit(event: Event) { const formData new FormData(event.target as HTMLFormElement) const tokenId formData.get(tokenId) as string writeContract({ address: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2, abi, functionName: mint, args: [BigInt(tokenId)], }) } /script template form submit.preventsubmit input nametokenId placeholder69420 required / button typesubmitMint/button div v-ifhashTransaction Hash: {{ hash }}/div /form /template配套的abi.ts只需声明用到的mint函数export const abi [ { name: mint, type: function, stateMutability: nonpayable, inputs: [{ internalType: uint32, name: tokenId, type: uint32 }], outputs: [], }, ] as const5.1 核心参数说明参数类型说明addressAddress目标合约地址示例为 CryptoKitties 相关的 NFT 合约地址0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2abiAbi合约 ABI建议使用as const断言以获得完整类型推断functionName字符串要调用的合约函数名如mint类型上被约束为 ABI 中nonpayable \| payable的函数args数组函数入参顺序与 ABI 声明一致数值类型需用BigInt转换args: [BigInt(tokenId)]value可选bigint调用payable函数时随交易发送的 ETH 数量chainId可选数字指定目标链不传则使用当前连接链connector可选Connector指定使用的连接器account可选Account指定签名账户5.2 源码视角useWriteContract 做了什么从源码看useWriteContract本质是对 TanStack Vue QueryuseMutation的一层封装见 packages/vue/src/composables/useWriteContract.ts内部通过writeContractMutationOptions生成 mutation 配置其中mutationKey: [writeContract]mutationFn直接调用wagmi/core的writeContractAction见 packages/core/src/query/writeContract.ts返回对象在展开useMutation结果的同时额外暴露了writeContract等价于mutate与writeContractAsync等价于mutateAsync两个别名源码注释标注二者为 deprecated建议优先使用mutate/mutateAsync返回值中的data即交易哈希0x...isPending表示交易签名请求是否正在等待钱包确认。wagmi/core层的writeContractAction见 packages/core/src/actions/writeContract.ts执行真正的调用链当未显式传入本地账户时通过getConnectorClient获取已连接钱包的 viem Client随后调用 viem 的writeContract完成eth_sendTransaction广播最终返回交易哈希。这也解释了为什么本指南与「发送交易」指南流程相似——写入合约的内部机制就是发送一笔交易。在仓库的单元测试 packages/vue/src/composables/useWriteContract.test.ts 中可以看到同样的调用范式先connect连接测试连接器再result.mutate({ abi, address, functionName: mint })随后waitFor(result.isSuccess)并断言result.data.value有值验证了「先连接钱包 → mutate 广播 → data 得到哈希」这一完整链路。六、添加加载状态可选钱包签名需要用户确认期间可以禁用按钮并显示「Sending...」提示。useWriteContract返回的isPending即表示交易正在等待签名script setup langts import { useWriteContract } from wagmi import { abi } from ./abi const { data: hash, isPending, writeContract } useWriteContract() function submit(event: Event) { const formData new FormData(event.target as HTMLFormElement) const tokenId formData.get(tokenId) as string writeContract({ address: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2, abi, functionName: mint, args: [BigInt(tokenId)], }) } /script template form submit.preventsubmit input nametokenId placeholder69420 required / button :disabledisPending typesubmit span v-ifisPendingSending.../span span v-elseSend/span /button div v-ifhashTransaction Hash: {{ hash }}/div /form /template七、等待交易回执可选交易广播成功后还需等待链上打包确认。将上一步拿到的hash传给useWaitForTransactionReceipt即可获得确认状态script setup langts import { useWaitForTransactionReceipt, useWriteContract } from wagmi import { abi } from ./abi const { data: hash, isPending, writeContract } useWriteContract() function submit(event: Event) { const formData new FormData(event.target as HTMLFormElement) const tokenId formData.get(tokenId) as string writeContract({ address: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2, abi, functionName: mint, args: [BigInt(tokenId)], }) } const { isLoading: isConfirming, isSuccess: isConfirmed } useWaitForTransactionReceipt({ hash, }) /script template form submit.preventsubmit input nametokenId placeholder69420 required / button :disabledisPending typesubmit span v-ifisPendingSending.../span span v-elseSend/span /button div v-ifhashTransaction Hash: {{ hash }}/div div v-ifisConfirmingWaiting for confirmation.../div div v-ifisConfirmedTransaction Confirmed!/div /form /template这里通过解构重命名将查询的isLoading/isSuccess分别映射为isConfirming/isConfirmed语义更贴合业务。与useWriteContract不同useWaitForTransactionReceipt是**查询型Query**Composable其实现见 packages/vue/src/composables/useWaitForTransactionReceipt.ts基于 TanStack Vue Query 的useQuery通过waitForTransactionReceiptQueryOptions轮询链上回执hash参数会自动deepUnref因此可以直接传入响应式引用。八、处理错误可选当用户拒绝签名、余额不足以支付 Gas、或交易失败时需要向用户展示可读的错误信息。useWriteContract返回的error字段携带具体错误对象script setup langts import { useWaitForTransactionReceipt, useWriteContract } from wagmi import { abi } from ./abi const { data: hash, error, isPending, writeContract } useWriteContract() function submit(event: Event) { const formData new FormData(event.target as HTMLFormElement) const tokenId formData.get(tokenId) as string writeContract({ address: 0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2, abi, functionName: mint, args: [BigInt(tokenId)], }) } const { isLoading: isConfirming, isSuccess: isConfirmed } useWaitForTransactionReceipt({ hash, }) /script template form submit.preventsubmit input nametokenId placeholder69420 required / button :disabledisPending typesubmit span v-ifisPendingSending.../span span v-elseSend/span /button div v-ifhashTransaction Hash: {{ hash }}/div div v-ifisConfirmingWaiting for confirmation.../div div v-ifisConfirmedTransaction Confirmed!/div div v-iferror Error: {{ (error as BaseError).shortMessage || error.message }} /div /form /templateWagmi 的错误类型继承自BaseError见 packages/vue/src/errors/base.ts其shortMessage字段提供了去掉堆栈与原因链的精简错误文案适合直接展示给用户回退到error.message可保证任何错误都有兜底文本。用户拒绝签名、Gas 不足等常见失败场景都会在此处体现。九、组装到应用入口最后在App.vue中基于连接状态渲染连接/铸造组件script setup langts import { useConnection } from wagmi/vue import Connection from ./Connection.vue import Connect from ./Connect.vue import MintNft from ./MintNft.vue const { isConnected } useConnection() /script template Connection v-ifisConnected / Connect v-else / MintNft v-ifisConnected / /template至此一个完整的 Mint NFT 流程已经打通未连接时展示Connect钱包选项连接后展示Connection地址、连接器、断开按钮与MintNft表单用户输入tokenId并点击 Mint钱包弹出签名请求确认后显示交易哈希、等待确认状态与最终确认结果失败时展示错误信息。十、类型推断让 ABI 驱动类型安全在abi.ts中使用as const断言并非可有可无——它让 ABI 从宽泛的对象类型收窄为字面量类型从而让useWriteContract在编译期精确推断functionName只能填写 ABI 中nonpayable | payable的函数名args的类型与顺序必须与所选functionName的inputs一一对应例如mint需要一个uint32对应bigintvalue参数仅在调用payable函数时可传。这一点在核心 Action 的类型定义中得到印证WriteContractParameters通过ContractFunctionNameabi, nonpayable | payable与ContractFunctionArgs对函数名与参数做约束见 packages/core/src/actions/writeContract.ts并在WriteContractMutate中利用传入的functionName收窄联合类型见 packages/core/src/query/writeContract.ts。更多细节可参考 TypeScript 文档 与useWriteContractAPI 参考。十一、延伸更稳的写入实践先模拟后写入正式广播前可结合useSimulateContract位于 packages/vue/src/composables/useSimulateContract.ts对参数进行静态校验减少失败交易useWriteContract也可通过mutation配置传入onSuccess/onError回调做更细粒度的流程编排。异步等待结果若希望在逻辑中串行拿到交易哈希可使用writeContractAsync即mutateAsync它会返回PromiseWriteContractData。多链支持通过chainId参数可在指定链上写入未指定时使用当前连接的链。示例运行可直接查看本文配套的 StackBlitz 在线示例体验完整效果也可以参照仓库中 packages/vue/src/composables/useWriteContract.test.ts 的测试写法理解调用范式。十二、完整代码汇总文件内容config.tscreateConfig声明链、连接器与传输层参考连接钱包指南main.ts注入WagmiPlugin与VueQueryPluginabi.tsas const声明的mint函数 ABIMintNft.vue表单 useWriteContractuseWaitForTransactionReceipt 错误处理App.vue按连接状态渲染Connect/Connection/MintNft将上述文件组合并完成钱包连接后你的 Vue DApp 就具备了完整的合约写入能力将functionName与args替换为任意 ABI 中的写入函数即可复用到转账、质押、兑换、治理投票等各类链上交互场景。【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表