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
- Creator
- 0xc8EE3C8B77…C76eF0BDa0
- Creation tx
- 0x0d49a57f03…40fda29a62
Token
- Name
- CatCoin
- Symbol
- CATCOIN
- Decimals
- 18
- Holders
- 121
- Market
- View token page →
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