You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用wagmi.js实现非原生代币授权与跨代币兑换?

解决ERC20代币授权与兑换流程问题

你遇到的核心问题是:非MATIC的ERC20代币兑换时,必须先授权DODO Router合约访问你的代币,合约才有权限转移你的代币完成兑换。MATIC是原生代币,不需要授权,所以之前的兑换能成功,而反向/跨代币兑换因为缺少授权步骤失败。

以下是基于wagmi.js实现完整授权+兑换流程的方案:

一、核心逻辑步骤

  1. 检查授权额度:查询用户已授权给DODO Router的代币数量,判断是否足够本次兑换使用
  2. 发起授权交易:如果授权不足,调用ERC20代币的approve方法完成授权
  3. 执行兑换交易:授权成功后,再执行之前的兑换逻辑

二、代码实现调整

1. 定义ERC20核心ABI片段

首先需要ERC20合约的approve和allowance方法的ABI,用来与代币合约交互:

const ERC20_ABI = [
  {
    constant: true,
    inputs: [
      { name: "owner", type: "address" },
      { name: "spender", type: "address" },
    ],
    name: "allowance",
    outputs: [{ name: "", type: "uint256" }],
    payable: false,
    stateMutability: "view",
    type: "function",
  },
  {
    constant: false,
    inputs: [
      { name: "spender", type: "address" },
      { name: "value", type: "uint256" },
    ],
    name: "approve",
    outputs: [{ name: "", type: "bool" }],
    payable: false,
    stateMutability: "nonpayable",
    type: "function",
  },
] as const;

2. 在DexPage.tsx中添加授权相关逻辑

修改现有代码,整合授权检查与交易流程:

import { useAllowance, useContractWrite, useWaitForTransaction, useAccount } from 'wagmi';
import { parseUnits } from 'viem';

// Polygon网络DODO Router合约地址(替换为实际地址)
const DODO_ROUTER_ADDRESS = "0x..." 

const DexPage = () => {
  const [transactionData, setTransactionData] = useState<DodoAPIData | undefined>();
  const [needsApproval, setNeedsApproval] = useState(false);
  const { address: userAddress } = useAccount();

  // 1. 检查授权额度(仅当fromToken不是MATIC时生效)
  const { data: allowance } = useAllowance({
    address: fromTokenAddress,
    owner: userAddress,
    spender: DODO_ROUTER_ADDRESS,
    enabled: !!userAddress && fromTokenAddress !== chain.polygon.nativeCurrency.address,
  });

  // 2. 发起授权交易的hooks
  const { write: approveWrite, data: approveTxHash } = useContractWrite({
    address: fromTokenAddress,
    abi: ERC20_ABI,
    functionName: 'approve',
    // 可选择授权本次兑换额度,或用最大额度避免重复授权:BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
    args: [DODO_ROUTER_ADDRESS, parseUnits(fromTokenAmount, fromTokenDecimals)], 
  });

  // 等待授权交易完成
  const { isSuccess: isApproveSuccess } = useWaitForTransaction({
    hash: approveTxHash,
  });

  // 3. 兑换交易的hooks(调整原有逻辑)
  const { data, isLoading, isSuccess, sendTransaction, error, status } = useSendTransaction({
    request: {
      from: userAddress,
      to: transactionData?.to || "",
      // 非MATIC代币兑换时,value设为0,代币转移由合约通过授权执行
      value: fromTokenAddress === chain.polygon.nativeCurrency.address 
        ? parseUnits(fromTokenAmount, fromTokenDecimals) 
        : BigInt(0), 
      gasLimit: 500000,
      data: transactionData?.data || "",
    },
    mode: "prepared",
    enabled: !needsApproval || isApproveSuccess, // 授权完成后才允许执行兑换
  });

  // 获取DODO交易参数后,判断是否需要授权
  const fetchDodoParams = async () => {
    try {
      const price = await axios.get(dodoAPI, {
        params: {
          fromTokenAddress,
          fromTokenDecimals,
          toTokenAddress,
          toTokenDecimals,
          fromAmount,
          slippage: 1,
          userAddr: userAddress,
          chainId: 137,
          rpc: rpcUrl,
        }
      });
      if (price.status !== 200) return;
      setTransactionData(price.data.data);

      // 判断是否需要授权:非MATIC代币且授权额度不足
      if (fromTokenAddress !== chain.polygon.nativeCurrency.address) {
        const requiredAmount = parseUnits(fromTokenAmount, fromTokenDecimals);
        setNeedsApproval(!allowance || allowance < requiredAmount);
      } else {
        setNeedsApproval(false);
      }
    } catch (e) {
      console.error(e);
    }
  };

  // 触发流程:先授权(如果需要),再兑换
  const handleSwap = () => {
    if (needsApproval) {
      approveWrite?.();
    } else {
      sendTransaction?.();
    }
  };

  return (
    // 你的UI组件示例:按钮点击触发handleSwap
    <button onClick={handleSwap} disabled={isLoading || !transactionData}>
      {needsApproval ? '授权代币' : '立即兑换'}
    </button>
  );
};

三、关键细节说明

  • 授权额度选择:可以授权本次兑换的精确额度,或直接授权最大额度(适合高频兑换场景,避免重复授权)
  • MATIC判断:通过chain.polygon.nativeCurrency.address区分原生代币与ERC20代币,原生代币无需授权
  • 交易依赖:用useWaitForTransaction监听授权交易的成功状态,确保授权完成后再执行兑换
  • 错误处理:可在useContractWrite和useSendTransaction中添加错误状态提示,提升用户体验

内容的提问来源于stack exchange,提问作者Abobker Elaghel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 01:20:33