Summoning the Elfiverse: A Technical Overview

Only a few months ago, the Elfiverse was summoned - a fun way for Element community members to visualize their identity with NFTs.

Many lessons were learnt while building Elfiverse! This article will walk through a full technical breakdown of the process, including each individual component and the thinking behind these design choices.

Smart Contracts

NFTs have gone through a lot of changes over the past year with many variations of the ERC-721 standard, each varying in complexity and design goals. The goal with the Elfiverse architecture was to emulate other successful recent projects and allow the project to continue to evolve after the launch.

Throughout the ideation process, inspiration was taken from Crypto Coven and Azuki, which were notorious for their staged minting process and gas efficient contracts. While alluring at first, the special features weren't really needed for this project.

That means no batch minting, auctioning mechanisms or other components for launch. Including these features would just increase complexity, testing time, and gas costs.

NFT Contract

The elegant Solmate’s ERC-721 contract was used as the starting point.

This contract is a minimal implementation of the ERC-721 standard and hyper optimized for gas cost. Reducing gas cost was a primary goal of this project since it was a free mint, and removing this barrier would allow more community members to be involved within the DAO.

Thankfully, Solmate’s best practices did much of the heavy lifting, giving us a total mint cost under $10 at the time of minting.

Let’s dive into the gas optimizations of Solmate’s NFT contract!

Gas Optimizations

Let’s break this up into three sections: 

  • Minimize On-Chain Storage with Events for Non-Critical Data
  • Unchecked Arithmetic
  • Short Circuit Evaluation

Minimize On-Chain Storage with Events for Non-Critical Data

A general best practice of smart contract development is to minimize the amount of data that needs to be stored on-chain. A contract only needs the minimum amount of data to perform internal logic and accounting, while some public methods can be computed off-chain. 

What does this mean?

Let’s take the example of wanting to know what token IDs a specific account owns. This is straightforward right? You just have to check the ownerOf mapping for each tokenId, but how would you figure out which token IDs to check?

A naive solution could be to create another data structure that maps an account to an array of tokenId’s they own. 

This method solves the problem but also uses a lot of on-chain storage. Another way around this is to reconstruct this data using transfer events. Each time an NFT is minted or transferred you get a new transfer event. You can search all events to and from a specific address and reconcile the current state of ownership. 

Reconciling transfer events
Reconciling transfer events

For example, think of going through N-transfer events and removing/adding IDs to a set whether the token was transferred in/out! Minimal changes to the data structure of Solmate’s base contract were made, thus the mint cost stayed really low.

Unchecked Arithmetic

Unchecked arithmetic is used widely in this smart contract. It allows modification of certain integer values without checking for overflows or underflows, which costs gas. 

In the case of this project, the mint ceiling was 10k, so it’s impossible for a uint256 value to overflow when doing simple incremental arithmetic. 

This should be a general practice for NFT projects as uint256’s ceiling is about the number of atoms in the universe. So unless you want every atom to have a spot on your whitelist, then using unchecked won’t cause any issues.

Proper judgment should be taken before implementing unchecked arithmetic in other use cases, as certain side effects and assumptions may break.

Mint function unchecked arithmetic
Mint function unchecked arithmetic

Short Circuit Evaluation

Another way to reduce gas is to simply reduce the runtime of your code. A first principle of programming is to use evaluation strategies such as short circuiting. Short circuiting means constructing boolean expressions in an optimal way such that an expression can be evaluated without computing the entire expression. 

For example, if you had a boolean expression that evaluates to true || false, you only need the value of the first truthy expression since this is an OR statement, the latter doesn’t need to be evaluated since the expression will always be true. 

This model can be used in Solidity as featured below:

In the safeMint function you can check if the recipient address is a contract by checking its code length. If the recipient address does not have any code, then it can be assumed the address is an EOA and can accept NFTs, the further expression does not even need to be evaluated.

safeMint function with short circuit evaluation
safeMint function with short circuit evaluation

Minter Contract

There was another contract, called the Minter contract, which verifies a Merkle proof and mints a new NFT on a signer's behalf. This logic was kept outside of the NFT contract to preserve the standard which has been audited.

