{"sources":{"Snowball.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\n/// @title Snowball (SNBL) — ERC-20 on BSC with a pool-integrated staircase sale.\n/// 10,000 shares of 1,000,000 SNBL each are sold at a staircase price\n/// (base 0.0005 BNB, +0.00005 every 10 shares distributed). Every payment\n/// splits in the same transaction: 80% is paired with freshly minted SNBL\n/// and added as PancakeSwap V2 liquidity (LP burned to 0x...dEaD), 20%\n/// goes straight to the treasury. The FIRST buyer's payment seeds the\n/// pool — there is no separate seeding step. The first share of every\n/// Agent ID wallet is discounted 90% (still paid, once per wallet).\n/// Referral: 1 bonus share per 10 paid shares routed through a referrer,\n/// drawn from the same 10,000-share cap. Trading tax on the official\n/// pair only: 1% buy / 2% sell, paid to the treasury in SNBL; plain\n/// wallet-to-wallet transfers are untaxed. No admin functions, no owner,\n/// no sale end date — the sale runs until the shares are gone.\ninterface IAgentRegistry {\n    function balanceOf(address account) external view returns (uint256);\n}\n\ninterface IPancakeFactory {\n    function createPair(address tokenA, address tokenB) external returns (address pair);\n}\n\ninterface IWBNB {\n    function deposit() external payable;\n    function transfer(address to, uint256 value) external returns (bool);\n    function balanceOf(address account) external view returns (uint256);\n}\n\ninterface IPancakePair {\n    function token0() external view returns (address);\n    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);\n    function mint(address to) external returns (uint256 liquidity);\n}\n\ncontract Snowball {\n    string public constant name = \"Snowball\";\n    string public constant symbol = \"SNBL\";\n    uint8 public constant decimals = 18;\n\n    uint256 public constant TOTAL_SHARES = 10_000;\n    uint256 public constant SHARE = 1_000_000 * 10 ** 18; // SNBL per share\n    /// Hard cap on everything ever minted: 10B buyer/referral shares plus\n    /// up to 10B of liquidity-side SNBL.\n    uint256 public constant MAX_SUPPLY = 20_000_000_000 * 10 ** 18;\n    uint256 public constant MAX_PER_TX = 20;\n    uint256 public constant BASE_PRICE = 0.0005 ether;\n    uint256 public constant STEP_UP = 0.00005 ether; // +10% of base per 10 shares\n\n    address public constant DEAD = 0x000000000000000000000000000000000000dEaD;\n\n    address public immutable registry;\n    address public immutable treasury;\n    address public immutable WBNB;\n    address public immutable pair;\n\n    // ---- sale state ----\n    uint256 public totalOut;          // shares distributed, all paths\n    uint256 public paidSold;          // paid shares (incl. discounted first shares)\n    uint256 public referralMintedTotal;\n    uint256 public totalMinted;       // every SNBL ever minted (buyers + legs + referral)\n    bool public poolSeeded;\n\n    mapping(address => bool) public firstShareUsed; // 90% discount consumed\n    mapping(address => uint256) public referralUnits;   // paid shares bought via this referrer\n    mapping(address => uint256) public referralMinted;  // reward shares already minted\n\n    // ---- ERC-20 state ----\n    mapping(address => uint256) private _balances;\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    bool private _lock;\n    modifier lock() {\n        require(!_lock, \"reentrant\");\n        _lock = true;\n        _;\n        _lock = false;\n    }\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n    event Bought(address indexed wallet, uint256 qty, address referrer, uint256 costWei);\n    event PoolSeeded(uint256 bnbWei, uint256 tokenWei);\n    event LiquidityAdded(uint256 bnbWei, uint256 tokenWei);\n    event ReferralReward(address indexed referrer, uint256 totalRewarded);\n\n    constructor(address registry_, address treasury_, address factory_, address wbnb_) {\n        require(registry_ != address(0) && treasury_ != address(0) && factory_ != address(0) && wbnb_ != address(0), \"zero addr\");\n        registry = registry_;\n        treasury = treasury_;\n        WBNB = wbnb_;\n        pair = IPancakeFactory(factory_).createPair(address(this), wbnb_);\n    }\n\n    receive() external payable {\n        if (_lock) return; // mid-buy flows settle through buy()'s own accounting\n        (bool ok, ) = treasury.call{value: msg.value}(\"\");\n        require(ok, \"forward failed\");\n    }\n\n    // ================= views =================\n    function totalSupply() external view returns (uint256) {\n        return totalMinted;\n    }\n\n    function balanceOf(address w) public view returns (uint256) {\n        return _balances[w];\n    }\n\n    function sharesOf(address w) external view returns (uint256) {\n        return _balances[w] / SHARE;\n    }\n\n    function sharesLeft() public view returns (uint256) {\n        return TOTAL_SHARES - totalOut;\n    }\n\n    /// Price of the share distributed at position `outCount` (0-based).\n    function priceAt(uint256 outCount) public pure returns (uint256) {\n        return BASE_PRICE + STEP_UP * (outCount / 10);\n    }\n\n    function priceNow() public view returns (uint256) {\n        return priceAt(totalOut);\n    }\n\n    function currentStep() public view returns (uint256) {\n        return totalOut / 10;\n    }\n\n    /// Total cost in wei of buying `n` shares right now (no discount).\n    function quote(uint256 n) public view returns (uint256 total) {\n        for (uint256 i = 0; i < n; i++) {\n            total += priceAt(totalOut + i);\n        }\n    }\n\n    /// Cost for a specific buyer: their first-ever unit is 90% off.\n    function quoteFor(address buyer, uint256 n) public view returns (uint256 total) {\n        for (uint256 i = 0; i < n; i++) {\n            uint256 p = priceAt(totalOut + i);\n            if (i == 0 && !firstShareUsed[buyer]) p = p / 10;\n            total += p;\n        }\n    }\n\n    function poolReserves() public view returns (uint256 bnbWei, uint256 tokenWei) {\n        (uint112 r0, uint112 r1, ) = IPancakePair(pair).getReserves();\n        if (IPancakePair(pair).token0() == address(this)) {\n            return (uint256(r1), uint256(r0));\n        }\n        return (uint256(r0), uint256(r1));\n    }\n\n    function status() external view returns (\n        uint256 totalOut_, uint256 paidSold_, uint256 referralMinted_,\n        uint256 step_, uint256 priceWei_, uint256 totalMinted_,\n        uint256 poolSeeded_, uint256 reserveBnb_, uint256 reserveToken_,\n        uint256 sharesLeft_\n    ) {\n        (uint256 rb, uint256 rt) = poolReserves();\n        return (totalOut, paidSold, referralMintedTotal, totalOut / 10,\n                priceNow(), totalMinted, poolSeeded ? 1 : 0, rb, rt, sharesLeft());\n    }\n\n    function walletInfo(address w) external view returns (\n        uint256 snblBalance, bool firstUsed, uint256 refUnits, uint256 refMinted\n    ) {\n        return (_balances[w], firstShareUsed[w], referralUnits[w], referralMinted[w]);\n    }\n\n    // ================= sale =================\n    function buy(uint256 n, address referrer) external payable lock {\n        require(IAgentRegistry(registry).balanceOf(msg.sender) > 0, \"no agent id\");\n        require(n >= 1 && n <= MAX_PER_TX, \"bad qty\");\n        require(paidSold + referralMintedTotal + n <= TOTAL_SHARES, \"sold out\");\n        uint256 cost = quoteFor(msg.sender, n);\n        require(msg.value >= cost, \"underpaid\");\n        uint256 refund = msg.value - cost;\n        uint256 bal0 = address(this).balance - msg.value;\n\n        bool firstNow = !firstShareUsed[msg.sender];\n        if (firstNow) firstShareUsed[msg.sender] = true;\n\n        paidSold += n;\n        totalOut += n;\n        _mint(msg.sender, n * SHARE);\n        emit Bought(msg.sender, n, referrer, cost);\n\n        // ---- 80% to the pool, in this same transaction ----\n        // The SNBL leg is always priced at the NOMINAL staircase price of\n        // this buy's first unit (never the discounted price), so a 90%-off\n        // first share cannot misprice the pool, the 80/20 split stays exact\n        // at every step, and the pool price ratchets up with the staircase.\n        // Liquidity is minted directly on the pair (the V2 router would\n        // force the stale reserve ratio instead); LP goes to 0x...dEaD.\n        uint256 liqBudget = (cost * 80) / 100;\n        uint256 legTokens = (liqBudget * SHARE) / priceAt(totalOut - n);\n        if (legTokens > MAX_SUPPLY - totalMinted) legTokens = MAX_SUPPLY - totalMinted;\n        if (legTokens > 0) {\n            _addLiquidity(liqBudget, legTokens);\n            if (!poolSeeded) {\n                poolSeeded = true;\n                emit PoolSeeded(liqBudget, legTokens);\n            } else {\n                emit LiquidityAdded(liqBudget, legTokens);\n            }\n        }\n\n        // ---- referral: 1 bonus share per 10 paid shares via a referrer ----\n        if (referrer != address(0) && referrer != msg.sender) {\n            referralUnits[referrer] += n;\n            uint256 due = referralUnits[referrer] / 10 - referralMinted[referrer];\n            while (due > 0) {\n                if (paidSold + referralMintedTotal >= TOTAL_SHARES) break;\n                if (totalMinted + SHARE > MAX_SUPPLY) break;\n                referralMinted[referrer]++;\n                referralMintedTotal++;\n                totalOut++;\n                _mint(referrer, SHARE);\n                emit ReferralReward(referrer, referralMinted[referrer]);\n                due--;\n            }\n        }\n\n        // ---- money out: treasury share + any unspent liquidity -> treasury;\n        // ---- the buyer's overpayment -> refunded\n        uint256 leftover = address(this).balance - bal0 - refund;\n        if (leftover > 0) {\n            (bool ok, ) = treasury.call{value: leftover}(\"\");\n            require(ok, \"treasury failed\");\n        }\n        if (refund > 0) {\n            (bool ok2, ) = msg.sender.call{value: refund}(\"\");\n            require(ok2, \"refund failed\");\n        }\n    }\n\n    function _addLiquidity(uint256 bnbWei, uint256 tokenWei) internal {\n        _mint(address(this), tokenWei);\n        _transfer(address(this), pair, tokenWei);\n        IWBNB(WBNB).deposit{value: bnbWei}();\n        require(IWBNB(WBNB).transfer(pair, bnbWei), \"wbnb transfer\");\n        IPancakePair(pair).mint(DEAD);\n    }\n\n    function _mint(address to, uint256 amount) internal {\n        totalMinted += amount;\n        require(totalMinted <= MAX_SUPPLY, \"cap exceeded\");\n        _balances[to] += amount;\n        emit Transfer(address(0), to, amount);\n    }\n\n    // ================= ERC-20 =================\n    function allowance(address owner, address spender) external view returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        _allowances[msg.sender][spender] = amount;\n        emit Approval(msg.sender, spender, amount);\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        _transfer(msg.sender, to, amount);\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        uint256 allowed = _allowances[from][msg.sender];\n        require(allowed >= amount, \"allowance\");\n        if (allowed != type(uint256).max) {\n            _allowances[from][msg.sender] = allowed - amount;\n        }\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    function _transfer(address from, address to, uint256 amount) internal {\n        require(to != address(0), \"zero to\");\n        require(_balances[from] >= amount, \"balance\");\n        uint256 tax = 0;\n        if (poolSeeded && from != address(this) && to != address(this)\n            && from != treasury && to != treasury) {\n            if (from == pair) tax = amount / 100;        // 1% buy tax\n            else if (to == pair) tax = (amount * 2) / 100; // 2% sell tax\n        }\n        _balances[from] -= amount;\n        if (tax > 0) {\n            _balances[treasury] += tax;\n            emit Transfer(from, treasury, tax);\n            amount -= tax;\n        }\n        _balances[to] += amount;\n        emit Transfer(from, to, amount);\n    }\n}\n"}},"abi":[{"type":"constructor","inputs":[{"name":"registry_","type":"address","internalType":"address"},{"name":"treasury_","type":"address","internalType":"address"},{"name":"factory_","type":"address","internalType":"address"},{"name":"wbnb_","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"name":"Approval","type":"event","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"spender","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"Bought","type":"event","inputs":[{"name":"wallet","type":"address","indexed":true,"internalType":"address"},{"name":"qty","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"referrer","type":"address","indexed":false,"internalType":"address"},{"name":"costWei","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"LiquidityAdded","type":"event","inputs":[{"name":"bnbWei","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"tokenWei","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"PoolSeeded","type":"event","inputs":[{"name":"bnbWei","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"tokenWei","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"ReferralReward","type":"event","inputs":[{"name":"referrer","type":"address","indexed":true,"internalType":"address"},{"name":"totalRewarded","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"Transfer","type":"event","inputs":[{"name":"from","type":"address","indexed":true,"internalType":"address"},{"name":"to","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"BASE_PRICE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"DEAD","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"MAX_PER_TX","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"MAX_SUPPLY","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"SHARE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"STEP_UP","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"TOTAL_SHARES","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"WBNB","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"allowance","type":"function","inputs":[{"name":"owner","type":"address","internalType":"address"},{"name":"spender","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"approve","type":"function","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"name":"balanceOf","type":"function","inputs":[{"name":"w","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"buy","type":"function","inputs":[{"name":"n","type":"uint256","internalType":"uint256"},{"name":"referrer","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"payable"},{"name":"currentStep","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"decimals","type":"function","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"name":"firstShareUsed","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"name","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"paidSold","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"pair","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"poolReserves","type":"function","inputs":[],"outputs":[{"name":"bnbWei","type":"uint256","internalType":"uint256"},{"name":"tokenWei","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"poolSeeded","type":"function","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"priceAt","type":"function","inputs":[{"name":"outCount","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"pure"},{"name":"priceNow","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"quote","type":"function","inputs":[{"name":"n","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"total","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"quoteFor","type":"function","inputs":[{"name":"buyer","type":"address","internalType":"address"},{"name":"n","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"total","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"referralMinted","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"referralMintedTotal","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"referralUnits","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"registry","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"sharesLeft","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"sharesOf","type":"function","inputs":[{"name":"w","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"status","type":"function","inputs":[],"outputs":[{"name":"totalOut_","type":"uint256","internalType":"uint256"},{"name":"paidSold_","type":"uint256","internalType":"uint256"},{"name":"referralMinted_","type":"uint256","internalType":"uint256"},{"name":"step_","type":"uint256","internalType":"uint256"},{"name":"priceWei_","type":"uint256","internalType":"uint256"},{"name":"totalMinted_","type":"uint256","internalType":"uint256"},{"name":"poolSeeded_","type":"uint256","internalType":"uint256"},{"name":"reserveBnb_","type":"uint256","internalType":"uint256"},{"name":"reserveToken_","type":"uint256","internalType":"uint256"},{"name":"sharesLeft_","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"symbol","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"totalMinted","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"totalOut","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"totalSupply","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"transfer","type":"function","inputs":[{"name":"to","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"name":"transferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"name":"treasury","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"walletInfo","type":"function","inputs":[{"name":"w","type":"address","internalType":"address"}],"outputs":[{"name":"snblBalance","type":"uint256","internalType":"uint256"},{"name":"firstUsed","type":"bool","internalType":"bool"},{"name":"refUnits","type":"uint256","internalType":"uint256"},{"name":"refMinted","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"receive","stateMutability":"payable"}],"matchId":"59105063","creationMatch":"exact_match","runtimeMatch":"exact_match","verifiedAt":"2026-11-11T14:33:07Z","match":"exact_match","chainId":"56","address":"0x56ec4a9A0914570EA6F96E0a53d98f6f8854F040"}