Intro to ERC-721: The CryptoKitty Token

Updated on: April 24th, 2020
This content has been Fact-Checked.
erc 721 and cryptokitties

Cryptokitties showed us that maybe creating ERC-721 compliant cryptocollectibles is the way to go forward when it comes to widespread mainstream adoption. In this guide, let’s look into what ERC-721 means and how it works.

Roughly around 10 months ago, everyone in the crypto space bumped into one of the strangest headlines ever.

Intro to ERC-721: The CryptoKitty Token

The idea of crypto kitties is very simple. You create your own digital cat on top of the Ethereum blockchain and then you can take care of them, breed them, auction them etc. People took to cryptokitties by the droves and soon enough, mainstream news publications started talking about cryptokitties and ethereum.

Creating Token Standards

According to Ethereum’s website, “Ethereum is a decentralized platform that runs smart contracts: applications that run exactly as programmed without any possibility of downtime, censorship, fraud or third-party interference. These apps run on a custom built blockchain, an enormously powerful shared global infrastructure that can move value around and represent the ownership of property.”

To put it simply, Ethereum is going to become a decentralized super-computer wherein anyone, anywhere can rent some computational power and create decentralized applications (Dapps) which can run on top of the Ethereum platform.

These Dapps are powered by smart contracts which are coded using the solidity programming language. These smart contracts are going to be self-executing with specific instructions written on its code which get executed when certain conditions are made.

There is another thing that needs to be accounted for when it comes to the functioning of these decentralized applications.

Dapps are funded by ICOs. ICOs or Initial Coin Offerings are the cryptocurrency version of the Initial Public Offerings or IPOs. However, when compared to IPOs, ICOs are a lot more entrepreneur-friendly. So, to keep it brief, when it comes to ICOs, the developers give out tokens in exchange for funds.

A token is a representation of something in its particular ecosystem. It could be value, stake, voting right, or anything. A token is not limited to one particular role; it can fulfill a lot of roles in its native ecosystem, such as:

  • Toll: A token can act as a gateway to the Dapp. Basically, in order to access the Dapp, you will need to hold the tokens.


  • Voting Rights: The tokens may also qualify the holders to have certain voting rights. Think of EOS, holding EOS tokens will allow you to vote for block producers.


  • Value Exchange: This is one of the more common roles of tokens within the ecosystem. Tokens can help create an internal economic system within the application.



  • Currency: Can be used as a store of value which can be used to conduct transactions both inside and outside the given ecosystem.

So, now we know the importance of tokens, however, all the ICOs in the early days were facing some serious obstacles.

Token Obstacles

In the early days, it seemed that each and every ICO token was trying to “reinvent the wheel” as far as the execution was concerned. Each one of those tokens had their own list of functions. Now, this led to a whole host of new problems.

To create a healthy ecosystem on top of Ethereum, it is absolutely essential that the Dapps built on top of it can interact with one another seamlessly. However, what will happen if we have two tokens, say Token Alpha and Token Beta, and both of them have different smart contract structures?

For the two tokens to interact, the developers will need to carefully study both their contracts and map out exactly how these tokens are going to work with each other.

Now, this doesn’t really bode well for scalability now, does it?

If there are 100 different tokens with 100 different contracts, then to narrow down on all the qualifications and conditions required to make sure that transfers can go through between all these tokens will need a humongous amount of complex calculations. This is not an ideal scenario at all.

Something needed to be done and on November 19, 2015, Fabian Vogelsteller came up with an ingenious solution.

According to Wikipedia, ERC-20 is a “list of rules that an Ethereum token has to implement, giving developers the ability to program how new tokens will function within the Ethereum ecosystem. The ERC-20 token standard became popular with crowdfunding companies working on initial coin offering (ICO) cases due to the simplicity of deployment, together with its potential for interoperability with other Ethereum token standards.”

To keep it simple, ERC-20 is a guide of rules and regulations that will help create a blueprint for Ethereum-based smart contracts to create their tokens. The “ERC” stands for “Ethereum Request for Comment”, while the number ’20’ is the number assigned to this request.

Let’s look into what builds the foundations of ERC20:

  • totalSupply
  • balanceOf
  • transfer
  • transferFrom
  • approve
  • allowance

Now, these are the rules and functions that the ERC20 tokens must mandatorily have. However, they can also have the following 3 optional characteristics.

  • Token Name
  • Symbol
  • Decimal (up to 18)

ERC-20 tokens are responsible for token standards of all the ICOs out there. However, since they are mainly used as a payment system, ERC-20 tokens must also have another feature….fungibility.

What is Fungibility?

