LaunchToken
0x8f0df045f3612f9dc5f8c77278c15ce0cbe515a0
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
2,401 bytes
ABI entries
26
14 read · 3 write
License
none
Contract information
- Address
- 0x8f0df045f3612f9dc5f8c77278c15ce0cbe515a0
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0xEaE70e3C35…4970eFBfE5
- Creation tx
- 0xdfba1a819e…8d13b01fdf
Token
- Name
- The first Robin hood
- Symbol
- TFRH
- Decimals
- 6
- Holders
- 133
- Market
- View token page →
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 (2)
ApprovalTransfer
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"
},
{
"internalType": "address",
"name": "quote_",
"type": "address"
},
{
"internalType": "address",
"name": "v3Factory_",
"type": "address"
},
{
"internalType": "uint24",
"name": "poolFee_",
"type": "uint24"
},
{
"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"
},
{
"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": "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": [],
"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 / instant pool, 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.
///
/// IMMUTABLE BY DESIGN (v2): `maxWalletBps` and `antiSnipeBlocks` are immutables and the
/// exemption set is written ONLY in the constructor — there is NO setter of any kind on this
/// contract. Nothing (not the factory, not the platform owner) can retune the cap, extend the
/// window, or exempt an address after deployment. The restriction is fixed at launch and
/// self-expires by block number, after which this is a fully standard ERC-20. This zero-
/// callable-surface design is deliberate: a mutable cap + owner-controlled exemption list is
/// bytecode-indistinguishable from a honeypot to security scanners (Blockaid flagged v1
/// tokens as malicious on exactly that pattern), and the platform never needed the levers —
/// every exemption is knowable at construction time.
///
/// The launch/graduation Uniswap V3 pool cannot be passed in by the factory (its address
/// derives from THIS token's address — circular), so the token computes it itself via the
/// canonical CREATE2 formula: the pool for (this, quote, fee) under `v3Factory`. This also
/// fixes a v1 launch bug: the real NFPM mints by transferring factory → pool, and v1 never
/// exempted the pool, so any single-sided launch (or same-block full-curve graduation) inside
/// an active anti-snipe window reverted "max wallet (anti-snipe)".
///
/// `maxWalletBps == 0` ⇒ no limits at all (the Monad / back-compatible default); exemptions
/// are then skipped entirely (never read when limits are off) to save launch gas.
contract LaunchToken is ERC20 {
uint8 private constant DECIMALS = 6;
uint256 public constant TOTAL_SUPPLY = 1_000_000_000 * 10 ** 6; // 1B, 6dp = 1e15
/// @dev Canonical Uniswap V3 pool init-code hash — verified against the live rh4663 deployment
/// (CeoCat pool recomputed byte-exact). Both target chains use canonical V3 deployments; a
/// chain with a non-standard hash needs a new token version, not a runtime knob.
bytes32 private constant POOL_INIT_CODE_HASH =
0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;
address public immutable factory; // the launchpad — holds reserves, runs the curve + graduation
uint16 public immutable maxWalletBps; // e.g. 300 = 3% of supply; 0 = no limit. Fixed at launch.
uint64 public immutable antiSnipeBlocks; // anti-snipe window length, in blocks. Fixed at launch.
uint64 public immutable launchBlock; // creation block — window = [launchBlock, launchBlock+window)
/// @notice Constructor-only exemption set: factory / zero / dead / launch infrastructure (locker,
/// position manager, router), the creator, and the self-computed launch/graduation pool.
/// No setter exists — this mapping is immutable after construction.
mapping(address => bool) public limitExempt;
/// @param recipient the factory — it holds the for-sale (800M) + LP-held (200M) reserves.
/// @param quote_ the pool counter-asset (WETH/WMON — or an ERC-20 quote like $ROBIN). Used only
/// to pre-compute the launch/graduation pool exemption; ignored when limits are off or
/// `v3Factory_` is zero.
/// @param v3Factory_ the canonical Uniswap V3 factory this token's pool will be created under.
/// Zero ⇒ skip pool pre-exemption (e.g. graduation venue not configured yet).
/// @param poolFee_ the fee tier of the launch/graduation pool.
/// @param exempt_ launch-time infrastructure + the creator. Zero entries are skipped.
constructor(
string memory name_,
string memory symbol_,
address recipient,
uint16 maxWalletBps_,
uint64 antiSnipeBlocks_,
address quote_,
address v3Factory_,
uint24 poolFee_,
address[] memory exempt_
) ERC20(name_, symbol_) {
require(maxWalletBps_ <= 10000, "bps");
factory = recipient;
maxWalletBps = maxWalletBps_;
antiSnipeBlocks = antiSnipeBlocks_;
launchBlock = uint64(block.number);
// Exemptions only matter while limits are active; skip the SSTOREs entirely when they never
// will be (maxWalletBps == 0 makes limitsActive() permanently false).
if (maxWalletBps_ > 0) {
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
for (uint256 i; i < exempt_.length; ++i) {
if (exempt_[i] != address(0)) limitExempt[exempt_[i]] = true;
}
// The launch/graduation pool: computed, not passed — its address derives from this
// token's own address (CREATE2), which no caller can know before deployment.
if (v3Factory_ != address(0) && quote_ != address(0)) {
(address t0, address t1) =
address(this) < quote_ ? (address(this), quote_) : (quote_, address(this));
address pool = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
v3Factory_,
keccak256(abi.encode(t0, t1, poolFee_)),
POOL_INIT_CODE_HASH
)
)
)
)
);
limitExempt[pool] = true;
}
}
_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;
}
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, launch infra, creator) are never capped. After the window — or
/// when maxWalletBps==0 — the cap is inert. `maxWalletBps`/`antiSnipeBlocks` are immutables,
/// so the post-window hot path costs no storage reads.
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 explorer3516msChain node108ms