// 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 {}
}
评论区