https://github.com/Dexaran/ERC223-token-standard
ERC223是以太坊上最新的代幣(token)介面標準,主要是為瞭解決ERC220代幣轉賬丟失問題
ERC220介面以transfer為例:
// @notice send `_value` token to `_to` from `msg.sender` // @param _to The address of the recipient // @param _value The amount of token to be transferred // @return Whether the transfer was successful or not function transfer(address _to, uint256 _value) public returns (bool success);
transfer的功能非常簡單,給一個指定地址轉多少代幣。
但是當初設計的時候沒有考慮到的一個問題就是如果接收者是一個智能合約,那麼合約是沒法感知自己收到了多少token的.
ERC223 中的方法定義
function transfer(address _to, uint _value) public returns (bool ok); function transfer(address _to, uint _value, bytes _data) public returns (bool ok); function transfer(address _to, uint _value, bytes _data, string _custom_fallback)
除此之外 ERC223 還提供了安全的數學運算方法。
pragma solidity ^0.4.11; /** * Math operations with safety checks */ library SafeMath { function mul(uint a, uint b) internal returns (uint) { uint c = a * b; assert(a == 0 || c / a == b); return c; } function div(uint a, uint b) internal returns (uint) { // assert(b > 0); // Solidity automatically throws when dividing by 0 uint c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function sub(uint a, uint b) internal returns (uint) { assert(b <= a); return a - b; } function add(uint a, uint b) internal returns (uint) { uint c = a + b; assert(c >= a); return c; } function max64(uint64 a, uint64 b) internal constant returns (uint64) { return a >= b ? a : b; } function min64(uint64 a, uint64 b) internal constant returns (uint64) { return a < b ? a : b; } function max256(uint256 a, uint256 b) internal constant returns (uint256) { return a >= b ? a : b; } function min256(uint256 a, uint256 b) internal constant returns (uint256) { return a < b ? a : b; } function assert(bool assertion) internal { if (!assertion) { throw; } } }
ERC223 介面
pragma solidity ^0.4.11; contract ERC223Interface { uint public totalSupply; function balanceOf(address who) constant returns (uint); function transfer(address to, uint value); function transfer(address to, uint value, bytes data); event Transfer(address indexed from, address indexed to, uint value, bytes data); }
pragma solidity ^0.4.11; /** * @title Contract that will work with ERC223 tokens. */ contract ERC223ReceivingContract { /** * @dev Standard ERC223 function that will handle incoming token transfers. * * @param _from Token sender address. * @param _value Amount of tokens. * @param _data Transaction metadata. */ function tokenFallback(address _from, uint _value, bytes _data); }
pragma solidity ^0.4.11; import './ERC223_interface.sol'; import './ERC223_receiving_contract.sol'; import '././SafeMath.sol'; /** * @title Reference implementation of the ERC223 standard token. */ contract ERC223Token is ERC223Interface { using SafeMath for uint; mapping(address => uint) balances; // List of user balances. /** * @dev Transfer the specified amount of tokens to the specified address. * Invokes the `tokenFallback` function if the recipient is a contract. * The token transfer fails if the recipient is a contract * but does not implement the `tokenFallback` function * or the fallback function to receive funds. * * @param _to Receiver address. * @param _value Amount of tokens that will be transferred. * @param _data Transaction metadata. */ function transfer(address _to, uint _value, bytes _data) { // Standard function transfer similar to ERC20 transfer with no _data . // Added due to backwards compatibility reasons . uint codeLength; assembly { // Retrieve the size of the code on target address, this needs assembly . codeLength := extcodesize(_to) } balances[msg.sender] = balances[msg.sender].sub(_value); balances[_to] = balances[_to].add(_value); if(codeLength>0) { ERC223ReceivingContract receiver = ERC223ReceivingContract(_to); receiver.tokenFallback(msg.sender, _value, _data); } Transfer(msg.sender, _to, _value, _data); } /** * @dev Transfer the specified amount of tokens to the specified address. * This function works the same with the previous one * but doesn't contain `_data` param. * Added due to backwards compatibility reasons. * * @param _to Receiver address. * @param _value Amount of tokens that will be transferred. */ function transfer(address _to, uint _value) { uint codeLength; bytes memory empty; assembly { // Retrieve the size of the code on target address, this needs assembly . codeLength := extcodesize(_to) } balances[msg.sender] = balances[msg.sender].sub(_value); balances[_to] = balances[_to].add(_value); if(codeLength>0) { ERC223ReceivingContract receiver = ERC223ReceivingContract(_to); receiver.tokenFallback(msg.sender, _value, empty); } Transfer(msg.sender, _to, _value, empty); } /** * @dev Returns balance of the `_owner`. * * @param _owner The address whose balance will be returned. * @return balance Balance of the `_owner`. */ function balanceOf(address _owner) constant returns (uint balance) { return balances[_owner]; } }