Crumpet NFTs (ERC‑721)
Passes, Badges & Future Utility (optional module)
Status: Optional · Ready for v1 when enabled Last updated: YYYY‑MM‑DD
1) Purpose & Scope
Crumpet NFTs are an optional ERC‑721 collection that communities can use for:
Access Passes (e.g., early beta, curated feeds, community frontends),
Badges / Achievements (e.g., Author Milestones, Node Operator badges),
Commemoratives (special events), without affecting the core protocol (Actions/Disputes/Registry/Vault) or single‑action voting.
ELI5: They’re stickers you can collect: some open doors (passes), some show achievements (badges). The news protocol works fine without them.
Out of scope (v0/v0.1): any requirement to hold NFTs to publish, read, vote, flag, or run a node. NFTs remain purely optional UX/community features.
2) Design Goals
Clean ERC‑721 with predictable behavior (no taxes, no transfer hooks).
Composable metadata (IPFS JSON), EIP‑2981 royalties, EIP‑4906 metadata update events.
Token classes with per‑class rules (soulbound or transferable, supply caps, allowlists, price in CRUMBS or free).
DAO‑operated via timelock; community expansions without redeploy (new classes).
No upgradeable proxies; use simple, auditable contracts. New features → new contracts if ever needed.
3) What this module is not
Not governance‑binding (DAO still uses Config/Timelock).
Not required for protocol incentives (Node Rewards in CRUMBS).
Not a “must‑have” for authors or readers.
4) Token Classes (Core Concept)
A Token Class defines mint rules & metadata template for a group of tokens:
classId (uint32)
Unique class identifier
name
e.g., “Access Pass — Alpha”, “Author Level 1”
baseURI
IPFS base for metadata (e.g., ipfs://…/alpha/)
supplyCap
Max tokens for the class (0 = uncapped)
price
Cost in CRUMBS (18 decimals); 0 = free
transferable
true means regular ERC‑721 transfers; false = soulbound
royaltyBps
Per‑token or per‑class EIP‑2981 royalty (0–1000 bps typical)
allowSigner
EIP‑712 minter allowlist signer (optional)
startTime / endTime
Optional mint window (0 = open)
Examples
Access Pass — Alpha: transferable, supplyCap 10,000, price 100 CRUMBS, royalty 5%.
Author Achievement L1: soulbound, supplyCap uncapped, free, awarded by
MINTER_ROLE.Node Operator v1: soulbound, free, gated by NodeRewards achievements (off‑chain issuance via DAO).
5) Metadata
Storage: IPFS JSON per token (
tokenURI = baseURI + tokenId.jsonby default).contractURI: for marketplaces (collection metadata).
Traits: keep consistent trait keys for indexers/frontends:
Example JSON:
EIP‑4906 MetadataUpdate(tokenId) and BatchMetadataUpdate(from, to) events allow dynamic art/traits (still pinned on IPFS).
6) Royalties (EIP‑2981)
Implement EIP‑2981 at the collection or per‑class level (
royaltyInfo(tokenId, salePrice)).Royalty receiver defaults to the DAO Treasury (configurable).
royaltyBpsset per class; 0 = no royalties.
Royalties are advisory and up to marketplace enforcement.
7) Payments: CRUMBS Integration (optional)
If a class
price > 0, minter must pay in CRUMBS:Approve CRUMBS to NFT contract, or use Permit2.
mint(classId, to, qty, EIP712Signature?)pullsprice * qty.Funds go to Vault or Treasury (configurable
PAY_DESTINATION).
Free classes (badges) skip payment.
8) Soulbound (non‑transferable) Classes
For
transferable=false, override_beforeTokenTransferto block transfers except:Mint and Burn (DAO/owner can burn with explicit role),
Optional escape hatch: owner may request burn to re‑issue (off‑chain approval to prevent lock‑ins).
Soulbound badges avoid secondary markets; ideal for achievements & roles.
9) Roles & Access Control
DEFAULT_ADMIN_ROLE → DAO Timelock.
MINTER_ROLE → addresses allowed to mint without signatures (DAO services, watchful bots).
CLASS_ADMIN_ROLE → manage classes (create/update/freeze).
URI_FREEZER_ROLE → irreversibly freeze
baseURIper class (setsfrozen=true).
Timelock delays class changes; freezing is immediate and irreversible for trust.
10) EIP‑712 Signature Mint (Allowlist)
Optional allowlist per class:
Message:
(minter, classId, maxQty, nonce, deadline).Signed by
allowSignerof the class.Contract checks signature,
block.timestamp <= deadline, and anti‑replay via per‑wallet nonce.Public mint (no signature) allowed if
allowSigner==address(0).
11) Interfaces & Events (Solidity Sketch)
Views
Minting
Admin
EIP‑165: supportsInterface for 721, 721Metadata, 2981, 4906.
12) Transfer Rules
13) Royalty Logic
14) Payments in CRUMBS
_mintSequentialissues tokenIds using a monotonic counter (e.g., 1…N), storingclassOf[tokenId] = classId.
15) Metadata Strategy
Default:
tokenURI = string.concat(c.baseURI, tokenId.toString(), ".json").Per‑class freeze: when frozen,
baseURIcannot change, providing collector trust.Metadata updates: if dynamic, emit
MetadataUpdate(tokenId)/BatchMetadataUpdate.
Best practice: generate JSON at publish time, pin to ≥3 IPFS pinning peers (reuse the Pin Orchestrator).
16) Security & Invariants
Supply invariant:
minted ≤ supplyCap(if cap>0).Soulbound enforcement: only mint/burn allowed; no internal bypasses.
Payment conservation:
CRUMBSpayments go only topayDestination.Timelock: class creation/updates routed through DAO timelock roles.
Reentrancy guards on mint/burn paths with transfers.
Signature replay protection for EIP‑712 allowlists (per‑wallet nonces).
17) Gas & Scale
Use a lightweight base (e.g., Solmate/OZ ERC‑721).
Sequential token IDs minimize storage costs.
Optional ERC‑721A pattern if very high‑volume mints are expected (not necessary for small badges/passes).
18) Testing Checklist
Unit
Create/update/freeze class (bounds: royaltyBps ≤ 10000; start<end).
Mint free & paid; supply caps enforced; windows enforced.
Soulbound transfer reverts; burn/mint allowed.
Royalty math; receiver updates.
EIP‑712 allowlist signatures (valid/expired/replay).
Integration
CRUMBS payments (permit vs approve); funds land in
payDestination.Pin orchestrator used by metadata generator (≥3 acks).
Marketplaces pick up 2981 royalties and 4906 updates.
Property/Fuzz
No token can belong to two classes; class counters cannot overflow.
Random sequences of mints/updates respect caps and windows.
19) Example Solidity Skeleton
(Implementation details omitted for brevity; follow tests checklist.)
20) Operational Guidance
Keep Access Passes transferable (secondary markets fine).
Keep Badges soulbound (non‑transferable).
Pin art/JSON to ≥3 IPFS peers (use the Pin Orchestrator).
Localized art/metadata: produce per‑locale variants (e.g.,
…/en/123.json,…/es/123.json), or include alocalesmap in JSON.Announce new classes with a DAO vote and short timelock.
21) Acceptance Criteria
Contract compiles & passes ERC‑721, 2981, 4906 compatibility tests.
Classes can be created/updated/frozen behind timelock.
Paid mints pull CRUMBS to the configured destination.
Soulbound enforcement prevents transfers; burns work.
TokenURI and contractURI resolve to IPFS JSON; ≥3 pin acks.
22) Changelog
v1: Initial optional NFT collection supporting classes, CRUMBS payments, EIP‑2981, soulbound badges, and metadata freeze.
Last updated