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

Base Layer2网络Uniswap V3+ethers.js代币兑换执行回滚问题

问题分析与修复方案

你遇到的合约执行回滚问题,主要是代码里的几个错误导致的,下面是具体修复点和修正后的代码:

关键错误点

  • swap参数错误:exactInputSingle的参数结构中不存在nounce(拼写也错误,应为nonce),交易的nonce是放在交易选项里,而非swap函数参数中,多余的参数会直接导致合约调用失败。
  • amountIn硬编码不匹配:你已经计算了amountIn变量,却使用硬编码的十六进制值,可能导致实际输入金额和授权金额不匹配。
  • Gas设置不符合Base网络规范:Base Layer2采用EIP-1559计费模式,使用gasPrice会引发兼容性问题,应改用maxFeePerGas和maxPriorityFeePerGas。
  • 未等待授权交易确认:授权交易提交后直接执行swap,可能授权还未上链生效,导致合约检测不到足够的授权额度。

修正后的完整代码

import { getPoolImmutables, getPoolState } from './utils';
const { ethers } = require('ethers');
const { abi: IUniswapV3PoolABI } = require('@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json');
const SwapRouterABI = require('./routerabi.json');
const ERC20ABI = require('./abi.json');

const QUICKNODE_HTTP_ENDPOINT = 'https://sepolia.base.org';
const WALLET_ADDRESS = ''; // 填入你的钱包地址
const WALLET_SECRET = ''; // 填入你的钱包私钥

const provider = new ethers.providers.JsonRpcProvider(QUICKNODE_HTTP_ENDPOINT);
const poolAddress = '0x7516D071921973fDFf29C071f42d21C227CF5740'; 
const swapRouterAddress = '0x050E797f3625EC8785265e1d9BDd4799b97528A1';

async function main() {
  try {
    const poolContract = new ethers.Contract(poolAddress, IUniswapV3PoolABI, provider);
    const immutables = await getPoolImmutables(poolContract);
    const state = await getPoolState(poolContract);

    const wallet = new ethers.Wallet(WALLET_SECRET);
    const connectedWallet = wallet.connect(provider);

    const swapRouterContract = new ethers.Contract(swapRouterAddress, SwapRouterABI, connectedWallet);
    const inputAmount = 0.09;
    const amountIn = ethers.utils.parseUnits(inputAmount.toString(), 18);
    const approvalAmount = amountIn.mul(10); // 用ethers的BigNumber运算,避免字符串转换错误
    const tokenContract0 = new ethers.Contract(immutables.token1, ERC20ABI, connectedWallet);

    // 提交授权交易并等待确认
    const approvalResponse = await tokenContract0.approve(swapRouterAddress, approvalAmount);
    await approvalResponse.wait();
    console.log('授权交易已确认,交易哈希:', approvalResponse.hash);

    // 构建正确的swap参数
    const params = {
      tokenIn: immutables.token1,
      tokenOut: immutables.token0,
      fee: immutables.fee,
      recipient: WALLET_ADDRESS,
      deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10分钟后过期
      amountIn: amountIn, // 使用计算好的变量,而非硬编码
      amountOutMinimum: 0, // 测试网可设为0,主网建议计算滑点后的最小值
      sqrtPriceLimitX96: 0, // 不限制价格滑点
    };

    // 获取当前交易nonce,作为交易选项参数
    const nonce = await connectedWallet.getTransactionCount();
    const transaction = await swapRouterContract.exactInputSingle(params, {
      gasLimit: ethers.utils.hexlify(1000000),
      maxFeePerGas: ethers.utils.parseUnits('10', 'gwei'),
      maxPriorityFeePerGas: ethers.utils.parseUnits('2', 'gwei'),
      nonce: nonce,
    });

    console.log('Swap交易已提交,交易哈希:', transaction.hash);
    const receipt = await transaction.wait();
    console.log('Swap交易已确认,区块号:', receipt.blockNumber);
  } catch (error) {
    console.error('交易失败:', error);
  }
}

main();

额外说明

  • 关于execute函数:你提到的execute是Uniswap Router的批量交易函数,用于一次执行多个操作(如swap+添加流动性),单纯的代币兑换使用exactInputSingle是完全正确的,不需要改用execute。
  • 滑点控制:主网环境下不要将amountOutMinimum设为0,建议根据当前池状态计算可接受的最小输出金额,避免因滑点过大导致损失。
  • BigNumber运算:ethers.js中处理代币金额时,应使用内置的BigNumber方法(如mul、div),避免直接用JavaScript的数值运算导致精度丢失。

内容的提问来源于stack exchange,提问作者Ghassane Aboughazaouat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 19:52:45