【转载请标明出处】:https://blog.csdn.net/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里边有目前的状态网站链接https://eips.ethereum.org】具体表现可以用抽象合约表现出来【注意: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);
/**
【替某人个别人转账】
从账户_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文件;先看看
文件的内容
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);
}
另外
文件的内容为:
pragma solidity ^0.4.16;
/* * Contract that is working with ERC223 tokens */
contract ContractReceiver {
struct TKN {
address sender; //调用合约的人
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.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字节的功能签名 */
}
}
【注意:】将在接收方合约中调用的token备用功能的函数必须命名为tokenFallback
,并使用参数address
, uint256
,bytes
。 此函数必须具有0xc0ee0b8a
签名[bytes4(keccak256('tonken(address,uint256,bytes)')) == c0ee0b8a ??]
然后,当我们需要来说一说怎么用这两个文件【这些代码都是网上抄的,原作者估计也是翻译的 注释写的牛头不对马嘴,我已经建议他回去学小学语文了,因为我比较懒 也搬运了下,但是我自己知道这说的是些什么鬼!!】下面演示一个ERC223的token代币合约示例
文件内容:
pragma solidity ^0.4.16;
import "./Receiver_Interface.sol";
import "./ERC223_Interface.sol";
/** * ERC223 token by Dexaran * * https://github.com/Dexaran/ERC223-token-standard */
/* 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) revert();
return x + y;
}
function safeSub(uint256 x, uint256 y) constant internal returns (uint256 z) {
if (x < y) revert();
return x - y;
}
function safeMul(uint256 x, uint256 y) constant internal returns (uint256 z) {
if (y == 0) return 0;
if (x > MAX_UINT256 / y) revert();
return x * y;
}
}
/**
ERC223示例的智能合约代码
*/
contract ERC223Token is ERC223, SafeMath {
mapping(address => uint) balances;
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;
// 获取token的名称
function name() public view returns (string) {
return name;
}
// 获取token的符号
function symbol() public view returns (string) {
return symbol;
}
// 获取token精确到小数点后的位数
function decimals() public view returns (uint8) {
return decimals;
}
// 获取token的发布总量
function totalSupply() public view returns (uint256) {
return totalSupply;
}
// 当用户或其他合同想要转移资金时调用的功能。
function transfer(address _to, uint _value, bytes _data, string _custom_fallback) public returns (bool success) {
//如果to是合约
if(isContract(_to)) {
if (balanceOf(msg.sender) < _value) revert(); //如果当前的余额不够就抛出
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) public 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) public returns (bool success) {
//类似于没有_data的ERC20传输的标准功能传输
//由于向后兼容性原因而增加
bytes memory empty;
if(isContract(_to)) {//如果是合约
return transferToContract(_to, _value, empty);
}
else {
return transferToAddress(_to, _value, empty);
}
}
/**
判断某账户地址是EOA地址还是合约地址
组装定地址字节码。 如果存在字节码,那么_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) revert();
balances[msg.sender] = safeSub(balanceOf(msg.sender), _value);
balances[_to] = safeAdd(balanceOf(_to), _value);
Transfer(msg.sender, _to, _value, _data);
return true;
}
/**
当传递目标是一个合约【合约账户】时调用函数
【注意】token接收者是合约的话,需要调用 自定义的具备了 tokenFallback函数的 合约对象的tokenFallback函数 【要求接受token的合约必须具备了tokenFallback函数】
*/
function transferToContract(address _to, uint _value, bytes _data) private returns (bool success) {
if (balanceOf(msg.sender) < _value) revert();
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) public constant returns (uint balance) {
return balances[_owner];
}
}
以上ERC223标准的token发币合约示例表示,当需要调用交易函数把ERC223标准token交易给某个合约地址时,要求合约必须具备tokenFallback函数【合约开发人员希望他们的合约使用指定的token,那么合约开发人员必须实现tokenFallback,并使用参数address
,uint256
,bytes
。 此函数必须具有0xc0ee0b8a
签名】,否则转账失败;现有的代币肯定是大部分基于 ERC20 标准的,迁移难度很大,毕竟这个事情需要大家一起动。至于新的代币,很多已经开始使用 ERC223 标准了,目前已经超过了三万种(某位网上的吊毛说的,不是我说的。。。)
好了,以上我们介绍了两种可以发行 【可代替性通证】的合约,(可代替性就是可以代替所有没有唯一性的事物,如:钱、积分等);下面我们开始研究研究下针对【不可代替性的事物】的一些合约标准,【CryptoKitties 以太猫】相信大家都对这款曾经让以太坊网络一度瘫痪的 猫科动物繁殖类无聊烧钱游戏有一点点耳闻吧?好了,废话不多说,先上代码:
pragma solidity ^0.4.16;
/**
以太猫使用的ERC721的合约标准
*/
contract ERC721 {
// Required method
function totalSupply() public constant returns (uint256 totalSupply);
function balanceOf(address _owner) public constant returns (uint256 balance);
/**
根据代币Id查询代币持有者
*/
function ownerOf(uint256 _tokenId) public constant returns (address _owner);
function transfer(address _to, uint256 _tokenId) public;
function approve(address _to, uint256 _tokenId) public;
/**
在Approve 允许的条件下, 交易方msg.sender 调用该函数可以指定_tokenId的代币从他人那转至自己名下
类似于ERC20的 transferFrom
*/
function takeOwnership(uint256 _tokenId) public;
// Optional method
function name() public constant returns (string name);
function symbol() public constant returns (string symbol);
/**
根据持有者和索引查询所持有的代币
*/
function tokenOfOwnerByIndex(address _owner, uint256 _index) public constant returns (uint tokenId);
/**
查看代币的元数据
根据代币Id查询到元数据对应的URL, 里面包含了 代币名称,图像和描述等
*/
function tokenMetadata(uint256 _tokenId) public constant returns (string infoUrl);
// Events
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
}
我们可以看到ERC721协议其实和ERC20协议还是很类似的,代币名称、代币符号、代币支持的小数位等等,然后在这基础上做了点改动,因为在ERC721中每个代币都将是唯一的一串Hash码,且代币是可以在各个持有者间相互转让的;所以有具备查询代币持有者地址的ownerOf函数、有根据持有者及索引查询持有的某个代币的tokenOfOwnerByIndex函数等等以上在代码里面都有所说明,这里就不做赘述;
好了现在我们来看看一个叫做ERC1155的标准;首先,我们要说下不管是ERC20系【可替代性通证】还是ERC721系【不可替代性通证】的token都具备的一个问题,对于一个项目中如果有几万种完全不同性质的东西,比如: 钱是钱、积分是积分、收藏品是收藏品那么我们需要部署几万种token的合约【不管是ERC20的还是ERC721的】那么问题来了,首先这几万种合约里面必然有大量的重复代码,但是矿工们依然会把这几万种合约都上链,【注意我说的是在一个项目里面,比如: 游戏项目】,所以给每一个不同的物品设立一个独立的合约,这产生的巨大成本和之后带来的管理费用,都将是几乎让人无法承受的,那么ERC1155就是为了解决这种问题而生的,现在『物品』(可能包含ERC20的token或ERC721的token或两者都有)可以被单一的一个合约(打包处理)来定义了。合约里包含区别token们所需的最小量的数据。好比,后来出现的视频压缩技术,后一帧只记录了与前一帧的不同之处,所以极大的压缩了整个视频的体积(老板说你确定你举得这个栗子真的能更好更简单的说明这个问题??)合约的状态包含了每个token ID的配置信息和管理收集的所有行为。ERC-1155的灵活性更强,它使得开发者可以自行选择是批量生成某一种特定的token,还是构建不可被复制的惟一元数据;说白点就是说ERC1155可以把一种token换成为另外一种token,最大进步就是可以融合不同token(可能是『可替换』的代币与『不可替换』的代币的混合体)进行『打包处理』;好了废话不多说,我们上代码,下面是一个ERC1155的合约标准
pragma solidity ^0.4.16;
/**
针对 可替代token的
https://github.com/ethereum/EIPs/issues/1155
*/
contract ERC1155 {
// Events
event Approval(address indexed _owner, address indexed _spender, uint256 indexed _itemId, uint256 _value);
event Transfer(address indexed _from, address indexed _to, uint256 indexed _itemId, uint256 _value);
// Required Functions
/**
【两个方法一个处理单个的一个批量处理】 【请参照 ERC20的transfer函数】
将每个itemId[]的数量转移到指定的地址。
每个参数数组应该是相同的长度,每个索引都是相关的。
必须触发 Transfer事件
itemId 可以看做是某个特定的tokenId
*/
function transfer(address _to, uint256 _itemId, uint256 _value) external;
function batchTransfer(address _to, uint256[] _itemIds, uint256[] _values) external;
/**
【两个方法一个处理单个的一个批量处理】 【请参照 ERC20的transferFrom函数】
将每一个itemId[]的数量从一个或多个地址转移到指定地址。
每个参数数组应该是相同的长度,每个索引都是相关的
必须触发 Transfer事件
itemId 可以看做是某个特定的tokenId
*/
function transferFrom(address _from, address _to, uint256 _itemId, uint256 _value) external;
function batchTransferFrom(address _from, address _to, uint256[] _itemIds, uint256[] _values) external;
/**
【两个方法一个处理单个的一个批量处理】 【请参照 ERC20的approve函数】
批准一个帐户可以替代表另一个帐户(使用转账)转移最大数量的多个itemId数目
必须触发 Approval事件
*/
function approve(address _spender, uint256 _itemId, uint256 _value) external;
function batchApprove(address _spender, uint256[] _itemIds, uint256[] _values) external;
/**
增加一个或多个itemId的余量,而不需要重置为0 【及变更approve函数指定的允许转移量??】
必须触发 Approval事件
*/
function increaseApproval(address _spender, uint256 _itemId, uint256 _addedValue) external;
function batchIncreaseApproval(address _spender, uint256[] _itemIds, uint256[] _addedValues) external;
/**
减少一个或多个itemId的余量,而不需要重置为0
必须触发 Approval事件
*/
function decreaseApproval(address _spender, uint256 _itemId, uint256 _subtractedValue) external;
function batchDecreaseApproval(address _spender, uint256[] _itemIds, uint256[] _subtractedValues) external;
// Required View Functions
function totalSupply(uint256 _itemId) external view returns (uint256);
/**
根据对应的tokenId查看余额
*/
function balanceOf(uint256 _itemId, address _owner) external view returns (uint256);
/**
根据对应的tokenId及拥有者及代替拥有者花钱者(注意 钱还是话拥有者的,只是拥有者给予某些权力给 第三者可以挪用她的部分资金) 具体参照ERC20 自明
*/
function allowance(uint256 _itemId, address _owner, address _spender) external view returns (uint256);
// Optional View Functions
function name(uint256 _itemId) external view returns (string);
function symbol(uint256 _itemId) external view returns (string);
function decimals(uint256 _itemId) external view returns (uint8);
}
/**
针对不可替代token的拓展
*/
contract ERC1155NonFungible {
// Optional Functions for Non-Fungible Items
/**
For NFTs, this returns the owner of a specific _itemId.
在【 Non-Fungible Items】,返回当前tokenId 所属者 【参照ERC721】
*/
function ownerOf(uint256 _itemId) external view returns (address);
/**
返回当前tokenId的描述的URL 【参照ERC721】
*/
function itemURI(uint256 _itemId) external view returns (string);
/**
列举可用的Non-Fungible Items
*/
function itemByIndex(uint256 _itemId, uint128 _index) external view returns (uint256);
/**
列举分配给所有者的Non-Fungible Items
*/
function itemOfOwnerByIndex(uint256 _itemId, address _owner, uint128 _index) external view returns (uint256);
}
基本上就是ERC1155的注释说明。还有最后说一个ERC165标准,废话少说上代码,自己看注释就知道ERC165是干什么的了,顺便说一下CryptoKities合约里面有实现了ERC165的,实在懒得编了
/**
这个才是 ERC165 标准
就是一个接口 里面就一个方法
创建标准方法以发布和检测智能合约实现的接口
ERC165同样是一个合约标准,这个标准要求合约提供其实现了哪些接口,
这样再与合约进行交互的时候可以先调用此接口进行查询。
interfaceID为函数选择器,计算方式有两种,
如:bytes4(keccak256('supportsInterface(bytes4)'));
或ERC165.supportsInterface.selector,多个函数的接口ID为函数选择器的异或值
此功能必须返回一个bool并使用最多30,000gas
*/
interface ERC165 {
/// @notice Query if a contract implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// uses less than 30,000 gas.
/// @return 'true' if the contract implements 'interfaceID' and
/// 'interfaceID' is not 0xffffffff, 'false' otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
OK〜那么我们ERC系列都就暂时写到这里,因为这一些列的问题实在是太多了如果想看,请自行去gayhub【github上我自己习惯叫gayhub】Ethereum的EIPs里面的issue里面去看吧,(注:想看什么标准就看问是否有,我们可以这样看https://github.com/ethereum/EIPs/issues/XXX,其中XXX就是ERCXXX里面的数字也就是ERC20就看https:/ /github.com/ethereum/EIPs/issues/20)
好了,夜深了,各位晚安〜