Ethereum Development Walkthrough (Part 4: Tokens and ERCs)

5,496 reads

From a developer point of view, tokens on Ethereum are simply smart contracts. In the world of drinks, they could be coffee, and anyone could make their own variant.

You’ve probably heard of ERC20, ERC721, or other standards. These are simply a set of basic functions that the community of developers agreed to adopt. Nobody will stop you from using your own functions, and creating a script that will manage virtual coins however you like.

A famous quote from Pirates of the Caribbean apply very well in this case:

But following a standard has a lot of advantages that you should not overlook. First of all, when you make a token that comply with a standard, everybody will know what your token does and how to interact with it, and therefore, will trust it a bit more. DApps, like Mist, will recognize it as a token, and will show it with a special UI. Also, you’ll find a generic implementation of the token smart contract already written by the community, in a framework like OpenZeppelin’s for example, that is well tested by many experts, and gives you a solid starting point.

In this tutorial, we will write a basic and incomplete ERC20 token from grounds up, then we will turn it into an ERC721 (which is fundamentally different) so we can see the differences between the two.

The reason for that is, you will understand how a token works, that it is not a closed black box, and that the ERC20, an accepted standard that has been in work for two years so far, has failure-points that you’ll not see if you are only running a couple commands to create your token instantly from a framework.

Let’s make our token

The ERC20 was created to standardize fungible tokens so they can be re-used by other applications: from wallets to decentralized exchanges.

Fungible means that it can be interchanged with a token of the same type, in other words, all the tokens are identical (like money, a dollar is the same as any other dollar). A non-fungible token would be one that represents a unique asset (like a house, a property, a piece of art etc.). While a fungible token hold value in itself, a non-fungible token is just the representation of an asset in a smart contract.

To make an ERC20 compliant token, we must implement the following functions and events:

The standard doesn’t provide the body of these functions, that’s because you could write them however you like, and it’s well within the standard to return null/false values if you don’t want to support some functions.

Note: In this tutorial, it’s not interesting to copy the code, you’ll benefit more from understanding what happens, full examples will be linked at the end of this tutorial anyway.

Implementation

At first, we would want to give our token a name, so we will use a public variable:

Then give it a symbol:

And of course the number of decimals:

Since Solidity doesn’t fully support fixed-point numbers, you have to represent all numbers like integers. Now, a value of “123456”, will be either “1234.56” tokens when you use 2 decimals, or “12.3456” if you use 4 decimals for example. A value of 0 decimals is when you don’t want you token to be “divisible”. Ether, the cryptocurrency of Ethereum, uses 18 decimals.

Generally, you wouldn’t use more than 18 decimals for your token, unless you want an expert from the other side of the world to tell you how stupid you are, and ask you why would you use more than 18 decimals, and tell you how 18 is the holy number because Ether uses 18 decimals.

We will count the total supply of our token, and keep track of how much tokens everyone has:

Of course you will start with 0 tokens, unless you generate some in the constructor of your token smart contract, like this for example:

The “totalSupply()” function is just a getter for the “totalSupply” variable:

Same for the “balanceOf()” function:

Now, the real magic happens in the “transfer()” function, it’s where an address can send tokens to another one

That’s really the core of an ERC20 token.

“approve()”, “transferFrom()”, and “allowance()” functions are part of what makes a token ERC20 compliant too, but they are vulnerable.

When an address “approve()” another one, the approved address could spend some tokens from the approving address balance on its behalf using the “transferFrom()” function. “allowance()” is just a getter function to see how much an address could “transferFrom()” from the balance of another address.

These functions actually represent security issues, because, when an address approve another one to spend X tokens, and for some reason decide to increase or decrease that amount to Y tokens, the approved address could quickly transfer the X tokens of the first allowance before the transaction to change the allowance is executed, and after it’s executed, the approved address could transfer the Y newly approved tokens again. I said in the last parts that there is no certainty when a transaction is mined, and miners can slightly tamper with when some transactions are executed.

Now, while some safer “transferFrom()” implementations were suggested to make the function more fail-proof (as outlined above, the standard is just a bunch of prototypes of functions and expected behavior, and it’s up to your to write the bodies) some other proposals are being discussed right now, because there are other shortcomings to the ERC20. Two of these propositions are the ERC223 and ERC777.

The motive behind the ERC223 proposal is to avoid sending tokens to the wrong addresses or contracts that doesn’t support using these tokens, because millions of dollars where lost due to that as outlined in the 223th Ethereum Request for Comments. The ERC777 tries to notify the receiving address of the token it will receive, among other things. The ERC777 proposal seems to have the most momentum in the community right now to replace the ERC20.

