You need to enable JavaScript to run this app. Solidity调用Uniswap V2配对合约获取币价触发交易回退问题求解
优惠活动
大模型
产品
解决方案
定价
更多

Solidity调用Uniswap V2配对合约获取币价触发交易回退问题求解

错误触发原因
  • 缺少接口声明:代码中直接使用了IUniswapV2Pair和IERC20接口,但没有提前定义或导入这两个接口,合约编译时无法识别接口对应的方法,调用时会直接回滚。
  • 函数修饰符配置错误:getTokenPrice仅做链上数据读取,不需要修改状态也不需要接收ETH,你额外加了payable修饰符且未加view修饰符,Remix会默认将该调用识别为状态修改类交易发起,而非本地只读调用。如果调用时你传入了超过账户余额的ETH,或是账户没有足够ETH支付gas,都会触发你看到的报错。
  • 代币顺序逻辑有漏洞:Uniswap V2交易对的token0、token1是按地址哈希大小排序的,ETH/USDT交易对中token0为WETH、token1为USDT,你当前代码固定取token1的小数位计算,没有适配你要查询的价格方向,极端情况会出现除零报错(该交易对不会出现,但逻辑不通用)。
  • 数值溢出风险:如果你使用的是0.8以下版本的Solidity,Res0*(10**token1.decimals())的运算很容易触发整数溢出,直接导致交易回滚。
修复方案

代码调整

首先在合约顶部补充两个接口的定义,再修改getTokenPrice的修饰符和计算逻辑,参考代码如下:

// 补充接口定义
interface IERC20 {
    function decimals() external view returns (uint8);
}

interface IUniswapV2Pair {
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}

contract Uniswap {
    constructor () public payable {
    }
   
    function getBalance() public view returns (uint) {
        return address(this).balance;    
    }
   
   // 优化后的价格查询函数:isToken0In为true表示输入token0数量,查询可兑换的token1数量,反之则相反
   function getTokenPrice(address pairAddress, uint inAmount, bool isToken0In) public view returns(uint outAmount)
   {
        IUniswapV2Pair pair = IUniswapV2Pair(pairAddress);
        IERC20 token0 = IERC20(pair.token0());
        IERC20 token1 = IERC20(pair.token1());
        (uint112 reserve0, uint112 reserve1,) = pair.getReserves();
        require(reserve0 > 0 && reserve1 > 0, "交易对储备为空");

        uint8 inDecimals = isToken0In ? token0.decimals() : token1.decimals();
        uint8 outDecimals = isToken0In ? token1.decimals() : token0.decimals();
        uint inReserve = isToken0In ? reserve0 : reserve1;
        uint outReserve = isToken0In ? reserve1 : reserve0;

        // 统一精度后计算,避免小数位差异导致结果错误
        uint inAmountAdjusted = inAmount * (10 ** 18) / (10 ** inDecimals);
        uint outAmountAdjusted = (inAmountAdjusted * outReserve) / inReserve;
        outAmount = outAmountAdjusted * (10 ** outDecimals) / (10 ** 18);
        return outAmount;
   }
}

如果使用的是0.8以下版本的Solidity,建议导入SafeMath库处理算术运算,避免溢出回滚。

调用逻辑调整

你使用的ETH/USDT交易对中token0为WETH(18位小数)、token1为USDT(6位小数):

  • 要查询1 ETH可兑换的USDT数量时,pairAddress填交易对地址,inAmount填1000000000000000000(对应1 WETH的精度),isToken0In填true。
  • 调用时不要传入任何ETH,因为调整后函数为view类型,Remix会走本地只读调用,不需要支付gas,也不会发起链上交易。

内容的提问来源于stack exchange,提问作者Viktor.w

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 00:36:07