【我的区块链之路】- ERC系列协议标准详解

【转载请标明出处】: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文件;先看看

 

 

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.sig是4字节的功能签名  */
    }
}

 

【注意:】将在接收方合约中调用的token备用功能的函数必须命名为tokenFallback,并使用参数addressuint256,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];
    }
}

以上ERC223标准的token发币合约示例表示,当需要调用交易函数把ERC223标准token交易给某个合约地址时,要求合约必须具备tokenFallback函数【合约开发人员希望他们的合约使用指定的token,那么合约开发人员必须实现tokenFallback,并使用参数address,uint256bytes。 此函数必须具有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)

好了,夜深了,各位晚安〜

 

 

 

你可能感兴趣的:(区块链,以太坊,ERC系列标准)