Merkle trees can be used to optimize on-chain whitelisting paradigms. Instead of having to store every eligible address on-chain, you can just store the Merkle root. Minters then provide a merkle proof attesting they are included in the set of eligible addresses.

This setup yields major gas savings and preserves privacy until the time of mint! This article is a great read for more on how Merkle trees can be used for NFT whitelisting.

Fortunately, there are great packages for creating / verifying merkle trees. The popular merkletreejs was used to generate the Merkle tree and OpenZepplin’s MerkleProof library for proof verification.

Open source

User Interface

User Interface: Entrance to the Elfiverse
User Interface: Entrance to the Elfiverse

Overview

The purpose of the interface was to inform users while letting them mint and view their Elfi NFT. These three goals are crucial for designing and building a great user experience. 

Following the footsteps of most web3 projects React was used, specifically the NextJS framework. NextJS lets developers hit the ground running, providing testing previews and content delivery when used with Vercel.

A couple of packages were relied on for building the app:

  • useWeb3React: Popular hooks library for web3. This library allows you to connect and interact with different wallets providers.
  • Styled-components: A CSS styling library that lets you write CSS as components. Any CSS library will work well here - Tailwind is used in other Element projects.
  • React-query-type chain: A combination of React Query and Typechain that provides developers with react-query hooks that interface with typechain read and write operations. This allows you to have type safe interactions with contracts abis, all wrapped together in a stale-while-revalidate compliant hook!

Features

Minting

The minting process in action
The minting process in action
Minting process for the Elfiverse
Minting process for the Elfiverse

The minting UX flow was by far the most challenging to develop. During launch many users will rush to your site and there are many reasons why someone cannot mint.

This leads to a lot of edge cases, so it’s important to not only build out a linear minting flow, but one that accounts for all reasonable possibilities and leads the user as to why.

The Collection

Viewing your NFTs on the collection page
Viewing your NFTs on the collection page

There is a page called the Collection, which is a way to view your NFTs and get some high level information about the project. The process of getting the minting data was interesting because this data is not stored on-chain, but is derived from events. 

A mint transaction emits a transfer event in the smart contract. With this, you can fetch the event information from the provider and transform it to time series format. The fetching process can happen on the client side, but this will put unnecessary pressure on the provider. 

A better solution is to cache this minting data since it’s client agnostic and build it into our app’s bundle. How was this done? NextJS’s getStaticProps feature was leveraged to act as a caching layer. So instead of each client fetching the same data, this data was cached on the server which updates every 60 seconds. This not only reduces the load on the provider but speeds up the rendering process dramatically.

Formation Library

Breakdown of each attribute within the Formation library
Breakdown of each attribute within the Formation library

The Formation library lets you view each attribute or layer used to compose each Elfi in the collection. A custom component based on react-slick was used for the carousels!

Storage

On-chain storage is expensive, everyone knows this. It’s good practice for smart contracts to store as little data as possible for lower gas consumption. 

Data that is omitted from the contract but still needed for a successful transaction has to be stored somewhere. A low-effort option is to use a web2 database. A simple key/value database was used between an address and Merkle proof.

Traditional databases are cheap and great, but have the same pitfalls of any centralized resource. Decentralized storage solutions have improved substantially throughout the years, IPFS being a prime example. 

That’s why it was decided that all the metadata and images should be uploaded to IPFS and have the contract reference this data as the source of truth for the project. 

The IPFS content identifier is immutable, much like a smart contract, so the data behind every NFT in this collection cannot be forged or changed.

A pinning service, Pinata, was helpful to make sure there is always a provider and not rely on altruism for the project’s data availability needs.

Governance

Most NFT projects either have a primitive governance system or none at all. It’s common for projects to solely rely on a central authority. This is partially why most NFT projects fail, because the community has little control of the ownership of the project.

The Elfiverse is built different.

This project is owned by the Element DAO which uses the Council governance protocol. Council provides several great features, including the ability to define any use case to be assigned voting power.

Because of the natural flexibility built into the Council protocol, you can create a voting vault that gives NFTs voting power or even create a subDAO. 

The combination of governance and NFTs hasn’t been explored in depth yet. The possibilities are endless. You can read more about the Council protocol in this post.

Open Source

The Elfiverse is completely open source so check it out today!

Subscribe to DELV (formerly Element Finance)
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.