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:

Field
Meaning

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.json by 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).

  • royaltyBps set 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:

    1. Approve CRUMBS to NFT contract, or use Permit2.

    2. mint(classId, to, qty, EIP712Signature?) pulls price * qty.

    3. Funds go to Vault or Treasury (configurable PAY_DESTINATION).

  • Free classes (badges) skip payment.


8) Soulbound (non‑transferable) Classes

  • For transferable=false, override _beforeTokenTransfer to 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 baseURI per class (sets frozen=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 allowSigner of 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

  • _mintSequential issues tokenIds using a monotonic counter (e.g., 1…N), storing classOf[tokenId] = classId.


15) Metadata Strategy

  • Default: tokenURI = string.concat(c.baseURI, tokenId.toString(), ".json").

  • Per‑class freeze: when frozen, baseURI cannot 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: CRUMBS payments go only to payDestination.

  • 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 a locales map 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