3.2 ERC223
状态:
草稿(Draft)
提交记录:
https://github.com/ethereum/EIPs/issues/223
标准说明:
https://github.com/Dexaran/ERC223-token-standard
推荐样例:
https://github.com/Dexaran/ERC223-token-standard/tree/Recommended
开发人员Dexaran在一篇文章中详细描述了ERC20不适合的两种场景:
“在ERC20中执行交易有两种方式:transfer函数,approve + transferFrom机制,通证余额只是通证合约中的一个变量。
通证的交易是合约内部变量的变化。 转出账户的余额将减少,转入账户的余额将增加。
交易发生时, transfer()函数不会通知转入账户。 因此转入账户将无法识别传入的交易! 我写了一个例子,可以展示这一导致未处理的交易和资金损失的过程 。
因此,如果接收账户是合约账户,那么必须使用approve + transferFrom机制来发送通证。
如果接受账户是外部帐户,则必须通过transfer函数发送通证。 如果选择了错误的机制,通证将卡在合约内(合约将不会识别交易),没有办法来提取这些卡壳的通证。“
他对这个问题提出的解决方案包含在ERC-223中 。 它与ERC-20标准非常相似,但解决了上述问题。当通证转移到智能合约账户时,该合约的特殊函数tokenFallback() 允许接收方合约拒绝令牌或触发进一步的操作。 大多数情况下,这可以用来代替approve()函数。
函数接口:
transfer(address _to, uint _value):
会区分代币是发往外部账户地址还是发往智能合约地址。
transfer(address _to, uint _value, bytes _data):
会区分代币是发往外部账户地址还是发往智能合约地址,还可以传送数据。
1、如果_to是合约,则此函数必须传输令牌并调_to中的函数tokenFallback(address,uint256.bytes)。
2、如果_to(接收方合同)中没有实现tokenFallback函数,则事务必须失败,并且不会发生令牌的传输。
3、如果_to是外部拥有的地址,则必须发送事务,而不尝试在_to中执行tokenFallback。
4、_data可以附加到这个令牌交易中,它将永远保持在块状(需要更多的gas)。 _data可以是空的。
注意:检查_to是合约还是地址的推荐方法是组装_to的代码。 如果_to中没有代码,那么这是一个外部拥有的地址,否则就是一个合约。
//assemble the given address bytecode. If bytecode exists then the _addr is a contract.
function isContract(address _addr) private view returns (bool is_contract) {
uint length;
assembly {
//retrieve the size of the code on target address, this needs assembly
length := extcodesize(_addr)
}
return (length>0);
}
function tokenFallback(address _from, uint _value, bytes _data)
_from是令牌发送者,_value是传入令牌的数量,_data是附加的数据,类似于Ether事务中的数据。 适用于以太交易的回退功能,并且不返回任何内容。
tokenFallback — 令牌持有者发送令牌时处理从令牌合同所调用的令牌传输的功能
注意:msg.sender将是tokenFallback函数内的令牌合同。 过滤哪些令牌(通过令牌契约地址)发送可能很重要。 令牌发送者(谁发起了代币交易的人)在_from thetokenFallback函数内。
示例代码:
ERC223_Interface.sol
pragma solidity ^0.4.9;
/* 新的 ERC23 contract 接口文件 */
contract ERC223 {
uint public totalSupply;
function balanceOf(address who) constant returns (uint);
function name() constant returns (string _name);
function symbol() constant returns (string _symbol);
function decimals() constant returns (uint8 _decimals);
function totalSupply() constant returns (uint256 _supply);
function transfer(address to, uint value) returns (bool ok);
function transfer(address to, uint value, bytes data) returns (bool ok);
function transfer(address to, uint value, bytes data, string custom_fallback) returns (bool ok);
event Transfer(address indexed from, address indexed to, uint value, bytes indexed data);
}
Receiver_Interface.sol
pragma solidity ^0.4.9;
/*
* Contract that is working with ERC223 tokens
*/
contract ContractReceiver {
struct TKN {
address sender; //调用合约的人
uint value;
bytes data;
bytes4 sig; //签名
}
function tokenFallback(address _from, uint _value, bytes _data){
TKN memory tkn;
tkn.sender = _from;
tkn.value = _value;
tkn.data = _data;
uint32 u = uint32(_data[3]) + (uint32(_data[2]) << 8) + (uint32(_data[1]) << 16) + (uint32(_data[0]) << 24);
tkn.sig = bytes4(u);
/* tkn变量是Ether交易的msg变量的模拟
* tkn.sender是发起这个令牌交易的人(类似于msg.sender)
* tkn.value发送的令牌数(msg.value的类比)
* tkn.data是令牌交易的数据(类似于msg.data)
* tkn.sig是4字节的功能签名
* 如果令牌事务的数据是一个函数执行
*/
}
}
ERC223_Token.sol
pragma solidity ^0.4.9;
import "./Receiver_Interface.sol";
import "./ERC223_Interface.sol";
/**
* ERC23 token by Dexaran
*
* https://github.com/Dexaran/ERC23-tokens
* https://github.com/LykkeCity/EthereumApiDotNetCore/blob/master/src/ContractBuilder/contracts/token/SafeMath.sol
*/
contract SafeMath {
uint256 constant public MAX_UINT256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
function safeAdd(uint256 x, uint256 y) constant internal returns (uint256 z) {
if (x > MAX_UINT256 - y) throw;
return x + y;
}
function safeSub(uint256 x, uint256 y) constant internal returns (uint256 z) {
if (x < y) throw;
return x - y;
}
function safeMul(uint256 x, uint256 y) constant internal returns (uint256 z) {
if (y == 0) return 0;
if (x > MAX_UINT256 / y) throw;
return x * y;
}
}
//示例的智能合约代码
contract ERC223Token is ERC223. SafeMath {
mapping(address => uint) balances;
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;
// 获取token的名称
function name() constant returns (string _name) {
return name;
}
// 获取token的符号
function symbol() constant returns (string _symbol) {
return symbol;
}
// 获取token精确到小数点后的位数
function decimals() constant returns (uint8 _decimals) {
return decimals;
}
// 获取token的发布总量
function totalSupply() constant returns (uint256 _totalSupply) {
return totalSupply;
}
// 当用户或其他合同想要转移资金时调用的功能。
function transfer(address _to, uint _value, bytes _data, string _custom_fallback) returns (bool success) {
//如果to是合约
if(isContract(_to)) {
if (balanceOf(msg.sender) < _value) throw; //如果当前的余额不够就抛出
balances[msg.sender] = safeSub(balanceOf(msg.sender), _value);//发送者的余额做减法
balances[_to] = safeAdd(balanceOf(_to), _value); //接收者的余额做加法
ContractReceiver receiver = ContractReceiver(_to); //初始化接收合约,构造函数参数为接收者的合约地址
receiver.call.value(0)(bytes4(sha3(_custom_fallback)), msg.sender, _value, _data);
Transfer(msg.sender, _to, _value, _data);
return true;
}
else {
return transferToAddress(_to, _value, _data);
}
}
// 当用户或其他合同想要转移资金时调用的功能。
function transfer(address _to, uint _value, bytes _data) returns (bool success) {
if(isContract(_to)) {
return transferToContract(_to, _value, _data);
}
else {
return transferToAddress(_to, _value, _data);
}
}
// 类似于ERC20传输的标准功能传输,没有_data。
// 由于向后兼容性原因而增加。
function transfer(address _to, uint _value) returns (bool success) {
//类似于没有_data的ERC20传输的标准功能传输
//由于向后兼容性原因而增加
bytes memory empty;
if(isContract(_to)) {//如果是合约
return transferToContract(_to, _value, empty);
}
else {
return transferToAddress(_to, _value, empty);
}
}
//组装定地址字节码。 如果存在字节码,那么_addr是一个合约。
function isContract(address _addr) private returns (bool is_contract) {
uint length;
assembly {
//检索目标地址上的代码大小,这需要汇编
length := extcodesize(_addr)
}
return (length>0);
}
//当传递目标是一个地址时调用函数
function transferToAddress(address _to, uint _value, bytes _data) private returns (bool success) {
if (balanceOf(msg.sender) < _value) throw;
balances[msg.sender] = safeSub(balanceOf(msg.sender), _value);
balances[_to] = safeAdd(balanceOf(_to), _value);
Transfer(msg.sender, _to, _value, _data);
return true;
}
//当传递目标是一个合约时调用函数
function transferToContract(address _to, uint _value, bytes _data) private returns (bool success) {
if (balanceOf(msg.sender) < _value) throw;
balances[msg.sender] = safeSub(balanceOf(msg.sender), _value);
balances[_to] = safeAdd(balanceOf(_to), _value);
ContractReceiver receiver = ContractReceiver(_to);
receiver.tokenFallback(msg.sender, _value, _data); //必须要调用这个回调
Transfer(msg.sender, _to, _value, _data);
return true;
}
//得到_owner的余额
function balanceOf(address _owner) constant returns (uint balance) {
return balances[_owner];
}
}
3.3 ERC621
状态:
草稿(Draft)
提交记录:
https://github.com/ethereum/EIPs/issues/621
标准说明:
推荐样例:
https://github.com/skmgoldin/EIP621Token/blob/master/contracts/EIP621Token.sol
ERC-621是ERC-20标准的扩展。 它增加了两个额外的功能, increaseSupply和decreaseSupply 。这可以增加和减少流通中的令牌供应。 ERC-20只允许单一的通证发放事件。 这将供应量限制在一个固定的不可改变的数目。 ERC-621建议totalSupply应当是可修改的。
接口函数说明:
increaseSupply(uint value, address to):
可以给特定账户to增加value值的供应量,代币总供应量totalSupply也同步增加;
decreaseSupply(uint value, address from):
可以给特定账户to减少value值的账户余额,代币总供应余额totalSupply也同步减少;
3.4 ERC777
状态:
草稿(Draft)
提交记录:
https://github.com/ethereum/EIPs/issues/777
标准说明:
https://eips.ethereum.org/EIPS/eip-777
推荐样例:
https://github.com/jacquesd/ERC777/tree/devel/contracts
功能描述
本标准用于提升ERC20标准的使用范围。这个标准的主要优点有:
可以同使用Ether一样的原理使用ERC777通证,通证发送采用函数send(dest, value, data)的。
不管是合约还是常规的地址都可以控制和拒绝那些通过注册tokensToSend 钩函数发送的通证(通过在钩函数内部执行reverting回滚函数触发拒绝。)
不管是合约还是常规的地址都可以控制和拒绝那些通过注册tokensToSend 钩函数接收的通证(通过在钩函数内部执行reverting回滚函数触发拒绝。)
tokensReceived 勾函数运行发送通证给一个合约,并在一次交易中通知完成,不像ERC20需要2次通知(approve/transferFrom) 才能达到相同效果。
通证持有者可以“授权”和“撤销”可以代表他们发送通证的操作员。这些操作员用于验证合约,如交易所,支票处理器或自动收费系统。
每次通证交易都包含一个“data”字节字段和一个类似的“operatorData”,可以自由地用于将数据传递给接收方。
通过部署实现钱包的“tokensReceived”钩子的代理合约,它与不包含“tokensReceived”钩子功能的钱包向后兼容。
协议代码
interface ERC777Token {
function name() public view returns (string);
function symbol() public view returns (string);
function totalSupply() public view returns (uint256);
function balanceOf(address owner) public view returns (uint256);
function granularity() public view returns (uint256);
function defaultOperators() public view returns (address[]);
function authorizeOperator(address operator) public;
function revokeOperator(address operator) public;
function isOperatorFor(address operator, address tokenHolder) public view returns (bool);
function send(address to, uint256 amount, bytes data) public;
function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) public;
function burn(uint256 amount, bytes data) public;
function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) public;
event Sent(
address indexed operator,
address indexed from,
address indexed to,
uint256 amount,
bytes data,
bytes operatorData
);
event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);
event Burned(address indexed operator, address indexed from, uint256 amount, bytes operatorData);
event AuthorizedOperator(address indexed operator, address indexed tokenHolder);
event RevokedOperator(address indexed operator, address indexed tokenHolder);
}
3.5 ERC827
状态:
草稿(Draft)
提交记录:
https://github.com/ethereum/EIPs/issues/827
标准说明:
推荐样

https://github.com/windingtree/erc827/blob/master/contracts/ERC827/ERC827Token.sol
它允许转让通证并允许持有人允许第三方使用通证。 以太坊上的通证可以被其他应用程序重复使用,这其中也包括钱包和交易所。 当需要支持第三方动态消费限额调整时这一点非常有用。
该标准目前处于草稿状态,并被证明有使用安全风险,建议暂不使用。
本文采摘于网络,不代表本站立场,转载联系作者并注明出处:http://www.longfuchaju.com//zmt/4011.html