NFTs, literally
There were $25 billion of NFT sales in 2021.
But what are people paying for? What does the code actually say?
I wanted to know so I did an investigation and I’m here to report that it’s shockingly simple to understand. The fundamentals are easy. That said, there are major complexities with security and more advanced programs beyond the scope of my detail.
So, here we are with a non-technical person’s guide to NFT contracts on Ethereum.
An NFT is software code on the blockchain network. To create an NFT, a developer adds software code to be run by the network computers. It is written in a certain way that enables it to represent a “token.” The fundamental tasks the token software does are:
Define the asset (name, associated data, image, etc.)
Define who owns the asset
Define the set of possible ways to interact with the assets like:
Mint
Transfer
Assign metadata (e.g. images)
Query ownership
OpenZeppelin says it another way:
A token contract is simply an Ethereum smart contract. "Sending tokens" actually means "calling a method on a smart contract that someone wrote and deployed". At the end of the day, a token contract is not much more than a mapping of addresses to balances, plus some methods to add and subtract from those balances.
Warning: I’m going to show you some code. I promise it’s not scary and will help make this all feel more real. We’ll walk through ownership, creating, and transferring a token.
There are two primary types of tokens: fungible and non-fungible. Fungible means inter-changeable (e.g. a dollar). Non-fungible means unique (e.g. deed to a house). The software code is different for these types of tokens. The core difference is in the mapping of owners to assets. A mapping is just like creating a spreadsheet.
For fungible tokens, the ownership mapping table is called _balances and maps owners to a token balance, like this table with mock data:
This is the code:
unit256 is a variable type for integer.
In contrast, for non-fungible tokens, the ownership mapping is called _owners and maps tokenID to the owner. This is important because each token is unique. It looks like this with mock data:
Below is the code for this
tokenID is an integer.
This design difference influences how all interactions are executed.
To mint a fungible token, the contract simply increments the supply and updates the balance of the receiving party. They key code is:
_totalSupply += amount
|| This adds the amount to the total supply
_balances[account] += amount
|| This searches the _balances table from before for the account number (i.e. address), then adds the amount to that balance column.
To create a non-fungible token adds a new step. First is appending a row to the _owners table mentioned before and assigning an owner.
_owners[tokenID] = to
|| the “to” is defined as the address of the new token owner, and it’s assigned in the table to that tokenID.
The new step is defining the unique data for the NFT (e.g. image). For this, there is another mapping table between token and the data. This table would also have a row appended with the new token. It would look like this:
URI means universal resource identifier which is essentially the same thing as URL, it’s an address to find something.
If you’re still with me, this last section on transfers will be easy.
For fungible tokens, transfer means simply to decrease balance of “from” address and increase balance of “to” address.
_balances[from] = fromBalance – amount
_balances[to] += amount
For non-fungible tokens, a transfer means simply updating the _owners table with the new owner.
_owners[tokenID] = to
And to make it easy, there are widely-used templates for this software: ERC20 is for fungible token and ERC721 is for non-fungible. The template is like a recipe that developer can use as a foundation, and add their own unique flavor on top.
That’s it!