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.sig是4字節的功能簽名 */
}
}
【注意:】將在接收方合約中調用的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]; } }
以上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); }
可以看到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); }
基本上就是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); }
OK〜 因為這一些列的問題實在是太多了如果想看,請自行去github 中里Ethereum的EIPs里面的issue里面去看吧,(注:想看什么標准就看問是否有,我們可以這樣看https://github.com/ethereum/EIPs/issues/XXX,其中XXX就是ERCXXX里面的數字也就是ERC20。
例如:看https://github.com/ethereum/EIPs/issues/20