LaunchTokenV3
0x65b6b935053d19e1e7311f911f2730778ce82dee
Verification
Verified
v0.8.24+commit.e11b9ed9
Type
Contract
5,049 bytes
ABI entries
46
21 read · 4 write
License
none
Contract information
- Address
- 0x65b6b935053d19e1e7311f911f2730778ce82dee
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.24+commit.e11b9ed9
- Optimization
- Enabled
- Creator
- 0x985DFae571…6D2cE1E46f
- Creation tx
- 0x6660a298e7…2fc545e268
Token
- Name
- Coinbarrel
- Symbol
- COINBARREL
- Decimals
- 18
- Holders
- 19
- Market
- View token page →
Read contract (21)
DEAD() → address
DOMAIN_SEPARATOR() → bytes32
MAX_WALLET() → uint256
POOL_FEE() → uint24
RESTRICTION_BLOCKS() → uint256
TOTAL_SUPPLY() → uint256
allowance(address, address) → uint256
balanceOf(address) → uint256
decimals() → uint8
eip712Domain() → bytes1, string, string, uint256, address, bytes32, uint256[]
launchBlock() → uint256
launcher() → address
locker() → address
logo() → string
name() → string
nonces(address) → uint256
pool() → address
restrictionEndBlock() → uint256
symbol() → string
tokenURI() → string
totalSupply() → uint256
Events (3)
ApprovalEIP712DomainChangedTransfer
ABI
[
{
"inputs": [
{
"internalType": "string",
"name": "name_",
"type": "string"
},
{
"internalType": "string",
"name": "symbol_",
"type": "string"
},
{
"internalType": "string",
"name": "tokenURI_",
"type": "string"
},
{
"internalType": "string",
"name": "logo_",
"type": "string"
},
{
"internalType": "address",
"name": "locker_",
"type": "address"
},
{
"internalType": "address",
"name": "uniswapV3Factory_",
"type": "address"
},
{
"internalType": "address",
"name": "weth_",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "ECDSAInvalidSignature",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "length",
"type": "uint256"
}
],
"name": "ECDSAInvalidSignatureLength",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"name": "ECDSAInvalidSignatureS",
"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": "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": [
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
}
],
"name": "ERC2612ExpiredSignature",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "signer",
"type": "address"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "ERC2612InvalidSigner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "currentNonce",
"type": "uint256"
}
],
"name": "InvalidAccountNonce",
"type": "error"
},
{
"inputs": [],
"name": "InvalidPoolKey",
"type": "error"
},
{
"inputs": [],
"name": "InvalidShortString",
"type": "error"
},
{
"inputs": [],
"name": "LaunchBlockBuyBlocked",
"type": "error"
},
{
"inputs": [],
"name": "MaxWalletExceeded",
"type": "error"
},
{
"inputs": [
{
"internalType": "string",
"name": "str",
"type": "string"
}
],
"name": "StringTooLong",
"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": [],
"name": "EIP712DomainChanged",
"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": "DEAD",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "DOMAIN_SEPARATOR",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_WALLET",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "POOL_FEE",
"outputs": [
{
"internalType": "uint24",
"name": "",
"type": "uint24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "RESTRICTION_BLOCKS",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"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": [
{
"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": [],
"name": "eip712Domain",
"outputs": [
{
"internalType": "bytes1",
"name": "fields",
"type": "bytes1"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "version",
"type": "string"
},
{
"internalType": "uint256",
"name": "chainId",
"type": "uint256"
},
{
"internalType": "address",
"name": "verifyingContract",
"type": "address"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
},
{
"internalType": "uint256[]",
"name": "extensions",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "launchBlock",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "launcher",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "locker",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "logo",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "nonces",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"name": "permit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "pool",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "restrictionEndBlock",
"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": "tokenURI",
"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";
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import {PoolAddress} from "./libraries/PoolAddress.sol";
/// @notice Read by the token during the launch window: the launcher raises
/// this flag around the atomic dev-buy swap so the dev-buy bypasses the
/// launch-block and max-wallet rules. Backed by regular storage (not
/// EIP-1153 transient storage) so behavior never depends on chain TSTORE
/// support; see the fork-test TSTORE probe for the optimization decision.
interface IDevBuyFlag {
function devBuyActive() external view returns (bool);
}
/// @notice Fixed-supply ERC-20 + Permit launched straight into a Uniswap v3
/// pool. Named LaunchTokenV3 because the Phase 1 bonding-curve LaunchToken
/// already exists in this Foundry project and artifact names must not
/// collide. Anti-snipe window: while
/// launchBlock <= block.number < launchBlock + 300 (block.number is the L1
/// estimate on Arbitrum Orbit, ~1 hour), launch-block buys from the pool
/// revert and no non-exempt wallet may exceed 2% of supply. From
/// launchBlock + 300 the hook short-circuits and the token is permanently
/// vanilla: no tax, no max-tx, no owner, no further mint path.
contract LaunchTokenV3 is ERC20, ERC20Permit {
uint256 public constant TOTAL_SUPPLY = 1e27; // 1B tokens, 18 decimals
uint256 public constant MAX_WALLET = 2e25; // 2% of supply
uint256 public constant RESTRICTION_BLOCKS = 300; // L1-estimate blocks (~1h on Orbit)
uint24 public constant POOL_FEE = 10000; // 1% tier, tickSpacing 200
address public constant DEAD = 0x000000000000000000000000000000000000dEaD;
address public immutable launcher;
address public immutable locker;
address public immutable pool;
uint256 public immutable launchBlock;
uint256 public immutable restrictionEndBlock;
string public tokenURI;
string public logo;
error LaunchBlockBuyBlocked();
error MaxWalletExceeded();
constructor(
string memory name_,
string memory symbol_,
string memory tokenURI_,
string memory logo_,
address locker_,
address uniswapV3Factory_,
address weth_
) ERC20(name_, symbol_) ERC20Permit(name_) {
tokenURI = tokenURI_;
logo = logo_;
launcher = msg.sender;
locker = locker_;
// The pool cannot exist before this token does, so its address is
// derived deterministically here; the launcher reverts the whole
// launch if the factory ever returns a different address
// (init-code-hash guard).
pool = PoolAddress.computeAddress(
uniswapV3Factory_, PoolAddress.getPoolKey(address(this), weth_, POOL_FEE)
);
// block.number is the L1 estimate on Arbitrum Orbit chains, which is
// exactly the semantics decision #6 of the spec wants.
launchBlock = block.number;
restrictionEndBlock = block.number + RESTRICTION_BLOCKS;
_mint(msg.sender, TOTAL_SUPPLY);
}
/// @dev OZ v5 transfer hook. Max wallet applies to EVERY transfer during
/// the window, not just pool buys: checking the final hop closes the
/// router-custody bypass (swap with recipient = router, then sweep to a
/// wallet). Sells stay uncapped because to == pool is exempt. No router
/// exemptions by design: a transfer path that needs a custodian holding
/// more than 2% during the window is meant to fail. No tx.origin
/// tricks, no max-tx rule, no transfer tax.
function _update(address from, address to, uint256 value) internal override {
// from == address(0) is the constructor mint only (no later mint
// path exists); skipping it first also avoids reading immutables
// mid-construction. launchBlock <= block.number is implicit: block
// numbers never decrease.
if (from != address(0) && block.number < restrictionEndBlock) {
bool exemptRecipient =
to == pool || to == locker || to == launcher || to == DEAD;
if (!exemptRecipient && !IDevBuyFlag(launcher).devBuyActive()) {
if (from == pool && block.number == launchBlock) {
revert LaunchBlockBuyBlocked();
}
if (balanceOf(to) + value > MAX_WALLET) {
revert MaxWalletExceeded();
}
}
}
super._update(from, to, value);
}
}
Chain explorer1656msChain node90ms