扭金蛋 GGE · 合约源码

BSC 主网 56 · 已验证(Sourcify exact match,字节码逐字节一致)

1. GGE 代币 0xdb86dAC3Ba63500f37FbB8704187d8b3aB2CF10d

Sourcify 验证记录 · BscScan · 下载源文件

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

/* ============================================================
   Golden Egg / GGE · BEP20
   - 买卖各 1% 税:0.5% → 团队钱包(代币形式,立即到账)
                    0.5% → 留在本合约,任何人可调用 swapTaxToBnb() 换成 BNB 进分红池
   - 分红池就是本合约本身:无 Owner、无提款函数,BNB 只能靠持有人 claim() 领走
   - 分红规则:
       · 持币 ≥ 10,000,000 GGE 才有资格
       · 按持币比例累计(进池那一刻的持仓决定份额,事后加仓不追补)
       · 累计可领 ≥ 0.01 BNB 才能领,避免 gas 吃掉收益
   ============================================================ */

interface IBEP20 {
    function balanceOf(address) external view returns (uint256);
    function transfer(address, uint256) external returns (bool);
}

interface IPancakeRouter {
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline
    ) external;
}

contract NiuJinDanToken {
    string public name = "Golden Egg";
    string public symbol = "GGE";
    uint8 public constant decimals = 18;
    uint256 public totalSupply;

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

    /* ---------- 税 ---------- */
    uint256 public constant TAX_BPS = 100;          // 1%
    uint256 public constant TEAM_SHARE_BPS = 50;    // 税里一半给团队
    address public immutable teamWallet;
    address public launchContract;                  // 打新合约(免税收发奖励用),仅 deployer 可设一次
    mapping(address => bool) public taxExempt;      // 分发/团队地址免税收发,deployer 设置一次后永久锁定
    bool public exemptionsLocked;

    IPancakeRouter public immutable router;
    address public immutable wbnb;
    uint256 public constant SWAP_THRESHOLD = 1_000_000 * 1e18;  // 攒够 100 万代币才换 BNB

    /* ---------- 分红 ---------- */
    uint256 public constant MAG = 1e18;
    uint256 public constant MIN_HOLD = 10_000_000 * 1e18;       // 门槛 1000 万
    uint256 public constant MIN_CLAIM = 0.01 ether;             // 最低领取 0.01 BNB
    uint256 public accPerShare;
    mapping(address => uint256) public lastAcc;
    mapping(address => uint256) public pending;
    uint256 public totalDividendReceived;
    uint256 public totalAllocated;      // 已记账给持有人的总额
    uint256 public totalClaimed;        // 已领走的总额
    uint256 public constant TICK_BPS = 500;   // 每轮分出合约余额的 5%

    address public immutable deployer;
    bool private _inSwap;

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event DividendIn(address indexed from, uint256 amount);
    event DividendClaimed(address indexed user, uint256 amount);
    event TaxSwapped(uint256 tokens, uint256 bnb);

    constructor(
        string memory _name,
        string memory _symbol,
        address _team,
        uint256 _supply,
        address _holder,
        address _router,
        address _wbnb
    ) {
        name = _name;
        symbol = _symbol;
        teamWallet = _team;
        totalSupply = _supply;
        deployer = msg.sender;
        router = IPancakeRouter(_router);
        wbnb = _wbnb;
        balanceOf[_holder] = _supply;
        emit Transfer(address(0), _holder, _supply);
    }

    /// 打新合约地址只登记一次(登记后永远生效,无法取消)
    function setLaunchOnce(address _launch) external {
        require(msg.sender == deployer, "not deployer");
        require(launchContract == address(0), "locked");
        require(_launch != address(0), "zero");
        launchContract = _launch;
    }

    function setExempt(address who, bool on) external {
        require(msg.sender == deployer, "not deployer");
        require(!exemptionsLocked, "locked");
        taxExempt[who] = on;
    }

    /// 上线后锁死,任何人都不能再改免税名单
    function lockExemptions() external {
        require(msg.sender == deployer, "not deployer");
        exemptionsLocked = true;
    }

    /* ---------- 分红 ---------- */

    receive() external payable {}

    /// 每轮把合约 BNB 余额的 5% 记到持有人账上(任何人可调用,没有权限)
    /// 未领取的部分不会被重复分配:分配上限 = 余额 - 未领取
    function distributeTick() external returns (uint256) {
        uint256 bal = address(this).balance;
        if (bal == 0) return 0;
        uint256 outstanding = totalAllocated - totalClaimed;
        uint256 avail = bal > outstanding ? bal - outstanding : 0;
        uint256 amount = (bal * TICK_BPS) / 10000;
        if (amount > avail) amount = avail;
        if (amount == 0) return 0;
        _distribute(amount);
        return amount;
    }

    function _eligibleSupply() internal view returns (uint256) {
        // 合约自己持有的税代币不参与分红
        return totalSupply - balanceOf[address(this)];
    }

    function _distribute(uint256 amount) internal {
        if (amount == 0) return;
        uint256 denom = _eligibleSupply();
        if (denom == 0) return;
        accPerShare += (amount * MAG) / denom;
        totalDividendReceived += amount;
        totalAllocated += amount;
        emit DividendIn(msg.sender, amount);
    }

    function _settle(address user) internal {
        uint256 bal = balanceOf[user];
        if (bal == 0) { lastAcc[user] = accPerShare; return; }
        uint256 owed = (bal * (accPerShare - lastAcc[user])) / MAG;
        if (owed > 0) pending[user] += owed;
        lastAcc[user] = accPerShare;
    }

    /// 持有人自己领 BNB(自付 gas),需持币 ≥ 1000 万、可领 ≥ 0.01 BNB
    function claim() external {
        _settle(msg.sender);
        uint256 amt = pending[msg.sender];
        require(balanceOf[msg.sender] >= MIN_HOLD, "hold < 10M");
        require(amt >= MIN_CLAIM, "less than 0.01 BNB");
        pending[msg.sender] = 0;
        totalClaimed += amt;
        (bool ok, ) = payable(msg.sender).call{value: amt}("");
        require(ok, "bnb fail");
        emit DividendClaimed(msg.sender, amt);
    }

    function claimable(address user) external view returns (uint256) {
        uint256 bal = balanceOf[user];
        uint256 extra = bal == 0 ? 0 : (bal * (accPerShare - lastAcc[user])) / MAG;
        uint256 total = pending[user] + extra;
        if (bal < MIN_HOLD || total < MIN_CLAIM) return 0;
        return total;
    }

    /* ---------- 税代币换 BNB(任何人可调用,无需权限) ---------- */

    function swapTaxToBnb(uint256 minBnbOut) external {
        require(!_inSwap, "busy");
        uint256 tokens = balanceOf[address(this)];
        require(tokens >= SWAP_THRESHOLD, "below threshold");
        _inSwap = true;

        _settle(address(this));
        balanceOf[address(this)] = 0;
        emit Transfer(address(this), address(this), 0);

        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = wbnb;
        allowance[address(this)][address(router)] = tokens;

        uint256 before = address(this).balance;
        router.swapExactTokensForETHSupportingFeeOnTransferTokens(
            tokens, minBnbOut, path, address(this), block.timestamp
        );
        uint256 gained = address(this).balance - before;
        _inSwap = false;

        emit TaxSwapped(tokens, gained);
    }

    /* ---------- 转账与税 ---------- */

    function transfer(address to, uint256 amount) external returns (bool) {
        _transfer(msg.sender, to, amount);
        return true;
    }

    function transferFrom(address from, address to, uint256 amount) external returns (bool) {
        uint256 a = allowance[from][msg.sender];
        require(a >= amount, "allowance");
        if (a != type(uint256).max) allowance[from][msg.sender] = a - amount;
        _transfer(from, to, amount);
        return true;
    }

    function approve(address spender, uint256 amount) external returns (bool) {
        allowance[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    function _isExempt(address a) internal view returns (bool) {
        return taxExempt[a] || a == address(this) || (launchContract != address(0) && a == launchContract);
    }

    function _transfer(address from, address to, uint256 amount) internal {
        require(balanceOf[from] >= amount, "balance");
        _settle(from);
        _settle(to);

        bool taxed = !_isExempt(from) && !_isExempt(to) && to != address(0);
        uint256 tax = taxed ? (amount * TAX_BPS) / 10000 : 0;
        uint256 net = amount - tax;

        balanceOf[from] -= amount;
        balanceOf[to] += net;

        if (tax > 0) {
            uint256 half = (tax * TEAM_SHARE_BPS) / 100;
            balanceOf[teamWallet] += half;
            balanceOf[address(this)] += tax - half;   // 留在合约,等着换 BNB 进分红池
            emit Transfer(from, teamWallet, half);
            emit Transfer(from, address(this), tax - half);
        }
        emit Transfer(from, to, net);
    }
}

2. 打新合约 0xAf98b0D9F9Dbe006d9b4cC13f9DBCa923F8756DD

Sourcify 验证记录 · BscScan · 下载源文件

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

/* ============================================================
   牛金丹 NIUJINDAN · 打新合约
   总量 4444 份:1111 免费 + 3333 付费(0.0028 BNB/份)= 9.3324 BNB
   每人(每个 .ai 身份)最多 4 份,限时 72 小时
   满额后分账:60% 加池(LP 打进黑洞烧掉)/ 20% 团队 / 20% 分红池
   未满额:到期后按已付金额退 80%
   ============================================================ */

interface IBEP20 {
    function transfer(address, uint256) external returns (bool);
    function transferFrom(address, address, uint256) external returns (bool);
    function approve(address, uint256) external returns (bool);
    function balanceOf(address) external view returns (uint256);
}

interface IPancakeRouter {
    function addLiquidityETH(
        address token, uint256 amountTokenDesired, uint256 amountTokenMin,
        uint256 amountETHMin, address to, uint256 deadline
    ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
}

interface IAIIdentity {
    function handleOf(address user) external view returns (string memory);
}

contract NiuJinDanLaunch {
    // ==== 参数 ====
    uint256 public constant TOTAL_SUPPLY = 5000;
    uint256 public constant FREE_SUPPLY = 500;
    uint256 public constant PRICE = 0.0028 ether;
    uint256 public constant MAX_PER_ID = 10;
    uint256 public constant DURATION = 72 hours;
    uint256 public constant REFUND_BPS = 8000;      // 未开盘退 80%

    // 稀有度奖励(18 位小数)
    uint256 private constant R1 = 50_000_000 * 1e18;
    uint256 private constant R2 = 90_000_000 * 1e18;
    uint256 private constant R3 = 120_000_000 * 1e18;
    uint256 private constant R4 = 150_000_000 * 1e18;

    // ==== 状态 ====
    address public owner;
    IAIIdentity public aiRegistry;
    IBEP20 public token;
    IPancakeRouter public router;
    address public teamWallet;
    address public dividendPool;
    address public constant DEAD = 0x000000000000000000000000000000000000dEaD;

    uint256 public constant POOL_RESERVE = 100_000_000_000 * 1e18;  // 100B 固定留给建池
    uint256 public startTime;
    uint256 public totalMinted;
    uint256 public paidMinted;
    uint256 public totalBnbPaid;
    bool public poolOpened;
    bool public liquidityAdded;

    mapping(address => uint256) public mintedByAddress;
    mapping(address => uint256) public bnbPaid;
    mapping(address => bool) public refunded;

    event Minted(address indexed user, uint256 tokenId, uint8 rarity, uint256 reward);
    event PoolOpened(uint256 bnbPool, uint256 tokensPool, uint256 bnbTeam, uint256 bnbDividend);
    event Refunded(address indexed user, uint256 amount);

    modifier onlyOwner() { require(msg.sender == owner, "not owner"); _; }

    constructor(
        address _registry, address _router, address _token,
        address _team, address _dividend, address _owner, uint256 _startTime
    ) {
        require(_startTime > block.timestamp, "start must be future");
        owner = _owner;
        aiRegistry = IAIIdentity(_registry);
        router = IPancakeRouter(_router);
        token = IBEP20(_token);
        teamWallet = _team;
        dividendPool = _dividend;
        startTime = _startTime;
    }

    /* ================= 铸造 ================= */

    function mint(uint256 amount) external payable {
        require(block.timestamp >= startTime, "not started");
        require(block.timestamp < startTime + DURATION, "ended");
        require(!poolOpened, "pool opened");
        require(amount > 0 && amount <= MAX_PER_ID, "bad amount");
        require(mintedByAddress[msg.sender] + amount <= MAX_PER_ID, "over per id");
        require(totalMinted + amount <= TOTAL_SUPPLY, "sold out");

        string memory handle = aiRegistry.handleOf(msg.sender);
        require(bytes(handle).length > 0, "no .ai id");

        // 免费额度:全站前 1111 份,且每个 .ai 钱包只能免费拿 1 份
        uint256 freeLeft = FREE_SUPPLY - (totalMinted - paidMinted);
        bool firstFree = (mintedByAddress[msg.sender] == 0 && freeLeft > 0);
        uint256 cost;
        uint256 newPaid;
        for (uint256 i = 0; i < amount; i++) {
            if (i == 0 && firstFree) { freeLeft--; }
            else { cost += PRICE; newPaid++; }
        }
        require(msg.value == cost, "wrong bnb");

        totalMinted += amount;
        paidMinted += newPaid;
        mintedByAddress[msg.sender] += amount;
        bnbPaid[msg.sender] += cost;
        totalBnbPaid += cost;

        // 开奖 + 发代币
        for (uint256 i = 0; i < amount; i++) {
            uint256 id = totalMinted - amount + i;
            uint256 seed = uint256(keccak256(abi.encodePacked(
                blockhash(block.number - 1), msg.sender, id, totalBnbPaid
            ))) % 100;

            uint8 rarity;
            uint256 reward;
            if (seed < 60) { rarity = 1; reward = R1; }
            else if (seed < 80) { rarity = 2; reward = R2; }
            else if (seed < 95) { rarity = 3; reward = R3; }
            else { rarity = 4; reward = R4; }

            // 玩家额度用完时按剩余量发,绝不超发、绝不 revert
            uint256 avail = token.balanceOf(address(this));
            uint256 spendable = avail > POOL_RESERVE ? avail - POOL_RESERVE : 0;
            if (reward > spendable) reward = spendable;
            require(reward > 0, "reward pool empty");
            require(token.transfer(msg.sender, reward), "token out");
            emit Minted(msg.sender, id, rarity, reward);
        }

        if (totalMinted == TOTAL_SUPPLY) _openPool();
    }

    /* ================= 分账 ================= */

    function _openPool() internal {
        poolOpened = true;
        uint256 bal = totalBnbPaid;
        uint256 bnbPool = (bal * 60) / 100;
        uint256 bnbTeam = (bal * 20) / 100;
        uint256 bnbDiv = bal - bnbPool - bnbTeam;

        if (bnbTeam > 0) { (bool a, ) = payable(teamWallet).call{value: bnbTeam}(""); require(a, "team fail"); }
        if (bnbDiv > 0) { (bool b, ) = payable(dividendPool).call{value: bnbDiv}(""); require(b, "div fail"); }

        uint256 tokensForPool = token.balanceOf(address(this));
        _addLiquidity(bnbPool, tokensForPool);
        emit PoolOpened(bnbPool, tokensForPool, bnbTeam, bnbDiv);
    }

    /// 加池:只做一次;万一 Pancake 调用失败,任何人都能重试,不需要 Owner
    function _addLiquidity(uint256 bnbAmount, uint256 tokenAmount) internal {
        if (liquidityAdded || tokenAmount == 0 || bnbAmount == 0) return;
        token.approve(address(router), tokenAmount);
        // 低层调用:失败不影响开盘状态,留给 retryAddLiquidity 重试
        (bool ok, ) = address(router).call{value: bnbAmount}(
            abi.encodeWithSignature(
                "addLiquidityETH(address,uint256,uint256,uint256,address,uint256)",
                address(token), tokenAmount, 0, 0, DEAD, block.timestamp + 600
            )
        );
        if (!ok) return;
        liquidityAdded = true;
    }

    /// 公开重试:开盘后若加池没成功,任何人可以调用
    function retryAddLiquidity() external {
        require(poolOpened, "not opened");
        require(!liquidityAdded, "added");
        uint256 bal = totalBnbPaid;
        uint256 bnbPool = (bal * 60) / 100;
        _addLiquidity(bnbPool, token.balanceOf(address(this)));
    }

    /// 手动触发(满额前可调用则 revert)
    function openPool() external onlyOwner {
        require(totalMinted == TOTAL_SUPPLY, "not sold out");
        require(!poolOpened, "opened");
        _openPool();
    }

    /* ================= 退款(80%) ================= */

    function refund() external {
        require(!poolOpened, "pool opened");
        require(block.timestamp >= startTime + DURATION, "not ended");
        require(!refunded[msg.sender], "done");
        uint256 paid = bnbPaid[msg.sender];
        require(paid > 0, "nothing");
        refunded[msg.sender] = true;
        uint256 back = (paid * REFUND_BPS) / 10000;
        (bool ok, ) = payable(msg.sender).call{value: back}("");
        require(ok, "bnb fail");
        emit Refunded(msg.sender, back);
    }

    /* ================= 只读 ================= */

    function freeRemaining() external view returns (uint256) {
        return FREE_SUPPLY - (totalMinted - paidMinted);
    }

    function endTime() external view returns (uint256) { return startTime + DURATION; }

    /* ================= 管理 ================= */

    function setWallets(address _team, address _dividend) external onlyOwner {
        teamWallet = _team; dividendPool = _dividend;
    }

    function rescueToken(address to, uint256 amt) external onlyOwner {
        require(poolOpened || block.timestamp >= startTime + DURATION, "too early");
        token.transfer(to, amt);
    }

    receive() external payable {}
}

编译器 solc 0.8.24+commit.e11b9ed9 · optimizer 200 runs · evmVersion paris