ERC系列协议标准

ERC系列协议标准

(一)概述

  在以太坊中,发布智能合约是自由的。但是,很多第三方想要做的事情可能有所类似,故延伸出来了许多基于以太坊的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等等合约协议规

 

(二)例子

1.ERC20

;下面先从最常用的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 的损失已经发生了;

 

2.ERC223

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 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.sig4字节的功能签名  */

    }

}

【注意:】将在接收方合约中调用的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 * * 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];

    }

}
View Code

以上ERC223标准的token发币合约示例表示,当需要调用交易函数把ERC223标准token交易给某个合约地址时,要求合约必须具备tokenFallback函数【合约开发人员希望他们的合约使用指定的token,那么合约开发人员必须实现tokenFallback,并使用参数address,uint256,bytes。 此函数必须具有0xc0ee0b8a签名】,否则转账失败;现有的代币肯定是大部分基于 ERC20 标准的,迁移难度很大,毕竟这个事情需要大家一起动。至于新的代币,很多已经开始使用 ERC223 标准了,目前已经超过了三万种(某位网上的博主说的,不是我说的。。。)

 

以上介绍了两种可以发行 【可代替性通证】的合约,(可代替性就是可以代替所有没有唯一性的事物,如:钱、积分等);

 

3.ERC721

下面开始研究针对【不可代替性的事物】的一些合约标准,【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);

}

 
View Code

可以看到ERC721协议其实和ERC20协议还是很类似的,代币名称、代币符号、代币支持的小数位等等,然后在这基础上做了点改动,因为在ERC721中每个代币都将是唯一的一串Hash码,且代币是可以在各个持有者间相互转让的;所以有具备查询代币持有者地址的ownerOf函数、有根据持有者及索引查询持有的某个代币的tokenOfOwnerByIndex函数等等以上在代码里面都有所说明,这里就不做赘述;

4.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);

}

 
View Code

基本上就是ERC1155的注释说明。

5.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);

}
View Code

OK〜 因为这一些列的问题实在是太多了如果想看,请自行去github 中里Ethereum的EIPs里面的issue里面去看吧,(注:想看什么标准就看问是否有,我们可以这样看https://github.com/ethereum/EIPs/issues/XXX,其中XXX就是ERCXXX里面的数字也就是ERC20。

例如:https://github.com/ethereum/EIPs/issues/20

 

posted @ 2021-12-09 15:38  SoyWang  阅读(1172)  评论(0编辑  收藏  举报