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

使用Ethers.js调用UniswapV2Router.swapExactTokensForTokens交易回滚问题

问题

在使用Ethers.js测试Uniswap V2 Router的swapExactTokensForTokens函数时,执行代码await swapInstances.connect(accounts[0]).swap(tokenIn, tokenOut, amountIn, amountOutMin, to);出现错误:Transaction reverted: function returned an unexpected amount of data。

单元测试代码

it("should be able to swap tokens", async function () {
    accounts = await ethers.getSigners()
    to = await accounts[1].getAddress();
    const Swap = await ethers.getContractFactory("Swap", accounts[0]);
    const swapInstances = await Swap.deploy();
    const LocandaToken = await ethers.getContractFactory("LocandaToken", accounts[0]); //ERC20
    const locandaToken = await LocandaToken.deploy();
    const RubiconPoolToken = await ethers.getContractFactory("RubiconPoolToken", accounts[1]); //ERC20
    const rubiconPoolToken = await RubiconPoolToken.deploy();
    tokenIn = locandaToken.address;
    tokenOut = rubiconPoolToken.address;

    await locandaToken.connect(accounts[0]).transfer(swapInstances.address, amountIn);
    await rubiconPoolToken.connect(accounts[1]).transfer(swapInstances.address, amountIn);

    
    const ethBalance = await ethers.provider.getBalance(accounts[0].address);
    console.log("eth balance" + ethBalance);

    await locandaToken.connect(accounts[0]).approve(swapInstances.address, amountIn)
    const test = await swapInstances.connect(accounts[0]).swap(tokenIn, tokenOut, amountIn, amountOutMin, to);
})

Swap合约swap函数代码

function swap(
        address _tokenIn,
        address _tokenOut,
        uint256 _amountIn,
        uint256 _amountOutMin,
        address _to // address where sending the tokenout
    ) external {
        IERC20(_tokenIn).transferFrom(msg.sender, address(this), _amountIn); // transfer from user wallet to this contract
        IERC20(_tokenIn).approve(UNISWAP_V2_ROUTER, _amountIn); // aprove the router to spend _tokenin
        address[] memory path; //represents the path/flow of the swap

        if (_tokenIn == WETH || _tokenOut == WETH) {
            path = new address[](2);
            path[0] = _tokenIn;
            path[1] = _tokenOut;
        } else {
            path = new address[](3);
            path[0] = _tokenIn;
            path[1] = WETH;
            path[2] = _tokenOut;
        }

        IUniswapV2Router(UNISWAP_V2_ROUTER).swapExactTokensForTokens(
            _amountIn,
            _amountOutMin,
            path,
            _to,
            block.timestamp
        );

    }
错误原因分析
  • Uniswap V2 Router接口调用不匹配
    swapExactTokensForTokens函数的返回值为uint[]类型,但你的Solidity代码调用时未处理该返回值。Ethers.js会根据ABI预期的返回值格式验证返回数据,若实际返回数据与ABI定义不一致,就会抛出该错误。需修改调用代码,接收返回值以匹配接口定义:

    uint[] memory amounts = IUniswapV2Router(UNISWAP_V2_ROUTER).swapExactTokensForTokens(
        _amountIn,
        _amountOutMin,
        path,
        _to,
        block.timestamp
    );
    
  • WETH地址未正确初始化
    合约中使用的WETH常量无初始化逻辑,若地址错误或未设置,会导致路径构建失效,调用swapExactTokensForTokens时直接revert,进而返回异常数据。需确认WETH地址已设置为测试网对应地址(如Goerli测试网WETH地址为0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6)。

  • 测试环境未添加对应流动性
    测试中仅将代币转入Swap合约,但未在Uniswap V2中为tokenIn-WETH、tokenOut-WETH交易对添加流动性。swapExactTokensForTokens依赖交易对的流动性支持,无流动性时会直接revert,引发返回数据异常。测试前需先通过Uniswap V2 Factory创建交易对,并注入初始流动性。

  • 授权逻辑或余额问题
    虽然合约中执行了approve操作,但需确认:调用transferFrom后,Swap合约中的_tokenIn余额是否足够;授权给Router的额度是否未被覆盖或失效。可在测试中添加日志,验证合约余额与授权状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 00:54:11