ERC721

Now, the ERC721 is fundamentally a different thing from the ERC20 and its family.

In ERC721, tokens are unique. The ERC721 was proposed a few months ago, and the implementation that has made it famous is CryptoKitties, a game where people collect virtual cats, and these cats are represented with non-fungible tokens inside the smart contract that runs the game.

Now, if we want to turn an ERC20 contract to an ERC721 one, we will need to see how the second keep track of the tokens.

In ERC20, every address has a balance of tokens. In an ERC721 contract, every address will have a list of its tokens:

Since Solidity has its limitations, and there is no “indexOf()” method for arrays, we have to keep track of a token in the owner array manually:

We could of course implement our own library that finds the index of an element, but taking into account possibly long running loops, it’s better to use a mapping.

And of course, to track tokens easily, we can add a mapping that shows the owner of each token:

That’s all the difference between how the two proposals manage tokens.

The “transfer()” functions inside an ERC721 contract will set a new owner for the token:

The code is longer, but it’s simply the necessary steps to move a token.

One point to not forget is, the ERC721 has also the “approve()” and “transferFrom()” methods, so inside our transfer function, we would have to add an other instruction inside our “transfer()” method, so an approved address for a token can no longer move the token once it has a new owner, something like the following one:

Minting

One thing that can apply to both ERC20 and ERC721 tokens is, we would probably want to generate more fungible tokens, or create a new non-fungible token, we would do that with a function generally named “Mint()”.

An example for such a function is the code below:

We create a new token with an arbitrary number. Depending on your use case, you would probably want to authorize only certain address(es) to be able to mint new tokens inside your contract.

An important thing to note here is, while the “mint()” function is not present on the interface of the standards, we added it, just like we can add other functions to enhance and add more functionalities to our token. For example, we could add a system of buying and selling tokens for an amount of ether, or a function to remove tokens that we don’t want anymore.

Metadata

Now, we said that non-fungible tokens represent an asset, so, in most cases, we would actually want to describe that asset. We could do using a string like the following:

See, the smart contract is a certification rather than something that contains an object. You can’t store a car inside a smart contract for example, but you could very well store its license plate, or some other legal identification.

One of the most used techniques right now, when it comes to virtual assets, is to use an IPFS hash as metadata. An IPFS hash is the address of a file stored on IPFS. To put it in simple words, IPFS is like a torrent version of HTTP. When a file is added on IPFS, it would become virtually always available on at least one of the computers that are connected to the IPFS network.

While the file is accessible on IPFS or a HTTP link for everyone to see, the “certification of ownership” is registered in a smart contract. This is really not programming, but a new application of non-fungible tokens. It has a name “Crypto-collectibles”, and it’s hot right now.

Now, back to our codes, the original discussion of the ERC721 proposal is a bit dead as of now, and the original poster hasn’t updated the thread in a while, so there is a new continuation of that discussion here. It’s called ERC841 and they changed the name of non-fungible tokens to “deeds”.

There is also another proposal, ERC821, that wishes to implement newer and better design patterns inspired by the ERC223 & ERC777 proposals. ERC821 and ERC841 seek to achieve the same goal, but with a slightly different approach, both are not perfected yet, and you can join the discussion around these two potential standards if you have a valuable input.

You can find example implementations of both ERC20 and ERC721 (that you should not use in production) on the Github repository for this part:

Alternatively, it will be a good idea to take a look at the OpenZepplin framework, they have excellent, (mostly) audited, and modular smart contracts (Of course, you should read the content of every contract before deciding which ones to use).

This conclude this fourth part of series. In the next one we will see how to create a DApp.

If you liked this tutorial, you can find me @dev_zl.

Bonus: ICOs & Crowdsales

Initial coin offerings (ICOs) are a bit outside of the development part of an Ethereum project, but in essence, they are just crowdfunding.

If a startup needs some funds, they create their own token, and sell some during a period of time, called a crowdsale or ICO.

Before smart contracts and the blockchain technology, startups would use a crowdfunding website to raise money, but those websites take generally a handsome fee in the process. Now, with an ICO, you cut the middleman and raise the money directly.

Right now, there are more scams than real projects raising money, so from an investor point of view, you should be wary where to put your money. From a developer point of view, a crowdsale is just a smart contract, that sells some tokens from a start to an ending date in exchange for ether. There is no standard way to achieve that, but you will find a good implementation on OpenZepplin’s repo for example. Alternatively, there is an easy tutorial on Ethereum’s website.

Tags