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.
| Property | Value |
|---|---|
| Base contract | AutoLoopVRFCompatible |
| VRF usage | Trait assignment seed |
| Gas per tick | ~35k + 12k per token |
| Source | autoloop/src/agents/NFTReveal.sol |
| Tests | 21 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 ofnextTokenIdand takesmintPriceETH - Reveal condition:
shouldProgressLoop()returns true whenblock.timestamp >= revealTime,nextTokenId > 0, and not yet revealed - One-shot reveal:
progressLoop()setsrevealed = true, stores the VRF seed inrevealSeed, then loops over all minted tokens assigning tiers based onkeccak256(seed, tokenId) % 10000matched againstrarityTiersBps[] - 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 --broadcastArgs: 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.jsDashboard
View NFTReveal on the AutoLoop Dashboard.