目 录CONTENT

文章目录

MemeToken使用solidity开发

懿曲折扇情
2025-10-29 / 0 评论 / 1 点赞 / 40 阅读 / 2,095 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2025-11-03,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
广告 广告



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

/**
 * MemeToken (SHIB-style) 教学示例
 * - 交易税:买/卖/转账可分别设置,税收进入金库或用于回流
 * - 流动性池:集成 UniswapV2 路由器,支持自动回流(swapBack)
 * - 交易限制:最大单笔、最大持仓、冷却与每日次数限制、白名单
 *
 * 注意:教学用途,未审计。上线主网请先审计与严格参数治理。
 */

interface IERC20 {
    /// @notice ERC20 总供给
    function totalSupply() external view returns (uint256);
    /// @notice 查询账户余额
    function balanceOf(address account) external view returns (uint256);
    /// @notice 向指定地址转账
    function transfer(address to, uint256 amount) external returns (bool);
    /// @notice 查询授权额度
    function allowance(address owner, address spender) external view returns (uint256);
    /// @notice 授权 spender 可花费的代币数量
    function approve(address spender, uint256 amount) external returns (bool);
    /// @notice 从 from 扣款并转给 to(需要事先授权)
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    /// @notice 标准事件:转账
    event Transfer(address indexed from, address indexed to, uint256 value);
    /// @notice 标准事件:授权
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

interface IUniswapV2Factory {
    /// @notice 创建交易对 (tokenA-tokenB)
    function createPair(address tokenA, address tokenB) external returns (address pair);
}

interface IUniswapV2Pair {
    /// @notice LP 余额查询
    function balanceOf(address) external view returns (uint);
}

interface IUniswapV2Router02 {
    /// @notice 工厂地址
    function factory() external view returns (address);
    /// @notice 路由所用的 WETH 地址
    function WETH() external view returns (address);

    /// @notice 向代币-ETH 池添加流动性(V2 路由)
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);

    /// @notice 代扣手续费模式下,将代币换成 ETH(用于税/回流)
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

abstract contract Ownable {
    /// @notice 所有权转移事件
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    /// @notice 合约当前所有者
    address public owner;

    /// @notice 仅限所有者修饰器
    modifier onlyOwner() { require(msg.sender == owner, "NOT_OWNER"); _; }

    /// @notice 构造函数,部署者成为所有者
    constructor() { owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); }

    /// @notice 将所有权转移给新地址
    /// @param newOwner 新的所有者地址(不可为0)
    function transferOwnership(address newOwner) external onlyOwner { require(newOwner!=address(0)); emit OwnershipTransferred(owner,newOwner); owner=newOwner; }
}

