A Guide to Designing Effective NFT Launches
Blockchains revolutionized fundraising for open-source software, but not everything worked right from the start. In fact, ICOs of the 2016-2018 era were often horribly broken mechanisms that allowed founders to cash out before delivering any products. Many lessons have been learned since, with today’s projects having a working product before launching a token and distributing it to incentivize usage and decentralize governance.
NFTs are proving to be another clear product-market-fit for crypto, but they are experiencing their own growing pains. The life of every NFT begins in an NFT launch (also sometimes called a mint or drop). An NFT launch is where a new collection is first created, sold, and distributed to buyers, who then decide to hold or trade it in secondary markets.
Like any item that goes on sale for the first time, NFT launches face the challenge of pricing something that has never had a price before. But unlike most other sales, they have the added difficulty of taking place in a highly adversarial environment full of idiosyncrasies that already alienate inexperienced users—a public blockchain. As a result, developers have to design mechanisms that are efficient and robust to exploitation.
This article starts with real-world examples of launches that empirically hurt their users to identify what goals a good launch should satisfy. Next, we deconstruct the idea of a launch into individual steps, exploring the design space for each of them. Finally, we provide a reference implementation of what we think is one well-designed launch mechanism for the community to use and build on.
Examples of user harm
Over time, we’ve come to notice that certain design patterns in NFT launches consistently lead to poor outcomes for users.
When a new collection launches, users can interact with its smart contract to mint an NFT with a random set of attributes. These attributes tend to be of different scarcities, making some combinations more rare and valuable than others. For example, only 9 of 10,000 CryptoPunks have the ultra-rare “Alien” attribute, with the cheapest one listed for 35,000 ETH right now.
While different people participate in mints for various reasons, many enjoy the excitement of not knowing what item and rarity they will get. In that sense, NFT mints are merely a continuation of the popular gacha mechanic in analog (e.g., booster packs for trading card games) and digital (e.g., loot boxes/crates in video games) economies for a long time.
Those who participate in gacha games tend to make an important assumption: they draw from a random distribution of items and have an actual (albeit slight) chance of getting a very rare drop. Unfortunately, past NFT mints have frequently failed to satisfy this assumption and create true randomness. In practice, this has allowed highly technical and motivated parties to exploit mints and snipe the rarest items of a collection, taking them away from honest participants.
With this pattern, we share two cases where NFT mints have been exploited in precisely that way. Both exploits relied on the same two-step process:
- An exploiter extracts the collection’s metadata, allowing them to represent the relative frequency of all traits in a single rarity score. Using this score, they can then determine the highest-value NFTs of a collection.
- The exploiter then breaks the minting contract’s randomness to mint only the rare, highest-value NFTs they want.
Loot derivatives and the on-chain metadata exploit
Recently, a project called Loot took the NFT world by storm. Seemingly simple, the project featured 8,000 loot bags made up of chest, foot, hand, head, neck, ring, waist, and weapon items of varying rarity.
With all attributes for each item slot stored directly in the contract, minters received a pseudorandom bag, using the bag ID as the hash. While permanent for as long as Ethereum exists, storing metadata on-chain also exposed Loot’s pseudorandom nature to exploiters. They quickly scraped the metadata for all 8,000 bags by simulating the randomization functions locally, getting a picture (and derived rarity) of the entire collection. Equipped with that info, they only had to exploit the contract’s last remaining weakness: the ability to mint exactly the IDs they wanted and snipe only the rarest bags.
However, despite the simplicity of this exploit, there is reason to believe that no one exploited the original Loot mint:
If we observe the rarity of bags up until the very end of the mint, rare items are well-distributed across the span of the mint. That indicates no standout cases of exploitation.
There are two potential explanations why Loot wasn’t exploited:
- It was a completely new contract, so people were not ready or lacked time to discover the exploit.
- The EV of minting Loot was unclear, as the collection’s value only exploded in the secondary market over the following days. That it took 2.5 hours for the collection to sell out further supports this hypothesis.
However, as the price of Loot kept increasing, a whole range of derivatives like More Loot and Extension Loot started popping up, most of which were simply minor forks of the original Loot contract. The new collections inherited Loot’s vulnerabilities but at a higher market value and with more eyes on them. This made all the difference to the fairness—or lack thereof— of these mints.
Comparing the distribution of rare items to the time of mint between More Loot and original Loot, evidence of exploitation becomes very obvious. After only a few blocks, all rare NFTs had been minted, leaving just scraps to future minters, who were mainly left unaware that sophisticated users had exploited the launch.
Below: The red line indicates when Anish made his rarity scores public on Twitter, starting a race to claim available rare bags.
Furthermore, because More Loot has an inflating supply, it is fair to expect exploiters will pre-score future available bags and race to mint them.
Similar to More Loot, Extension Loot features a single address minting five of the rarest ten bags (all mints highlighted in red). Uniquely, these mints are hidden in near plain sight, as the exploiter distributes them over time and available bags before targeting rare bags in succession.
Meebits and the off-chain metadata exploit
Meebits was a highly anticipated NFT mint of 20,000 unique 3D characters from Larva Labs, the creators of CryptoPunks.
Larva Labs knew savvy users could use a collection’s metadata to calculate rarity and snipe rare NFTs. To combat this, they designed their website in a way that allowed buyers to see the complete metadata of each Meebit, but only after it had been minted.
While the website explicitly hid unminted Meebits, someone inspected the source code to see that LarvaLabs pulled the metadata from IPFS. Using this information, they scraped IPFS to extract the metadata of unminted Meebits anyway, identifying the most desirable ones.
However, Larvalabs still didn’t make it easy on the exploiter: unlike Loot, a user couldn't mint a specific Meebit ID. Instead, on-chain randomness used as a hash (in theory still exploitable by miners) made it harder for this particular user to mint a rare Meebit.
The exploiter, however, knew how to make the best of a bad situation. They wrote a contract to buy Meebits, see their ID, and then “reroll” them. Specifically, the Meebit contract was an ERC721 with a mint() function that returned a random Meebit ID. The exploiter’s contract would call mint, check the returned Meebit ID against their rarity list, and if it didn’t exceed a certain rarity score, revert the transaction (sample code). Using this trick, they only paid about 0.03 ETH to check each ID instead of ~2.5 ETH for buying each Meebit outright.
While the attacker burned through many failed transactions and hence gas fees in the process, they walked away with ~400 ETH in profit. Today, the same exploiter could send their transactions via Flashbots bundles and only pay the miner if they got one of the IDs they wanted—making reverts completely free.
The attacker minted and sold Meebit #16647, which had the ultra-rare “visitor” trait.
In September, the Ethereum base fee per gas surpassed 1,250 gwei over seven unique periods. Alarmingly, all seven of these occurrences were because highly-anticipated NFT launches disrupted the network.
From left to right: G’EVOLS, The Sevens, Sipher, Galaxy Eggs, Omnimorphs + ArtBlocks Democracity, Galactic Apes, King Frogs
Most of these launches employed a fixed-price, first-come-first-served (FCFS) mechanism. With low prices and excessive demand, competition to acquire such NFTs transitioned from the contract sale to a gas auction in the mempool.
One such example was The Sevens NFT drop, a highly anticipated collection of 7,000 collectible profile pictures featuring dystopian characters. With an initial price of 0.07 ETH per NFT, eager participants hurried to the contract to mint. Within just 6 minutes, gas prices peaked at 12,246 gwei, with the median participant paying ~1.49 ETH per NFT and the highest 5% of individuals paying 2.44+ ETH per NFT in gas alone to mint from the contract.
Rapid escalation of block base fee for the duration of the Sevens mint
The problem with gas auctions is not just that they are more challenging to use, but by “abusing” the public mempool in this way, they create negative externalities for all Ethereum users. They also force users to pay different amounts for the same NFT, resulting in thousands of failed transactions from insufficient bids, hurting users.
As we’ve seen before, Ethereum is a Dark Forest, with advanced, adversarial actors always on the lookout. NFT mints, especially rare ones where buyers expect to pocket a premium in the secondary markets after minting, offer lucrative opportunities for technically-adept parties to outskill the average participant.
These participants interact directly with the minting contracts through botting and automated strategies, often bypassing frontends and occasionally even the mempool.
The TIMEPieces NFT drop showcased a prime example of this. Advanced bot operators inspected the nft.time.com frontend source code ahead of the minting process. Through this, they were able to find deployed minting contracts on mainnet and built bots hours in advance. As a result, these bots had a significant advantage during the mint, which completely sold out in under three minutes. By the time the average participant had connected their wallet and submitted a transaction, it was too late.
Furthermore, some parties used Flashbots to circumvent the mempool and submit direct-to-miner transactions. While the TIMEPieces contract restricted participants to minting a maximum of ten NFTs per address, bot operator 0x35...ce5 planned ahead, split funds across five wallets, and sniped 50 NFTs in a single Flashbots bundle. Even after paying a 20 ETH miner tip (bringing their average mint cost to 0.5 ETH per NFT), this bot operator stood to profit nearly 120 ETH when the NFTs began to hit the secondary market.
This bundle included 5 mint transactions from different addresses, circumventing the per-address minting limit
Additionally, because this participant used Flashbots (which reverts failing transactions at zero cost), they did not suffer from the failed transactions we described in the previous example. This is unlike the near 10,962 average-skilled participants that lost a cumulative 252.62 ETH (almost $800,000) in transaction fees, across 12,743 reverts in 100 blocks, for their attempts that were unsuccessful.
An effective NFT minting mechanism is easy to use for all participants—ideally, with few steps and simple implementation. A common pitfall for mints that implement alternatives to the FCFS distribution model is that they introduce complexity, increasing the number of on-chain transactions a user must make.
One example is the Jay Pegs Auto Mart $DONA auction on Miso. While the mint pioneered batch auction NFT distributions and effectively showcased how fair metadata generation could look in practice, it did so at the expense of gas and transaction efficiency.
To participate in the minting process, users had to make a minimum of four on-chain transactions over eight days:
- To begin, users committed ETH to a Miso batch auction without knowing how many $DONA tokens they’d receive in exchange (depends on the final clearing price)
- Once the auction was over, users had to claim their $DONA tokens
- At this point, all users had either too few tokens to mint an NFT, just enough, or too many. Based on 1,363 minters who participated, we found 273 had too few, 0 had just enough, and 1,090 had too many (excess fractions of a token).
- Users with too few tokens would have to transact to acquire the necessary surplus from Sushiswap.
- Users with too many tokens had the option to approve the $DONA token for trading and then transact to sell their surplus via Sushiswap.
- When users had enough $DONA to mint an NFT, they could approve the NFT contract to spend their $DONA, and then burn their $DONA to mint an NFT.
- Finally, metadata would be assigned to NFTs in batches, with no way to reveal one’s NFT unilaterally.
While this mechanism strived for fairness, it made user participation difficult and gas-inefficient.
One way that NFT collectors and enthusiasts assess the value of a collection is by the strength of its community. Commonly, this involves measuring the concentration of tokens among holders. Ideal collections tend to have low concentration, favoring individual participants over many whales.
Among recent mints, though, there has been a new trend of introducing batch minting, where participants can mint more than one token, at once, in a single transaction. Via this mechanism, whale minters are incentivized with less gas overhead to mint many NFTs.
An example of this in practice is the Stoner Cats drop, a collectible NFT mint to support producing animated shorts from Mila Kunis and friends that allowed minting up to 20 NFTs at once. Given this functionality, 89% of the NFTs were minted via the batch mint function, and nearly 31% of Stoner Cats were minted in batches of the maximum 20 NFTs.
Additionally, all NFTs sold with a fixed price implicitly prevent individuals from participating below the clearing price. This reduces the fairness in distribution, tipping the scales in favor of those with larger wallets, especially given how expensive minting can get.
Whether implementing centralized raffling to prevent gas wars or Chainlink to improve fairness, a common trade-off is introducing trust assumptions in third parties. The more off-chain infrastructure an NFT mint must rely on, the more trust users must have in the centralized, off-chain entities.
Goals of a good launch
From looking at these launches and analyzing the problems people had with them in practice, we can now derive what we see as six desirable properties of an NFT launch. Our list has no ambition to be complete, but it‘s a start.
Unexploitable fairness: Launches must have true randomness to ensure that predatory users cannot snipe the rarest items at the expense of less sophisticated users.
No race conditions: Whenever an NFT (or any good, really) goes on sale below its fair market price, it turns into what Vitalik Buterin has called auction-by-other-means. In practice, buyers race to get their transaction mined as fast as possible or attach large bribes to incentivize miners. Any auction-by-other-means favors people with deep knowledge about the blockchain and access to power tools like bots, private relays like Flashbots or Eden, or even direct-to-miner access.
Time-zone agnostic: Commonly, FCFS launches are announced at a particular block height, and then sell out in a short period of time. No matter what block height is chosen, it will always disadvantage users of other time zones who are currently sleeping or at work. Therefore, launches shouldn’t be too short so people can participate without changing their daily routine.
Gas-efficiency: Transacting on chain (especially on Ethereum) is expensive, and so a good launch should try to minimize the number of transactions that users have to make.
Inclusivity and sybil-resistance: Often, it is in the best interest of an NFT creator to ensure the launch is open to a diverse base of holders, even if it causes the market to clear a bit lower initially. That is because a vibrant community is what ultimately drives the value of a collection in secondary markets.
Trustlessness: Of course, all that said, the launch mechanism should work to preserve the properties of the underlying blockchain. That means it has to afford the aforementioned benefits without becoming custodial or requiring too many trust assumptions in the operator.
Obscurity is no excuse for bad design
Most launches have one or several of the aforementioned problems in theory, but in practice, there is insufficient demand for these problems to appear. This is an example of security by obscurity.
For example, if a new collection has low perceived market value, there may be no race condition that leads to a bidding war in the mempool, no need to buy priority blockspace, and no incentive for predatory users to exploit it. Likewise, if a new collection has too much demand, then the collection might sell out so fast that there is no time to write custom software for it or exploit its fairness.
While security from too little or too much demand is a thing, we posit that one should always design their launch to be robust across all market conditions, and especially not rely on collections selling out fast as a means of protecting them from exploitation.
Unbundling NFT launches
While we now know what we want in a good launch, we still don’t know how to get there. We can slowly reveal that path (or, as we will see, the many paths) by unbundling what actually happens under the hood.
Every NFT launch consists, at its heart, of four steps:
- Bidding: The sale goes live, and users submit their bids to the operator (can be a smart contract).
- Clearing: The operator matches the collected bids against remaining supply, determines a clearing price, and selects winning bids.
- Distribution: Winners can claim their newly-minted NFTs (or receive them from the operator).
- Metadata reveal: The operator reveals the properties of the NFTs.
Look at Loot, for example. Loot went live on block 13,108,877 in an FCFS sale. The collection’s creator dom set the sale price to zero in the smart contract, but users still had to bid with gas. Every block, miners cleared the new bids against the remaining supply, deciding who won and who didn’t. When a bid was successful, the user received the item in the same transaction.
Most users learned the attributes of their item after they received it. However, in practice, a sophisticated user could have read the attributes of their item from the smart contract before minting, thereby allowing them to snipe the rarest items of the collection. This shows that whether the other steps happen sequentially or continuously, the metadata must be revealed only after the item has been bought and settled conclusively.
Next, we will explore the options NFT developers have at each of the four steps. We discuss each choice’s effect on the desirable properties, filtering the good design choices from the bad.
Phase 1: Bidding
In this phase, the operator collects bids (i.e., purchase requests) from its users.
Continuous vs. sequential clearing
Before anything else, the operator has to decide whether they want bidding and clearing to happen continuously within the same or two non-overlapping phases.
Any FCFS, fixed-price sale (which is most NFT launches to date) is an example of continuous clearing. Every block, miners look at the bids and clear them against the remaining supply. This mechanism has several problems: If the operator over-guesses the NFT’s clearing price, the items are too expensive and might not sell out. If the operator under-guesses the NFT’s clearing price, the items are too cheap, and users race each other with either speed (who has the most direct access to blockspace) or gas price (who can pay miners the most for their transaction). As discussed, this leads to massive dead-loss from failed transactions and greatly favors more skilled participants. If you must, the former can be mitigated by routing all user transactions to Flashbots RPC and letting the auction play out in an environment where failed transactions don’t have a cost.
When going with the second option, bidding and clearing happen in two non-overlapping phases. In practice, the operator first collects all the bids and then matches them against the available supply, clearing the market at a fair price. This approach includes mechanisms like batched auctions or raffles. One example of this approach is Jay Pegs Auto Mart, which gave users one week to submit their bids before clearing the market.
The sequential approach has several benefits that are in line with our stated goals:
- No race condition: Users have plenty of time to submit their bids, and the outcome is decided by how much users are willing to pay, not by how fast or skilled they are.
- Timezone-agnostic: The approach respects people who work or live in other time zones.
Furthermore, because there are no gas auctions, there are no negative externalities on other network users.
However, this approach has downsides, such as requiring more on-chain transactions (depending on the design of the auction) or reducing the fun for participants who now have to wait longer. We recommend not letting the bidding period stretch too long to mitigate the latter concern, probably no longer than 48 hours.
On-chain vs. off-chain bidding
After deciding between continuous or sequential clearing, the next choice is whether users submit their bids on- or off-chain.
As we will see, today’s launches often collect bids on-chain because it is easiest, effectively letting miners clear the winning bids and letting the rest fail. If we assume the network itself is uncensored, there is also the strong guarantee that no valid bid can be omitted from the sale.
However, collecting bids off-chain is equally possible. In this process, users sign a message that contains information like their on-chain address, the number of tokens or tickets they want to buy, their maximum price, etc., with their private key. They send this message to the operator without executing it on-chain, using their signature to prove its validity.
The operator can then use these bids to either clear the market off-chain or bundle the winning bids and submit them to the contract for execution on-chain. With either approach, some level of trust is necessary for the operator to execute the correct bids.
This last approach combines off-chain bid collection with on-chain winner selection robust, gas-efficient, and flexible ways. The only thing users have to trust is that the operator does not omit any bids when submitting them on-chain—a relatively weak assumption to make.
Who is allowed to bid
The third decision to make is who is allowed to bid and how much. As discussed in the goal of Inclusivity and Sybil resistance, projects might want to ensure that a diverse set of users buys their items. To that matter, they may limit the number of items available to users with specific characteristics or reserve items specifically for holders of existing NFT communities.
When the bidding happens off-chain, such KYC rules are easy to implement—you merely ask the user to prove certain information before letting them submit their signature to the server. On-chain KYC is more complex, but advances are being made by initiatives like Gitcoin’s privacy-preserving Proof of Personhood.
Even if a project does not want any form of KYC, they can still take measures to ensure that one dollar buys the same amount of tokens for large and small users alike. This principle is often violated when contracts allow users to buy or claim many NFTs in the same transaction because whales get to amortize gas fees across more tokens, hence paying less per token than smaller users. To mitigate, capping the number of tokens per address or per transaction is usually a good idea.
Further, the operator must decide when the user has to pay for the token—together with the bid, or after the market has cleared?
In the latter case, the user merely reserves the token in the bidding phase, the market clears, and then they can complete the purchase within a certain time window. One project using this method, together with off-chain bidding, was Parallel. While it worked well in a quieter market, when demand is very high this model can turn into a race condition in which users want to reserve as many tokens as possible, given it is costless to do so.
To mitigate the problem of race conditions, a cost should be associated with the bid itself. The best solution here is to let users submit bids only after locking funds in a smart contract from the same address. The operator can then decide whether to return the funds if the bid was unsuccessful (resembling a limit order on an exchange) or to keep the bid (resembling a raffle ticket that did not pay out).
Granularity of bidding
Finally, one must decide how much granularity they want users to express with their bids. When there are losing bids (because demand exceeds supply), one must further decide what it means to be a winner and a loser. Here are three viable options:
“Dumb” batched auction: People commit an amount of ETH with no further instructions. In the clearing phase, the number of items is divided by the overall ETH committed, and everyone receives fractional tokens in the form of an ERC-20 that can later be redeemed for an ERC-721 NFT. Jay Pegs Auto Mart used this approach, and it has the benefit that there are no losing bids. However, it has the downside of requiring three extra on-chain transactions—two to sell or buy tokens to reach a useful amount (e.g., one “full” ERC-20) and one to redeem the NFT. Most importantly, this approach does not allow buyers to express the price at which they want certain quantities of tokens—a feature one has come to expect in almost every market.
“Smart” batched auction: A similar but arguably better approach was used years earlier by SpankChain for their ICO. Unlike Jay Peg, SpankChain collected bids that allowed specifying the quantity of tokens and price per token. After the bidding phase, they calculated a strike price off-chain and submitted it with the winning bids to a smart contract, allowing people to withdraw either SPANK if they won or their ETH if they didn’t. The downside of this approach is that the computational complexity of matching all the bids is so large that it can only be done off-chain, which requires some trust in the operator.
Raffle: Finally, one can run a raffle or lottery in which users make bids by buying tickets or reservations. Winners are then randomly selected from the pool of all tickets. This way, users receive either a full token or none, saving the three extra transactions that Jay Peg’s $DONA needed. It is also inclusive of smaller wallets that might be unable to afford one full NFT. However, it introduces randomness into the sale, which some users may prefer and others not.
Phase 2: Clearing
In this phase, the operator (or someone on their behalf) matches the bids against the available supply, deciding who gets to buy an item and who doesn’t.
On- vs. off-chain clearing
The last major junction is who gets to select the winners from the pool of all bids. In the FCFS model, this is done by miners, which we showed is broken in several ways.
In Jay Peg’s clearing mechanism, the computational complexity is just low enough to do it on-chain in a fully trustless way.
In SpankChain’s model, winners are selected entirely off-chain. While bidders cannot get filled above their desired price (the smart contract ensures this), they still have to trust the operator to not push them to their maximum fill price, similar to how a sandwich attack on decentralized exchanges works.
The raffle approach is the easiest to clear since all you need is a single random number (e.g., from Chainlink VRF). However, requiring randomness also introduces another trust assumption: whoever produces this randomness could favor their own bids over others. In contrast, this is not possible when the winning bids are simply the highest ones.
Phase 3: Distribution
After the market has cleared, the operator must mint the tokens, get them to the user, and return any losing bids if that was the model they went with. This step is generally all about gas efficiency and preventing race conditions.
Instant vs. spaced settlement
If the operator wants to prevent their users from claiming simultaneously, causing gas fees to spike, they can reuse the same randomness from the clearing process to let people claim in batches. This solves a collective action problem because users are better off not claiming all at the same time. Still, curiosity about learning about their metadata and being among the first to sell in the secondary markets might create a race condition anyway. That said, a spaced settlement also increases the waiting time for users.
Claiming vs. receiving a token
The only other thing to mention in distribution is whether users have to claim the token on their own or whether the operator can simply send it to them over time. The latter is a variation on the spaced settlement, but with the added benefit that users don’t need to do anything. The Parallel launch mentioned earlier used this method to good effect, simply requiring users to add a “delivery fee” when they initially paid for their NFTs.
Phase 4: Metadata reveal
Finally, once a token has been distributed, its metadata can be revealed. Of the four phases of NFT launches, this step must come last. It cannot be a shared last step either (e.g., by bundling payment, distribution, and reveal in the same transaction, as Meebit did) as fairness can be exploited by rerolling items with bad attributes through reverting transactions. There must be at least a one-block gap between payment and reveal to make rerolling impossible, although you may choose to increase this gap to protect against reorgs too.
When to reveal the metadata
We have now established that minting the NFT and revealing its metadata cannot happen within the same transaction, raising the question of when to reveal it instead. This is not just important for fairness, but user experience and gas efficiency play a role, too. In general, there are three options:
Full-collection reveal: In a full collection reveal, the operator waits until all NFTs of the collection have been minted before revealing the metadata. This approach is highly gas efficient, requiring only a single random number that can then be used to shuffle metadata for ticket IDs with no further action from users.
However, it has significant downsides. Namely, users have to wait until all NFTs have been minted to see metadata for their tokens. If one sets an upper bound on when to reveal the metadata (e.g., 24 hours), some users might still fail to mint in time, resulting in the collection not selling out.
Per-NFT reveal: To improve the UX of the full-collection reveal, the operator can also allow users to reveal randomness on a per-NFT basis. This is more engaging as users can “open” their item shortly after purchasing it. It also allows “unopened” items to trade in secondary markets (which is popular in trading card games like MTG).
However, this method comes with the burden of requiring users to make additional on-chain transactions, such as calling Chainlink VRF and applying a random number to their NFT. This is unavoidable even for users who don’t feel a particular urgency to reveal or who are not interested in trading unopened items.
Batched reveal: As a potential middle-ground, we propose the concept of the batched reveal. In this method, users have an indefinite period of time to mint but can also reveal their item in the next block if they want to. Every new random number requested automatically reveals the metadata of all items minted and pending assignment, revealing them at virtually the same, constant cost.
As a result, users with high time-preference have the optionality to pay for the extra on-chain transaction to reveal metadata, and this benefits all users before them. Should no user choose to reveal, the operator can also do it according to some schedule, e.g., every full hour.
Source of Randomness
After deciding when to reveal, the remaining question is where to get the randomness. The two options we suggest are using Chainlink VRF or a commit-reveal scheme.
With the former, you can access a verifiable source of randomness on-chain, on-demand. Using any of the reveal mechanisms, you can call Chainlink to request randomness, and once fulfilled, use the randomly generated number as an input to your metadata calculation. This will ensure it is randomized for each NFT.
With the latter, an operator can create one random number (for full-reveal) or several random numbers (for per-NFT or batched reveal) before the sale and pre-commit their hash. Once an NFT has been minted, the operator can reveal these numbers, allowing anyone to verify their authenticity through the hash. Still, this approach requires some trust in the operator to not exploit their privileged insight into the random numbers to mint the best NFTs. To minimize the need for trust, we recommend that some independent randomization in minting order still occur.
Additionally, for off-chain metadata, instead of committing a random number, operators may instead choose to commit a hash of the complete metadata (id-to-attributes for all NFTs). This ensures that metadata is predetermined and not altered during or after the minting process. Still, independent randomization in minting order is necessary to prevent operators from exploiting their knowledge of order and attributes.
Our reference implementation
We have provided a reference implementation that we consider a good balance between all properties and simple to understand and modulate.
Bidding: In our implementation, users can bid by buying tickets to a raffle. The duration of the raffle is determined by the operator (we recommend 24-48h). The price per ticket consists of gas as well as the price per NFT, specified by the operator. The latter acts as a “security deposit” and is refunded on all losing tickets after clearing the market. Sybil resistance is created in three ways: the gas per transaction, the cost of capital on locked funds, and the maximum number of tickets per address.
Clearing: Once the bidding period has concluded, a number of winners equal to the number of available NFTs must be drawn from the pool of all tickets. First, anyone can call `collectEntropy()` to get a random number from Chainlink VRF. This randomness is used in ‘shuffleEntries(),’ which implements a Fisher-Yates Shuffle. Anyone can call this function, guaranteeing liveness and making the gas cost socializable (e.g., by whales).
Distribution: After all the winners have been drawn, users have an indefinite period to claim an NFT from their winning tickets and get a refund on their losing tickets. Both happen within the same transaction. The operator can now start withdrawing the proceeds from winning tickets.
Metadata Reveal: Users can reveal their NFTs metadata one block after they claim. Anyone can request a new random number that automatically reveals the metadata of all items that have been minted and are pending assignment. This allows users with a high time preference to pay to reveal immediately but benefit all users.
In this article, we have given real-world examples to show how poorly designed NFT launches can lead to suboptimal outcomes for users. But, when one clearly defines their goals and takes the time to deconstruct what steps a launch actually has, many designs become possible—and almost all are better than the fixed-price, first-come-first-served, network-congesting sales we are used to today.
If you take nothing else away from this article, let it be these three rules:
- Unexploitable fairness is the most critical property of an NFT launch with random metadata. Use robust randomness and never reveal the metadata of an NFT before it has been bought and settled.
- Race conditions hurt users, both those who participate in the mint and those who don’t. Use sequential bidding and clearing (e.g., a raffle or a batched auction) to solve this problem.
- Consider cost-efficiency from minute one. Ask if any step that currently happens on-chain could also happen off-chain to save money for your users. Off-chain steps can include bidding but also market clearing, assuming users can establish some degree of trust in the operator. Consider batching in the reveal phase.
We would love to see NFT developers start experimenting with some of these ideas, leading to a better variety of launches in the wild. Finally, we want to shout out those who have been sharing their advice with the NFT community, helping improve the quality of launches:
- Vitalik—for his explainer on the problems of FCFS fixed-price sales
- FairDrop—for sharing their proof-of-concept design of fair raffles
- dotta—for advice on building a robust frontend
- Parallel—for showcasing best practices with off-chain raffling
- 0xmons—for advice and tooling around designing fair launches