Lack of fungibility is a big problem that cryptocurrencies need to solve.

According to Investopedia, “Fungibility is a good or asset’s interchangeability with other individual goods or assets of the same type.

So, what is fungible and what is non-fungible.

If you borrow 100 USD from your friend, and you return them another 100 dollar note, then it is perfectly fine. In fact, you can give your friend 2 50-dollar notes or even 10 10-dollar notes. It will be perfectly fine because dollars (or paper currencies in general) are, for the most part, fungible.

On the other hand, what about… a collectible material?

Eg. Suppose for some reason you took your friend’s Picasso painting for a day? Now, what will happen if, when you have to return it, you give her back some other Picasso painting? Even worse, what if instead of giving back the painting, you give back the painting in smaller pieces?

Either way, you will be lucky if she doesn’t eviscerate you.

Why is that the case?

Unlike currency, paintings, and any kind of collectibles, are non-fungible.

Currency actually gains more value by its fungibility. The more widely regarded and accepted a currency is, the more people will use it and hence more its perceived value will be.

This equation, however, completely changes when you replace currency with collectibles. A collectible gets its value only from its uniqueness and rarity.

Intro to ERC-721: The CryptoKitty Token

This 1952 baseball card of the legendary Mickey Mantle went for as much as $1.13 million in an auction. Now, would it have really gone for that much if there were like 100 other “Mickey Mantle 1952” cards available?

This right here is the core fundamental difference between ERC-20 and ERC-721.


The ERC-721 token standard helps create non-fungible tokens. In many ways, it is pretty similar to ERC-20 in functionality. This similarity exists for two reasons:

  • Firstly, it is easier for developers to make the transition. Since all ethereum developers are familiar with ERC-20 already, they won’t have to learn a host of new things
  • It makes life much easier for users who can store these tokens in ordinary wallets and trade them on exchanges.

ERC-721 gains its non-fungible properties by capturing the ownership of that particular token. This is why takeOwnership functions are included in the ERC-721 standard.

ERC-721 Functions

The ERC-721 standard defines the following functions: name, symbol, totalSupply, balanceOf, ownerOf, approve, takeOwnership, transfer, tokenOfOwnerByIndex, and tokenMetadata. It also defines two events: Transfer and Approval.

Before we go into individual function discussions, you must know what we mean by the Token Ownership and Token Creation of the ERC-721 functions

Token Ownership

When you buy ERC-20 tokens, your rights of ownership will be written in the smart contracts. The smart contract also has data of how much tokens each and every address will have after the deal…and that’s it. The thing is that these contracts don’t need to worry about specific tokens because they are fungible, so they are all the same.

However, the value of one ERC-721 token is not the same as another ERC-721 token because of its non-fungibility. Adding an address and balance to the contract won’t be enough, a token’s unique ownership details also need to be added.

Token Creation

Token Creation in ERC-20 tokens is about the balance of tokens. So, all that you need to do is to set an upper limit and make sure that people cannot create more tokens than the upper limit. When compared to that, ERC-721 token creation is much more complicated. The ERC-721 standard maintains an array of tokens and each and every single token is added to the array separately.

The contract is defined like this:


contract ERC721 {

// ERC20 compatible functions

function name() constant returns (string name);

function symbol() constant returns (string symbol);

function totalSupply() constant returns (uint256 totalSupply);

function balanceOf(address _owner) constant returns (uint balance);

// Functions that define ownership

function ownerOf(uint256 _tokenId) constant returns (address owner);

function approve(address _to, uint256 _tokenId);

function takeOwnership(uint256 _tokenId);

function transfer(address _to, uint256 _tokenId);

function tokenOfOwnerByIndex(address _owner, uint256 _index) constant returns (uint tokenId);

// Token metadata

function tokenMetadata(uint256 _tokenId) constant returns (string infoUrl);

// Events

event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);

event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);


Now let’s look into each of these functions. Shoutout to Gerald Nash for the data.

#1 name()

This function is used to define the name of the token to outside contracts and applications. Lets see how this works.

