【我的区块链之路】-ERC系列协议标准详解
【转载请标明出处】:blog.csdn/qq_25870633/article/details/80884646
在以太坊中,发布智能合约是⾃由的;但是,很多第三⽅想要做的事情可能有所类似,故延伸出来了ERC系列协议;
基于以太坊的区块链平台的数字资产分为原⽣令牌(硬币)和代币(令牌)两⼤类,原⽣的⾃然就是以太坊(ETH),令牌是通过智能合约创设的数字资产。代币则是按ERC创设协议分类,主流类别有ERC20代币,ERC223代币,ERC721代币,另外还有⼀些⼩众类别,包括ERC621,ERC721和ERC827等。
ERC代表“Etuereum征求意见”,这是Ethereum版的意见征求稿(RFC),ERC是由以太坊开发者为以太坊社区编写,ERC后⾯的数字是议案的编号。当开发⼈员提交了⼀个以太坊改进⽅案(EIP),该⽅案⼀旦EIP被委员会批准并最终确定后,⼀个新的以太坊开发标准就形成了,它包括协议规范和合约标准;【注:好多新⼈都不知道这个.ERC =以太坊请求评论,你要看EIP这个项⽬,应该去看问题.ERC20,就是问题#20,ERC721,就是问题#721。并不是所有的ERC都是标准,最终被采纳的问题才会被收进EIP ; EIP的readme⾥边有⽬前的状态⽹站链接hereum】具体表现可以⽤抽象合约表现出来【注意:ERC并不是指某些特定的合约,⽽是指合约应该符合某些规范】;根据具备
某些特征归类⽬前有ERC20,ERC223,ERC664,ERC667,ERC721,ERC875,ERC1155及ERC156等等合约协议规 范;下⾯我们先从⼤家最常⽤的ERC20铸币合约标准开始说,以下为⼀个标准的ERC20的解析:
pragma solidity ^0.4.16;
/**
ERC20标准
*/
contract ERC20 {
/**
代币的名字,例如"Gavin token"
*/
function name() constant public returns (string name);
/**
代币的简称,例如:GAVC
也是我们⼀般在代币交易所看到的名字
*/
function symbol() public constant returns (string symbol);
/**
代币的最⼩分割量
token使⽤的⼩数点后⼏位。⽐如如果设置为3,就是⽀持0.001表⽰
*/
function decimals() public constant returns (uint8 decimals);
/**
token的总量
*/
function totalSupply() public constant returns (uint totalSupply);
/**
【余额】
返回某个地址(账户)的账户余额
*/
function balanceOf(address _owner) public constant returns (uint balance);
/**
【转账】
交易代币
从消息发送者账户中往_to账户转数量为_value的token
从代币合约的调⽤者地址上转移 _value的数量token到的地址 _to,并且必须触发Transfer事件
*/
function transfer(address _to, uint _value) public returns (bool success);
function transfer(address _to, uint _value) public returns (bool success);
/**
【替某⼈个别⼈转账】
从账户_from中往账户_to转数量为_value的token,与approve⽅法配合使⽤
从地址 _from发送数量为 _value的token到地址 _to,必须触发Transfer事件。
transferFrom⽅法⽤于允许合约代理某⼈转移token。条件是from账户必须经过了approve。这个后⾯会举例说明
*/
function transferFrom(address _from, address _to, uint _value) public returns (bool success);
/**
【允许量值】
限定_spender能从合约调⽤账户中转出数量为_value的token
*/
function approve(address _spender, uint _value) public returns (bool success);
/**
【限额】
获取账户_spender可以从账户_owner中转出token的数量
*/
function allowance(address _owner, address _spender) public constant returns (uint remaining);
/
**
发⽣转账时必须要触发的事件
⼀般位于 transfer 和 transferFrom 函数中
*/
event Transfer(address indexed _from, address indexed _to, uint _value);
/**
当函数approve(address _spender, uint256 _value)成功执⾏时必须触发的事件
*/
event Approval(address indexed _owner, address indexed _spender, uint _value);
}
上述就是传说中的ERC20 标准接⼝总共分为三⼤类: 常量、功能函数及事件
【常量】
<1> name: 代币名称,就是⼀串指定的字符串,如: "GavinNetToken"
<2> symbol: 代币的代号,由3-4个⼤写字母组成, 如: "GVTC"
<3> decimals: ⼩数点后⼏位,表⽰该代币⽀持最⼩的⼩数位是多少,默认为18 (ETH也是18,之所以需要有⼩数位字段是因为EVM 不⽀持⼩数点运算,需要在做计算的时候先转成整型,最后根据⼩数位把运算结果转换会对应的⼩数位)
【功能函数】
<4> totalSupply(): 总供应量;表⽰该代币的总发⾏量 [后期并没有承诺不会被更改]
<5> balanceOf(address _owner): 查询余额;根据账户地址查询该地址的余额,为⽆符号整数常量
糯米球的做法<6> transfer(address _to, uint _value): 转账;表⽰合约的调⽤者 转移_value 数量的token⾄ _to ⽬标账户地址
<7> transferFrom(address _from, address _to, uint _value): 替别⼈转账;合约调⽤者代替_from给_to
转账 _value数⽬,【该⽅法需要有approve()⽅法的先决条件,即是说 需要_from 先⽤approve() 给当前合约的调⽤者 设置课允许当前合约调⽤者 代替⾃⼰(即: _from)给_to转账_value数⽬】
<8> approve(address _spender, uint _value): 给某⼈赋予多少转账数⽬权限;当前合约调⽤者给予_spender账户有替代⾃⼰给别⼈转账 总额为_value数⽬ 【注意,这个⽅法会对⼀个全局的 map[最终花钱者(approve()⽅法的调⽤者)][替代⾃⼰拿着⾃⼰的钱去花者] 进⾏设置,后续transferFrom函数每次转账后都需要更新该Map中记载的被给予转账的余额;allowance()⽅法会查询这个map中的值】
<9> allowance(address _owner, address _spender): 查询限额的数⽬;查询_spender还可以从_owner拿多少数⽬去花销【底层读取的是 approve()⽅法中设置的那个全局的map的值】
【事件】
<10> event Transfer : 每次调⽤ function transfer时最末尾都需要调⽤的事件,⽤于捕获交易的⽇志
<11> event Approval : 每次调⽤ function approve时最末尾都需要调⽤的事件,⽤于捕获给予第三⽅代替⾃⼰做交易事件的⽇志
⾄此ERC20标准的各项⽅法说明已经写完;下⾯我们来看看ERC223标准:
各位币圈⼤佬都知道,现有的 ETH 代币基本上都基于 ERC20 标准实现,⽽ ERC20 存在某些严重问题【ERC-20标准还有待完善。其中⼀个障碍是,将令牌直接发送给令牌的智能合同将导致资⾦损失】
根据 ERC20 标准,交易(transaction)可以有两种处理⽅式:通过transfer函数和通过approve+transferFrom,
对于开发来说,事件处理(Event Handling)是⼀个标准性的操作,我们所说的交易也可以被当做⼀种事件进⾏考虑。
但是很遗憾,在 ERC20 标准中,缺乏事件处理机制,也就是说,当交易发⽣的时候,收款⼈并不会得知这⼀消息。
在 ERC20 标准中,我们要求⽤户向合约发送代币的时候,必须使⽤approve+transferFrom模式进⾏代币转账,
与此同时,如果收件⼈是⼀个账户地址,就必须使⽤transfer函数完成交易。
如果⽤户搞错了,这些代币就会由于合约⽆法识别交易⽽被困在合约中。⽽合约没有提供⼀个可以把这些困住的代币提取出来的⽅法。
到⽬前为⽌,⼤概有 $3,000,000 的损失已经发⽣了;
ERC223 是 ERC20 的⼀个升级版本。ERC223 标准提供了更安全的⽅法⽤于完成交易。
在 ERC223 标准中,交易发起⽅⽆需关注接收⽅到底是合约还是钱包地址,使代币交易更接近 ETH 交易。
相对⽐ ERC20 标准,ERC223 通过全新的transfer函数,⾃动回滚向不⽀持代币的合约发送代币的⾏为。
它的实现⽅法是定义⼀个接收器(receiver),接受⽅合约必须通过它来正确地处理收到的代币,否则就会有异常抛出。
就好像你在发送 ETH 到⼀个没有payable关键字的合约⼀样;其实就是 【它与之前的ERC20相⽐,该标准更注重保护合约本⾝和防⽌您的数字代币丢失。作为ERC20的升级⽅案,该标准有不允许代币转到不⽀持代币接收和处理的合约中的功能;ERC223标准允许⽤户发送代币到钱包或合同地址,从⽽消除了丢失代币的危险性。同时ERC223中的转让合同功能让其合同的gas消耗⽐ERC20少。简⽽⾔
之,ERC223更侧重于安全,被誉为取代ERC20的标准】,下⾯我们先看看具体的ERC223标准 ⾸先
我们需要有2个*.sol⽂件;先看看
ERC223_Interface.sol
⽂件的内容
contract ERC223 {
uint public totalSupply;
/**
代币名称【同ERC20】
*/
function name() public constant returns (string _name);
/**
代币的标识符【同ERC20】
*/
function symbol() public constant returns (string _symbol);
如何提高学习
焖面的家常做法/**
⼩数点后⼏位【同ERC20】
*/
function decimals() public constant returns (uint8 _decimals);
/**
代币总发⾏量【同ERC20】
*/
function totalSupply() public constant returns (uint256 _supply);
/**
查询某地址余额【同ERC20】
*/
function balanceOf(address who) public constant returns (uint);
解决办法英语
/**
转账给某个外部账户【同ERC20】
*/
function transfer(address to, uint value) public returns (bool ok);
/**
转账给合约该合约必须是实现了名为: tokenFallback的函数
data可以附加到这个令牌交易中,它将永远保持在块状(需要更多的gas)。 _data可以是空的
*/
function transfer(address to, uint value, bytes data) public returns (bool ok);尘封已久
/**
重载转账给合约
*/
function transfer(address to, uint value, bytes data, string custom_fallback) public returns (bool ok); event Transfer(address indexed from, address indexed to, uint value, bytes indexed data);
}
另外
Receiver_Interface.sol
⽂件的内容为:
pragma solidity ^0.4.16;
/* * Contract that is working with ERC223 tokens */
contract ContractReceiver {
struct TKN {
address nder; //调⽤合约的⼈
购房协议书uint value;
bytes data;
bytes4 sig; //签名
}
/**
该函数表明了当调⽤了 transfer交易函数由A(可以使任何账户) 向合约B交易token时时,函数中的逻辑必须是
_from是令牌发送者,_value是传⼊令牌的数量,
_data是附加的数据,类似于Ether事务中的数据。适⽤于以太交易的回退功能,并且不返回任何内容。
【注意】: 过滤哪些令牌(通过token合约的账户地址)发送可以被发送很重要。
令牌发送者(谁发起了代币交易的⼈)将_from传⼊tokenFallback函数内。
【重要】: 这个函数必须命名为tokenFallback,并使⽤参数地址uint256,字节来匹配函数签名0xc0ee0b8a
*/
function tokenFallback(address _from, uint _value, bytes _data) public {
TKN memory tkn;
tkn.nder = _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.nder是发起这个令牌交易的⼈(类似于msg.nder) * tkn.value发送的令牌数(msg.value的类⽐) * tkn.data是 }
}
【注意:】将在接收⽅合约中调⽤的token备⽤功能的函数必须命名为tokenFallback,并使⽤参数address, uint256,bytes。 此函数必须具
有0xc0ee0b8a签名[bytes4(keccak256('tonken(address,uint256,bytes)')) == c0ee0b8a ??]
然后,当我们需要来说⼀说怎么⽤这两个⽂件【这些代码都是⽹上抄的,原作者估计也是翻译的 注释写的⽜头不对马嘴,我已经建议他回去
学⼩学语⽂了,因为我⽐较懒 也搬运了下,但是我⾃⼰知道这说的是些什么⿁!!】下⾯演⽰⼀个ERC223的token代币合约⽰例
ERC223_Token.sol
⽂件内容:
pragma solidity ^0.4.16;
import "./Receiver_Interface.sol";
import "./ERC223_Interface.sol";
/** * ERC223 token by Dexaran * * /Dexaran/ERC223-token-standard */
/* /LykkeCity/EthereumApiDotNetCore/blob/master/src/ContractBuilder/contracts/token/SafeMath.sol */
contract SafeMath {
uint256 constant public MAX_UINT256 =
万圣节面具0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
小学生阅读手抄报