HoodsCreatorNFT
0x0a19f9a844eccc0a49e08bcabd54d3d541ab1b4a
Verification
Unverified
v0.8.26+commit.8a97fa7a
Type
Contract
4,535 bytes
ABI entries
33
13 read · 12 write
License
none
Contract information
- Address
- 0x0a19f9a844eccc0a49e08bcabd54d3d541ab1b4a
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0x221e0B4809…340b0C1100
- Creation tx
- 0x6fa6238991…f4e28d2e8f
Token
- Name
- hoods.meme Creator
- Symbol
- HOODC
- Decimals
- —
- Holders
- 1
- Market
- View token page →
Read contract (13)
CTO_DELAY() → uint256
balanceOf(address) → uint256
deployer() → address
factory() → address
getApproved(uint256) → address
guardian() → address
isApprovedForAll(address, address) → bool
name() → string
ownerOf(uint256) → address
pendingCto(uint256) → address, uint64
splitter() → address
supportsInterface(bytes4) → bool
symbol() → string
Events (7)
ApprovalApprovalForAllCTOTransferCtoCancelledCtoQueuedGuardianChangedTransfer
ABI
[
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "approved",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "ApprovalForAll",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
}
],
"name": "CTOTransfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "CtoCancelled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint64",
"name": "eta",
"type": "uint64"
}
],
"name": "CtoQueued",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousGuardian",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newGuardian",
"type": "address"
}
],
"name": "GuardianChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"inputs": [],
"name": "CTO_DELAY",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "approve",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "cancelCtoTransfer",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "deployer",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "executeCtoTransfer",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "factory",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "getApproved",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "guardian",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "isApprovedForAll",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "ownerOf",
"outputs": [
{
"internalType": "address",
"name": "o",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "pendingCto",
"outputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint64",
"name": "eta",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "address",
"name": "to",
"type": "address"
}
],
"name": "queueCtoTransfer",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "setApprovalForAll",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "factory_",
"type": "address"
}
],
"name": "setFactory",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newGuardian",
"type": "address"
}
],
"name": "setGuardian",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "splitter_",
"type": "address"
}
],
"name": "setSplitter",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "splitter",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
/*
█ █ ███ ███ ████ ████ █ █ █████ █ █ █████
█ █ █ █ █ █ █ █ █ ██ ██ █ ██ ██ █
█████ █ █ █ █ █ █ ███ █ █ █ ████ █ █ █ ████
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
█ █ ███ ███ ████ ████ █ █ █ █████ █ █ █████
The most rewarding place to launch and trade.
Fixed supply · LP burned forever · fees flow to creators.
web https://hoods.meme
x https://x.com/hoodsmeme
tg https://t.me/hoods_meme
*/
import { IERC721Receiver } from "./common/Interfaces.sol";
interface IHoodsSplitterSettle {
function settleTo(address token, address to) external;
}
/// @title CreatorNFT — creator-fee ownership indirection (spec §2.4)
/// @notice One NFT per launched token (tokenId = uint160(token address)), minted by the factory
/// to the launch creator. The CreatorSplitter always pays the CURRENT holder — transferring this
/// NFT transfers the fee stream (creator-fee sales, CTO handovers).
///
/// TRUST MODEL — stated plainly: a platform `guardian` can reassign any Creator NFT via
/// `ctoTransfer` (community-takeover handovers when a dev abandons a project). This is deliberate,
/// platform-controlled custody of the FEE STREAM ONLY — it cannot touch the token, the pool, the
/// locked LP, or anyone's funds. Guardian mechanics (multisig/timelock/veto) may be layered on later
/// by rotating `guardian` to a stricter controller.
/// Minimal, self-contained ERC-721; no enumerable/metadata extensions beyond tokenURI-less name.
contract HoodsCreatorNFT {
string public constant name = "hoods.meme Creator";
string public constant symbol = "HOODC";
address public immutable deployer; // only address allowed to wire factory/splitter (anti front-run, M-1)
address public factory; // set once at deploy wiring (breaks the factory↔nft ctor cycle)
address public splitter; // set-once; lets ctoTransfer settle the OUTGOING holder's fees (CON-2)
address public guardian; // platform CTO authority (see trust-model note above)
mapping(uint256 => address) private _owner;
mapping(address => uint256) public balanceOf;
mapping(uint256 => address) public getApproved;
mapping(address => mapping(address => bool)) public isApprovedForAll;
// CTO handovers are TIMELOCKED: the guardian queues one, and only after CTO_DELAY can anyone execute
// it. The delay is a fixed safety window (not tunable) — a public interval in which a compromised
// guardian can be rotated (setGuardian) or the move cancelled, so no single key can seize a creator's
// fee stream instantly. Pair with a multisig guardian at deploy for defense in depth.
uint256 public constant CTO_DELAY = 48 hours;
struct PendingCto {
address to;
uint64 eta;
}
mapping(uint256 => PendingCto) public pendingCto;
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
event GuardianChanged(address indexed previousGuardian, address indexed newGuardian);
event CTOTransfer(uint256 indexed tokenId, address indexed from, address indexed to);
event CtoQueued(uint256 indexed tokenId, address indexed to, uint64 eta);
event CtoCancelled(uint256 indexed tokenId);
constructor() {
deployer = msg.sender;
guardian = msg.sender; // deployer; rotate later via setGuardian (e.g. to a multisig)
emit GuardianChanged(address(0), msg.sender);
}
/// One-shot wiring: the factory is the only minter. Deployer-only so it can't be front-run into an
/// attacker address (which would let them pre-mint NFTs / brick the real factory, M-1).
function setFactory(address factory_) external {
require(msg.sender == deployer, "not deployer");
require(factory == address(0) && factory_ != address(0), "factory set");
factory = factory_;
}
/// One-shot wiring: the splitter used to settle a departing holder's fees on ctoTransfer. Deployer-only.
function setSplitter(address splitter_) external {
require(msg.sender == deployer, "not deployer");
require(splitter == address(0) && splitter_ != address(0), "splitter set");
splitter = splitter_;
}
/// Rotate the platform CTO authority (guardian-only). Set to a multisig/timelock as governance
/// matures; setting to address(0) permanently renounces CTO power.
function setGuardian(address newGuardian) external {
require(msg.sender == guardian, "not guardian");
emit GuardianChanged(guardian, newGuardian);
guardian = newGuardian;
}
/// Queue a platform CTO handover (guardian-only). Takes effect after CTO_DELAY. Queuing again for
/// the same token overwrites the pending entry (and restarts the clock).
function queueCtoTransfer(uint256 tokenId, address to) external {
require(msg.sender == guardian, "not guardian");
require(to != address(0), "zero to");
ownerOf(tokenId); // reverts if the token doesn't exist
uint64 eta = uint64(block.timestamp + CTO_DELAY);
pendingCto[tokenId] = PendingCto({ to: to, eta: eta });
emit CtoQueued(tokenId, to, eta);
}
/// Cancel a queued handover (guardian-only) — e.g. after rotating a compromised guardian.
function cancelCtoTransfer(uint256 tokenId) external {
require(msg.sender == guardian, "not guardian");
require(pendingCto[tokenId].to != address(0), "none queued");
delete pendingCto[tokenId];
emit CtoCancelled(tokenId);
}
/// Execute a queued CTO handover once its delay has elapsed. PERMISSIONLESS — the timelock is the
/// safeguard, not the caller. Reassigns the fee-stream NFT and settles the OUTGOING holder's earned
/// fees to them first (CON-2), so a takeover never captures accrued fees.
function executeCtoTransfer(uint256 tokenId) external {
PendingCto memory p = pendingCto[tokenId];
require(p.to != address(0), "none queued");
require(block.timestamp >= p.eta, "timelocked");
delete pendingCto[tokenId]; // effect before the reassign + external call (CEI)
address from = ownerOf(tokenId);
delete getApproved[tokenId];
unchecked {
balanceOf[from]--;
balanceOf[p.to]++;
}
_owner[tokenId] = p.to;
emit Transfer(from, p.to, tokenId);
emit CTOTransfer(tokenId, from, p.to);
address sp = splitter;
if (sp != address(0)) IHoodsSplitterSettle(sp).settleTo(address(uint160(tokenId)), from);
}
function ownerOf(uint256 tokenId) public view returns (address o) {
o = _owner[tokenId];
require(o != address(0), "no token");
}
/// Factory-only, once per launch (tokenId = the launched token's address).
function mint(address to, uint256 tokenId) external {
require(msg.sender == factory, "not factory");
require(_owner[tokenId] == address(0), "exists");
_owner[tokenId] = to;
unchecked {
balanceOf[to]++;
}
emit Transfer(address(0), to, tokenId);
}
function approve(address spender, uint256 tokenId) external {
address o = ownerOf(tokenId);
require(msg.sender == o || isApprovedForAll[o][msg.sender], "not authorized");
getApproved[tokenId] = spender;
emit Approval(o, spender, tokenId);
}
function setApprovalForAll(address operator, bool approved) external {
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function transferFrom(address from, address to, uint256 tokenId) public {
address o = ownerOf(tokenId);
require(o == from, "wrong from");
require(to != address(0), "zero to");
require(msg.sender == o || msg.sender == getApproved[tokenId] || isApprovedForAll[o][msg.sender], "not authorized");
delete getApproved[tokenId];
unchecked {
balanceOf[from]--;
balanceOf[to]++;
}
_owner[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function safeTransferFrom(address from, address to, uint256 tokenId) external {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public {
transferFrom(from, to, tokenId);
if (to.code.length > 0) {
require(
IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data)
== IERC721Receiver.onERC721Received.selector,
"unsafe recipient"
);
}
}
function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
return interfaceId == 0x80ac58cd || interfaceId == 0x01ffc9a7; // ERC721 + ERC165
}
}
Chain explorer3979msChain node90ms