DAICO Open-source Framework, Part 3: DaicovoStandardToken.sol

DAICO Open-source Framework, Part 3: DaicovoStandardToken.sol

In part 1, we explained the structure of DAICOVO. And in part 2, we talked about the deployment and operation flow. In this part 3 of the series, we will look at the most basic contract: the token contract.

Requirements of a Token

We have DaicovoStandardToken contract as a template of a token contract. This contract is ERC20 compatible token with some extended features from ERC223. You can either use this template to issue tokens or use other types of tokens to start your ICOs with the DAICOVO. However, keep in mind that your token needs to meet requirements below.

 

ERC20 Interface

Mintable Interface

Ownable Interface

 

In the DAICOVO, tokens are issued(minted) through the TokenControllermint(address _to, uint256 _amount) function will be called from theTokenController. As only the owner of the contract can call mint, you need to transfer the ownership to the TokenController.

Structure of DaicovoStandardToken

The DaicovoStandardToken is the ERC20 compatible token contract template. We also borrowed some functions from the ERC223 token standard that eliminates the problem of lost tokens. On top of that, there are other functions and variables for flexibility. They also help us to solve known issues. You can see the members of the DaicovoStandardToken contract below.

 

We won’t mention members in ERC20 in this post. You can find more than enough articles about this standard online.

*The DaicovoStandardToken contract is based on the code from ERC20 compatible contract in OpenZeppelin and ERC223 compatible contract from Dexaran. Both of them are OSS under the MIT license.

Problems with ERC20

The problem with ERC20 is that tokens will be lost forever when ERC20 tokens are transferred to a contract address. This is why we borrowed some functions from ERC223 in the DaicovoStandardToken.

 

When you send ERC20 tokens in your balance, you use the transfer()function. If the recipient were an EOA(Externaly Owned Account), they will know that they receive tokens because humans are in control.

 

However, a contract cannot notice that they have received tokens because it doesn’t check transactions autonomously. They do not even have the system to sync with the transfer() function and execute the function in the contract. Unless the contract has the function to pull tokens out, the tokens will be locked up in the contract for good.

 

Billions of dollars’ worth of tokens have been lost due to this flaw in ERC20.

 

We can imagine that this happens often when somebody uses the contract that takes some actions by receiving tokens. Let’s say you have ContractC with the function that exchanges ten TokenA with one TokenB. If UserX uses thetransfer() function to send ten TokenA to the ContractC, the tokens will be locked up because the ContractC has no way of knowing that it has received the tokens. Here is a proper way to send the tokens:

  1. UserX gives permission to ContractC to spend on behalf of her with the approve() function in TokenA.
  2. The UserX calls the function in the ContractC that exchanges ten TokenA with one TokenB. The ContractC spends ten TokenA on behalf of UserX with thetransferFrom()function in TokenA. This is only possible because the ContractC was given the permission with theapprove()function.

A lot of people didn’t know that these two transactions were required, and they ended up using only thetransfer()function to send their tokens.

How ERC223 Works

ERC223 was proposed to solve the issue of lost tokens (But beware that this proposal is not officially accepted as the EIP yet.) .

Here is how the ERC223 works:

  1. When transfer(), check if the recipient of the token is an EOA or a contract
  2. a. transfer() in case it is an EOA.
    b. Invoke the tokenFallback() function if the recipient were a contract.
  3. a. The token transfer fails if the contract does not implement the tokenFallback() function or the fallback function to receive funds.
    b. If the contract does implement the tokenFallback() function, proceed to receive tokens.

This is a proposed implementation below:

 

As you can see, the transfer() function in ERC223 send tokens only when 1) the recipient is an EOA or 2) the recipient is a contract that supports token receiving and handling.

 

This assembly code is checking if the recipient of the token is an EOA or a contract by retrieving the size of the code on a specific address. If the size were zero, the address is an EOA. If the size were larger than zero, the address is a contract.

 

ERC223 Interface

The ERC223 doesn’t have any approve related functions below.

 

 

This is because we don’t need the two steps that are required to send ERC20 tokens as I mentioned previously. We should note that ERC223 doesn’t have upward compatibility with ERC20 because these function has other usages.

 

*For example, you can give permission to your another address so that it can spend on behalf of you in case you lose your private key.

transfer(address _to, uint _value, bytes _data) is the new function with three arguments in ERC223. You can use either this function or transfer(address _to, uint _value) function from ERC20 to send tokens.

 

The third argument bytes _data in transfer(address _to, uint _value, bytes _data) can be attached to the tokenFallback() function and then will be handled on a receiver contract. Since byte data is not fixed length, you need to encode all the argument data and bundle them as one argument.

 

I’d say this function is not usable because 1) users need to encode the data by following the specifics of contracts and 2) contracts need to have the logic to decode(there is no helpful library for this).

DaicovoStandardToken

The DaicovoStandardToken replaces the transfer() function among the members of ERC20 with the one in ERC223. However, unlike ERC223, we still have approve related functions, and all the other interfaces are compatible with ERC20(ERC223 has some other different interfaces with ERC20).

 

On top of that, we have functions and variables below.

 

 

forceTransfer

forceTransfer() is the same function with the ERC20 transfer() function. It transfers tokens regardless of the recipients: either an EOA or a contract.

 

increaseApproval, decreaseApproval

increaseApproval() and decreaseApproval() are added as a solution to the problem associated with approve. We are taking the same approach with OpenZeppelin.

 

We don’t discuss the problem in detail in this post, but you can read more here. In a nutshell, tokens can be spent more than they should be because of double spending when the approve value has been changed.

 

approve() is the function that directly change the allowance value(give permission to another address so that it can spend a certain amount of tokens). Essentially, you can avoid the double spending by allowing approve() to change the value only by addition and subtraction.

 

name, symbol, decimals

You are probably familiar with these three variables. name is a name of a token. symbol is a token symbol. decimals is the number of decimal places. These variables are actually not defined officially in ERC20, but most of the ERC20 do have these. The DaicovoStandardToken has these variables by default considering this situation.

 

Again, as I mentioned at the beginning, this token template is what we recommend, but you don’t have to use it as long as you meet the requirements.

 

In the next post of this series, I will explain about TokenController contract that is in charge of token issuance.

 

Profile

Takuya Obata

Chief Operating Officer at ICOVO AG. And a blockchain engineer at the same time. He got MVP in Blockchain Hackathon Tokyo 2016. He is also experienced in natural language processing and chess like game programming.