Docs/Examples/Nft Reveal

NFTReveal (VRF Trait Reveal)

Assigns rarity tiers to all minted NFTs at reveal time using a single VRF seed.


Overview

NFTReveal is a two-phase NFT contract: mint, then reveal. During the mint phase users pay mintPrice to receive a token with no assigned traits. After revealTime passes, AutoLoop fires once and uses ECVRF to seed trait assignment for every minted token in a single transaction.

PropertyValue
Base contractAutoLoopVRFCompatible
VRF usageTrait assignment seed
Gas per tick~35k + 12k per token
Sourceautoloop/src/agents/NFTReveal.sol
Tests21 passing (unit + fuzz)

Why AutoLoop + VRF Are Structurally Required

The trigger holder can front-run the reveal. With a deterministic reveal, whoever triggers can pre-compute all trait assignments before calling — selectively revealing only when they hold rare tokens, or selling at inflated prices based on advance knowledge. AutoLoop separates the triggering role from token ownership: the keeper fires the reveal and has no stake in which tokens are rare.

ECVRF makes trait assignments unguessable to collectors (they don't have the keeper's private key) and verifiable on-chain once the reveal transaction lands.

Keeper Trust Model

What AutoLoop guarantees: Token holders cannot predict or influence trait assignments. The keeper's private key is required to generate the VRF proof, so no collector can pre-compute rarity before the reveal transaction.

What the keeper knows: Each keeper generates the proof off-chain before submitting, so it knows its own output — but the keeper holds none of the tokens, so it has no direct financial interest in any specific assignment.

How collusion resistance works: AutoLoop registers multiple independent controllers per VRF contract. Each controller produces a different VRF output for the same seed. They race to submit — if one withholds their output, another submits with a completely independent assignment. Manipulating the final result requires ALL registered controllers to coordinate on withholding, which is the effective collusion bar.

For maximum security on high-value NFT collections, register additional independent controllers via registerControllerKey() before the reveal window opens.

Mechanics

  • Mint phase: mint() assigns ownership of nextTokenId and takes mintPrice ETH
  • Reveal condition: shouldProgressLoop() returns true when block.timestamp >= revealTime, nextTokenId > 0, and not yet revealed
  • One-shot reveal: progressLoop() sets revealed = true, stores the VRF seed in revealSeed, then loops over all minted tokens assigning tiers based on keccak256(seed, tokenId) % 10000 matched against rarityTiersBps[]
  • Tiers: defined at construction as an array of BPS values summing to 10000 (e.g. [5000, 3000, 1500, 500] for Common/Uncommon/Rare/Legendary)
  • tokenTier(id): returns 0 (unrevealed) or 1..N after reveal

Revenue Model

  • 2% protocol fee on each mint payment
  • AutoLoop gas fee on reveal tick

Deploy

# Example: 1000 supply, 0.01 ETH mint, reveal in 7 days, 4 tiers
forge create src/agents/NFTReveal.sol:NFTReveal \
  --constructor-args 1000 10000000000000000 $(($(date +%s) + 604800)) "[5000,3000,1500,500]" '["Common","Uncommon","Rare","Legendary"]' \
  --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast

Args: maxSupply, mintPrice (wei), revealTime (unix timestamp), rarityTiersBps[], rarityTierNames[].

VRF Key Registration

Register each controller worker's ECVRF public key before revealTime:

nftReveal.registerControllerKey(controllerAddress, pkX, pkY);

Without registration, VRF proof verification will revert on the reveal tick. Use register-vrf-keys.js to automate all workers:

NETWORK=sepolia VRF_CONTRACTS=<nftRevealAddress> node scripts/register-vrf-keys.js

Dashboard

View NFTReveal on the AutoLoop Dashboard.