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

Uniswap V3:部署含交易税机制的ERC20代币后无法添加流动性

解决Uniswap V3添加流动性失败问题并保留ERC20交易税机制

问题根源

你的ERC20合约在_update函数中对所有转账强制收取4%交易税,但Uniswap V3添加流动性时,合约会校验实际收到的代币数量是否等于预期值。由于扣税导致Pool实际到账数量仅为预期的96%,触发Uniswap的校验逻辑,交易直接回滚,无法完成流动性添加。

解决方案

修改合约逻辑,对Uniswap V3流动性操作和Pool间转账豁免交易税,同时保证普通转账、用户兑换场景的交易税正常收取。

修改后的完整合约代码

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";

contract T2T is ERC20, Ownable {
    uint256 public constant TAX_PERCENT = 4; // 4%交易税
    ISwapRouter public immutable uniswapRouter;
    INonfungiblePositionManager public immutable positionManager;
    address public immutable WETH;
    address public immutable taxReceiver;
    mapping(address => bool) public isExcludedFromTax; // 免税地址列表

    constructor(
        address _uniswapRouter,
        address _positionManager,
        address _WETH
    ) ERC20("T2T", "T2T") Ownable(msg.sender) {
        _mint(msg.sender, 1_000_000 * 10 ** decimals()); // 铸造初始供应量
        uniswapRouter = ISwapRouter(_uniswapRouter);
        positionManager = INonfungiblePositionManager(_positionManager);
        WETH = _WETH;
        taxReceiver = msg.sender;

        // 默认豁免合约自身和税接收地址的交易税
        isExcludedFromTax[address(this)] = true;
        isExcludedFromTax[taxReceiver] = true;
    }

    // 仅合约所有者可配置免税地址
    function setExcludedFromTax(address account, bool excluded) external onlyOwner {
        isExcludedFromTax[account] = excluded;
    }

    function _update(address sender, address recipient, uint256 amount) internal override {
        // 触发免税的场景:
        // 1. 发送方或接收方在免税列表中
        // 2. 调用者是Uniswap V3流动性管理合约(PositionManager)
        // 3. 接收方是Uniswap V3 Pool地址
        bool isTaxExempt = isExcludedFromTax[sender] || isExcludedFromTax[recipient] || 
            msg.sender == address(positionManager) || 
            _isUniswapV3Pool(recipient);

        if (isTaxExempt) {
            super._update(sender, recipient, amount);
            return;
        }

        // 正常收取交易税
        uint256 taxAmount = (amount * TAX_PERCENT) / 100;
        uint256 amountAfterTax = amount - taxAmount;

        super._update(sender, taxReceiver, taxAmount);
        super._update(sender, recipient, amountAfterTax);
    }

    // 辅助函数:判断地址是否为Uniswap V3 Pool合约
    function _isUniswapV3Pool(address account) internal view returns (bool) {
        (bool success, ) = account.staticcall(abi.encodeWithSignature("slot0()"));
        return success;
    }
}

关键修改说明

  1. 新增免税地址管理:通过isExcludedFromTax映射和setExcludedFromTax函数,允许所有者灵活配置无需扣税的地址
  2. 自动识别免税场景:
    • 豁免Uniswap V3流动性操作(调用者为NonfungiblePositionManager),确保添加/移除流动性时代币数量完全匹配Uniswap的校验要求
    • 自动识别Uniswap V3 Pool地址,避免兑换过程中Pool间的代币转移被征税
    • 默认豁免合约自身和税接收地址,防止循环转账问题
  3. 保留核心税机制:普通用户转账、通过Uniswap兑换代币时,仍会自动扣除4%交易税并转入所有者地址

使用注意事项

  • 部署合约时,需传入对应链的Uniswap V3 SwapRouter和NonfungiblePositionManager地址(以太坊主网地址分别为0xE592427A0AEce92De3Edee1F18E0157C05861564和0xC36442b4a4522E871399CD717aBDD847Ab11FE88,测试网需对应调整)
  • 添加流动性需通过Uniswap官方界面或调用NonfungiblePositionManager的mint函数,此时合约会自动豁免交易税

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 18:00:58