[Alpha Labs #3] The journey of Blockalizer
From conception of an idea to trending #4 on OpenSea in under a month
Welcome to the third edition of Alpha Labs Newsletter — where we will update you on what we are cookin’ over at the labs 🧪 Today’s post is a special one.
Where do I even begin? On December 16th we made a post announcing Alpha Labs, where we shared a tiny teaser on what was brewing up in the lab. Since then, we have been building silently. We decided against revealing too much; simply given how early things were. What followed was a crazy ride that didn’t let us to catch a breath and we never got a chance to write much about it. Things have been moving fast! The last few weeks have been a blur and a month seems like an eternity ago.
Fast forward to January 15th, 2023. And we have an NFT collection that is trending #4 on OpenSea. This is just a start! But how did we get here?
An idea 💡
We were bullish on NFTs from the start and wanted to do something unique. With Evan’s experience as a product and brand designer, and my expertise in engineering and knowing best practices, we knew we were capable of making a splash in the space. It was a no-brainer for us to do an NFT collection to help inject capital that would bootstrap the company. The idea of Blockalizer was conceived: creating memento from existing blockchain data. 12 generations overall with each generation allowing for 1000 mints. I won’t go too much into the details of how the mechanics work. But this medium post is a pretty comprehensive read. If you are more curious, I highly recommend you check it out.
Execution ⚙️
Blockalizer takes some inspiration from QQL Art, which allows users to create generative art. We also felt QQL Art was a little too heavy on the controls and we wanted to keep it simple. We came up with a few controls that were fun and easy to toy with: adjusting grid-size, removing blocks, fill or no fill and an appealing color palette. You don’t just mint an art. You create it. Head over to https://www.blockalizer.xyz/ to check it out!
We also made it a priority to engage with community from day one. We would actively engage with our followers and ask them what they’d like to see. This way we were not making a decision that just made sense for us. But also ensured that people liked it!
Let’s talk about the algorithm behind the art generation. It’s not all just random. The orientation of the generated art is determined by the block-hash. And you can’t just choose any arbitrary block-hash. You have to have transacted with it!
We pull historical transaction data tied to your address and fetch the blocks that they were part of. If you haven’t done any transaction, too bad (but then again, you can always just send yourself tiny amount of ETH)! This allows user to create a memento of their favorite transaction.
Was this a lot of work? Damn right! 🥵
Let’s get a little more technical. We have a Blockalizer controller contract that is UUPSUpgradeable (meaning that it is deployed as a proxy). It also uses OpenZeppelin’s Access Controls that allows us to define roles. The controller contract captures information such as size of the generation, price of a mint, maximum wallets that are allowed to mint, start time and end time. The ERC721 contract is defined as a child contract. In itself, the ERC721 is straightforward with the only addition being the logic for Operator Filter, which is a new requirement from OpenSea to collect royalties. But the bulk of the logic is in the controller contract. With the minting function being the most complicated one.
function publicMint(
uint256 _collectionId,
string memory _uri
) public payable {
IBlockalizer collection = IBlockalizer(_collections[_collectionId]);
uint256 tokenId = collection.currentTokenId();
uint256 generationId = _generationCounter.current();
BlockalizerGenerationV2 generation = BlockalizerGenerationV2(
_generations[generationId]
);
uint256 tokenCount = generation.getTokenCount();
require(
generation.balanceOf(_msgSender()) < generation.maxMintsPerWallet(),
"User has already minted max tokens in this generation"
);
require(
generation.maxSupply() > tokenCount,
"All NFTs in this generation have been minted"
);
require(msg.value == generation.mintPrice(), "Not enough ETH provided");
// whitelisted users can by-pass
if (!_whitelisted[msg.sender]) {
require(
block.timestamp > generation.startTime(),
"Minting not yet live"
);
}
require(generation.expiryTime() > block.timestamp, "Expiry has passed");
collection.safeMint(msg.sender, tokenId);
collection.setTokenURI(tokenId, _uri);
generation.incrementTokenCount(msg.sender);
collection.incrementTokenId();
}
You’d only pray that with this much logic, everything goes smoothly as expected. But does it ever?
The launch 🚀
Right before the launch, we did some fun giveaways on Twitter to allow members from the community get ahead in the line by letting them mint before Blockalizer goes public.
We collected a list of 200+ whitelisted users. It was really cool to see the enthusiasm. On January 11th 2023, we deployed the code to Mainnet and opened the gates to only those who were on the list.
Some people were upset about missing the whitelist spot. But we were able to mint 100+ on the first day. And it was clear that there was demand for it! We were praying to sell just enough to help us infuse minimal capital. But then something crazy happened! We opened the gates for the public mint! And we started noticing…
Oh no! What is going on? I started looking into the database and checking if everything was OK there. Nope, looks like running on free tier plan on MongoDB Atlas was a bad idea 😬. We pulled the plug to upgrade the database! But didn’t solve the problems for us! Looks like sophisticated users weren’t even using the website. They’d call the contract directly and mint from there. There is nothing in place to stop them from doing that! There was panic! Clearly these sophisticated users were accessing the contract programmatically somehow. Generating new addresses and putting in random URIs. We started seeing a ton of duplicates! On the bright side, we were sold out in under an hour!!!
The horror 😱! Can we fix this? Has our hard work all gone to waste? It was a rush of emotions. On one hand, all pieces were minted on the first day. On the other hand, ton of artwork on OpenSea was in smithereens. We had to fix this!
So we rolled up our sleeves and got to work. We created a script to read all token URIs.
Next we updated the contract and generated new art for the broken pieces. But again, we didn’t want to make it all random. We inspected the holders of the token and programmatically determined the last block they transacted with. This was then fed into the art generator script which produced the art piece. Which in turn was uploaded to IPFS and finally fed to the smart contract to update the token URIs with the correct art! Phew! 😓
Also, shout out to the OpenSea folks who were cooperative throughout the process!
The big question on our mind was: did we manage to salvage it? It was clear that some people on Twitter weren’t happy. But you can’t please everyone all the time. We had a slight hiccup but we were committed to fixing it. And while there were folks who weren’t happy, the majority of the community saw this positively and seemed bullish on us!
At this point, the hard work was done. We were hoping that everything keeps going smoothly. And then, Evan’s tweet on Ghost Boy went viral and the floor just went lava on OpenSea.
This concludes our story so far. Now you are up-to speed with where we are today! To-date 150+ ETH have been traded with Blockalizer which gave us the #4 spot on trending. Obviously there is a lot more to the story. How the Twitter crowd found us without us sharing anything about the project! How we hunkered down at a WeWork location and stole meeting rooms! And how Evan’s flight delay allowed him to make timely tweets to calm down the angry mob!
It’s been a wild journey so far. But we are just getting started. Stay tuned to keep updated with our journey!
Very interesting stuff, with the emotion coming through in the writing! I look forward to your future presentations!💓