contract Blockgeeks {

 function name() constant returns (string name){

   return "Read Blockgeeks";



#2 symbol()

The symbol() function helps with token identification, by creating its shorthand and symbol. The function also provides compatibility with the ERC20 token standard.

contract Blockgeeks {

 function symbol() constant returns (string symbol) {

   return "BG";



#3 totalSupply()

The totalSupply() function defines the total number of the tokens available in the contract and it also returns the total number of coins available on the blockchain. The supply does not have to be constant.

contract Blockgeeks {

 // This can be an arbitrary number

 uint256 private totalSupply = 1000000000;

 function totalSupply() constant returns (uint256 supply) {

   return totalSupply;



#4 balanceOf()

This function is used to find the number of tokens that a given address owns.

contract Blockgeeks {

 mapping(address => uint) private balances;

 function balanceOf(address _owner) constant returns (uint balance)


   return balances[_owner];



Ownership Functions

Now we come to the ownership functions of the ERC-721 tokens. The two particular areas where ERC-721 tokens show their unique quality is ownership and creation. Let’s look into both these areas and how both ERC-20 and ERC-721 do in those categories.

The ownership functions are as follows:

  • ownerOf()
  • approve()
  • takeOwnership()
  • transfer()
  • tokenOfOwnerByIndex()

#1 ownerOf()

The purpose of this function is to return the address of the token owner. Since each and every ERC721 token is non-fungible and unique, it’s referenced on the blockchain via its unique ID.

One can easily determine the token owner by using the ID.

contract Blockgeeks {

 mapping(uint256 => address) private tokenOwners;

 mapping(uint256 => bool) private tokenExists;

 function ownerOf(uint256 _tokenId)

 constant returns (address owner) {


   return tokenOwners[_tokenId];



#2 approve()

This function approves, or grants, another entity permission to transfer a token on the owner’s behalf.

Let’s understand this with an example.

If Alice owns 1 BG then she can call the approve function for her friend Bob. When that call is successful, Bob will take full ownership to perform operations on the token at a later time on Alice’s behalf.

contract Blockgeeks {

 mapping(address => mapping (address => uint256)) allowed;

 function approve(address _to, uint256 _tokenId){

   require(msg.sender == ownerOf(_tokenId));

   require(msg.sender != _to);

   allowed[msg.sender][_to] = _tokenId;

   Approval(msg.sender, _to, _tokenId);



#3 takeOwnership()

The idea of the takeOwnership() function is to act like a withdraw function. An outside party can call it in order to take tokens out of another user’s account. So, if Alice allows Bob to own a certain amount of tokens and wishes him to withdraw said tokens from another user’s balance, she will use the takeOwnership() function.

contract Blockgeeks {

 function takeOwnership(uint256 _tokenId){


   address oldOwner = ownerOf(_tokenId);

   address newOwner = msg.sender;

   require(newOwner != oldOwner);

   require(allowed[oldOwner][newOwner] == _tokenId);

   balances[oldOwner] -= 1;

   tokenOwners[_tokenId] = newOwner;

   balances[newOwner] += 1;

   Transfer(oldOwner, newOwner, _tokenId);




#4 transfer()

The transfer() function is another method used for transferring tokens. It allows the owner of the token to send it to another user, similar to a standalone cryptocurrency. This transfer can only be initiated if the receiving account has previously been approved to own the token by the sending account.

contract Blockgeeks {

 mapping(address => mapping(uint256 => uint256)) private ownerTokens;

 function removeFromTokenList(address owner, uint256 _tokenId) private {

   for(uint256 i = 0;ownerTokens[owner][i] != _tokenId;i++){

     ownerTokens[owner][i] = 0;



 function transfer(address _to, uint256 _tokenId){

   address currentOwner = msg.sender;

   address newOwner = _to;


   require(currentOwner == ownerOf(_tokenId));

   require(currentOwner != newOwner);

   require(newOwner != address(0));


   balances[oldOwner] -= 1;

   tokenOwners[_tokenId] = newOwner;

   balances[newOwner] += 1;

   Transfer(oldOwner, newOwner, _tokenId);



#5 tokenOfOwnerByIndex() [Optional]

Each non-fungible token owner can own more than one token at one time. Like we have said, each and every token is referenced by its unique ID, so it can be really difficult for each user to keep track of the individual tokens that they may own.

To streamline this process and make it a whole lot simpler, the contract keeps a record of the IDs of each token that each user owns. Because of this, each individual token owned by a user can be retrieved by its index in the list (array) of tokens owned by the user.

The tokenOfOwnerByIndex function allows us to retrieve a token in this method.

contract Blockgeeks {

 mapping(address => mapping(uint256 => uint256)) private ownerTokens;

 function tokenOfOwnerByIndex(address _owner, uint256 _index) constant returns (uint tokenId){

   return ownerTokens[_owner][_index];




Metadata is a set of data which gives more character and personality to the main data. Metadata serves many important purposes like data description, data browsing, data transfer, metadata has an important role in digital resource management. Metadata plays a key role in digital information system.

In ERC-721, the tokenMetada() function helps in defining the token’s metadata.


contract Blockgeeks {

 mapping(uint256 => string) tokenLinks;

 function tokenMetadata(uint256 _tokenId) constant returns (string infoUrl) {

   return tokenLinks[_tokenId];




Events are fired whenever a contract calls them, and they’re broadcasted to any listening programs once they’ve been fired.

Programs outside the contract listen in to the events so that they can execute the code within it as soon as it is fired. The ERC-721 standard deals with two events:

  • Transfer()
  • Approval()

#1 Transfer

Whenever a token changes hands, this event is fired. Every single time a token’s ownership moves from one person to another, this event is fired away. It details the following:

  • Which account sent the token
  • Which account received the token
  • Which token was transferred (by ID checking)
<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%">contract Blockgeeks {

 event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);




#2 Approval

This second event is fired whenever a user allows another user to take ownership of a particular token. The event details which account has been currently owning the token and which account is getting the permission to own it in the future. It also checks the token ID to know which particular token has been approved to have its ownership transferred.

contract Blockgeeks {

 event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);


ERC-271 and the Future

Cryptokitties at its peak became well and truly viral. In fact, at one point it was the third most gas hungry contract on Ethereum.

Intro to ERC-721: The CryptoKitty Token

However, it became too popular for its own good. Before long, it completely clogged up the Ethereum network, which was simply not ready to handle the enormous demand

Intro to ERC-721: The CryptoKitty Token

Things became so bad that Axiom aka the company behind cryptokitties was forced to increase their birthing fees. This is what they said in their medium article:

The excitement and adoption we’ve seen this week has been overwhelming and we couldn’t be happier! However, the Ethereum network is completely full. The only way to keep CryptoKitties from lagging is to increase the gas prices so that all transactions can complete quickly. We know that increased prices will mean that some of you will need to slow down your breeding regimen, and we are incredibly disappointed by that. But who knows? Maybe this slowdown will just mean that you’ll love the Kitties you already have that much more.

We learned two invaluable lessons from this whole episode:

  • Ethereum isn’t ready for large-scale Dapps (yet)
  • There is a huge demand for crypto collectibles.

Let’s expand on the second point.

Mainstream Adoption via ERC-721

Let’s not forget that Cryptokitties, one of the most successful Dapps of all time, wasn’t fixing any problems in the ecosystem, and nor was it bringing revolutionary utility into the system. It is a simple recreational Dapp which allowed users to grow and breed their own kitties.

Maybe, this where the true path to mainstream adoption lies.

History has taught us that people have repeatedly embraced and adopted a new technology via a vehicle which may not have been the intended target (of those technologies) in the first place.

Let’s take a pretty relevant example.

Jeff Bezos, the richest man in the world, has a net worth which exceeds $150 billion. He has made his riches by establishing Amazon, easily the biggest e-commerce website in the world.

The gaming console marketplace is worth $50 billion and Sony’s Playstation owns 53% of the market share. The PlayStation famously makes the use of Blu Ray discs.

The sheer popularity of Amazon and PS4 is all due to its ridiculous mainstream adoption.

However, can you guess what made e-commerce and Blu Ray widely accepted in the first place?

The pornography industry.

Seriously. Look it up.

We are pretty sure that the pornography industry wasn’t the intended market of e-commerce and Blu Ray when they both started out.

ERC721 – Conclusion

erc 721 and cryptokitties

ERC-721 collectibles have shown us a proven way to gain mainstream crypto adoption. There is, however, a lot of work that needs to be done before we can do that. Having said that, the idea of creating non-fungible collectibles on the blockchain has a lot of promise and it is going to become more and more sophisticated over time.


Like what you read? Give us one like or share it to your friends and get +16

newest oldest most voted

Thanks for this post. I must again say please remove this always popped up “having a question? ask our community”.
Please correct me if I’m wrong anywhere in my comment, It’s still a little confusing and I’ve even read the document in but not yet clear! And after reading the github I understand that this post is old, because I couldn’t see the any different between “takeownership” and “transferfrom” and there isn’t “takeownership” in github.
So as I understand what differentiate it with ERC20 is the “token_ID” and so owning it and the “Metadata”, but I couldn’t see any “Metadata” function in github.
And as a general question (that I’ve even had in ERC20), are mapping variables in the first lines of contract such as “_tokenOwner” already filled by looking up at ethereum blockchain and contract address?
Again, thanks for your attention.

Felix Amesimeku

Will be a nice if it was brought more to light

Felix Amesimeku what part is still unclear for you?

Hungry for knowledge?
New guides and courses each week
Looking to invest?
Market data, analysis, and reports
Just curious?
A community of blockchain experts to help

Get started today

Already have an account? Sign In