├── ABI └── ERC223Token.abi ├── LICENSE ├── PossibleAPI.md ├── README.md ├── token └── ERC223 │ ├── ERC223.sol │ ├── IERC223.sol │ ├── IERC223Recipient.sol │ ├── README.md │ └── extensions │ ├── ERC223Burnable.sol │ └── ERC223Mintable.sol └── utils └── Address.sol /ABI/ERC223Token.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "string", 6 | "name": "new_name", 7 | "type": "string" 8 | }, 9 | { 10 | "internalType": "string", 11 | "name": "new_symbol", 12 | "type": "string" 13 | }, 14 | { 15 | "internalType": "uint8", 16 | "name": "new_decimals", 17 | "type": "uint8" 18 | } 19 | ], 20 | "stateMutability": "nonpayable", 21 | "type": "constructor" 22 | }, 23 | { 24 | "anonymous": false, 25 | "inputs": [ 26 | { 27 | "indexed": true, 28 | "internalType": "address", 29 | "name": "from", 30 | "type": "address" 31 | }, 32 | { 33 | "indexed": true, 34 | "internalType": "address", 35 | "name": "to", 36 | "type": "address" 37 | }, 38 | { 39 | "indexed": false, 40 | "internalType": "uint256", 41 | "name": "value", 42 | "type": "uint256" 43 | }, 44 | { 45 | "indexed": false, 46 | "internalType": "bytes", 47 | "name": "data", 48 | "type": "bytes" 49 | } 50 | ], 51 | "name": "Transfer", 52 | "type": "event" 53 | }, 54 | { 55 | "inputs": [ 56 | { 57 | "internalType": "address", 58 | "name": "_owner", 59 | "type": "address" 60 | } 61 | ], 62 | "name": "balanceOf", 63 | "outputs": [ 64 | { 65 | "internalType": "uint256", 66 | "name": "", 67 | "type": "uint256" 68 | } 69 | ], 70 | "stateMutability": "view", 71 | "type": "function" 72 | }, 73 | { 74 | "inputs": [ 75 | { 76 | "internalType": "address", 77 | "name": "", 78 | "type": "address" 79 | } 80 | ], 81 | "name": "balances", 82 | "outputs": [ 83 | { 84 | "internalType": "uint256", 85 | "name": "", 86 | "type": "uint256" 87 | } 88 | ], 89 | "stateMutability": "view", 90 | "type": "function" 91 | }, 92 | { 93 | "inputs": [], 94 | "name": "decimals", 95 | "outputs": [ 96 | { 97 | "internalType": "uint8", 98 | "name": "", 99 | "type": "uint8" 100 | } 101 | ], 102 | "stateMutability": "view", 103 | "type": "function" 104 | }, 105 | { 106 | "inputs": [], 107 | "name": "name", 108 | "outputs": [ 109 | { 110 | "internalType": "string", 111 | "name": "", 112 | "type": "string" 113 | } 114 | ], 115 | "stateMutability": "view", 116 | "type": "function" 117 | }, 118 | { 119 | "inputs": [], 120 | "name": "symbol", 121 | "outputs": [ 122 | { 123 | "internalType": "string", 124 | "name": "", 125 | "type": "string" 126 | } 127 | ], 128 | "stateMutability": "view", 129 | "type": "function" 130 | }, 131 | { 132 | "inputs": [], 133 | "name": "totalSupply", 134 | "outputs": [ 135 | { 136 | "internalType": "uint256", 137 | "name": "", 138 | "type": "uint256" 139 | } 140 | ], 141 | "stateMutability": "view", 142 | "type": "function" 143 | }, 144 | { 145 | "inputs": [ 146 | { 147 | "internalType": "address", 148 | "name": "_to", 149 | "type": "address" 150 | }, 151 | { 152 | "internalType": "uint256", 153 | "name": "_value", 154 | "type": "uint256" 155 | } 156 | ], 157 | "name": "transfer", 158 | "outputs": [ 159 | { 160 | "internalType": "bool", 161 | "name": "success", 162 | "type": "bool" 163 | } 164 | ], 165 | "stateMutability": "nonpayable", 166 | "type": "function" 167 | }, 168 | { 169 | "inputs": [ 170 | { 171 | "internalType": "address", 172 | "name": "_to", 173 | "type": "address" 174 | }, 175 | { 176 | "internalType": "uint256", 177 | "name": "_value", 178 | "type": "uint256" 179 | }, 180 | { 181 | "internalType": "bytes", 182 | "name": "_data", 183 | "type": "bytes" 184 | } 185 | ], 186 | "name": "transfer", 187 | "outputs": [ 188 | { 189 | "internalType": "bool", 190 | "name": "success", 191 | "type": "bool" 192 | } 193 | ], 194 | "stateMutability": "nonpayable", 195 | "type": "function" 196 | } 197 | ] 198 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /PossibleAPI.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### API 4 | 5 | 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`. 6 | 7 | An example of the high-level API for a receiver contract is: 8 | 9 | ```solidity 10 | contract ExampleReceiver is StandardReceiver { 11 | function foo() tokenPayable { 12 | LogTokenPayable(tkn.addr, tkn.sender, tkn.value); 13 | } 14 | 15 | function () tokenPayable { 16 | LogTokenPayable(tkn.addr, tkn.sender, tkn.value); 17 | } 18 | 19 | event LogTokenPayable(address token, address sender, uint value); 20 | } 21 | ``` 22 | 23 | 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. 24 | 25 | The function `foo()` will be called when a user transfers ERC223 tokens to the receiver address. 26 | 27 | ```solidity 28 | // 0xc2985578 is the identifier for function foo. Sending it in the data parameter of a tx will result in the function being called. 29 | 30 | erc223.transfer(receiverAddress, 10, 0xc2985578) 31 | ``` 32 | 33 | 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 `tokenReceived` 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. 34 | 35 | The current `tkn` values are: 36 | 37 | - `tkn.sender` the original `msg.sender` to the token contract, the address originating the token transfer. 38 | - For user originated transfers sender will be equal to `tx.origin` 39 | - For contract originated transfers, `tx.origin` will be the user that made the transaction to that contract. 40 | 41 | - `tkn.origin` the origin address from whose balance the tokens are sent 42 | - For `transfer()`, it will be the same as `tkn.sender` 43 | - For `transferFrom()`, it will be the address that created the allowance in the token contract 44 | 45 | - `tkn.value` the amount of tokens sent 46 | - `tkn.data` arbitrary data sent with the token transfer. Simulates ether `tx.data`. 47 | - `tkn.sig` the first 4 bytes of `tx.data` that determine what function is called. 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### EIP-223 2 | 3 | Read the original discussion and formal description here: https://github.com/ethereum/eips/issues/223 4 | 5 | ### Current implementation 6 | 7 | Main ERC-223 contracts: 8 | 9 | - [IERC223.sol](https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/IERC223.sol): Token interface. The minimal common API ERC-223 tokens and receivers must implement in order to interact with each other. 10 | - [ERC223.sol](https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/ERC223.sol): Token contract. Defines logic of the basic ERC-223 token. This functionality can be extended with additional functions (such as `burn()`, `mint()`, ownership or `approve / transferFrom` pattern of ERC20). 11 | - [Recipient interface](https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/IERC223Recipient.sol): A dummy receiver that is intended to accept ERC-223 tokens. Use `contract MyContract is IERC223Recipient` to make contract capable of accepting ERC-223 token transactions. Contract that does not support IERC223Recipient interface can receive tokens if this contract implements a permissive fallback function (this method of token receiving is not recommended). If a contract does not implement IERC223Recipient `tokenReceived` function and does not implement a permissive fallback function then this contract can not receive ERC-223 tokens. 12 | 13 | ### Extensions of the base functionality 14 | 15 | - [ERC223Mintable.sol](https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/extensions/ERC223Mintable.sol): Minting functionality for ERC223 tokens. 16 | 17 | - [ERC223Burnable.sol](https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/extensions/ERC223Burnable.sol): Burning functionality implementation for ERC223 tokens. Allows any address to burn its tokens by calling the `burn` function of the contract. 18 | 19 | ## ERC223 token standard. 20 | 21 | ERC-20 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 problem is the lack of event handling mechanism in ERC20 standard. 22 | 23 | ERC-223 is a superset of the [ERC20](https://github.com/ethereum/EIPs/issues/20). 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 secure standard as it doesn't allow token transfers to contracts that do not explicitly support token receiving. 24 | 25 | [See EIP discussion](https://github.com/ethereum/EIPs/issues/223) 26 | 27 | ```js 28 | contract ERC223 { 29 | function transfer(address to, uint value, bytes data) { 30 | uint codeLength; 31 | assembly { 32 | codeLength := extcodesize(_to) 33 | } 34 | balances[msg.sender] = balances[msg.sender].sub(_value); 35 | balances[_to] = balances[_to].add(_value); 36 | if(codeLength>0) { 37 | // Require proper transaction handling. 38 | ERC223Receiver receiver = ERC223Receiver(_to); 39 | receiver.tokenReceived(msg.sender, _value, _data); 40 | } 41 | } 42 | } 43 | ``` 44 | 45 | ### The main problems of ERC-20 that ERC-223 solves 46 | 47 | 1. **Lost tokens**: 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. 48 | 2. **Impossibility of handling incoming token transactions / lack of event handling in ERC20**: 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. 49 | 3. **Optimization of ERC20 address-to-contract communication**: You should call `approve` on token contract and then call `transferFrom` on another contract when you want to deposit your tokens into it. In fact address-to-contract transfer is a couple of two different transactions in ERC20. It also costs twice more gas compared to ERC223 transfers. In ERC223 address-to-contract transfer is a single transaction just like address-to-address transfer. 50 | 4. **Ether transactions and token transactions behave differently**: 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. 51 | 52 | ### ERC-223 advantages. 53 | 54 | 1. Provides a possibility to avoid accidentally lost tokens inside contracts that are not designed to work with sent tokens. 55 | 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. 56 | 3. Allows contract developers to handle incoming token transactions. 57 | 4. ERC223 `transfer` to contract consumes 2 times less gas than ERC20 `approve` and `transferFrom` at receiver contract. 58 | 5. Allows to deposit tokens into contract with a single transaction. Prevents extra blockchain bloating. 59 | 6. Makes token transactions similar to Ether transactions. 60 | 61 | ERC-223 tokens are backwards compatible with ERC-20 tokens. It means that ERC-223 supports every ERC-20 functional and contracts or services working with ERC-20 tokens will work with ERC-223 tokens correctly. 62 | ERC-223 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 ERC-223 token transfer will be same to ERC-20 transfer. If the receiver is a contract ERC-223 token contract will try to call `tokenReceived` function on receiver contract. If there is no `tokenReceived` function on receiver contract transaction will fail. `tokenReceived` 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 `tokenReceived` function on receiver contract. There is also a way to call `transfer` function on ERC-223 token contract with no data argument or using ERC-20 ABI with no data on `transfer` function. In this case `_data` will be empty bytes array. 63 | 64 | ### The reason of designing ERC-223 token standard. 65 | Here is a description of the ERC-20 token standard problem that is solved by ERC-223: 66 | 67 | ERC-20 token standard is leading to money losses for end users. The main problem is lack of possibility to handle incoming ERC-20 transactions, that were performed via `transfer` function of ERC-20 token. 68 | 69 | 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 ERC-20 tokens to a contract that is not intended to work with ERC-20 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. 70 | 71 | How much ERC20 tokens are currently lost (31 Dec, 2017): 72 | 73 | 1. QTUM, **$1,358,441** lost. [watch on Etherscan](https://etherscan.io/address/0x9a642d6b3368ddc662CA244bAdf32cDA716005BC) 74 | 75 | 2. EOS, **$1,015,131** lost. [watch on Etherscan](https://etherscan.io/address/0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0) 76 | 77 | 3. GNT, **$249,627** lost. [watch on Etherscan](https://etherscan.io/address/0xa74476443119A942dE498590Fe1f2454d7D4aC0d) 78 | 79 | 4. STORJ, **$217,477** lost. [watch on Etherscan](https://etherscan.io/address/0xe41d2489571d322189246dafa5ebde1f4699f498) 80 | 81 | 5. Tronix , **$201,232** lost. [watch on Etherscan](https://etherscan.io/address/0xf230b790e05390fc8295f4d3f60332c93bed42e2) 82 | 83 | 6. DGD, **$151,826** lost. [watch on Etherscan](https://etherscan.io/address/0xe0b7927c4af23765cb51314a0e0521a9645f0e2a) 84 | 85 | 7. OMG, **$149,941** lost. [watch on Etherscan](https://etherscan.io/address/0xd26114cd6ee289accf82350c8d8487fedb8a0c07) 86 | 87 | 8. STORJ, **$102,560** lost. [watch on Etherscan](https://etherscan.io/address/0xb64ef51c888972c908cfacf59b47c1afbc0ab8ac) 88 | 89 | 9. MANA, **$101,967** lost. [watch on Etherscan](https://etherscan.io/address/0x0f5d2fb29fb7d3cfee444a200298f468908cc942) 90 | 91 | Another disadvantages of ERC-20 that ERC-223 solves: 92 | 1. Lack of `transfer` handling possibility. 93 | 2. Loss of tokens. 94 | 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. 95 | 96 | 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). 97 | 98 | 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. 99 | 100 | The most important here is a call of `tokenReceived` when performing a transaction to a contract. 101 | 102 | ERC20 EIP https://github.com/ethereum/EIPs/issues/20 103 | -------------------------------------------------------------------------------- /token/ERC223/ERC223.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import "https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/IERC223.sol"; 4 | import "https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/IERC223Recipient.sol"; 5 | import "https://github.com/Dexaran/ERC223-token-standard/blob/development/utils/Address.sol"; 6 | 7 | /** 8 | * @title Reference implementation of the ERC223 standard token. 9 | */ 10 | contract ERC223Token is IERC223 { 11 | 12 | string private _name; 13 | string private _symbol; 14 | uint8 private _decimals; 15 | uint256 private _totalSupply; 16 | 17 | mapping(address => uint256) private balances; // List of user balances. 18 | 19 | /** 20 | * @dev Sets the values for {name} and {symbol}, initializes {decimals} with 21 | * a default value of 18. 22 | * 23 | * To select a different value for {decimals}, use {_setupDecimals}. 24 | * 25 | * All three of these values are immutable: they can only be set once during 26 | * construction. 27 | */ 28 | 29 | constructor(string memory new_name, string memory new_symbol, uint8 new_decimals) 30 | { 31 | _name = new_name; 32 | _symbol = new_symbol; 33 | _decimals = new_decimals; 34 | } 35 | 36 | /** 37 | * @dev Returns the name of the token. 38 | */ 39 | function name() public view virtual override returns (string memory) 40 | { 41 | return _name; 42 | } 43 | 44 | /** 45 | * @dev Returns the symbol of the token, usually a shorter version of the 46 | * name. 47 | */ 48 | function symbol() public view virtual override returns (string memory) 49 | { 50 | return _symbol; 51 | } 52 | 53 | /** 54 | * @dev Returns the number of decimals used to get its user representation. 55 | * For example, if `decimals` equals `2`, a balance of `505` tokens should 56 | * be displayed to a user as `5,05` (`505 / 10 ** 2`). 57 | * 58 | * Tokens usually opt for a value of 18, imitating the relationship between 59 | * Ether and Wei. This is the value {ERC223} uses, unless {_setupDecimals} is 60 | * called. 61 | * 62 | * NOTE: This information is only used for _display_ purposes: it in 63 | * no way affects any of the arithmetic of the contract, including 64 | * {IERC223-balanceOf} and {IERC223-transfer}. 65 | */ 66 | function decimals() public view virtual override returns (uint8) 67 | { 68 | return _decimals; 69 | } 70 | 71 | /** 72 | * @dev See {IERC223-totalSupply}. 73 | */ 74 | function totalSupply() public view override returns (uint256) 75 | { 76 | return _totalSupply; 77 | } 78 | 79 | 80 | /** 81 | * @dev Returns balance of the `_owner`. 82 | * 83 | * @param _owner The address whose balance will be returned. 84 | * @return balance Balance of the `_owner`. 85 | */ 86 | function balanceOf(address _owner) public view override returns (uint256) 87 | { 88 | return balances[_owner]; 89 | } 90 | 91 | /** 92 | * @dev Transfer the specified amount of tokens to the specified address. 93 | * Invokes the `tokenReceived` function if the recipient is a contract. 94 | * The token transfer fails if the recipient is a contract 95 | * but does not implement the `tokenReceived` function 96 | * or the fallback function to receive funds. 97 | * 98 | * @param _to Receiver address. 99 | * @param _value Amount of tokens that will be transferred. 100 | * @param _data Transaction metadata. 101 | */ 102 | function transfer(address _to, uint _value, bytes calldata _data) public override returns (bool success) 103 | { 104 | // Standard function transfer similar to ERC20 transfer with no _data . 105 | // Added due to backwards compatibility reasons . 106 | balances[msg.sender] = balances[msg.sender] - _value; 107 | balances[_to] = balances[_to] + _value; 108 | if(Address.isContract(_to)) { 109 | // It is subjective if the contract call must fail or not 110 | // when ERC-223 token transfer does not trigger the `tokenReceived` function 111 | // by the standard if the receiver did not explicitly rejected the call 112 | // the transfer can be considered valid. 113 | IERC223Recipient(_to).tokenReceived(msg.sender, _value, _data); 114 | } 115 | emit Transfer(msg.sender, _to, _value, _data); 116 | return true; 117 | } 118 | 119 | /** 120 | * @dev Transfer the specified amount of tokens to the specified address. 121 | * This function works the same with the previous one 122 | * but doesn't contain `_data` param. 123 | * Added due to backwards compatibility reasons. 124 | * 125 | * @param _to Receiver address. 126 | * @param _value Amount of tokens that will be transferred. 127 | */ 128 | function transfer(address _to, uint _value) public override returns (bool success) 129 | { 130 | bytes memory _empty = hex"00000000"; 131 | balances[msg.sender] = balances[msg.sender] - _value; 132 | balances[_to] = balances[_to] + _value; 133 | if(Address.isContract(_to)) { 134 | IERC223Recipient(_to).tokenReceived(msg.sender, _value, _empty); 135 | } 136 | emit Transfer(msg.sender, _to, _value, _empty); 137 | return true; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /token/ERC223/IERC223.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | /** 4 | * @dev Interface of the ERC223 standard token as defined in the EIP-223 https://eips.ethereum.org/EIPS/eip-223. 5 | */ 6 | 7 | abstract contract IERC223 { 8 | 9 | function name() public view virtual returns (string memory); 10 | function symbol() public view virtual returns (string memory); 11 | function decimals() public view virtual returns (uint8); 12 | function totalSupply() public view virtual returns (uint256); 13 | 14 | /** 15 | * @dev Returns the balance of the `who` address. 16 | */ 17 | function balanceOf(address who) public virtual view returns (uint); 18 | 19 | /** 20 | * @dev Transfers `value` tokens from `msg.sender` to `to` address 21 | * and returns `true` on success. 22 | */ 23 | function transfer(address to, uint value) public virtual returns (bool success); 24 | 25 | /** 26 | * @dev Transfers `value` tokens from `msg.sender` to `to` address with `data` parameter 27 | * and returns `true` on success. 28 | */ 29 | function transfer(address to, uint value, bytes calldata data) public virtual returns (bool success); 30 | 31 | /** 32 | * @dev Event that is fired on successful transfer. 33 | */ 34 | event Transfer(address indexed from, address indexed to, uint value, bytes data); 35 | } 36 | -------------------------------------------------------------------------------- /token/ERC223/IERC223Recipient.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | /** 4 | * @title Contract that will work with ERC-223 tokens. 5 | */ 6 | 7 | abstract contract IERC223Recipient { 8 | 9 | 10 | struct ERC223TransferInfo 11 | { 12 | address token_contract; 13 | address sender; 14 | uint256 value; 15 | bytes data; 16 | } 17 | 18 | ERC223TransferInfo private tkn; 19 | 20 | /** 21 | * @dev Standard ERC223 function that will handle incoming token transfers. 22 | * 23 | * @param _from Token sender address. 24 | * @param _value Amount of tokens. 25 | * @param _data Transaction metadata. 26 | */ 27 | function tokenReceived(address _from, uint _value, bytes memory _data) public virtual returns (bytes4) 28 | { 29 | /** 30 | * @dev Note that inside of the token transaction handler the actual sender of token transfer is accessible via the tkn.sender variable 31 | * (analogue of msg.sender for Ether transfers) 32 | * 33 | * tkn.value - is the amount of transferred tokens 34 | * tkn.data - is the "metadata" of token transfer 35 | * tkn.token_contract is most likely equal to msg.sender because the token contract typically invokes this function 36 | */ 37 | tkn.token_contract = msg.sender; 38 | tkn.sender = _from; 39 | tkn.value = _value; 40 | tkn.data = _data; 41 | 42 | // ACTUAL CODE 43 | 44 | return 0x8943ec02; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /token/ERC223/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sections: 3 | - title: Core 4 | contracts: 5 | - IERC223 6 | - ERC223 7 | - title: Hooks 8 | contracts: 9 | - IERC223Recipient 10 | - title: Extensions 11 | contracts: 12 | - ERC223Burnable 13 | - ERC223Mintable 14 | --- 15 | 16 | This set of interfaces and contracts are all related to the [ERC223 token standard](https://github.com/ethereum/EIPs/issues/223). 17 | 18 | The token behavior itself is implemented in the core contracts: `IERC223`, `ERC223`. 19 | 20 | Additionally there are interfaces used to develop contracts that handle incoming token transfers: `IERC223Recipient`. 21 | 22 | Advanced token contract that supports calls of custom token handler functions is implemented as `ERC223CustomFallback.sol`. 23 | -------------------------------------------------------------------------------- /token/ERC223/extensions/ERC223Burnable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import "https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/IERC223.sol"; 4 | import "https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/IERC223Recipient.sol"; 5 | import "https://github.com/Dexaran/ERC223-token-standard/blob/development/utils/Address.sol"; 6 | 7 | /** 8 | * @title Reference implementation of the ERC223 standard token. 9 | */ 10 | contract ERC223MintableToken is IERC223 { 11 | 12 | string private _name; 13 | string private _symbol; 14 | uint8 private _decimals; 15 | uint256 private _totalSupply; 16 | 17 | event Burn(address indexed _from, uint256 _amount); 18 | 19 | mapping(address => uint256) public balances; // List of user balances. 20 | 21 | /** 22 | * @dev Sets the values for {name} and {symbol}, initializes {decimals} with 23 | * a default value of 18. 24 | * 25 | * To select a different value for {decimals}, use {_setupDecimals}. 26 | * 27 | * All three of these values are immutable: they can only be set once during 28 | * construction. 29 | */ 30 | 31 | constructor(string memory new_name, string memory new_symbol, uint8 new_decimals) 32 | { 33 | _name = new_name; 34 | _symbol = new_symbol; 35 | _decimals = new_decimals; 36 | } 37 | 38 | /** 39 | * @dev Returns the name of the token. 40 | */ 41 | function name() public view virtual override returns (string memory) 42 | { 43 | return _name; 44 | } 45 | 46 | /** 47 | * @dev Returns the symbol of the token, usually a shorter version of the 48 | * name. 49 | */ 50 | function symbol() public view virtual override returns (string memory) 51 | { 52 | return _symbol; 53 | } 54 | 55 | /** 56 | * @dev Returns the number of decimals used to get its user representation. 57 | * For example, if `decimals` equals `2`, a balance of `505` tokens should 58 | * be displayed to a user as `5,05` (`505 / 10 ** 2`). 59 | * 60 | * Tokens usually opt for a value of 18, imitating the relationship between 61 | * Ether and Wei. This is the value {ERC223} uses, unless {_setupDecimals} is 62 | * called. 63 | * 64 | * NOTE: This information is only used for _display_ purposes: it in 65 | * no way affects any of the arithmetic of the contract, including 66 | * {IERC223-balanceOf} and {IERC223-transfer}. 67 | */ 68 | function decimals() public view virtual override returns (uint8) 69 | { 70 | return _decimals; 71 | } 72 | 73 | /** 74 | * @dev See {IERC223-totalSupply}. 75 | */ 76 | function totalSupply() public view override returns (uint256) 77 | { 78 | return _totalSupply; 79 | } 80 | 81 | 82 | /** 83 | * @dev Returns balance of the `_owner`. 84 | * 85 | * @param _owner The address whose balance will be returned. 86 | * @return balance Balance of the `_owner`. 87 | */ 88 | function balanceOf(address _owner) public view override returns (uint256) 89 | { 90 | return balances[_owner]; 91 | } 92 | 93 | /** 94 | * @dev Transfer the specified amount of tokens to the specified address. 95 | * Invokes the `tokenFallback` function if the recipient is a contract. 96 | * The token transfer fails if the recipient is a contract 97 | * but does not implement the `tokenFallback` function 98 | * or the fallback function to receive funds. 99 | * 100 | * @param _to Receiver address. 101 | * @param _value Amount of tokens that will be transferred. 102 | * @param _data Transaction metadata. 103 | */ 104 | function transfer(address _to, uint _value, bytes calldata _data) public override returns (bool success) 105 | { 106 | // Standard function transfer similar to ERC20 transfer with no _data . 107 | // Added due to backwards compatibility reasons . 108 | balances[msg.sender] = balances[msg.sender] - _value; 109 | balances[_to] = balances[_to] + _value; 110 | if(Address.isContract(_to)) { 111 | // It is subjective if the contract call must fail or not 112 | // when ERC-223 token transfer does not trigger the `tokenReceived` function 113 | // by the standard if the receiver did not explicitly rejected the call 114 | // the transfer can be considered valid. 115 | IERC223Recipient(_to).tokenReceived(msg.sender, _value, _data); 116 | } 117 | emit Transfer(msg.sender, _to, _value, _data); 118 | return true; 119 | } 120 | 121 | /** 122 | * @dev Transfer the specified amount of tokens to the specified address. 123 | * This function works the same with the previous one 124 | * but doesn't contain `_data` param. 125 | * Added due to backwards compatibility reasons. 126 | * 127 | * @param _to Receiver address. 128 | * @param _value Amount of tokens that will be transferred. 129 | */ 130 | function transfer(address _to, uint _value) public override returns (bool success) 131 | { 132 | bytes memory _empty = hex"00000000"; 133 | balances[msg.sender] = balances[msg.sender] - _value; 134 | balances[_to] = balances[_to] + _value; 135 | if(Address.isContract(_to)) { 136 | IERC223Recipient(_to).tokenReceived(msg.sender, _value, _empty); 137 | } 138 | emit Transfer(msg.sender, _to, _value, _empty); 139 | return true; 140 | } 141 | 142 | function burn(address _from, uint256 _amount) public returns (bool) 143 | { 144 | balances[_from] -= _amount; 145 | _totalSupply -= _amount; 146 | emit Burn(_from, _amount); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /token/ERC223/extensions/ERC223Mintable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import "https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/IERC223.sol"; 4 | import "https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/IERC223Recipient.sol"; 5 | import "https://github.com/Dexaran/ERC223-token-standard/blob/development/utils/Address.sol"; 6 | 7 | /** 8 | * @title Reference implementation of the ERC223 standard token. 9 | */ 10 | contract ERC223MintableToken is IERC223 { 11 | 12 | string private _name; 13 | string private _symbol; 14 | uint8 private _decimals; 15 | uint256 private _totalSupply; 16 | 17 | mapping(address => uint256) public balances; // List of user balances. 18 | 19 | /** 20 | * @dev Sets the values for {name} and {symbol}, initializes {decimals} with 21 | * a default value of 18. 22 | * 23 | * To select a different value for {decimals}, use {_setupDecimals}. 24 | * 25 | * All three of these values are immutable: they can only be set once during 26 | * construction. 27 | */ 28 | 29 | constructor(string memory new_name, string memory new_symbol, uint8 new_decimals) 30 | { 31 | _name = new_name; 32 | _symbol = new_symbol; 33 | _decimals = new_decimals; 34 | } 35 | 36 | /** 37 | * @dev Returns the name of the token. 38 | */ 39 | function name() public view virtual override returns (string memory) 40 | { 41 | return _name; 42 | } 43 | 44 | /** 45 | * @dev Returns the symbol of the token, usually a shorter version of the 46 | * name. 47 | */ 48 | function symbol() public view virtual override returns (string memory) 49 | { 50 | return _symbol; 51 | } 52 | 53 | /** 54 | * @dev Returns the number of decimals used to get its user representation. 55 | * For example, if `decimals` equals `2`, a balance of `505` tokens should 56 | * be displayed to a user as `5,05` (`505 / 10 ** 2`). 57 | * 58 | * Tokens usually opt for a value of 18, imitating the relationship between 59 | * Ether and Wei. This is the value {ERC223} uses, unless {_setupDecimals} is 60 | * called. 61 | * 62 | * NOTE: This information is only used for _display_ purposes: it in 63 | * no way affects any of the arithmetic of the contract, including 64 | * {IERC223-balanceOf} and {IERC223-transfer}. 65 | */ 66 | function decimals() public view virtual override returns (uint8) 67 | { 68 | return _decimals; 69 | } 70 | 71 | /** 72 | * @dev See {IERC223-totalSupply}. 73 | */ 74 | function totalSupply() public view override returns (uint256) 75 | { 76 | return _totalSupply; 77 | } 78 | 79 | 80 | /** 81 | * @dev Returns balance of the `_owner`. 82 | * 83 | * @param _owner The address whose balance will be returned. 84 | * @return balance Balance of the `_owner`. 85 | */ 86 | function balanceOf(address _owner) public view override returns (uint256) 87 | { 88 | return balances[_owner]; 89 | } 90 | 91 | /** 92 | * @dev Transfer the specified amount of tokens to the specified address. 93 | * Invokes the `tokenFallback` function if the recipient is a contract. 94 | * The token transfer fails if the recipient is a contract 95 | * but does not implement the `tokenFallback` function 96 | * or the fallback function to receive funds. 97 | * 98 | * @param _to Receiver address. 99 | * @param _value Amount of tokens that will be transferred. 100 | * @param _data Transaction metadata. 101 | */ 102 | function transfer(address _to, uint _value, bytes calldata _data) public override returns (bool success) 103 | { 104 | // Standard function transfer similar to ERC20 transfer with no _data . 105 | // Added due to backwards compatibility reasons . 106 | balances[msg.sender] = balances[msg.sender] - _value; 107 | balances[_to] = balances[_to] + _value; 108 | if(Address.isContract(_to)) { 109 | // It is subjective if the contract call must fail or not 110 | // when ERC-223 token transfer does not trigger the `tokenReceived` function 111 | // by the standard if the receiver did not explicitly rejected the call 112 | // the transfer can be considered valid. 113 | IERC223Recipient(_to).tokenReceived(msg.sender, _value, _data); 114 | } 115 | emit Transfer(msg.sender, _to, _value, _data); 116 | return true; 117 | } 118 | 119 | /** 120 | * @dev Transfer the specified amount of tokens to the specified address. 121 | * This function works the same with the previous one 122 | * but doesn't contain `_data` param. 123 | * Added due to backwards compatibility reasons. 124 | * 125 | * @param _to Receiver address. 126 | * @param _value Amount of tokens that will be transferred. 127 | */ 128 | function transfer(address _to, uint _value) public override returns (bool success) 129 | { 130 | bytes memory _empty = hex"00000000"; 131 | balances[msg.sender] = balances[msg.sender] - _value; 132 | balances[_to] = balances[_to] + _value; 133 | if(Address.isContract(_to)) { 134 | IERC223Recipient(_to).tokenReceived(msg.sender, _value, _empty); 135 | } 136 | emit Transfer(msg.sender, _to, _value, _empty); 137 | return true; 138 | } 139 | 140 | function mint(address _to, uint256 _amount) public returns (bool) 141 | { 142 | balances[_to] += _amount; 143 | _totalSupply += _amount; 144 | emit Transfer(address(0), _to, _amount, hex"00000000"); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /utils/Address.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | /** 4 | * @dev Collection of functions related to the address type 5 | */ 6 | library Address { 7 | /** 8 | * @dev Returns true if `account` is a contract. 9 | * 10 | * This test is non-exhaustive, and there may be false-negatives: during the 11 | * execution of a contract's constructor, its address will be reported as 12 | * not containing a contract. 13 | * 14 | * > It is unsafe to assume that an address for which this function returns 15 | * false is an externally-owned account (EOA) and not a contract. 16 | */ 17 | function isContract(address account) internal view returns (bool) { 18 | // This method relies in extcodesize, which returns 0 for contracts in 19 | // construction, since the code is only stored at the end of the 20 | // constructor execution. 21 | 22 | uint256 size; 23 | // solhint-disable-next-line no-inline-assembly 24 | assembly { size := extcodesize(account) } 25 | return size > 0; 26 | } 27 | 28 | /** 29 | * @dev Converts an `address` into `address payable`. Note that this is 30 | * simply a type cast: the actual underlying value is not changed. 31 | */ 32 | function toPayable(address account) internal pure returns (address payable) { 33 | return payable(account); 34 | } 35 | } 36 | --------------------------------------------------------------------------------