├── token └── ERC223 │ ├── ERC223_interface.sol │ ├── ERC223_receiving_contract.sol │ └── ERC223_token.sol ├── LICENSE ├── SafeMath.sol └── README.md /token/ERC223/ERC223_interface.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | contract ERC223Interface { 4 | uint public totalSupply; 5 | function balanceOf(address who) constant returns (uint); 6 | function transfer(address to, uint value); 7 | function transfer(address to, uint value, bytes data); 8 | event Transfer(address indexed from, address indexed to, uint value, bytes data); 9 | } 10 | -------------------------------------------------------------------------------- /token/ERC223/ERC223_receiving_contract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | /** 4 | * @title Contract that will work with ERC223 tokens. 5 | */ 6 | 7 | contract ERC223ReceivingContract { 8 | /** 9 | * @dev Standard ERC223 function that will handle incoming token transfers. 10 | * 11 | * @param _from Token sender address. 12 | * @param _value Amount of tokens. 13 | * @param _data Transaction metadata. 14 | */ 15 | function tokenFallback(address _from, uint _value, bytes _data); 16 | } 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | /** 5 | * Math operations with safety checks 6 | */ 7 | library SafeMath { 8 | function mul(uint a, uint b) internal returns (uint) { 9 | uint c = a * b; 10 | assert(a == 0 || c / a == b); 11 | return c; 12 | } 13 | 14 | function div(uint a, uint b) internal returns (uint) { 15 | // assert(b > 0); // Solidity automatically throws when dividing by 0 16 | uint c = a / b; 17 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 18 | return c; 19 | } 20 | 21 | function sub(uint a, uint b) internal returns (uint) { 22 | assert(b <= a); 23 | return a - b; 24 | } 25 | 26 | function add(uint a, uint b) internal returns (uint) { 27 | uint c = a + b; 28 | assert(c >= a); 29 | return c; 30 | } 31 | 32 | function max64(uint64 a, uint64 b) internal constant returns (uint64) { 33 | return a >= b ? a : b; 34 | } 35 | 36 | function min64(uint64 a, uint64 b) internal constant returns (uint64) { 37 | return a < b ? a : b; 38 | } 39 | 40 | function max256(uint256 a, uint256 b) internal constant returns (uint256) { 41 | return a >= b ? a : b; 42 | } 43 | 44 | function min256(uint256 a, uint256 b) internal constant returns (uint256) { 45 | return a < b ? a : b; 46 | } 47 | 48 | function assert(bool assertion) internal { 49 | if (!assertion) { 50 | throw; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /token/ERC223/ERC223_token.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import './ERC223_interface.sol'; 4 | import './ERC223_receiving_contract.sol'; 5 | import '././SafeMath.sol'; 6 | 7 | /** 8 | * @title Reference implementation of the ERC223 standard token. 9 | */ 10 | contract ERC223Token is ERC223Interface { 11 | using SafeMath for uint; 12 | 13 | mapping(address => uint) balances; // List of user balances. 14 | 15 | /** 16 | * @dev Transfer the specified amount of tokens to the specified address. 17 | * Invokes the `tokenFallback` function if the recipient is a contract. 18 | * The token transfer fails if the recipient is a contract 19 | * but does not implement the `tokenFallback` function 20 | * or the fallback function to receive funds. 21 | * 22 | * @param _to Receiver address. 23 | * @param _value Amount of tokens that will be transferred. 24 | * @param _data Transaction metadata. 25 | */ 26 | function transfer(address _to, uint _value, bytes _data) { 27 | // Standard function transfer similar to ERC20 transfer with no _data . 28 | // Added due to backwards compatibility reasons . 29 | uint codeLength; 30 | 31 | assembly { 32 | // Retrieve the size of the code on target address, this needs assembly . 33 | codeLength := extcodesize(_to) 34 | } 35 | 36 | balances[msg.sender] = balances[msg.sender].sub(_value); 37 | balances[_to] = balances[_to].add(_value); 38 | if(codeLength>0) { 39 | ERC223ReceivingContract receiver = ERC223ReceivingContract(_to); 40 | receiver.tokenFallback(msg.sender, _value, _data); 41 | } 42 | Transfer(msg.sender, _to, _value, _data); 43 | } 44 | 45 | /** 46 | * @dev Transfer the specified amount of tokens to the specified address. 47 | * This function works the same with the previous one 48 | * but doesn't contain `_data` param. 49 | * Added due to backwards compatibility reasons. 50 | * 51 | * @param _to Receiver address. 52 | * @param _value Amount of tokens that will be transferred. 53 | */ 54 | function transfer(address _to, uint _value) { 55 | uint codeLength; 56 | bytes memory empty; 57 | 58 | assembly { 59 | // Retrieve the size of the code on target address, this needs assembly . 60 | codeLength := extcodesize(_to) 61 | } 62 | 63 | balances[msg.sender] = balances[msg.sender].sub(_value); 64 | balances[_to] = balances[_to].add(_value); 65 | if(codeLength>0) { 66 | ERC223ReceivingContract receiver = ERC223ReceivingContract(_to); 67 | receiver.tokenFallback(msg.sender, _value, empty); 68 | } 69 | Transfer(msg.sender, _to, _value, empty); 70 | } 71 | 72 | 73 | /** 74 | * @dev Returns balance of the `_owner`. 75 | * 76 | * @param _owner The address whose balance will be returned. 77 | * @return balance Balance of the `_owner`. 78 | */ 79 | function balanceOf(address _owner) constant returns (uint balance) { 80 | return balances[_owner]; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Implementation. 2 | 3 | ### Current implementation 4 | 5 | This repo's contracts are separated in 3 parts: 6 | 7 | - [Interface](https://github.com/Dexaran/ERC223-token-standard/blob/master/token/ERC223/ERC223_interface.sol): The standard itself. The minimal common API ERC223 tokens and receivers to interact with each other. 8 | - [Proposed implementations](https://github.com/Dexaran/ERC223-token-standard/blob/master/token/ERC223/ERC223_token.sol): A first approach as to how this could be implemented. 9 | - [Receiver interface](https://github.com/Dexaran/ERC223-token-standard/blob/master/token/ERC223/ERC223_receiving_contract.sol): A dummy receiver that is intended to accept ERC223 tokens. 10 | 11 | ### Minimal viable implementation of the token, ready for use. 12 | 13 | https://github.com/Dexaran/ERC223Token 14 | 15 | ## ERC223 token standard. 16 | 17 | ERC20 token standard suffers [critical problems](https://medium.com/@dexaran820/erc20-token-standard-critical-problems-3c10fd48657b), that caused loss of approximately $3,000,000 at the moment (31 Dec, 2017). The main and the most important is lack of event handling mechanism of ERC20 standard. 18 | 19 | ERC223 is a superset of the [ERC20](https://github.com/ethereum/EIPs/issues/20) token standard. It is a step forward towards economic abstraction at the application/contract level allowing the use of tokens as first class value transfer assets in smart contract development. It is also a more safe standard as it doesn't allow token transfers to contracts that don't support token receiving and handling. 20 | 21 | [See EIP discussion](https://github.com/ethereum/EIPs/issues/223) 22 | 23 | ```js 24 | contract ERC223 { 25 | function transfer(address to, uint value, bytes data) { 26 | uint codeLength; 27 | assembly { 28 | codeLength := extcodesize(_to) 29 | } 30 | balances[msg.sender] = balances[msg.sender].sub(_value); 31 | balances[_to] = balances[_to].add(_value); 32 | if(codeLength>0) { 33 | // Require proper transaction handling. 34 | ERC223Receiver receiver = ERC223Receiver(_to); 35 | receiver.tokenFallback(msg.sender, _value, _data); 36 | } 37 | } 38 | } 39 | ``` 40 | 41 | ### API 42 | 43 | ERC223 requires contract to implement the `ERC223Receiver` interface in order to receive tokens. If a user tries to send ERC223 tokens to a non-receiver contract the function will throw in the same way that it would if you sent ether to a contract without the called function being `payable`. 44 | 45 | An example of the high-level API for a receiver contract is: 46 | 47 | ```solidity 48 | contract ExampleReceiver is StandardReceiver { 49 | function foo() tokenPayable { 50 | LogTokenPayable(tkn.addr, tkn.sender, tkn.value); 51 | } 52 | 53 | function () tokenPayable { 54 | LogTokenPayable(tkn.addr, tkn.sender, tkn.value); 55 | } 56 | 57 | event LogTokenPayable(address token, address sender, uint value); 58 | } 59 | ``` 60 | 61 | Where functions that have the `tokenPayable` can only be called via a token fallback and inside the functions you have access to the `tkn` struct that tries to mimic the `msg` struct used for ether calls. 62 | 63 | The function `foo()` will be called when a user transfers ERC223 tokens to the receiver address. 64 | 65 | ```solidity 66 | // 0xc2985578 is the identifier for function foo. Sending it in the data parameter of a tx will result in the function being called. 67 | 68 | erc223.transfer(receiverAddress, 10, 0xc2985578) 69 | ``` 70 | 71 | What happens under the hood is that the ERC223 token will detect it is sending tokens to a contract address, and after setting the correct balances it will call the `tokenFallback` function on the receiver with the specified data. `StandardReceiver` will set the correct values for the `tkn` variables and then perform a `delegatecall` to itself with the specified data, this will result in the call to the desired function in the contract. 72 | 73 | The current `tkn` values are: 74 | 75 | - `tkn.sender` the original `msg.sender` to the token contract, the address originating the token transfer. 76 | - For user originated transfers sender will be equal to `tx.origin` 77 | - For contract originated transfers, `tx.origin` will be the user that made the transaction to that contract. 78 | 79 | - `tkn.origin` the origin address from whose balance the tokens are sent 80 | - For `transfer()`, it will be the same as `tkn.sender` 81 | - For `transferFrom()`, it will be the address that created the allowance in the token contract 82 | 83 | - `tkn.value` the amount of tokens sent 84 | - `tkn.data` arbitrary data sent with the token transfer. Simulates ether `tx.data`. 85 | - `tkn.sig` the first 4 bytes of `tx.data` that determine what function is called. 86 | 87 | ### The main goals of developing ERC223 token standard were: 88 | 1. Accidentally lost tokens inside contracts: there are two different ways to transfer ERC20 tokens depending on is the receiver address a contract or a wallet address. You should call `transfer` to send tokens to a wallet address or call `approve` on token contract then `transferFrom` on receiver contract to send tokens to contract. Accidentally call of `transfer` function to a contract address will cause a loss of tokens inside receiver contract. 89 | 2. Inability of handling incoming token transactions: ERC20 token transaction is a call of `transfer` function inside token contract. ERC20 token contract is not notifying receiver that transaction occurs. Also there is no way to handle incoming token transactions on contract and no way to reject any non-supported tokens. 90 | 3. ERC20 token transaction between wallet address and contract is a couple of two different transactions in fact: You should call `approve` on token contract and then call `transferFrom` on another contract when you want to deposit your tokens intor it. 91 | 4. Ether transactions and token transactions behave different: one of the goals of developing ERC223 was to make token transactions similar to Ether transactions to avoid users mistakes when transferring tokens and make interaction with token transactions easier for contract developers. 92 | 93 | ### ERC223 advantages. 94 | 1. Provides a possibility to avoid accidentally lost tokens inside contracts that are not designed to work with sent tokens. 95 | 2. Allows users to send their tokens anywhere with one function `transfer`. No difference between is the receiver a contract or not. No need to learn how token contract is working for regular user to send tokens. 96 | 3. Allows contract developers to handle incoming token transactions. 97 | 4. ERC223 `transfer` to contract consumes 2 times less gas than ERC20 `approve` and `transferFrom` at receiver contract. 98 | 5. Allows to deposit tokens intor contract with a single transaction. Prevents extra blockchain bloating. 99 | 6. Makes token transactions similar to Ether transactions. 100 | 101 | ERC23 tokens are backwards compatible with ERC20 tokens. It means that ERC223 supports every ERC20 functional and contracts or services working with ERC20 tokens will work with ERC23 tokens correctly. 102 | ERC23 tokens should be sent by calling `transfer` function on token contract with no difference is receiver a contract or a wallet address. If the receiver is a wallet ERC223 token transfer will be same to ERC20 transfer. If the receiver is a contract ERC223 token contract will try to call `tokenFallback` function on receiver contract. If there is no `tokenFallback` function on receiver contract transaction will fail. `tokenFallback` function is analogue of `fallback` function for Ether transactions. It can be used to handle incoming transactions. There is a way to attach `bytes _data` to token transaction similar to `_data` attached to Ether transactions. It will pass through token contract and will be handled by `tokenFallback` function on receiver contract. There is also a way to call `transfer` function on ERC223 token contract with no data argument or using ERC20 ABI with no data on `transfer` function. In this case `_data` will be empty bytes array. 103 | 104 | ### The reason of designing ERC223 token standard. 105 | Here is a description of the ERC20 token standard problem that is solved by ERC223: 106 | 107 | 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. 108 | 109 | 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. 110 | 111 | How much ERC20 tokens are currently lost (31 Dec, 2017): 112 | 113 | 1. QTUM, **$1,358,441** lost. [watch on Etherscan](https://etherscan.io/address/0x9a642d6b3368ddc662CA244bAdf32cDA716005BC) 114 | 115 | 2. EOS, **$1,015,131** lost. [watch on Etherscan](https://etherscan.io/address/0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0) 116 | 117 | 3. GNT, **$249,627** lost. [watch on Etherscan](https://etherscan.io/address/0xa74476443119A942dE498590Fe1f2454d7D4aC0d) 118 | 119 | 4. STORJ, **$217,477** lost. [watch on Etherscan](https://etherscan.io/address/0xe41d2489571d322189246dafa5ebde1f4699f498) 120 | 121 | 5. Tronix , **$201,232** lost. [watch on Etherscan](https://etherscan.io/address/0xf230b790e05390fc8295f4d3f60332c93bed42e2) 122 | 123 | 6. DGD, **$151,826** lost. [watch on Etherscan](https://etherscan.io/address/0xe0b7927c4af23765cb51314a0e0521a9645f0e2a) 124 | 125 | 7. OMG, **$149,941** lost. [watch on Etherscan](https://etherscan.io/address/0xd26114cd6ee289accf82350c8d8487fedb8a0c07) 126 | 127 | 8. STORJ, **$102,560** lost. [watch on Etherscan](https://etherscan.io/address/0xb64ef51c888972c908cfacf59b47c1afbc0ab8ac) 128 | 129 | 9. MANA, **$101,967** lost. [watch on Etherscan](https://etherscan.io/address/0x0f5d2fb29fb7d3cfee444a200298f468908cc942) 130 | 131 | Another disadvantages of ERC20 that ERC223 will solve: 132 | 1. Lack of `transfer` handling possibility. 133 | 2. Loss of tokens. 134 | 3. 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. 135 | 136 | 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). 137 | 138 | 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. 139 | 140 | The most important here is a call of `tokenFallback` when performing a transaction to a contract. 141 | 142 | ERC223 EIP https://github.com/ethereum/EIPs/issues/223 143 | ERC20 EIP https://github.com/ethereum/EIPs/issues/20 144 | --------------------------------------------------------------------------------