On September 3, we launched Lost Poet Pages with Pak, a collection of 65,536 NFTs and a precursor to the Lost Poets event. This drop sold out in 75 minutes and was designed to reward Pak collectors and keep gas costs low. This is how we did it.
Rewarding Pak collectors
Pak wanted to reward collectors, in particular ASH holders. To achieve this, there were two elements that were exclusive to ASH holders with a balance of at least 25 ASH:
An airdrop
An exclusive purchase period before the public sale
The Airdrop
To accomplish the airdrop, we took a snapshot of all ASH holders as well as the Uniswap V2 and V3 ASH pools.
Itβs important to note that the computation of ASH allocation in V2 and V3 is quite different, and calculating V3 allocation is quite involved, requiring the following high-level steps:
Get all open positions (by looking for all the ASH LP NFTs) and separate by each exchange pair
Get the current tick for each exchange pair
Go through each position and compute the ASH amount for the provided liquidity given the current tick for the given pair
With the balances and Uniswap values in hand, we were able to determine the aggregate balance for each wallet, and airdrop the appropriate number of pages. The block height of the snapshot was published, along with ASH balances and rewarded pages for public verification.
The Exclusivity Period
For ASH hodlers with at least 25 ASH, there was a 1 hour exclusivity period to purchase Pages prior to the public sale. To support this, we built the ASH balance check into the frontend client AND the smart contract.
When building content gates in web3 dApps, it is important to keep both the user experience and security in mind. On the user experience end, the appropriate checks should be put in place to ensure there is a good UI flow for those that donβt meet the access requirements. On the security side, you should always enforce access rules on the smart contract, as anyone can bypass the website and call the smart contract directly. If you are building a smart contract that is reliant on an access gate, it is critical that you encode these rules into the smart contract itself.
For Pages, the web3 application detected the ASH balance of a wallet and used that to show the appropriate sale status. Having >= 25 ASH gave a countdown leading up to the exclusive sale period, and access to the sale age during the exclusivity period. If someone did not have sufficient ASH, it would simply count down to the public sale. The smart contract also codified the ASH balance requirements and would check to see if a buyer had sufficient ASH during the exclusivity period.
Keeping Gas Costs Low - Using ERC1155
Similar to FVCK_CRYSTALS//, the exclusivity window for the Lost Poet Pages drop ensured that Pak collectors wouldnβt have to contend with the general public with respect to transaction fees. However, another innovative aspect kept gas consumption low: using ERC1155. This came out of a discussion with Pak, who initially proposed a ticketing system with an objective of minimizing costs. Weβve seen this mechanism used in the past, via mint-passes, but not to this scale.
The core benefits of using an ERC1155 are threefold:
Minting many NFTs costs the same as a single NFT, meaning that those purchasing multiple Pages wouldnβt incur additional cost
Minting a single NFT is slightly cheaper than an ERC721, as the token id and metadata does not change
Due to the general lower minting costs, especially for purchase requests for multiple NFTs, failed transactions result in less wasted gas
As a result, the contract distributed 65,536 NFTs with an aggregate gas cost of $392k.
When these Pages are eventually used, we are able to avoid any gas wars by having an extended redemption window, thereby allowing collectors to choose an appropriate low gas period to redeem.
Post-sale mechanic and locking transfers
One unique aspect of this drop was the post-sale mechanic. In order to ensure that a fair market price was paid, we decided to implement a mechanic whereby any unsold pages at the end of the sale would be proportionally distributed to the buyers. Although this wasnβt necessary, the rationale for this mechanic was to ensure that buyers would not feel like they overpaid if the NFTs did not sell out. In this case, all buyers would receive an effective βdiscountβ as they would get the remaining unsold NFTs, reducing the price per NFT paid. In order to implement this mechanic, we also had to lock transfers during the sale period, to ensure that there were no price manipulations on the secondary market. While this mechanic never came into play, we feel that it would have ended up being an elegant price discovery mechanism.
Further UX Optimizations
To make sure that collectors had the best experience possible, we made sure to design and test for all possible state transitions. This meant the following:
Timers to switch state between private sale, public sale, and sale end
Event listeners to detect purchase events and update the available Page count
Automatic state transition for sale end (either via a sellout scenario or sale ending scenario)
Of course, like all our projects, we intentionally overestimate the transaction gas cost to ensure that any gas underestimates donβt result in failed transactions. The following lines of code can save a lot of heartache. It costs the end-user nothing, as any excess gas is returned.
An unexpected issue - Breaking Metamask
One interesting item we ran into during the first few minutes of the sale was a Metamask connection issue. It did resolve itself after about 5 minutes though, leading us to suspect that it was either some rate-limiting scoped by domain, or the excess traffic triggering some form of load balancing and automatic scaling for the Metamask node provider that took a few minutes to occur.
More comingβ¦
As always, the key to a smooth experience comes down to good user interaction design and comprehensive testing. Hopefully, this article helps some of you with your next drops, and weβre excited to see what new innovations come out of the NFT community. This is just the beginning of the Lost Poets journey. Stay tuned for more!