ArchrFactoryV3
0x218b50eab2cc0b8786c414f58f8e33ba9851f1fa
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
19,145 bytes
ABI entries
98
41 read · 17 write
License
none
Contract information
- Address
- 0x218b50eab2cc0b8786c414f58f8e33ba9851f1fa
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0x9008C9eE6e…13083680c6
- Creation tx
- 0xb9d3f67e4d…552e6220bd
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (41)
AIRDROP_BPS_30() → uint256
AIRDROP_BPS_60() → uint256
AIRDROP_DISTRIBUTOR() → address
ESCROW() → address
ESCROW_BPS() → uint256
ETH_USD_FEED() → address
FEED_STALE_AFTER() → uint256
FLOOR_FDV_USD8() → uint256
HOOK() → address
MAX_USABLE_TICK() → int24
MIGRATION_ESCROW_BPS() → uint256
MIGRATION_MAX_POT_BPS() → uint256
MIN_POOL_WETH_USD8() → uint256
MIN_USABLE_TICK() → int24
PERMIT2() → address
POOL_MANAGER() → address
POSITION_MANAGER() → address
STATE_VIEW() → address
SUPPLY() → uint256
TICKER_STAGE_WINDOW() → uint256
TICK_SPACING() → int24
V2_FACTORY() → address
V3_FACTORY() → address
WETH() → address
creator(address) → address
creatorRegistrar() → address
disabledTicker(bytes32) → bool
foldedKey(string) → bytes32, bool
isLauncher(address) → bool
migratedSource(address) → address
migrationRegistrar() → address
onERC721Received(address, address, uint256, bytes) → bytes4
owner() → address
pendingOwner() → address
poolIdByToken(address) → bytes32
positionIdByToken(address) → uint256
renounceOwnership()
tickerRegistrar() → address
tickerStagedAt(bytes32) → uint256
tickerVetoed(bytes32) → bool
tokenByPost(bytes32) → address
Events (14)
AirdropLaunchedCreatorFeesCollectedCreatorRegistrarSetCreatorSetLaunchedLauncherSetMigrationLaunchedMigrationRegistrarSetOwnershipTransferStartedOwnershipTransferredTickerDisabledSetTickerRegistrarSetTickerStagedTickerVetoed
ABI
[
{
"inputs": [
{
"internalType": "address[]",
"name": "initialLaunchers",
"type": "address[]"
},
{
"internalType": "address",
"name": "_poolManager",
"type": "address"
},
{
"internalType": "address",
"name": "_positionManager",
"type": "address"
},
{
"internalType": "address",
"name": "_hook",
"type": "address"
},
{
"internalType": "address",
"name": "_permit2",
"type": "address"
},
{
"internalType": "address",
"name": "_stateView",
"type": "address"
},
{
"internalType": "address",
"name": "_airdropDistributor",
"type": "address"
},
{
"internalType": "address",
"name": "_escrow",
"type": "address"
},
{
"internalType": "address",
"name": "_v2Factory",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "AlreadyLaunched",
"type": "error"
},
{
"inputs": [],
"name": "AlreadyMigrated",
"type": "error"
},
{
"inputs": [],
"name": "AlreadyStaged",
"type": "error"
},
{
"inputs": [],
"name": "BadAirdropBps",
"type": "error"
},
{
"inputs": [],
"name": "BadTick",
"type": "error"
},
{
"inputs": [],
"name": "CreatorAlreadySet",
"type": "error"
},
{
"inputs": [],
"name": "CreatorUnset",
"type": "error"
},
{
"inputs": [],
"name": "EthTransferFailed",
"type": "error"
},
{
"inputs": [],
"name": "NotCreatorRegistrar",
"type": "error"
},
{
"inputs": [],
"name": "NotLauncher",
"type": "error"
},
{
"inputs": [],
"name": "NotMigrationRegistrar",
"type": "error"
},
{
"inputs": [],
"name": "NotStaged",
"type": "error"
},
{
"inputs": [],
"name": "NotTickerRegistrar",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "OwnableInvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "OwnableUnauthorizedAccount",
"type": "error"
},
{
"inputs": [],
"name": "ReentrancyGuardReentrantCall",
"type": "error"
},
{
"inputs": [],
"name": "RenounceDisabled",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "SafeERC20FailedOperation",
"type": "error"
},
{
"inputs": [],
"name": "SourceBelowFloor",
"type": "error"
},
{
"inputs": [],
"name": "StageWindowOpen",
"type": "error"
},
{
"inputs": [],
"name": "StalePrice",
"type": "error"
},
{
"inputs": [],
"name": "TickerDisabled",
"type": "error"
},
{
"inputs": [],
"name": "UnknownToken",
"type": "error"
},
{
"inputs": [],
"name": "Vetoed",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "poolId",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "uint256",
"name": "positionTokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "airdropAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "string",
"name": "name",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "launchId",
"type": "string"
}
],
"name": "AirdropLaunched",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "ethAmount",
"type": "uint256"
}
],
"name": "CreatorFeesCollected",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "registrar",
"type": "address"
}
],
"name": "CreatorRegistrarSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
}
],
"name": "CreatorSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "poolId",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "uint256",
"name": "positionTokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "string",
"name": "name",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "launchId",
"type": "string"
}
],
"name": "Launched",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "launcher",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "allowed",
"type": "bool"
}
],
"name": "LauncherSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "source",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "airdropBps",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "potAmount",
"type": "uint256"
}
],
"name": "MigrationLaunched",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "registrar",
"type": "address"
}
],
"name": "MigrationRegistrarSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferStarted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "key",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "bool",
"name": "disabled",
"type": "bool"
}
],
"name": "TickerDisabledSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "registrar",
"type": "address"
}
],
"name": "TickerRegistrarSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "key",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "uint256",
"name": "stagedAt",
"type": "uint256"
}
],
"name": "TickerStaged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "key",
"type": "bytes32"
}
],
"name": "TickerVetoed",
"type": "event"
},
{
"inputs": [],
"name": "AIRDROP_BPS_30",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "AIRDROP_BPS_60",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "AIRDROP_DISTRIBUTOR",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "ESCROW",
"outputs": [
{
"internalType": "contract TrancheEscrow",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "ESCROW_BPS",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "ETH_USD_FEED",
"outputs": [
{
"internalType": "contract IChainlinkFeed",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "FEED_STALE_AFTER",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "FLOOR_FDV_USD8",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "HOOK",
"outputs": [
{
"internalType": "contract IHooks",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_USABLE_TICK",
"outputs": [
{
"internalType": "int24",
"name": "",
"type": "int24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MIGRATION_ESCROW_BPS",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MIGRATION_MAX_POT_BPS",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MIN_POOL_WETH_USD8",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MIN_USABLE_TICK",
"outputs": [
{
"internalType": "int24",
"name": "",
"type": "int24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "PERMIT2",
"outputs": [
{
"internalType": "contract IAllowanceTransfer",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "POOL_MANAGER",
"outputs": [
{
"internalType": "contract IPoolManager",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "POSITION_MANAGER",
"outputs": [
{
"internalType": "contract IPositionManager",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "STATE_VIEW",
"outputs": [
{
"internalType": "contract IStateView",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "SUPPLY",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "TICKER_STAGE_WINDOW",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "TICK_SPACING",
"outputs": [
{
"internalType": "int24",
"name": "",
"type": "int24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "V2_FACTORY",
"outputs": [
{
"internalType": "contract IArchrFactoryV2",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "V3_FACTORY",
"outputs": [
{
"internalType": "contract IUniswapV3Factory",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "WETH",
"outputs": [
{
"internalType": "contract IWETH9",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "acceptOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "key",
"type": "bytes32"
}
],
"name": "activateTickerDisable",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "collectCreatorFees",
"outputs": [
{
"internalType": "uint256",
"name": "amt",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "creator",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "creatorRegistrar",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"name": "disabledTicker",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "symbol",
"type": "string"
}
],
"name": "foldedKey",
"outputs": [
{
"internalType": "bytes32",
"name": "key",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "conforming",
"type": "bool"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "isLauncher",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
},
{
"internalType": "int24",
"name": "launchTick",
"type": "int24"
},
{
"internalType": "string",
"name": "launchId",
"type": "string"
},
{
"internalType": "address",
"name": "creator_",
"type": "address"
}
],
"name": "launch",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "bytes32",
"name": "poolId",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "positionTokenId",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
},
{
"internalType": "int24",
"name": "launchTick",
"type": "int24"
},
{
"internalType": "string",
"name": "launchId",
"type": "string"
},
{
"internalType": "address",
"name": "source",
"type": "address"
},
{
"internalType": "uint256",
"name": "airdropBps",
"type": "uint256"
},
{
"internalType": "address",
"name": "creator_",
"type": "address"
}
],
"name": "launchMigration",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "bytes32",
"name": "poolId",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "positionTokenId",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
},
{
"internalType": "int24",
"name": "launchTick",
"type": "int24"
},
{
"internalType": "string",
"name": "launchId",
"type": "string"
},
{
"internalType": "address",
"name": "source",
"type": "address"
},
{
"internalType": "uint256",
"name": "airdropBps",
"type": "uint256"
},
{
"internalType": "address",
"name": "creator_",
"type": "address"
}
],
"name": "launchWithAirdrop",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "bytes32",
"name": "poolId",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "positionTokenId",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "migratedSource",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "migrationRegistrar",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"name": "onERC721Received",
"outputs": [
{
"internalType": "bytes4",
"name": "",
"type": "bytes4"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pendingOwner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "poolIdByToken",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "positionIdByToken",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "a",
"type": "address"
}
],
"name": "setCreator",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "a",
"type": "address"
}
],
"name": "setCreatorRegistrar",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "a",
"type": "address"
},
{
"internalType": "bool",
"name": "allowed",
"type": "bool"
}
],
"name": "setLauncher",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "a",
"type": "address"
}
],
"name": "setMigrationRegistrar",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "key",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "disabled",
"type": "bool"
}
],
"name": "setTickerDisabled",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "a",
"type": "address"
}
],
"name": "setTickerRegistrar",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "key",
"type": "bytes32"
}
],
"name": "stageTickerDisable",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
}
],
"name": "sweepEth",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "t",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
}
],
"name": "sweepToken",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "tickerRegistrar",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"name": "tickerStagedAt",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"name": "tickerVetoed",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"name": "tokenByPost",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "key",
"type": "bytes32"
}
],
"name": "vetoTickerDisable",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20 as IERC20OZ} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {IPositionManager} from "@uniswap/v4-periphery/src/interfaces/IPositionManager.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol";
import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
import {LiquidityAmounts} from "@uniswap/v4-periphery/src/libraries/LiquidityAmounts.sol";
import {Actions} from "@uniswap/v4-periphery/src/libraries/Actions.sol";
import {IStateView} from "@uniswap/v4-periphery/src/interfaces/IStateView.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {CoinV3} from "./CoinV3.sol";
import {IUniswapV3Factory} from "./interfaces/IUniswapV3Factory.sol";
import {IUniswapV3Pool} from "./interfaces/IUniswapV3Pool.sol";
import {IChainlinkFeed} from "./interfaces/IChainlinkFeed.sol";
import {IWETH9} from "./interfaces/IWETH9.sol";
import {TrancheEscrow} from "./TrancheEscrow.sol";
/// @dev Cross-registry read surface of the legacy v2 factory (case-folded ticker registry + migration dedupe).
interface IArchrFactoryV2 {
function disabledTicker(bytes32 key) external view returns (bool);
function migratedSource(address source) external view returns (address);
}
/// @title ArchrFactoryV3
/// @notice v3-generation launch factory: deploys a `CoinV3`, DIRECTLY initializes a native-ETH Uniswap-V4
/// pool (currency0 = ETH, currency1 = coin, fee 0, tickSpacing 200, hook = the singleton ArchrHookV3),
/// mints the single-sided coin wall as a PositionManager NFT **burned to 0xdEaD** (rug-proof — no
/// address can ever withdraw the LP), escrows 5% into a TrancheEscrow, records the creator, and exposes
/// a permissionless ETH-only `collectCreatorFees`. Direct-from-factory `initialize` is what passes the
/// hook's `beforeInitialize` factory gate (`sender == FACTORY`).
contract ArchrFactoryV3 is Ownable2Step, IERC721Receiver, ReentrancyGuard {
using SafeERC20 for IERC20OZ;
using PoolIdLibrary for PoolKey;
// ---- V4 stack (constructor args; the Task-10 deploy wires the pinned 4663 addresses) ----
IPoolManager public immutable POOL_MANAGER;
IPositionManager public immutable POSITION_MANAGER;
IHooks public immutable HOOK;
IAllowanceTransfer public immutable PERMIT2;
IStateView public immutable STATE_VIEW; // V4 spot read for the own-coin source-floor branch
IArchrFactoryV2 public immutable V2_FACTORY; // cross-registry reads; address(0) => skipped
// ---- Kept from v2 (escrow + legacy-floor branch, wired for Task 8) ----
address public immutable AIRDROP_DISTRIBUTOR;
TrancheEscrow public immutable ESCROW;
IWETH9 public constant WETH = IWETH9(0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73);
IUniswapV3Factory public constant V3_FACTORY = IUniswapV3Factory(0x1f7d7550B1b028f7571E69A784071F0205FD2EfA);
IChainlinkFeed public constant ETH_USD_FEED = IChainlinkFeed(0x78F3556b67E17Df817D51Ef5a990cDaF09E8d3A9);
uint256 public constant FEED_STALE_AFTER = 26 hours;
uint256 public constant FLOOR_FDV_USD8 = 50_000e8;
uint256 public constant MIN_POOL_WETH_USD8 = 500e8;
uint256 public constant MIGRATION_ESCROW_BPS = 200;
uint256 public constant MIGRATION_MAX_POT_BPS = 7000;
int24 public constant TICK_SPACING = 200;
int24 public constant MIN_USABLE_TICK = -887200;
int24 public constant MAX_USABLE_TICK = 887200;
uint256 public constant SUPPLY = 1_000_000_000e18;
uint256 public constant AIRDROP_BPS_30 = 3000;
uint256 public constant AIRDROP_BPS_60 = 6000;
uint256 public constant ESCROW_BPS = 500;
uint256 public constant TICKER_STAGE_WINDOW = 14 days;
address constant DEAD = 0x000000000000000000000000000000000000dEaD;
mapping(address => bool) public isLauncher;
mapping(bytes32 => address) public tokenByPost;
// V4: PoolId (bytes32) + the burned position NFT id (informational — NFT is at 0xdEaD).
mapping(address => bytes32) public poolIdByToken;
mapping(address => uint256) public positionIdByToken;
mapping(address => address) public creator;
address public creatorRegistrar;
mapping(bytes32 => bool) public disabledTicker;
mapping(bytes32 => uint256) public tickerStagedAt;
mapping(bytes32 => bool) public tickerVetoed;
address public tickerRegistrar;
mapping(address => address) public migratedSource;
address public migrationRegistrar;
event LauncherSet(address indexed launcher, bool allowed);
event CreatorRegistrarSet(address indexed registrar);
event CreatorSet(address indexed token, address indexed creator);
event CreatorFeesCollected(address indexed token, address indexed creator, uint256 ethAmount);
event TickerRegistrarSet(address indexed registrar);
event TickerStaged(bytes32 indexed key, uint256 stagedAt);
event TickerVetoed(bytes32 indexed key);
event TickerDisabledSet(bytes32 indexed key, bool disabled);
event MigrationRegistrarSet(address indexed registrar);
event Launched(
address indexed token, bytes32 indexed poolId, uint256 positionTokenId,
string name, string symbol, string launchId
);
event AirdropLaunched(
address indexed token, bytes32 indexed poolId, uint256 positionTokenId,
uint256 airdropAmount, string name, string symbol, string launchId
);
event MigrationLaunched(
address indexed token, address indexed source, uint256 airdropBps, uint256 potAmount
);
error NotLauncher();
error BadTick();
error AlreadyLaunched();
error RenounceDisabled();
error NotCreatorRegistrar();
error CreatorUnset();
error CreatorAlreadySet();
error UnknownToken();
error EthTransferFailed();
error NotTickerRegistrar();
error AlreadyStaged();
error NotStaged();
error StageWindowOpen();
error Vetoed();
error TickerDisabled();
error NotMigrationRegistrar();
error BadAirdropBps();
error SourceBelowFloor();
error StalePrice();
error AlreadyMigrated();
modifier onlyLauncher() {
if (!isLauncher[msg.sender]) revert NotLauncher();
_;
}
constructor(
address[] memory initialLaunchers,
address _poolManager,
address _positionManager,
address _hook,
address _permit2,
address _stateView,
address _airdropDistributor,
address _escrow,
address _v2Factory
) Ownable(msg.sender) {
POOL_MANAGER = IPoolManager(_poolManager);
POSITION_MANAGER = IPositionManager(_positionManager);
HOOK = IHooks(_hook);
PERMIT2 = IAllowanceTransfer(_permit2);
STATE_VIEW = IStateView(_stateView);
ESCROW = TrancheEscrow(_escrow);
V2_FACTORY = IArchrFactoryV2(_v2Factory);
AIRDROP_DISTRIBUTOR = _airdropDistributor;
for (uint256 i; i < initialLaunchers.length; ++i) {
isLauncher[initialLaunchers[i]] = true;
emit LauncherSet(initialLaunchers[i], true);
}
disabledTicker[keccak256("ARCHR")] = true;
emit TickerDisabledSet(keccak256("ARCHR"), true);
}
// --------------------------------------------------------------------- setters (ported verbatim)
function setLauncher(address a, bool allowed) external onlyOwner {
isLauncher[a] = allowed;
emit LauncherSet(a, allowed);
}
function setCreatorRegistrar(address a) external onlyOwner {
creatorRegistrar = a;
emit CreatorRegistrarSet(a);
}
function setTickerRegistrar(address a) external onlyOwner {
tickerRegistrar = a;
emit TickerRegistrarSet(a);
}
function setMigrationRegistrar(address a) external onlyOwner {
migrationRegistrar = a;
emit MigrationRegistrarSet(a);
}
// --------------------------------------------------------------------- ticker registry (ported)
function foldedKey(string memory symbol) public pure returns (bytes32 key, bool conforming) {
bytes memory b = bytes(symbol);
if (b.length < 2 || b.length > 12) return (bytes32(0), false);
for (uint256 i; i < b.length; ++i) {
bytes1 c = b[i];
if (c >= 0x61 && c <= 0x7A) {
b[i] = bytes1(uint8(c) - 32);
} else if (!((c >= 0x41 && c <= 0x5A) || (c >= 0x30 && c <= 0x39))) {
return (bytes32(0), false);
}
}
return (keccak256(b), true);
}
function stageTickerDisable(bytes32 key) external {
if (msg.sender != tickerRegistrar) revert NotTickerRegistrar();
if (tickerStagedAt[key] != 0) revert AlreadyStaged();
tickerStagedAt[key] = block.timestamp;
emit TickerStaged(key, block.timestamp);
}
function activateTickerDisable(bytes32 key) external {
uint256 stagedAt = tickerStagedAt[key];
if (stagedAt == 0) revert NotStaged();
if (tickerVetoed[key]) revert Vetoed();
if (block.timestamp < stagedAt + TICKER_STAGE_WINDOW) revert StageWindowOpen();
disabledTicker[key] = true;
emit TickerDisabledSet(key, true);
}
function vetoTickerDisable(bytes32 key) external onlyOwner {
if (tickerStagedAt[key] == 0) revert NotStaged();
tickerVetoed[key] = true;
emit TickerVetoed(key);
}
function setTickerDisabled(bytes32 key, bool disabled) external onlyOwner {
disabledTicker[key] = disabled;
emit TickerDisabledSet(key, disabled);
}
// --------------------------------------------------------------------- plain launch
function launch(
string calldata name, string calldata symbol,
bytes32 salt, int24 launchTick, string calldata launchId, address creator_
) external onlyLauncher returns (address token, bytes32 poolId, uint256 positionTokenId) {
(token, poolId, positionTokenId) =
_deployAndLP(name, symbol, salt, launchTick, launchId, SUPPLY - SUPPLY * ESCROW_BPS / 10000);
_recordCreator(token, creator_);
_escrowPlainProfile(token);
emit Launched(token, poolId, positionTokenId, name, symbol, launchId);
}
function _recordCreator(address token, address creator_) internal {
if (creator_ != address(0)) {
creator[token] = creator_;
emit CreatorSet(token, creator_);
}
}
function _escrowPlainProfile(address token) internal {
IERC20OZ(token).safeTransfer(address(ESCROW), SUPPLY * ESCROW_BPS / 10000);
ESCROW.register(
token,
uint64(block.timestamp),
[uint128(11_600_000e18), uint128(11_600_000e18), uint128(11_600_000e18), uint128(15_200_000e18)],
[uint32(86_400), uint32(259_200), uint32(604_800), uint32(604_800)]
);
}
// --------------------------------------------------------------------- airdrop launch (30% / 60%)
/// @notice Source-holder airdrop launch. Wall = 650M at 30% / 350M at 60%; 300M/600M to the distributor;
/// the plain 50M escrow profile. Gated on the source's spot mcap clearing the $50k floor.
function launchWithAirdrop(
string calldata name, string calldata symbol,
bytes32 salt, int24 launchTick, string calldata launchId,
address source, uint256 airdropBps, address creator_
) external onlyLauncher returns (address token, bytes32 poolId, uint256 positionTokenId) {
if (airdropBps != AIRDROP_BPS_30 && airdropBps != AIRDROP_BPS_60) revert BadAirdropBps();
_checkSourceFloor(source);
(token, poolId, positionTokenId) = _deployAndLP(
name, symbol, salt, launchTick, launchId,
SUPPLY - SUPPLY * airdropBps / 10000 - SUPPLY * ESCROW_BPS / 10000
);
_recordCreator(token, creator_);
_settleAirdrop(token, name, symbol, launchId, airdropBps);
}
function _settleAirdrop(
address token, string calldata name, string calldata symbol, string calldata launchId, uint256 airdropBps
) internal {
uint256 airdropAmount = SUPPLY * airdropBps / 10000;
IERC20OZ(token).safeTransfer(AIRDROP_DISTRIBUTOR, airdropAmount);
_escrowPlainProfile(token);
bytes32 poolId = poolIdByToken[token];
uint256 positionTokenId = positionIdByToken[token];
emit Launched(token, poolId, positionTokenId, name, symbol, launchId);
emit AirdropLaunched(token, poolId, positionTokenId, airdropAmount, name, symbol, launchId);
}
// --------------------------------------------------------------------- migration launch (team-gated CTO)
/// @notice Team-gated CTO revival. 2% escrow (not 5%), pot up to 70%, no $50k floor (the team gate is the
/// filter), one-per-source dedupe across BOTH v3 and the legacy v2 registry, immediate ticker disable.
function launchMigration(
string calldata name, string calldata symbol,
bytes32 salt, int24 launchTick, string calldata launchId,
address source, uint256 airdropBps, address creator_
) external returns (address token, bytes32 poolId, uint256 positionTokenId) {
if (msg.sender != migrationRegistrar) revert NotMigrationRegistrar();
if (airdropBps > MIGRATION_MAX_POT_BPS) revert BadAirdropBps();
if (
migratedSource[source] != address(0)
|| (address(V2_FACTORY) != address(0) && V2_FACTORY.migratedSource(source) != address(0))
) revert AlreadyMigrated();
(token, poolId, positionTokenId) = _deployAndLP(
name, symbol, salt, launchTick, launchId,
SUPPLY - SUPPLY * airdropBps / 10000 - SUPPLY * MIGRATION_ESCROW_BPS / 10000
);
migratedSource[source] = token;
_recordCreator(token, creator_);
_disableTickerNow(symbol);
_settleMigration(token, name, symbol, launchId, source, airdropBps);
}
function _disableTickerNow(string calldata symbol) internal {
(bytes32 tkey, bool conforming) = foldedKey(symbol);
if (conforming) {
disabledTicker[tkey] = true;
emit TickerDisabledSet(tkey, true);
}
}
function _settleMigration(
address token,
string calldata name, string calldata symbol, string calldata launchId,
address source, uint256 airdropBps
) internal {
uint256 potRaw = SUPPLY * airdropBps / 10000;
uint256 escrowAmount = SUPPLY * MIGRATION_ESCROW_BPS / 10000;
uint128 t = uint128(escrowAmount / 3);
IERC20OZ(token).safeTransfer(address(ESCROW), potRaw + escrowAmount);
ESCROW.register(
token,
uint64(block.timestamp),
[uint128(potRaw), t, t, uint128(escrowAmount) - 2 * t],
[uint32(0), uint32(86_400), uint32(259_200), uint32(604_800)]
);
_emitMigrationEvents(token, name, symbol, launchId, source, airdropBps);
}
function _emitMigrationEvents(
address token, string calldata name, string calldata symbol, string calldata launchId,
address source, uint256 airdropBps
) internal {
emit Launched(token, poolIdByToken[token], positionIdByToken[token], name, symbol, launchId);
emit MigrationLaunched(token, source, airdropBps, SUPPLY * airdropBps / 10000);
}
// --------------------------------------------------------------------- source-mcap floor ($50k)
/// @dev V4 branch first (own v3 coins, read via StateView), then the V2 legacy external-pool branch.
function _checkSourceFloor(address source) internal view {
uint256 ethUsd8 = _ethUsd8();
// ---- V4 branch: the source is one of our own v3 coins (poolId is registered here). ----
bytes32 pid = poolIdByToken[source];
if (pid != 0) {
(uint160 sp,,,) = STATE_VIEW.getSlot0(PoolId.wrap(pid));
if (sp == 0) revert SourceBelowFloor();
uint256 supplyRaw = _trySupply(source);
// Coin is ALWAYS currency1 (currency0 = ETH), so the single "token1" formula applies.
uint256 fdvWethWei = Math.mulDiv(Math.mulDiv(supplyRaw, 1 << 96, sp), 1 << 96, sp);
if (Math.mulDiv(fdvWethWei, ethUsd8, 1e18) < FLOOR_FDV_USD8) revert SourceBelowFloor();
return;
}
// ---- Legacy branch: external / non-v3 source (a v2-native source routes here — intended). ----
address pool = _bestExternalPool(source);
if (pool == address(0)) revert SourceBelowFloor();
uint256 wethBal = _tryBalanceOf(address(WETH), pool);
if (Math.mulDiv(wethBal, ethUsd8, 1e18) < MIN_POOL_WETH_USD8) revert SourceBelowFloor();
if (_spotFdvUsd8(source, pool, ethUsd8) < FLOOR_FDV_USD8) revert SourceBelowFloor();
}
function _ethUsd8() internal view returns (uint256) {
try ETH_USD_FEED.latestRoundData() returns (uint80, int256 answer, uint256, uint256 updatedAt, uint80) {
if (answer <= 0 || block.timestamp > updatedAt + FEED_STALE_AFTER) revert StalePrice();
return uint256(answer);
} catch {
revert StalePrice();
}
}
function _bestExternalPool(address source) internal view returns (address best) {
uint24[4] memory tiers = [uint24(100), uint24(500), uint24(3000), uint24(10000)];
uint256 bestBal;
for (uint256 i; i < 4; ++i) {
address pool;
try V3_FACTORY.getPool(source, address(WETH), tiers[i]) returns (address p) {
pool = p;
} catch {
continue;
}
if (pool == address(0)) continue;
uint256 bal = _tryBalanceOf(address(WETH), pool);
if (bal > bestBal) {
bestBal = bal;
best = pool;
}
}
}
function _tryBalanceOf(address token, address holder) internal view returns (uint256) {
try IERC20OZ(token).balanceOf(holder) returns (uint256 b) {
return b;
} catch {
return 0;
}
}
function _trySupply(address source) internal view returns (uint256) {
try IERC20OZ(source).totalSupply() returns (uint256 s) {
return s;
} catch {
return 0;
}
}
function _spotFdvUsd8(address source, address pool, uint256 ethUsd8) internal view returns (uint256) {
uint160 sp;
try IUniswapV3Pool(pool).slot0() returns (uint160 sqrtPriceX96, int24, uint16, uint16, uint16, uint8, bool) {
sp = sqrtPriceX96;
} catch {
return 0;
}
if (sp == 0) return 0;
uint256 supplyRaw = _trySupply(source);
if (supplyRaw == 0) return 0;
uint256 fdvWethWei = source > address(WETH)
? Math.mulDiv(Math.mulDiv(supplyRaw, 1 << 96, sp), 1 << 96, sp)
: Math.mulDiv(Math.mulDiv(supplyRaw, sp, 1 << 96), sp, 1 << 96);
return Math.mulDiv(fdvWethWei, ethUsd8, 1e18);
}
// --------------------------------------------------------------------- deploy + V4 LP
function _deployAndLP(
string calldata name, string calldata symbol,
bytes32 salt, int24 launchTick, string calldata launchId,
uint256 lpAmount
) internal returns (address token, bytes32 poolId, uint256 positionTokenId) {
if (launchTick % TICK_SPACING != 0 || launchTick <= MIN_USABLE_TICK || launchTick >= MAX_USABLE_TICK) {
revert BadTick();
}
bytes32 key = keccak256(bytes(launchId));
if (tokenByPost[key] != address(0)) revert AlreadyLaunched();
(bytes32 tkey, bool conforming) = foldedKey(symbol);
if (
conforming
&& (disabledTicker[tkey] || (address(V2_FACTORY) != address(0) && V2_FACTORY.disabledTicker(tkey)))
) revert TickerDisabled();
// V4 native-ETH: coin is always currency1 (currency0 = address(0)) — NO `token > WETH` constraint.
token = address(new CoinV3{salt: keccak256(abi.encode(salt, launchId))}(name, symbol));
(poolId, positionTokenId) = _initPoolAndMint(token, launchTick, lpAmount);
tokenByPost[key] = token;
poolIdByToken[token] = poolId;
positionIdByToken[token] = positionTokenId;
}
function _initPoolAndMint(address token, int24 launchTick, uint256 lpAmount)
internal
returns (bytes32 poolId, uint256 positionTokenId)
{
PoolKey memory poolKey = PoolKey({
currency0: CurrencyLibrary.ADDRESS_ZERO,
currency1: Currency.wrap(token),
fee: 0,
tickSpacing: TICK_SPACING,
hooks: HOOK
});
// DIRECT initialize from the factory — this is what satisfies the hook's beforeInitialize gate.
POOL_MANAGER.initialize(poolKey, TickMath.getSqrtPriceAtTick(launchTick));
poolId = PoolId.unwrap(poolKey.toId());
// Single-sided coin wall over [MIN_USABLE_TICK, launchTick]: at the top of range the position holds
// 100% currency1 (coin) and 0 ETH, so the ETH settle leg is 0.
uint128 liquidity = LiquidityAmounts.getLiquidityForAmount1(
TickMath.getSqrtPriceAtTick(MIN_USABLE_TICK), TickMath.getSqrtPriceAtTick(launchTick), lpAmount
);
// Approve the coin through Permit2 to the PositionManager (posm pulls currency1 via Permit2).
IERC20OZ(token).forceApprove(address(PERMIT2), lpAmount);
PERMIT2.approve(token, address(POSITION_MANAGER), uint160(lpAmount), uint48(block.timestamp + 3600));
// The id the mint will assign (read BEFORE minting).
positionTokenId = POSITION_MANAGER.nextTokenId();
bytes memory actions = abi.encodePacked(uint8(Actions.MINT_POSITION), uint8(Actions.SETTLE_PAIR));
bytes[] memory params = new bytes[](2);
params[0] = abi.encode(
poolKey,
MIN_USABLE_TICK, // tickLower
launchTick, // tickUpper
liquidity,
uint128(0), // amount0Max — no ETH is owed on a top-of-range single-sided position
uint128(lpAmount), // amount1Max — the coin wall
DEAD, // owner — permanently burned
bytes("") // hookData
);
params[1] = abi.encode(poolKey.currency0, poolKey.currency1);
// No ETH value sent — the top-of-range single-sided position deposits 0 currency0.
POSITION_MANAGER.modifyLiquidities(abi.encode(actions, params), block.timestamp);
}
// --------------------------------------------------------------------- creator registry + fees
function setCreator(address token, address a) external {
if (msg.sender != creatorRegistrar) revert NotCreatorRegistrar();
if (poolIdByToken[token] == bytes32(0)) revert UnknownToken();
if (creator[token] != address(0)) revert CreatorAlreadySet();
creator[token] = a;
emit CreatorSet(token, a);
}
/// @notice Permissionless ETH-only collect: pulls the coin's vault balance (the hook's accrued skim) and
/// forwards it to the recorded creator. Single leg — v3 coins never accrue a coin fee. Zero-balance
/// collect is an idempotent no-op.
function collectCreatorFees(address token) external nonReentrant returns (uint256 amt) {
address to = creator[token];
if (to == address(0)) revert CreatorUnset();
uint256 balBefore = address(this).balance;
CoinV3(payable(token)).withdrawFees();
amt = address(this).balance - balBefore;
if (amt != 0) {
(bool ok,) = to.call{value: amt}("");
if (!ok) revert EthTransferFailed();
}
emit CreatorFeesCollected(token, to, amt);
}
// --------------------------------------------------------------------- sweeps + housekeeping (ported)
function sweepToken(address t, address to) external onlyOwner {
IERC20OZ(t).safeTransfer(to, IERC20OZ(t).balanceOf(address(this)));
}
function sweepEth(address to) external onlyOwner {
(bool ok,) = to.call{value: address(this).balance}("");
require(ok, "ETH transfer failed");
}
function renounceOwnership() public view override onlyOwner {
revert RenounceDisabled();
}
function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}
receive() external payable {}
}
Chain explorer2910msChain node118ms