Playbook
Placeholder URI and Owner Reveal Pipeline (Placeholder Uri And Owner Reveal Pipeline)
Placeholder metadata at mint, uridata map, reveal(tokenId, uriHash), and an owner-only reveal surface.
NFT Collection Mint & Mainnet Hardening
Part 3 of 4
CBD All-Stars and Confident Gorillas mint surfaces: WIP whitelist funnel, IPFS metadata, placeholder→reveal pipeline, and Web3Modal mainnet wallet hardening.
Mint does not give the final art — reveal does
In Confident Gorillas 1.4, mint often does not show final art immediately. A placeholder / interim URI is written at mint; real CIDs wait in a uridata table as tokenId → hash/link. The Reveal container, after an owner check, sends reveal(tokenId, uriHash) — that is the 'appears in your wallet' promise.
mint → placeholder / interim tokenURI
│
uridata[tokenId] = { hash, link }
│
ownerOf(tokenId) === connected wallet?
yes │ no → deny
↓
reveal(tokenId, uriHash)
↓
tokenURI updated → retrieveJSON / image
This part locks reveal as a product and security boundary; the next hardens wallet connect for mainnet.
Concepts, defined where they first appear
📦 Placeholder Metadata
Interim URI written at mint; final traits/art not yet bound.
📦 uridata
tokenId → { hash, link, index } map; CID table ready for reveal.
📦 reveal(tokenId, uri)
Contract call where the owner updates tokenURI to the real hash.
📦 Owner Gate
ownerOf === connected address check inside revealToken.
Viewer Reveal may be disabled; operational reveal can run from an owner panel or script. The gate remains ownership.
Why placeholder?
Fairness and ops: reduce metadata leaks before full supply mints, decouple art generation from mint cadence. Users mint; art arrives later via reveal. Landing FAQ frames it as appearing in MetaMask.
Mint window
→ same placeholder look
Reveal window
→ unique CID per tokenId
Reveal pipeline
Reveal.ts reads uridata.uri[tokenId], takes the hash, calls revealToken(tokenId, hash). nftContractUtils verifies ownerOf; on match, contract.methods.reveal(...).send({ from }). Then tokenURI returns the new hash; retrieveJSON resolves the image CID.
Reveal.ts
uridata[tokenId].hash
↓
revealToken → owner check
↓
reveal(tokenId, hash).send
ADR: off-chain table + on-chain owner reveal
Decision: final CID list lives in client/bundle (uridata); mutation authority stays in owner-gated reveal. Alternatives (on-chain commit-reveal, VRF) cost more. Trade-off: uridata can leak from the bundle — timing and access are product risks.
ADR-03 Placeholder + owner reveal
Store: uridata off-chain map
Auth: ownerOf gate
Mutate: reveal(tokenId, uriHash)
Reject: non-owner / wrong id
Failure scenarios
Wrong tokenId → wrong art. Hash/link mismatch → gateway 404. Non-owner wallet → silent no-op (returns null). Missing reveal in ABI → encode failure. Never updating placeholder leaves a collection of empty boxes.
Fail matrix
wrong tokenId → wrong art
hash ≠ pinned CID → 404
non-owner → no-op / deny
missing reveal ABI→ encode fail
The mappings that get confused most often
❌ Reveal = only removing a UI blur
✓ Reveal = on-chain tokenURI update; UI only shows the result
❌ Anyone should reveal any token
✓ Only the owner (or a designed minter/owner role) reveals
❌ uridata stays secret because it is in the bundle
✓ Frontend bundles are readable; timing and access are the real controls
A checklist for auditing your own system
- Is each tokenId hash in uridata pinned and retrievable?
- Is ownerOf checked on client and contract before reveal?
- Are placeholder and final URIs clearly separated?
- Is Reveal disabled/denied safely for non-owners?
- Any index drift in the 750-entry table?
What to take away from this part
- Placeholder mint plus reveal separates fairness from ops cadence.
- Without an owner gate, reveal breaks collection integrity.
- uridata is a product decision; do not assume secrecy — design timing.
Giving art at mint is easy; giving it fairly and irreversibly is reveal discipline.
FAQ
Frequently asked questions
What is Placeholder Metadata?
Interim URI written at mint; final traits/art not yet bound.
What is uridata?
tokenId → { hash, link, index } map; CID table ready for reveal.
Is it true that "Reveal = only removing a UI blur"?
Reveal = on-chain tokenURI update; UI only shows the result
What does this part lock in?
This part locks reveal as a product and security boundary; the next hardens wallet connect for mainnet. In Confident Gorillas 1.4, mint often does not show final art immediately. A placeholder / interim URI is written at mint; real CIDs wait in a uridata table as tokenId → hash/link. The Reveal container, after an owner check, sends reveal(tokenId, uriHash) — that is the 'appears in your wallet' promise.
Engineering Principles Learned
- Separate mint URI from final URI on purpose.
- Lock reveal authority behind ownerOf (or an explicit role).
- Audit the off-chain CID table for pin and index integrity.
Continue reading
Continue reading
Next in series
Mainnet Web3Modal and Wallet Hardening
From MetaMask-only to Web3Modal + WalletConnect + Coinbase WalletLink; harden chainId, gas, and addresses.
Next in series
IPFS (InterPlanetary File System) Metadata, Mint, and Multiple Mint
Infura IPFS + Pinata pin, metadata JSON, mint(tokenId, uri) and multipleMint: 0.1 ETH × n, 750 supply.
Same series
Collection Landing and WIP Whitelist Funnel
CBD All-Stars mint landing: #GETINTHEWIP, 750 slots, discount funnel, and how a MetaMask-only mint surface becomes a product.