vrnft
ExperimentBy Andrew AarestadProject: 2021–2022
- Solidity
- NFT
- Chainlink VRF
- pseudorandomness
vrnft is a sample NFT contract with a verifiably random rarity reveal. I built it as an experiment with randomness in a blockchain setting. It was also a proof that there is a better way to do NFT drops in 2021.
If you paid attention to the space at that time you will remember the pattern: a new collection would get hyped, buyers would go and mint all the tokens, then they would do the big reveal. The reveal was a map that said which tokens were rare and what attributes they had. If you were lucky the tokens you minted would be at the top of the chart.
The problem: collection founders could get a sneak peek at the map. Seems crazy in retrospect but it was standard practice for collections to use rarity maps that were essentially just a spreadsheet the founders would upload. In other words, even if they acted with complete honesty, there was no way for the community to be confident that no insider trading had taken place.
I wanted to show that a reveal could be done so that nobody could know the rarity of any token until the reveal, and it could be provably random.
Try both reveals
Mint the collection below, then reveal it. In the typical reveal the rarity map existed from the start, so the founders can see it and insiders can acquire the rare tokens first. In the vrnft reveal there is nothing to see until the random seed is generated.
The rarity map is made before the drop. The team can see which token IDs will be rare and mint them for friends before the public sale.
Token #1 top-left to #100 bottom-right.
Press "Peek at the map" to start.
- Team looks at the rarity map
- Insiders mint the rare IDs
- Public mints the rest
- Reveal
- Legendary 2
- Rare 8
- Uncommon 20
- Common 70
- Unminted
- Minted
- Friends wallet
Tiers are scaled down for 100 tokens; the contract uses ranks 1–10 Legendary, 11–100 Rare, 101–1000 Uncommon. The contract hashes with keccak256; this demo uses SHA-256 in the same construction.
How a reveal usually worked
Most collections generated their art and traits off-chain ahead of time, assigned them to token IDs, and uploaded the metadata somewhere the contract would point to after the reveal. The reveal itself was just the project locking in that pointer.
Since they controlled the rarity map pre-reveal, duplicitous founders could steer their friends toward the valuable tokens. Sometimes this meant minting specific tokens, other times it meant buying valuable tokens second-hand before the reveal. It was not uncommon for projects to have accusations of insider trading, with wallets suspiciously holding multiple valuable mints or OpenSea purchases.
A reveal nobody can game
vrnft flips the order. Tokens mint as plain sequential IDs with no rarity attached. Once the collection sells out, the owner calls reveal(), which asks Chainlink VRF for a single random number. VRF answers in a later transaction with the number and a cryptographic proof that it wasn't chosen or tampered with by anyone, including the oracle.
When that number arrives, the contract expands it into one value per token and runs a Fisher–Yates shuffle over the collection. Every token ends up with a unique rarity rank, and the rank maps to a tier:
rank 1–10 Legendary rank 11–100 Rare rank 101–1000 Uncommon rank 1001+ Common
The owner still decides when to reveal, but not what the reveal produces. And because the seed is public, the shuffle is deterministic, and the contract is open, anyone can verify that the rarity was not gamed.
It's the same mechanism I explored with the cube scrambles in mevcube: a blockchain can't produce randomness, so any reordering done will be pseudorandom without some external seed.
What it costs
Verifiable randomness isn't free. Each VRF request is serviced by the Chainlink oracles, so the contract has to hold LINK tokens before it can reveal. The request is asynchronous: reveal() pays for the seed in one transaction, and the collection stays unrevealed until the oracle answers in a separate transaction.
That makes it awkward to test. A local chain has no oracle to answer the request, so I tested against a fork of Ethereum mainnet, swapping ETH for LINK through Uniswap to fund the contract first.
Nobody was asking for this
I still think this is a useful concept, but it never got used in a serious collection.
At the end of the day, NFT buyers mostly followed the people driving the projects: the artists and influencers with an audience. If a popular artist announced a drop, it sold out, and nobody cared which contract it ran on or how the reveal worked.