StoxesFunSimpleToken

0x96b2a9ddd445bffc08f900008f894c405a275afe

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
3,441 bytes
ABI entries
42
18 read · 6 write
License
none

Contract information

Address
0x96b2a9ddd445bffc08f900008f894c405a275afe
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0x4524362401…e93d19ab99

Token

Name
pancake mascot
Symbol
BABYBUNNY
Decimals
18
Holders
38

Read contract (18)

ANTI_SNIPE_DURATION()uint256
GRADUATION_WETH()uint256
MAX_SUPPLY()uint256
MAX_WALLET_BPS()uint256
WETH()address
allowance(address, address)uint256
antiSnipeEndsAt()uint256
balanceOf(address)uint256
decimals()uint8
factory()address
maxWalletExempt(address)bool
metaURI()string
migrated()bool
name()string
owner()address
pool()address
symbol()string
totalSupply()uint256

Events (5)

ApprovalMaxWalletExemptSetMigratedPoolSetTransfer

ABI

[
  {
    "inputs": [],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "AlreadyMigrated",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "allowance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientAllowance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "balance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidReceiver",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSender",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidParams",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "wouldHold",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "cap",
        "type": "uint256"
      }
    ],
    "name": "MaxWalletExceeded",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotFactory",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotYetMigratable",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PoolAlreadySet",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PoolNotSet",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "WiringFinalized",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "exempt",
        "type": "bool"
      }
    ],
    "name": "MaxWalletExemptSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "poolWethBalance",
        "type": "uint256"
      }
    ],
    "name": "Migrated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "pool",
        "type": "address"
      }
    ],
    "name": "PoolSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "ANTI_SNIPE_DURATION",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "GRADUATION_WETH",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_WALLET_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "WETH",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "antiSnipeEndsAt",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "declareMigrated",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "factory",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "maxWalletExempt",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "metaURI",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "migrated",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pool",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "exempt",
        "type": "bool"
      }
    ],
    "name": "setMaxWalletExempt",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "pool_",
        "type": "address"
      }
    ],
    "name": "setPool",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Source code

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

import {ERC20CloneBase} from "./base/ERC20CloneBase.sol";

interface IERC20BalanceView {
    function balanceOf(address account) external view returns (uint256);
}

/// @notice The launch factory callback the token constructor reads its params
///         from. Deployer-callback pattern (same trick as UniswapV3Pool): the
///         constructor takes NO arguments, so the CREATE2 init-code hash is a
///         CONSTANT — the in-browser vanity salt miner only ever needs the
///         creation-code hash, independent of name/symbol/metadata.
interface IStoxesFunSimpleTokenDeployer {
    function launchParams()
        external
        view
        returns (
            string memory name,
            string memory symbol,
            string memory metaURI,
            address devBuyer,
            address weth
        );
}

