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

Solidity合约添加Uniswap流动性报错,如何实现代币兑ETH?

问题:Uniswap流动性添加失败(insufficient liquidity)

用户开发的Solidity合约中,调用swapTokensForEthAndAddLiquidity时出现Gas估算错误,控制台提示insufficient liquidity,无法完成代币兑换与流动性添加操作。

错误原因分析

  1. 资金流向错误:swapExactTokensForETH的接收地址设为msg.sender,兑换得到的ETH直接转给了用户,合约账户没有ETH储备用于后续的流动性添加。
  2. 代币余额不足:swap操作已经将用户的代币全部兑换为ETH,后续调用addLiquidityETH时传入的tokenAmount是初始代币数量,但此时合约内已无足够代币,导致流动性添加失败。
  3. 授权逻辑错误:_approve(address(this), address(uniswapRouter), tokenAmount)是让合约自己授权Router使用代币,但用户的代币还在自己账户,Router无法直接转移用户的代币。

修正后的合约代码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";

contract YourToken is ERC20, Ownable, ReentrancyGuard {
    IUniswapV2Router02 public uniswapRouter;
    address public uniswapPair;

    event TokensSwappedForEth(uint256 tokenAmount, uint256 ethAmount);
    event LiquidityAdded(uint256 tokenAmount, uint256 ethAmount, uint256 liquidityTokens);
    event TokensMinted(address indexed account, uint256 amount);

    constructor(address _uniswapRouter) ERC20("Infuraa Token", "INXT") Ownable(msg.sender) {
        uniswapRouter = IUniswapV2Router02(_uniswapRouter);
        uniswapPair = IUniswapV2Factory(uniswapRouter.factory()).createPair(address(this), uniswapRouter.WETH());
        _mint(msg.sender, 980 * 10**12 * 10**18);
    }

    // 用户将代币兑换为ETH(前提是LP池已有流动性)
    function swapTokensForEth(uint256 tokenAmount) external nonReentrant {
        require(balanceOf(msg.sender) >= tokenAmount, "Insufficient balance");
        
        // 用户需先在前端调用approve授权Router使用自己的代币
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = uniswapRouter.WETH();

        uniswapRouter.swapExactTokensForETH(
            tokenAmount,
            1, // 设置最小接收ETH数量,防止滑点过大
            path,
            msg.sender,
            block.timestamp + 300 // 延长过期时间,避免交易超时
        );

        emit TokensSwappedForEth(tokenAmount, address(msg.sender).balance);
    }

    // 用户添加代币+ETH到Uniswap流动性池
    function addLiquidity(uint256 tokenAmount) external payable nonReentrant {
        require(balanceOf(msg.sender) >= tokenAmount, "Insufficient token balance");
        require(msg.value > 0, "ETH amount cannot be zero");

        // 转移用户的代币到合约,再授权Router使用
        _transfer(msg.sender, address(this), tokenAmount);
        _approve(address(this), address(uniswapRouter), tokenAmount);

        (uint256 tokenAdded, uint256 ethAdded, uint256 liquidity) = uniswapRouter.addLiquidityETH{value: msg.value}(
            address(this),
            tokenAmount,
            tokenAmount * 95 / 100, // 5%滑点容忍度
            msg.value * 95 / 100,
            msg.sender,
            block.timestamp + 300
        );

        emit LiquidityAdded(tokenAdded, ethAdded, liquidity);
    }

    // 合约所有者初始化流动性池(首次添加流动性)
    function initLiquidity(uint256 tokenAmount) external payable onlyOwner nonReentrant {
        require(balanceOf(msg.sender) >= tokenAmount, "Owner insufficient token balance");
        require(msg.value > 0, "ETH amount cannot be zero");

        _transfer(msg.sender, address(this), tokenAmount);
        _approve(address(this), address(uniswapRouter), tokenAmount);

        (uint256 tokenAdded, uint256 ethAdded, uint256 liquidity) = uniswapRouter.addLiquidityETH{value: msg.value}(
            address(this),
            tokenAmount,
            tokenAmount * 95 / 100,
            msg.value * 95 / 100,
            msg.sender,
            block.timestamp + 300
        );

        emit LiquidityAdded(tokenAdded, ethAdded, liquidity);
    }

    // 更新Uniswap Router地址
    function setUniswapRouter(address _uniswapRouter) external onlyOwner {
        uniswapRouter = IUniswapV2Router02(_uniswapRouter);
        address pair = IUniswapV2Factory(uniswapRouter.factory()).getPair(address(this), uniswapRouter.WETH());
        uniswapPair = pair == address(0) ? IUniswapV2Factory(uniswapRouter.factory()).createPair(address(this), uniswapRouter.WETH()) : pair;
    }

    // 铸造代币(仅所有者)
    function mint(address account, uint256 amount) external onlyOwner {
        _mint(account, amount);
        emit TokensMinted(account, amount);
    }

    receive() external payable {}
}

关键修改说明

  • 拆分功能:将原函数拆分为swapTokensForEth(代币换ETH)和addLiquidity(添加流动性)两个独立函数,逻辑更清晰,符合Uniswap的使用流程。
  • 修正资金流向:兑换ETH时直接转给用户,添加流动性时由用户通过msg.value传入ETH,确保合约有足够的ETH用于流动性添加。
  • 授权逻辑修正:通过_transfer将用户代币转移到合约后,再授权Router使用,确保Router有足够的代币权限。
  • 滑点与超时优化:设置5%的滑点容忍度和5分钟的交易过期时间,避免因市场波动导致交易失败。
  • 初始化流动性:新增initLiquidity函数,由合约所有者首次添加流动性,为用户兑换提供基础储备。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 03:20:02