LaunchToken

0x8bada99332848483995ef9c61f4bffced1bafeed

Verification
Verified
v0.8.24+commit.e11b9ed9
Type
Contract
2,581 bytes
ABI entries
41
16 read · 3 write
License
none

Contract information

Address
0x8bada99332848483995ef9c61f4bffced1bafeed
Chain
Robinhood Chain (4663)
Compiler
v0.8.24+commit.e11b9ed9
Optimization
Enabled
Creation tx
0x0d49a57f03…40fda29a62

Token

Name
CatCoin
Symbol
CATCOIN
Decimals
18
Holders
121

Read contract (16)

BPS()uint256
MAX_RESTRICTION_SECONDS()uint256
MIN_MAX_TX_BPS()uint256
MIN_MAX_WALLET_BPS()uint256
allowance(address, address)uint256
balanceOf(address)uint256
decimals()uint8
isExempt(address)bool
maxTxAmount()uint256
maxWalletAmount()uint256
name()string
pool()address
restrictionsActive()bool
restrictionsEndTime()uint256
symbol()string
totalSupply()uint256

Events (2)

ApprovalTransfer

ABI

[
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol_",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "totalSupply_",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "maxTxBps_",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "maxWalletBps_",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "restrictionSeconds_",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "pool_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "recipient_",
        "type": "address"
      },
      {
        "internalType": "address[]",
        "name": "exempt_",
        "type": "address[]"
      }
    ],
    "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"
  },
  {
    "inputs": [],
    "name": "ExemptIsPool",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "MaxTxAmountZero",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "MaxTxBpsOOB",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "MaxTxExceeded",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "MaxWalletAmountZero",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "MaxWalletBpsOOB",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "MaxWalletExceeded",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PoolZero",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "RecipientIsPool",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "RecipientZero",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "SupplyTooLarge",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "SupplyZero",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "WindowTooLong",
    "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": "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": "BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_RESTRICTION_SECONDS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MIN_MAX_TX_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MIN_MAX_WALLET_BPS",
    "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": [
      {
        "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": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "isExempt",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxTxAmount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxWalletAmount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pool",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "restrictionsActive",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "restrictionsEndTime",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "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; // >= 0.8.21 required: constructor reads immutables during construction

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

/// @notice Fixed-supply memecoin with a bounded, auto-lifting, time-based anti-sniper.
/// @dev Only safe when deployed by the trusted factory (which sanitizes params + exemptions).
contract LaunchToken is ERC20 {
    uint256 public constant BPS = 10_000;
    uint256 public constant MAX_RESTRICTION_SECONDS = 3600; // 1h hard cap
    uint256 public constant MIN_MAX_TX_BPS = 50;            // >= 0.5%
    uint256 public constant MIN_MAX_WALLET_BPS = 50;        // >= 0.5%

    uint256 public immutable maxTxAmount;
    uint256 public immutable maxWalletAmount;
    uint256 public immutable restrictionsEndTime;
    address public immutable pool;

    mapping(address => bool) public isExempt;

    error SupplyZero();
    error SupplyTooLarge();
    error RecipientZero();
    error PoolZero();
    error RecipientIsPool();
    error ExemptIsPool();
    error MaxTxBpsOOB();
    error MaxWalletBpsOOB();
    error WindowTooLong();
    error MaxTxAmountZero();
    error MaxWalletAmountZero();
    error MaxTxExceeded();
    error MaxWalletExceeded();

    constructor(
        string memory name_,
        string memory symbol_,
        uint256 totalSupply_,
        uint256 maxTxBps_,
        uint256 maxWalletBps_,
        uint256 restrictionSeconds_,
        address pool_,
        address recipient_,
        address[] memory exempt_
    ) ERC20(name_, symbol_) {
        if (totalSupply_ == 0) revert SupplyZero();
        // Guards the maxTx/maxWallet bps math below: with totalSupply_ bounded here, and
        // maxTxBps_/maxWalletBps_ <= BPS (enforced further down), `totalSupply_ * bps_` cannot
        // overflow uint256 — turning what would otherwise be a raw Panic(0x11) on huge (but
        // otherwise in-bounds) supplies into a named, documented rejection.
        if (totalSupply_ > type(uint256).max / BPS) revert SupplyTooLarge();
        if (recipient_ == address(0)) revert RecipientZero();
        if (pool_ == address(0)) revert PoolZero();
        if (recipient_ == pool_) revert RecipientIsPool();
        if (maxTxBps_ < MIN_MAX_TX_BPS || maxTxBps_ > BPS) revert MaxTxBpsOOB();
        if (maxWalletBps_ < MIN_MAX_WALLET_BPS || maxWalletBps_ > BPS) revert MaxWalletBpsOOB();
        if (restrictionSeconds_ > MAX_RESTRICTION_SECONDS) revert WindowTooLong();

        uint256 mtx = (totalSupply_ * maxTxBps_) / BPS;
        if (mtx == 0) revert MaxTxAmountZero(); // dust-supply guard
        maxTxAmount = mtx;
        uint256 mw = (totalSupply_ * maxWalletBps_) / BPS;
        if (mw == 0) revert MaxWalletAmountZero(); // dust-supply guard
        maxWalletAmount = mw;
        restrictionsEndTime = block.timestamp + restrictionSeconds_;
        pool = pool_;

        // to-side exemptions only; the pool may NEVER be exempt (would bypass buy limits).
        isExempt[recipient_] = true;
        for (uint256 i; i < exempt_.length; ++i) {
            if (exempt_[i] == pool_) revert ExemptIsPool();
            isExempt[exempt_[i]] = true;
        }
        // _mint triggers _update, which reads the immutables + isExempt set above.
        // Assignments MUST precede _mint — do not reorder.
        _mint(recipient_, totalSupply_);
    }

    function restrictionsActive() public view returns (bool) {
        // Deliberate: on Arbitrum Orbit, block.number tracks the parent chain (~12s), so
        // block.timestamp is the only usable clock for the anti-sniper window.
        // forge-lint: disable-next-line(block-timestamp)
        return block.timestamp < restrictionsEndTime;
    }

    function _update(address from, address to, uint256 value) internal override {
        // Only during the window, only for non-exempt inbound, and never for transfers
        // INTO the pool (sells / liquidity deposits are always free).
        if (restrictionsActive() && to != pool && !isExempt[to]) {
            // maxWallet: caps accumulation for ALL inbound (buys + p2p) -> anti park-and-rebuy.
            // Note: balanceOf(to) is read pre-debit, so a self-transfer (from == to) is double-
            // counted; harmless no-op except it blocks self-transfer at the exact ceiling. Do not "fix".
            if (balanceOf(to) + value > maxWalletAmount) revert MaxWalletExceeded();
            // maxTx: caps per-BUY size only (tokens leaving the pool).
            if (from == pool && value > maxTxAmount) revert MaxTxExceeded();
        }
        super._update(from, to, value);
    }
}
Chain explorer4143msChain node75ms