/// @title  StoxesFunSimpleToken — the stoxes.fun NON-taxed launch token
/// @author stoxes.fun
/// @notice Immutable, plain ERC-20 launched straight into a Uniswap V3 pool
///         (bow.fun model). NO tax, NO owner, NO mint path, NO blacklist:
///         the full fixed supply is minted once to the launch factory, which
///         locks it single-sided into the V3 position held forever by the
///         Locker. Platform + creator revenue is the pool's 1% swap fee only.
///
///         The only transfer-time logic, both temporary or inert:
///           - Anti-snipe max-wallet: for a short window after launch, a
///             non-exempt wallet cannot hold more than 2% of supply. The
///             window expires by timestamp; after that the check is dead code.
///             The dev buy (launch creator) is exempt, like bow.fun.
///           - `declareMigrated()`: a PERMISSIONLESS, purely cosmetic latch
///             that flips `migrated` once the V3 pool holds >= 3.7 WETH.
///             It gates nothing on-chain — it exists so UIs/scanners can show
///             a "graduated" badge, mirroring bow.fun's latch.
///
///         Ownership is renounced from birth: `owner()` returns address(0)
///         forever. The immutable launch factory can wire the pool address +
///         max-wallet exemptions ONLY during the launch transaction (before
///         `setPool` finalizes the wiring) — afterwards nothing can change.
contract StoxesFunSimpleToken is ERC20CloneBase {
    /// @notice Fixed launch supply: 1 billion tokens (matches the taxed side).
    uint256 public constant MAX_SUPPLY = 1e9 ether;

    /// @notice Anti-snipe max wallet: 2% of supply while the window is open.
    uint256 public constant MAX_WALLET_BPS = 200;

    /// @notice Anti-snipe window length after deploy.
    uint256 public constant ANTI_SNIPE_DURATION = 10 minutes;

    /// @notice V3 pool WETH depth at which the cosmetic `migrated` latch opens.
    uint256 public constant GRADUATION_WETH = 3.7 ether;

    /// @notice The stoxes.fun V3 launch factory that deployed this token.
    ///         Its ONLY power is one-shot wiring during the launch tx.
    address public immutable factory;

    /// @notice WETH on Robinhood Chain (read from the factory at deploy).
    address public immutable WETH;

    /// @notice Timestamp when the anti-snipe max-wallet check stops applying.
    uint256 public immutable antiSnipeEndsAt;

    /// @notice The token's Uniswap V3 pool (set once by the factory at launch).
    address public pool;

    /// @notice Cosmetic graduation latch (see `declareMigrated`).
    bool public migrated;

    /// @notice Off-chain metadata URI (socials, logo) — "stoxes.fun" branded.
    string public metaURI;

    /// @notice Wallets exempt from the anti-snipe max-wallet check (factory,
    ///         pool, locker, position manager, dev buyer, dead address).
    mapping(address => bool) public maxWalletExempt;

    event PoolSet(address indexed pool);
    event MaxWalletExemptSet(address indexed account, bool exempt);
    event Migrated(uint256 poolWethBalance);

    error NotFactory();
    error PoolAlreadySet();
    error PoolNotSet();
    error NotYetMigratable();
    error AlreadyMigrated();
    error MaxWalletExceeded(address account, uint256 wouldHold, uint256 cap);
    error WiringFinalized();
    error InvalidParams();

    modifier onlyFactory() {
        if (msg.sender != factory) revert NotFactory();
        _;
    }

    /// @dev No constructor args (constant init-code hash for vanity mining):
    ///      everything comes from the deployer callback.
    constructor() {
        factory = msg.sender;
        (
            string memory name_,
            string memory symbol_,
            string memory metaURI_,
            address devBuyer,
            address weth_
        ) = IStoxesFunSimpleTokenDeployer(msg.sender).launchParams();
        if (weth_ == address(0)) revert InvalidParams();

        _initERC20(name_, symbol_);
        metaURI = metaURI_;
        WETH = weth_;
        antiSnipeEndsAt = block.timestamp + ANTI_SNIPE_DURATION;

        // Launch-infrastructure exemptions. The dev buy lands in the same
        // transaction and is exempt from the max wallet, like bow.fun.
        maxWalletExempt[msg.sender] = true;
        if (devBuyer != address(0)) {
            maxWalletExempt[devBuyer] = true;
            emit MaxWalletExemptSet(devBuyer, true);
        }
        maxWalletExempt[address(0xdead)] = true;

        _mint(msg.sender, MAX_SUPPLY);
    }

    /// @notice Ownership is renounced from birth: there is no owner, ever.
    /// @dev    Explicit view so explorers/scanners that probe `owner()` read
    ///         the token as renounced from block one.
    function owner() public pure returns (address) {
        return address(0);
    }

    // ------------------------------------------------------------------
    // One-shot factory wiring (launch transaction only)
    // ------------------------------------------------------------------

    /// @notice Marks launch-infrastructure addresses max-wallet exempt.
    ///         Callable only by the factory and only BEFORE `setPool`
    ///         finalizes the wiring — after launch nothing can change.
    function setMaxWalletExempt(address account, bool exempt) external onlyFactory {
        if (pool != address(0)) revert WiringFinalized();
        maxWalletExempt[account] = exempt;
        emit MaxWalletExemptSet(account, exempt);
    }

    /// @notice Sets the V3 pool address ONCE. This is the LAST wiring call:
    ///         it permanently freezes the exemption list too.
    function setPool(address pool_) external onlyFactory {
        if (pool != address(0)) revert PoolAlreadySet();
        if (pool_ == address(0)) revert InvalidParams();
        pool = pool_;
        maxWalletExempt[pool_] = true;
        emit MaxWalletExemptSet(pool_, true);
        emit PoolSet(pool_);
    }

    // ------------------------------------------------------------------
    // Cosmetic graduation latch (permissionless)
    // ------------------------------------------------------------------

    /// @notice Latches `migrated` once the pool holds >= 3.7 WETH. Anyone can
    ///         call it; it changes NO transfer/economic behavior — it is a
    ///         badge for UIs, mirroring bow.fun's graduation latch.
    function declareMigrated() external {
        if (migrated) revert AlreadyMigrated();
        address p = pool;
        if (p == address(0)) revert PoolNotSet();
        uint256 depth = IERC20BalanceView(WETH).balanceOf(p);
        if (depth < GRADUATION_WETH) revert NotYetMigratable();
        migrated = true;
        emit Migrated(depth);
    }

    // ------------------------------------------------------------------
    // Transfer hook: anti-snipe max wallet during the launch window only
    // ------------------------------------------------------------------

    function _transfer(address from, address to, uint256 amount) internal override {
        if (block.timestamp < antiSnipeEndsAt && !maxWalletExempt[to]) {
            uint256 cap = (MAX_SUPPLY * MAX_WALLET_BPS) / 10_000;
            uint256 wouldHold = balanceOf(to) + amount;
            if (wouldHold > cap) revert MaxWalletExceeded(to, wouldHold, cap);
        }
        _rawTransfer(from, to, amount);
    }
}
Chain explorer6402msChain node89ms