contract MemeToken is IERC20, Ownable {
    string public name = "Meme Token";
    string public symbol = "MEME";
    uint8  public decimals = 18;

    uint256 public override totalSupply;
    mapping(address => uint256) public override balanceOf;
    mapping(address => mapping(address => uint256)) public override allowance;

    // 税率(基点,10000 = 100%)
    uint16 public buyTaxBps = 300;      // 3%
    uint16 public sellTaxBps = 300;     // 3%
    uint16 public transferTaxBps = 0;   // 0%

    address public taxWallet;           // 金库地址

    // 交易限制
    uint256 public maxTxAmount;         // 单笔最大
    uint256 public maxWalletAmount;     // 最大持仓
    uint256 public cooldownSeconds = 0; // 冷却时间
    uint256 public dailyTxLimit = 0;    // 每日次数上限(0 即不限制)

    mapping(address => bool) public isExcludedFromFees;
    mapping(address => bool) public isExcludedFromLimits;

    mapping(address => uint256) private _lastTxTimestamp;
    mapping(address => uint256) private _dailyTxCount;
    mapping(address => uint256) private _dailyTxStart;

    // DEX 路由与交易对
    IUniswapV2Router02 public router;
    address public pair;

    // 自动回流/换税
    bool public swapBackEnabled = true;
    uint256 public swapThreshold; // 累计到一定代币量后换成ETH
    bool private _inSwap;

    bool public tradingEnabled = false;

    event TaxesUpdated(uint16 buyTaxBps, uint16 sellTaxBps, uint16 transferTaxBps);
    event LimitsUpdated(uint256 maxTxAmount, uint256 maxWalletAmount, uint256 cooldownSeconds, uint256 dailyTxLimit);
    event SwapBack(uint256 tokenSwapped, uint256 ethToTreasury);

    /// @notice 防止在 swap 过程中重入
    modifier lockSwap() { _inSwap = true; _; _inSwap = false; }

    /// @notice 构造函数:初始化供给、路由、交易对、限制与白名单
    /// @param _supply 初始总供给
    /// @param _router UniswapV2 路由地址
    /// @param _taxWallet 税金接收地址
    constructor(
        uint256 _supply,
        address _router,
        address _taxWallet
    ) {
        require(_router != address(0) && _taxWallet != address(0), "bad params");
        taxWallet = _taxWallet;

        // mint
        totalSupply = _supply;
        balanceOf[msg.sender] = _supply;
        emit Transfer(address(0), msg.sender, _supply);

        // router & pair
        router = IUniswapV2Router02(_router);
        address weth = router.WETH();
        pair = IUniswapV2Factory(router.factory()).createPair(address(this), weth);

        // 初始限制:最大单笔与持仓为总量 2%
        maxTxAmount = _supply / 50;
        maxWalletAmount = _supply / 50;

        // 初始白名单
        isExcludedFromFees[msg.sender] = true;
        isExcludedFromFees[address(this)] = true;
        isExcludedFromLimits[msg.sender] = true;
        isExcludedFromLimits[address(this)] = true;

        // swap 阈值(总量的 0.05%)
        swapThreshold = _supply / 2000;
    }

    // ========= ERC20 =========

    /// @notice 授权 spender 可花费的代币数量
    /// @param spender 被授权地址
    /// @param amount 授权额度
    /// @return 是否成功
    function approve(address spender, uint256 amount) external override returns (bool) {
        allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true;
    }

    /// @notice 从调用者向 to 转账 amount 数量的代币
    /// @param to 接收地址
    /// @param amount 转账数量
    /// @return 是否成功
    function transfer(address to, uint256 amount) external override returns (bool) {
        _transfer(msg.sender, to, amount); return true;
    }

    /// @notice 从 from 扣款并转给 to(需要事先由 from 授权给 msg.sender)
    /// @param from 支付地址
    /// @param to 接收地址
    /// @param amount 转账数量
    /// @return 是否成功
    function transferFrom(address from, address to, uint256 amount) external override returns (bool) {
        uint256 allowed = allowance[from][msg.sender];
        require(allowed >= amount, "allowance");
        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
        _transfer(from, to, amount); return true;
    }

    // ========= Core logic =========

    /// @notice 内部转账入口:处理税费、限额、冷却、每日次数限制与自动回流
    /// @dev 仅在本合约内部被调用(transfer/transferFrom)
    /// @param from 支付地址
    /// @param to 接收地址
    /// @param amount 转账数量
    function _transfer(address from, address to, uint256 amount) internal {
        require(from != address(0) && to != address(0), "zero addr");
        require(balanceOf[from] >= amount, "balance");

        if (!tradingEnabled) {
            require(isExcludedFromLimits[from] || isExcludedFromLimits[to], "trading off");
        }

        // 限制(maxTx / maxWallet / 冷却 / 每日次数)
        if (!isExcludedFromLimits[from] && !isExcludedFromLimits[to]) {
            require(amount <= maxTxAmount, ">maxTx");
            if (to != pair) { // 买或转账入普通地址检查持仓
                require(balanceOf[to] + amount <= maxWalletAmount, ">maxWallet");
            }
            if (cooldownSeconds > 0) {
                require(block.timestamp - _lastTxTimestamp[from] >= cooldownSeconds, "cooldown");
            }
            if (dailyTxLimit > 0) {
                if (block.timestamp - _dailyTxStart[from] >= 1 days) {
                    _dailyTxStart[from] = block.timestamp;
                    _dailyTxCount[from] = 0;
                }
                require(_dailyTxCount[from] < dailyTxLimit, "daily limit");
                _dailyTxCount[from] += 1;
            }
        }

        // 自动回流:仅在卖出到 pair 时触发,且不在递归中
        if (_shouldSwapBack(from, to)) {
            _swapBack();
        }

        // 计算税额
        uint256 taxBps = _taxBps(from, to);
        uint256 taxAmount = isExcludedFromFees[from] || isExcludedFromFees[to] ? 0 : (amount * taxBps) / 10000;
        uint256 sendAmount = amount - taxAmount;

        // 扣款与入账
        unchecked { balanceOf[from] -= amount; }
        balanceOf[to] += sendAmount;
        emit Transfer(from, to, sendAmount);

        if (taxAmount > 0) {
            balanceOf[address(this)] += taxAmount; // 税先进入合约
            emit Transfer(from, address(this), taxAmount);
        }

        _lastTxTimestamp[from] = block.timestamp;
    }

    /// @notice 根据转账方向(买/卖/普通)返回应适用的税率(基点)
    /// @param from 支付地址
    /// @param to 接收地址
    /// @return 税率(基点制)
    function _taxBps(address from, address to) internal view returns (uint16) {
        if (from == pair) return buyTaxBps;      // 买
        if (to == pair) return sellTaxBps;       // 卖
        return transferTaxBps;                   // 普通转账
    }

    /// @notice 判断当前是否需要进行自动回流(swap back)
    /// @dev 只在卖出到 pair 且达到阈值、非重入时成立
    /// @return 是否需要 swapBack
    function _shouldSwapBack(address from, address to) internal view returns (bool) {
        return swapBackEnabled && !_inSwap && to == pair && balanceOf[address(this)] >= swapThreshold;
    }

    /// @notice 将累计的税代币兑换为 ETH 并发送到金库
    /// @dev 使用支持手续费的兑换路径,避免因代扣失败
    function _swapBack() internal lockSwap {
        uint256 amountToSwap = balanceOf[address(this)];
        if (amountToSwap == 0) return;

        // 授权给路由器
        allowance[address(this)][address(router)] = amountToSwap;
        emit Approval(address(this), address(router), amountToSwap);

        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = router.WETH();

        uint256 balanceBefore = address(this).balance;
        router.swapExactTokensForETHSupportingFeeOnTransferTokens(
            amountToSwap,
            0,
            path,
            address(this),
            block.timestamp
        );
        uint256 gained = address(this).balance - balanceBefore;

        // 全部发送至金库(也可部分回流 LP,根据策略扩展)
        if (gained > 0) {
            (bool ok,) = taxWallet.call{value: gained}("");
            require(ok, "send tax");
        }
        emit SwapBack(amountToSwap, gained);
    }

    // ========= Admin =========

    /// @notice 设置买/卖/转账税率(基点),各自最高 10%
    /// @param buyBps 买税(基点)
    /// @param sellBps 卖税(基点)
    /// @param transferBps 转账税(基点)
    function setTaxRates(uint16 buyBps, uint16 sellBps, uint16 transferBps) external onlyOwner {
        require(buyBps<=1000 && sellBps<=1000 && transferBps<=1000, "tax too high");
        buyTaxBps = buyBps; sellTaxBps = sellBps; transferTaxBps = transferBps;
        emit TaxesUpdated(buyBps, sellBps, transferBps);
    }

    /// @notice 设置税金接收地址
    /// @param w 新的金库地址
    function setTaxWallet(address w) external onlyOwner { require(w!=address(0)); taxWallet = w; }

    /// @notice 设置单笔最大额度与最大持仓
    /// @param _maxTx 单笔最大
    /// @param _maxWallet 最大持仓
    function setLimits(uint256 _maxTx, uint256 _maxWallet) external onlyOwner {
        require(_maxTx>0 && _maxWallet>0, "zero");
        maxTxAmount = _maxTx; maxWalletAmount = _maxWallet;
        emit LimitsUpdated(maxTxAmount, maxWalletAmount, cooldownSeconds, dailyTxLimit);
    }

    /// @notice 设置交易冷却时间(秒)
    /// @param secs 两次交易的最小时间间隔
    function setCooldown(uint256 secs) external onlyOwner { cooldownSeconds = secs; emit LimitsUpdated(maxTxAmount, maxWalletAmount, cooldownSeconds, dailyTxLimit); }

    /// @notice 设置每日最大交易次数(0 表示不限制)
    /// @param n 每日次数上限
    function setDailyTxLimit(uint256 n) external onlyOwner { dailyTxLimit = n; emit LimitsUpdated(maxTxAmount, maxWalletAmount, cooldownSeconds, dailyTxLimit); }

    /// @notice 将地址加入/移出费用白名单
    /// @param a 地址
    /// @param v 是否白名单
    function excludeFromFees(address a, bool v) external onlyOwner { isExcludedFromFees[a]=v; }

    /// @notice 将地址加入/移出限额白名单
    /// @param a 地址
    /// @param v 是否白名单
    function excludeFromLimits(address a, bool v) external onlyOwner { isExcludedFromLimits[a]=v; }

    /// @notice 启用/关闭自动回流
    /// @param v 是否启用
    function setSwapBackEnabled(bool v) external onlyOwner { swapBackEnabled = v; }

    /// @notice 设置自动回流触发阈值(代币量)
    /// @param v 触发阈值
    function setSwapThreshold(uint256 v) external onlyOwner { swapThreshold = v; }

    /// @notice 启用交易(上市开关)
    function enableTrading() external onlyOwner { tradingEnabled = true; }

    /// @notice 接收 ETH(路由器兑换时进入本合约)
    receive() external payable {}
}
1

评论区