如何在wagmi的useContractWrite钩子中指定ETH值,实现ETH+ERC20代币转账?
同时发送ETH与ERC20代币的wagmi实现方案
一、核心:在useContractWrite中指定ETH金额
如果是通过自定义合约方法同时处理ETH接收与ERC20转账,可以直接在useContractWrite的配置中通过value字段指定ETH数值(单位为wei)。前提是合约方法需用payable修饰,支持接收ETH。
示例代码
import { useContractWrite, usePrepareContractWrite } from 'wagmi'; import { ethers } from 'ethers'; // 替换为你的合约ABI(需包含同时处理ETH和ERC20的方法) const customContractAbi = [ { inputs: [{ internalType: 'address', name: 'to', type: 'address' }, { internalType: 'uint256', name: 'tokenAmount', type: 'uint256' }], name: 'transferWithEth', outputs: [], stateMutability: 'payable', type: 'function', }, ]; const contractAddress = '0x...'; // 你的合约地址 const targetAddress = '0x...'; // 接收地址 export function TransferWithEth() { // 提前准备合约调用配置 const { config } = usePrepareContractWrite({ address: contractAddress, abi: customContractAbi, functionName: 'transferWithEth', args: [targetAddress, ethers.utils.parseUnits('100', 18)], // ERC20转账数量(100代币,18位小数) value: ethers.utils.parseEther('0.5'), // 要发送的ETH金额(0.5 ETH) }); // 发起合约调用 const { write, isLoading, error } = useContractWrite(config); return ( <button onClick={() => write?.()} disabled={isLoading}> {isLoading ? '处理中...' : '转ETH+ERC20'} </button> ); }
二、独立发起ETH+ERC20转账(两个交易)
如果没有自定义合约,需要分别发起ETH转账和ERC20转账,可以结合useSendTransaction(处理ETH)和useContractWrite(处理ERC20),用Promise管理异步逻辑。
1. 并行发起两个交易
import { useContractWrite, usePrepareContractWrite, useSendTransaction, useWaitForTransaction } from 'wagmi'; import { erc20Abi } from 'wagmi'; import { ethers } from 'ethers'; const erc20Address = '0x...'; // ERC20代币地址 const targetAddress = '0x...'; // 接收地址 export function DualTransfer() { // 准备ERC20转账配置 const { config: erc20Config } = usePrepareContractWrite({ address: erc20Address, abi: erc20Abi, functionName: 'transfer', args: [targetAddress, ethers.utils.parseUnits('100', 18)], }); const { write: writeErc20, data: erc20TxHash } = useContractWrite(erc20Config); // 准备ETH转账配置 const { sendTransaction: sendEth, data: ethTxHash } = useSendTransaction({ to: targetAddress, value: ethers.utils.parseEther('0.5'), }); // 监听交易确认状态 const { isLoading: ethLoading } = useWaitForTransaction({ hash: ethTxHash?.hash }); const { isLoading: erc20Loading } = useWaitForTransaction({ hash: erc20TxHash?.hash }); const handleDualTransfer = async () => { try { // 并行发起两个交易 await Promise.all([sendEth?.(), writeErc20?.()]); console.log('两个交易已提交'); } catch (err) { console.error('交易失败:', err); } }; return ( <button onClick={handleDualTransfer} disabled={ethLoading || erc20Loading}> {ethLoading || erc20Loading ? '处理中...' : '同时转ETH+ERC20'} </button> ); }
2. 串行发起(确保前一个交易成功后再执行下一个)
如果需要保证ETH转账确认后再发起ERC20转账,调整异步逻辑:
const handleDualTransfer = async () => { try { // 先发起ETH转账并等待确认 const ethTx = await sendEth?.(); if (!ethTx) throw new Error('ETH转账发起失败'); await ethTx.wait(); // ETH确认后发起ERC20转账并等待确认 const erc20Tx = await writeErc20?.(); if (!erc20Tx) throw new Error('ERC20转账发起失败'); await erc20Tx.wait(); console.log('两个交易均已确认'); } catch (err) { console.error('交易失败:', err); } };
三、异步逻辑与嵌套问题的解决技巧
- 提前准备配置:用
usePrepareContractWrite提前解析参数、ABI等,避免在write函数中嵌套复杂逻辑。 - 用Promise管理异步流:用
Promise.all并行或await串行处理交易,替代嵌套回调,代码更清晰。 - 利用wagmi状态变量:通过
isLoading、data(交易哈希)、error直接维护UI状态,无需手动管理复杂状态。 - 统一错误处理:在async函数中用
try/catch捕获所有异常,包括用户拒绝签名、交易失败等场景。
注意:原生ETH转账和ERC20转账是两个独立操作,无法在单个原生交易中完成,必须通过自定义合约中转才能实现同一交易内的双转账。
内容的提问来源于stack exchange,提问作者user130657
相关产品推荐
相关产品推荐

