Description
The below is an old draft of the proposal. The up-to-date proposal can be found at https://eips.ethereum.org/EIPS/eip-223
Discussion should occur at https://ethereum-magicians.org/t/erc-223-token-standard/12894
ERC: 223
Title: Token standard
Author: Dexaran, dexaran@ethereumclassic.org
Status: Draft
Type: ERC
Created: 5-03.2017
Reference implementation: https://github.com/Dexaran/ERC223-token-standard
Abstract
The following describes standard functions a token contract and contract working with specified token can implement to prevent accidentally sends of tokens to contracts and make token transactions behave like ether transactions.
Motivation
Here is a description of the ERC20 token standard problem that is solved by ERC223:
ERC20 token standard is leading to money losses for end users. The main problem is lack of possibility to handle incoming ERC20 transactions, that were performed via transfer
function of ERC20 token.
If you send 100 ETH to a contract that is not intended to work with Ether, then it will reject a transaction and nothing bad will happen. If you will send 100 ERC20 tokens to a contract that is not intended to work with ERC20 tokens, then it will not reject tokens because it cant recognize an incoming transaction. As the result, your tokens will get stuck at the contracts balance.
How much ERC20 tokens are currently lost (27 Dec, 2017):
-
QTUM, $1,204,273 lost. watch on Etherscan
-
EOS, $1,015,131 lost. watch on Etherscan
-
GNT, $249,627 lost. watch on Etherscan
-
STORJ, $217,477 lost. watch on Etherscan
-
Tronix , $201,232 lost. watch on Etherscan
-
DGD, $151,826 lost. watch on Etherscan
-
OMG, $149,941 lost. watch on Etherscan
NOTE: These are only 8 token contracts that I know. Each Ethereum contract is a potential token trap for ERC20 tokens, thus, there are much more losses than I showed at this example.
Another disadvantages of ERC20 that ERC223 will solve:
- Lack of
transfer
handling possibility. - Loss of tokens.
- Token-transactions should match Ethereum ideology of uniformity. When a user wants to transfer tokens, he should always call
transfer
. It doesn't matter if the user is depositing to a contract or sending to an externally owned account.
Those will allow contracts to handle incoming token transactions and prevent accidentally sent tokens from being accepted by contracts (and stuck at contract's balance).
For example decentralized exchange will no more need to require users to call approve
then call deposit
(which is internally calling transferFrom
to withdraw approved tokens). Token transaction will automatically be handled at the exchange contract.
The most important here is a call of tokenReceived
when performing a transaction to a contract.
Specification
Token
Contracts that works with tokens
Methods
NOTE: An important point is that contract developers must implement tokenReceived
if they want their contracts to work with the specified tokens.
If the receiver does not implement the tokenReceived
function, consider the contract is not designed to work with tokens, then the transaction must fail and no tokens will be transferred. An analogy with an Ether transaction that is failing when trying to send Ether to a contract that did not implement function() payable
.
totalSupply
function totalSupply() constant returns (uint256 totalSupply)
Get the total token supply
name
function name() constant returns (string _name)
Get the name of token
symbol
function symbol() constant returns (bytes32 _symbol)
Get the symbol of token
decimals
function decimals() constant returns (uint8 _decimals)
Get decimals of token
standard
function standard() constant returns (string _standard)
Get the standard of token contract. For some services it is important to know how to treat this particular token. If token supports ERC223 standard then it must explicitly tell that it does.
This function MUST return "erc223" for this token standard. If no "standard()" function is implemented in the contract then the contract must be considered to be ERC20.
balanceOf
function balanceOf(address _owner) constant returns (uint256 balance)
Get the account balance of another account with address _owner
transfer(address, uint)
function transfer(address _to, uint _value) returns (bool)
Needed due to backwards compatibility reasons because of ERC20 transfer function doesn't have bytes
parameter. This function must transfer tokens and invoke the function tokenReceived(address, uint256, bytes calldata)
in _to
, if _to is a contract. If the tokenReceived
function is not implemented in _to
(receiver contract), then the transaction must fail and the transfer of tokens should be reverted.
transfer(address, uint, bytes)
function transfer(address _to, uint _value, bytes calldata _data) returns (bool)
function that is always called when someone wants to transfer tokens.
This function must transfer tokens and invoke the function tokenReceived (address, uint256, bytes)
in _to
, if _to is a contract. If the tokenReceived
function is not implemented in _to
(receiver contract), then the transaction must fail and the transfer of tokens should not occur.
If _to
is an externally owned address, then the transaction must be sent without trying to execute tokenReceived
in _to
.
_data
can be attached to this token transaction and it will stay in blockchain forever (requires more gas). _data
can be empty.
NOTE: The recommended way to check whether the _to
is a contract or an address is to assemble the code of _to
. If there is no code in _to
, then this is an externally owned address, otherwise it's a contract.
Events
Transfer
event Transfer(address indexed _from, address indexed _to, uint256 _value)
Triggered when tokens are transferred. Compatible with ERC20 Transfer
event.
TransferData
event TransferData(bytes _data)
Triggered when tokens are transferred and logs transaction metadata. This is implemented as a separate event to keep Transfer(address, address, uint256)
ERC20-compatible.
Contract to work with tokens
function tokenReceived(address _from, uint _value, bytes calldata _data)
A function for handling token transfers, which is called from the token contract, when a token holder sends tokens. _from
is the address of the sender of the token, _value
is the amount of incoming tokens, and _data
is attached data similar to msg.data
of Ether transactions. It works by analogy with the fallback function of Ether transactions and returns nothing.
NOTE: since solidity version 0.6.0+ there is a new reveive()
function to handle plain Ether transfers - therefore the function tokenFallback
was renamed to tokenReceived
to keep the token behavior more intuitive and compatible with Ether behavior.
NOTE: msg.sender
will be a token-contract inside the tokenReceived
function. It may be important to filter which tokens are sent (by token-contract address). The token sender (the person who initiated the token transaction) will be _from
inside the tokenReceived
function.
IMPORTANT: This function must be named tokenReceived
and take parameters address
, uint256
, bytes
to match the function signature 0xc0ee0b8a
.
Recommended implementation
This is highly recommended implementation of ERC 223 token: https://github.com/Dexaran/ERC223-token-standard/tree/development/token/ERC223