LaunchToken

0xfb4729659eef22bfc1c2b680f6f873f8147aaaab

Verification
Verified
v0.8.24+commit.e11b9ed9
Type
Contract
2,831 bytes
ABI entries
29
14 read · 5 write
License
none

Contract information

Address
0xfb4729659eef22bfc1c2b680f6f873f8147aaaab
Chain
Robinhood Chain (4663)
Compiler
v0.8.24+commit.e11b9ed9
Optimization
Enabled
Creation tx
0x74685f1275…b53b1ab84e

Token

Name
Robin
Symbol
ROBIN
Decimals
6
Holders
600

Read contract (14)

TOTAL_SUPPLY()uint256
allowance(address, address)uint256
antiSnipeBlocks()uint64
balanceOf(address)uint256
decimals()uint8
factory()address
launchBlock()uint64
limitExempt(address)bool
limitsActive()bool
maxWallet()uint256
maxWalletBps()uint16
name()string
symbol()string
totalSupply()uint256

Events (3)

ApprovalLimitsUpdatedTransfer

ABI

[
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol_",
        "type": "string"
      },
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "internalType": "uint16",
        "name": "maxWalletBps_",
        "type": "uint16"
      },
      {
        "internalType": "uint64",
        "name": "antiSnipeBlocks_",
        "type": "uint64"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "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": "sender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "balance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "approver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidApprover",
    "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": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSpender",
    "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": false,
        "internalType": "uint16",
        "name": "maxWalletBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "uint64",
        "name": "antiSnipeBlocks",
        "type": "uint64"
      }
    ],
    "name": "LimitsUpdated",
    "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": "TOTAL_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "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": "antiSnipeBlocks",
    "outputs": [
      {
        "internalType": "uint64",
        "name": "",
        "type": "uint64"
      }
    ],
    "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": "factory",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchBlock",
    "outputs": [
      {
        "internalType": "uint64",
        "name": "",
        "type": "uint64"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "limitExempt",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "limitsActive",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxWallet",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxWalletBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "a",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "ok",
        "type": "bool"
      }
    ],
    "name": "setLimitExempt",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint16",
        "name": "maxWalletBps_",
        "type": "uint16"
      },
      {
        "internalType": "uint64",
        "name": "antiSnipeBlocks_",
        "type": "uint64"
      }
    ],
    "name": "setLimits",
    "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.24;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/// @title LaunchToken
/// @notice The per-launch ERC-20. 6 decimals, a fixed 1,000,000,000 * 1e6 supply minted ONCE to the
///         factory at construction, no mint function (mint authority effectively renounced).
///
///         Optional NOXA-style anti-snipe: when `maxWalletBps > 0`, a max-wallet cap (in bps of total
///         supply) is enforced for the first `antiSnipeBlocks` blocks after launch — it applies during
///         the bonding curve, so no single wallet can grab more than the cap at launch — then it
///         auto-lifts and the token trades freely. Enforced in OZ's `_update` hook. The factory (the
///         constructor `recipient`) is exempt and can exempt the graduated Uniswap pool (which holds
///         the 20% LP reserve) so the cap never blocks migration.
///
///         `maxWalletBps == 0` ⇒ no limits at all (the Monad / back-compatible default). The factory
///         bakes its current limits into each token's CREATE2 init code.
contract LaunchToken is ERC20 {
    uint8 private constant DECIMALS = 6;
    uint256 public constant TOTAL_SUPPLY = 1_000_000_000 * 10 ** 6; // 1B, 6dp = 1e15

    address public immutable factory; // the launchpad — holds reserves, runs the curve + graduation
    uint16 public maxWalletBps; // e.g. 300 = 3% of supply; 0 = no limit. Owner-mutable post-launch (via factory).
    uint64 public antiSnipeBlocks; // anti-snipe window length, in blocks. Owner-mutable post-launch (via factory).
    uint64 public immutable launchBlock; // creation block — window = [launchBlock, launchBlock+window)
    mapping(address => bool) public limitExempt; // factory / zero / dead / the graduated pool

    event LimitsUpdated(uint16 maxWalletBps, uint64 antiSnipeBlocks);

    /// @param recipient the factory — it holds the for-sale (800M) + LP-held (200M) reserves.
    constructor(
        string memory name_,
        string memory symbol_,
        address recipient,
        uint16 maxWalletBps_,
        uint64 antiSnipeBlocks_
    ) ERC20(name_, symbol_) {
        factory = recipient;
        maxWalletBps = maxWalletBps_;
        antiSnipeBlocks = antiSnipeBlocks_;
        launchBlock = uint64(block.number);
        limitExempt[recipient] = true; // factory holds ~100% of supply through the curve phase
        limitExempt[address(0)] = true; // mint / burn endpoints
        limitExempt[0x000000000000000000000000000000000000dEaD] = true; // LP / burn sink
        _mint(recipient, TOTAL_SUPPLY);
    }

    /// @notice Max tokens a non-exempt wallet may hold while limits are active (max ⇒ unlimited).
    function maxWallet() public view returns (uint256) {
        return maxWalletBps == 0 ? type(uint256).max : (TOTAL_SUPPLY * maxWalletBps) / 10000;
    }

    /// @notice True while the max-wallet cap is enforced (anti-snipe window still open).
    function limitsActive() public view returns (bool) {
        return maxWalletBps > 0 && block.number < uint256(launchBlock) + antiSnipeBlocks;
    }

    /// @notice Factory-only: exempt an address from the cap. The factory calls this for the graduated
    ///         Uniswap pool (which receives the 200M LP reserve, > the cap) so graduation within the
    ///         anti-snipe window isn't blocked.
    function setLimitExempt(address a, bool ok) external {
        require(msg.sender == factory, "only factory");
        limitExempt[a] = ok;
    }

    /// @notice Factory-only: retune this token's anti-snipe AFTER launch. The factory gates this behind
    ///         onlyOwner, so effectively only the platform owner can call it. `maxWalletBps_ == 0` disables
    ///         the cap; the window stays anchored at launchBlock, i.e. [launchBlock, launchBlock+blocks).
    function setLimits(uint16 maxWalletBps_, uint64 antiSnipeBlocks_) external {
        require(msg.sender == factory, "only factory");
        require(maxWalletBps_ <= 10000, "bps");
        maxWalletBps = maxWalletBps_;
        antiSnipeBlocks = antiSnipeBlocks_;
        emit LimitsUpdated(maxWalletBps_, antiSnipeBlocks_);
    }

    function decimals() public pure override returns (uint8) {
        return DECIMALS;
    }

    /// @dev Enforce the max wallet on the recipient during the anti-snipe window only; exempt addresses
    ///      (factory, pool, zero, dead) are never capped. After the window — or when maxWalletBps==0 —
    ///      the cap is inert.
    function _update(address from, address to, uint256 value) internal override {
        if (limitsActive() && !limitExempt[to]) {
            require(balanceOf(to) + value <= maxWallet(), "max wallet (anti-snipe)");
        }
        super._update(from, to, value);
    }
}
Chain explorer8814msChain node75ms