1、摘要
透過本文學習,瞭解ERC定義及知名ERC協議標準,如ERC20以及ERC223、ERC621.ERC777.ERC827.ERC1410協議; ERC721以及 ERC875.ERC1155.ERC998協議,ERC 865等描述和定義。
2、ERC的定義及標準列表
ERC代表“Etuereum Request for Comment”,這是Ethereum版的意見徵求稿 (RFC),RFC是由網際網路工程任務組制定的一個概念。 RFC中的備忘錄包含技術和組織注意事項。 對於ERC,意見徵求稿中包括一些關於以太坊網路建設的技術指導。
ERC是Ethereum開發者為以太坊社羣編寫的。 因此,ERC的建立流程中包括開發人員。 為了建立一個以太坊平臺的標準,開發人員應當提交了一個以太坊改進方案(EIP), 改進方案中包括協議規範和合約標準。 一旦EIP被委員會批准並最終確定,它就成為ERC。 EIP的完整列表可以在GITHUB網址找到。
EIP有4種狀態:
草稿(Draft) - 處於開啟狀態,便於考察討論;
接受(Accepted) - 即將被接受,例如將包含在下一個硬分叉中;
定稿(Final)- 在上一個硬分叉中被接受,已定稿;
延期(Deferred)- 不會馬上被接受,但也許在將來的硬分叉版本會考慮。
最終確定的EIP為以太坊開發者提供了一套可實施的標準。 這使得智慧合約可以遵循這些通用的介面標準來構建。
ERC-20是整個加密社羣中最為人熟知的標準,在Ethereum平臺之上釋出的大多數通證(token)都使用它。
3、ERC20系列 – ERC20、ERC223、ERC621、ERC777、ERC827、ERC1400
3.1 ERC20標準
狀態:
定稿(Final)
提交記錄:
https://github.com/ethereum/EIPs/issues/20
標準說明:
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
推薦樣例:
https://github.com/OpenZeppelin/openzeppelin-solidity/tree/master/contracts/token/ERC20
ERC-20標準中定義了以下函式介面:
totalSupply():
返回代幣供給總量
balanceOf(address _owner):
返回_owner的帳戶餘額
transfer(address _to,uint256 _value):
並將數量為_value的代幣轉入地址_to並觸發transfer事件
transferFrom(address _from,address _to,uint256_value):
將地址_from中的_value數量的代幣轉入地址_to ,並觸發transfer事件
approve(address _spender,uint256 _value):
允許_spender提取限額_value的代幣
allowance(address _owner,address _spender):
返回_spender可從_owner提款的代幣數量上限
ERC-20於2015年提出並於2017年9月正式實施。這是代幣標準化的一個很好的起點。 然而,開發者社羣 已經注意到它存在一些缺陷和漏洞,此外,還有一些場景它不能很好的滿足。因此陸續提出了其他的ERC標準。
3.2 ERC223
狀態:
草稿(Draft)
提交記錄:
https://github.com/ethereum/EIPs/issues/223
標準說明:
https://github.com/Dexaran/ERC223-token-standard
推薦樣例:
https://github.com/Dexaran/ERC223-token-standard/tree/Recommended
開發人員Dexaran在一篇文章中詳細描述了ERC20不適合的兩種場景:
“在ERC20中執行交易有兩種方式:transfer函式,approve + transferFrom機制,通證餘額只是通證合約中的一個變數。
通證的交易是合約內部變數的變化。 轉出賬戶的餘額將減少,轉入賬戶的餘額將增加。
交易發生時, transfer()函式不會通知轉入賬戶。 因此轉入賬戶將無法識別傳入的交易! 我寫了一個例子,可以展示這一導致未處理的交易和資金損失的過程 。
因此,如果接收賬戶是合約賬戶,那麼必須使用approve + transferFrom機制來傳送通證。
如果接受賬戶是外部帳戶,則必須透過transfer函式傳送通證。 如果選擇了錯誤的機制,通證將卡在合約內(合約將不會識別交易),沒有辦法來提取這些卡殼的通證。“
他對這個問題提出的解決方案包含在ERC-223中 。 它與ERC-20標準非常相似,但解決了上述問題。當通證轉移到智慧合約賬戶時,該合約的特殊函式tokenFallback() 允許接收方合約拒絕令牌或觸發進一步的操作。 大多數情況下,這可以用來代替approve()函式。
函式介面:
transfer(address _to, uint _value):
會區分代幣是發往外部賬戶地址還是發往智慧合約地址。
transfer(address _to, uint _value, bytes _data):
會區分代幣是發往外部賬戶地址還是發往智慧合約地址,還可以傳送資料。
1、如果_to是合約,則此函式必須傳輸令牌並調_to中的函式tokenFallback(address,uint256.bytes)。
2、如果_to(接收方合同)中沒有實現tokenFallback函式,則事務必須失敗,並且不會發生令牌的傳輸。
3、如果_to是外部擁有的地址,則必鬚髮送事務,而不嘗試在_to中執行tokenFallback。
4、_data可以附加到這個令牌交易中,它將永遠保持在塊狀(需要更多的gas)。 _data可以是空的。
注意:檢查_to是合約還是地址的推薦方法是組裝_to的程式碼。 如果_to中沒有程式碼,那麼這是一個外部擁有的地址,否則就是一個合約。
//assemble the given address bytecode. If bytecode exists then the _addr is a contract.
function isContract(address _addr) private view returns (bool is_contract) {
uint length;
assembly {
//retrieve the size of the code on target address, this needs assembly
length := extcodesize(_addr)
}
return (length>0);
}
function tokenFallback(address _from, uint _value, bytes _data)
_from是令牌傳送者,_value是傳入令牌的數量,_data是附加的資料,類似於Ether事務中的資料。 適用於以太交易的回退功能,並且不返回任何內容。
tokenFallback — 令牌持有者傳送令牌時處理從令牌合同所呼叫的令牌傳輸的功能
注意:msg.sender將是tokenFallback函式內的令牌合同。 過濾哪些令牌(透過令牌契約地址)傳送可能很重要。 令牌傳送者(誰發起了代幣交易的人)在_from thetokenFallback函式內。
示例程式碼:
ERC223_Interface.sol
pragma solidity ^0.4.9;
/* 新的 ERC23 contract 介面檔案 */
contract ERC223 {
uint public totalSupply;
function balanceOf(address who) constant returns (uint);
function name() constant returns (string _name);
function symbol() constant returns (string _symbol);
function decimals() constant returns (uint8 _decimals);
function totalSupply() constant returns (uint256 _supply);
function transfer(address to, uint value) returns (bool ok);
function transfer(address to, uint value, bytes data) returns (bool ok);
function transfer(address to, uint value, bytes data, string custom_fallback) returns (bool ok);
event Transfer(address indexed from, address indexed to, uint value, bytes indexed data);
}
Receiver_Interface.sol
pragma solidity ^0.4.9;
/*
* Contract that is working with ERC223 tokens
*/
contract ContractReceiver {
struct TKN {
address sender; //呼叫合約的人
uint value;
bytes data;
bytes4 sig; //簽名
}
function tokenFallback(address _from, uint _value, bytes _data){
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位元組的功能簽名
* 如果令牌事務的資料是一個函式執行
*/
}
}
ERC223_Token.sol
pragma solidity ^0.4.9;
import "./Receiver_Interface.sol";
import "./ERC223_Interface.sol";
/**
* ERC23 token by Dexaran
*
* https://github.com/Dexaran/ERC23-tokens
* 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) throw;
return x + y;
}
function safeSub(uint256 x, uint256 y) constant internal returns (uint256 z) {
if (x < y) throw;
return x - y;
}
function safeMul(uint256 x, uint256 y) constant internal returns (uint256 z) {
if (y == 0) return 0;
if (x > MAX_UINT256 / y) throw;
return x * y;
}
}
//示例的智慧合約程式碼
contract ERC223Token is ERC223. SafeMath {
mapping(address => uint) balances;
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;
// 獲取token的名稱
function name() constant returns (string _name) {
return name;
}
// 獲取token的符號
function symbol() constant returns (string _symbol) {
return symbol;
}
// 獲取token精確到小數點後的位數
function decimals() constant returns (uint8 _decimals) {
return decimals;
}
// 獲取token的釋出總量
function totalSupply() constant returns (uint256 _totalSupply) {
return totalSupply;
}
// 當使用者或其他合同想要轉移資金時呼叫的功能。
function transfer(address _to, uint _value, bytes _data, string _custom_fallback) returns (bool success) {
//如果to是合約
if(isContract(_to)) {
if (balanceOf(msg.sender) < _value) throw; //如果當前的餘額不夠就丟擲
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) 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) returns (bool success) {
//類似於沒有_data的ERC20傳輸的標準功能傳輸
//由於向後相容性原因而增加
bytes memory empty;
if(isContract(_to)) {//如果是合約
return transferToContract(_to, _value, empty);
}
else {
return transferToAddress(_to, _value, empty);
}
}
//組裝定地址位元組碼。 如果存在位元組碼,那麼_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) throw;
balances[msg.sender] = safeSub(balanceOf(msg.sender), _value);
balances[_to] = safeAdd(balanceOf(_to), _value);
Transfer(msg.sender, _to, _value, _data);
return true;
}
//當傳遞目標是一個合約時呼叫函式
function transferToContract(address _to, uint _value, bytes _data) private returns (bool success) {
if (balanceOf(msg.sender) < _value) throw;
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) constant returns (uint balance) {
return balances[_owner];
}
}
3.3 ERC621
狀態:
草稿(Draft)
提交記錄:
https://github.com/ethereum/EIPs/issues/621
標準說明:
推薦樣例:
https://github.com/skmgoldin/EIP621Token/blob/master/contracts/EIP621Token.sol
ERC-621是ERC-20標準的擴充套件。 它增加了兩個額外的功能, increaseSupply和decreaseSupply 。這可以增加和減少流通中的令牌供應。 ERC-20只允許單一的通證發放事件。 這將供應量限制在一個固定的不可改變的數目。 ERC-621建議totalSupply應當是可修改的。
介面函式說明:
increaseSupply(uint value, address to):
可以給特定賬戶to增加value值的供應量,代幣總供應量totalSupply也同步增加;
decreaseSupply(uint value, address from):
可以給特定賬戶to減少value值的賬戶餘額,代幣總供應餘額totalSupply也同步減少;
3.4 ERC777
狀態:
草稿(Draft)
提交記錄:
https://github.com/ethereum/EIPs/issues/777
標準說明:
https://eips.ethereum.org/EIPS/eip-777
推薦樣例:
https://github.com/jacquesd/ERC777/tree/devel/contracts
功能描述
本標準用於提升ERC20標準的使用範圍。這個標準的主要優點有:
可以同使用Ether一樣的原理使用ERC777通證,通證傳送採用函式send(dest, value, data)的。
不管是合約還是常規的地址都可以控制和拒絕那些透過註冊tokensToSend 鉤函式傳送的通證(透過在鉤函式內部執行reverting回滾函式觸發拒絕。)
不管是合約還是常規的地址都可以控制和拒絕那些透過註冊tokensToSend 鉤函式接收的通證(透過在鉤函式內部執行reverting回滾函式觸發拒絕。)
tokensReceived 勾函式執行傳送通證給一個合約,並在一次交易中通知完成,不像ERC20需要2次通知(approve/transferFrom) 才能達到相同效果。
通證持有者可以“授權”和“撤銷”可以代表他們傳送通證的操作員。這些操作員用於驗證合約,如交易所,支票處理器或自動收費系統。
每次通證交易都包含一個“data”位元組欄位和一個類似的“operatorData”,可以自由地用於將資料傳遞給接收方。
透過部署實現錢包的“tokensReceived”鉤子的代理合約,它與不包含“tokensReceived”鉤子功能的錢包向後相容。
協議程式碼
interface ERC777Token {
function name() public view returns (string);
function symbol() public view returns (string);
function totalSupply() public view returns (uint256);
function balanceOf(address owner) public view returns (uint256);
function granularity() public view returns (uint256);
function defaultOperators() public view returns (address[]);
function authorizeOperator(address operator) public;
function revokeOperator(address operator) public;
function isOperatorFor(address operator, address tokenHolder) public view returns (bool);
function send(address to, uint256 amount, bytes data) public;
function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) public;
function burn(uint256 amount, bytes data) public;
function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) public;
event Sent(
address indexed operator,
address indexed from,
address indexed to,
uint256 amount,
bytes data,
bytes operatorData
);
event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);
event Burned(address indexed operator, address indexed from, uint256 amount, bytes operatorData);
event AuthorizedOperator(address indexed operator, address indexed tokenHolder);
event RevokedOperator(address indexed operator, address indexed tokenHolder);
}
3.5 ERC827
狀態:
草稿(Draft)
提交記錄:
https://github.com/ethereum/EIPs/issues/827
標準說明:
推薦樣例:
https://github.com/windingtree/erc827/blob/master/contracts/ERC827/ERC827Token.sol
它允許轉讓通證並允許持有人允許第三方使用通證。 以太坊上的通證可以被其他應用程式重複使用,這其中也包括錢包和交易所。 當需要支援第三方動態消費限額調整時這一點非常有用。
該標準目前處於草稿狀態,並被證明有使用安全風險,建議暫不使用。
3.6 ERC1400(ERC1410.ERC1411)
狀態:
草稿(Draft)
提交記錄:
1)ERC 1410: Partially Fungible Token Standard:
https://github.com/ethereum/EIPs/issues/1410
2)ERC 1400: Security Token Standard #1411
https://github.com/ethereum/EIPs/issues/1411
標準說明
推薦樣例:
https://blog.neufund.org/good-protocols-how-to-properly-standardize-security-tokens-95ff83c81c4a
標準說明
無論是 ERC20 還是 ERC777.每個單位的 Token 都是相同的,並無附加屬性,屬於 fungible token(同質化代幣/可互換 Token)。ERC721標準的 Token,每個 Token 均有不同的ID,不同ID可以有不同的解釋,屬於 no-fungible token(非同質化 Token,不可互換 Token)。
ERC1410標準的 Token 屬於Partially-Fungible Token (部分可互換 Token ),將 ERC20/ERC777 中不存在解釋屬性的餘額,附加額外的資訊,從而劃分成不同的部分,就可以做一些操作上的限制(例如:某些操作只限定於指定 tranche 的 Token,某些操作優先消耗指定tranche的 Token)。
ERC1400 則是繼承 ERC1410 標準,增加了證券相關業務會使用到的函式:證券增發,相關法律檔案儲存等。
先前一些證券型 Token 的合約大多是在 ERC20 標準的基礎上,透過維護一個或多個以太坊地址集合,對這部分地址做出了劃分:是否透過kyc,是否處於鎖定期等,來進行轉賬上的限制。這些都是在地址層面做出不同的解釋。而 ERC1400 對 Token 本身做了不同解釋,以適用於更復雜的證券相關業務場景。
關於ERC20.以及其它ERC成員的關係,可見下圖:
函式介面說明
/// @title ERC-1410 Partially Fungible Token Standard
/// @dev See https://github.com/SecurityTokenStandard/EIP-Spec
interface IERC1410 is IERC777 {
// Token Information
function balanceOfByTranche(bytes32 _tranche, address _tokenHolder) external view returns (uint256);
function tranchesOf(address _tokenHolder) external view returns (bytes32[]);
// Token Transfers
function sendByTranche(bytes32 _tranche, address _to, uint256 _amount, bytes _data) external returns (bytes32);
function sendByTranches(bytes32[] _tranches, address _to, uint256[] _amounts, bytes _data) external returns (bytes32[]);
function operatorSendByTranche(bytes32 _tranche, address _from, address _to, uint256 _amount, bytes _data, bytes _operatorData) external returns (bytes32);
function operatorSendByTranches(bytes32[] _tranches, address _from, address _to, uint256[] _amounts, bytes _data, bytes _operatorData) external returns (bytes32[]);
// Default Tranche Management
function getDefaultTranches(address _tokenHolder) external view returns (bytes32[]);
function setDefaultTranche(bytes32[] _tranches) external;
// Operators
function defaultOperatorsByTranche(bytes32 _tranche) external view returns (address[]);
function authorizeOperatorByTranche(bytes32 _tranche, address _operator) external;
function revokeOperatorByTranche(bytes32 _tranche, address _operator) external;
function isOperatorForTranche(bytes32 _tranche, address _operator, address _tokenHolder) external view returns (bool);
// Transfer Events
event SentByTranche(
bytes32 indexed fromTranche,
address operator,
address indexed from,
address indexed to,
uint256 amount,
bytes data,
bytes operatorData
);
event ChangedTranche(
bytes32 indexed fromTranche,
bytes32 indexed toTranche,
uint256 amount,
);
// Operator Events
event AuthorizedOperator(address indexed operator, address indexed tokenHolder);
event RevokedOperator(address indexed operator, address indexed tokenHolder);
event AuthorizedOperatorByTranche(bytes32 indexed tranche, address indexed operator, address indexed tokenHolder);
event RevokedOperatorByTranche(bytes32 indexed tranche, address indexed operator, address indexed tokenHolder);
}
/// @title IERCST Security Token Standard (EIP 1400)
/// @dev See https://github.com/SecurityTokenStandard/EIP-Spec
interface IERCST is IERCPFT {
// Document Management
function getDocument(bytes32 _name) external view returns (string, bytes32);
function setDocument(bytes32 _name, string _uri, bytes32 _documentHash) external;
// Controller Operation
function isControllable() external view returns (bool);
// Token Issuance
function isIssuable() external view returns (bool);
function issueByTranche(bytes32 _tranche, address _tokenHolder, uint256 _amount, bytes _data) external;
event IssuedByTranche(bytes32 indexed tranche, address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);
// Token Redemption
function redeemByTranche(bytes32 _tranche, uint256 _amount, bytes _data) external;
function operatorRedeemByTranche(bytes32 _tranche, address _tokenHolder, uint256 _amount, bytes _operatorData) external;
event RedeemedByTranche(bytes32 indexed tranche, address indexed operator, address indexed from, uint256 amount, bytes operatorData);
// Transfer Validity
function canSend(address _from, address _to, bytes32 _tranche, uint256 _amount, bytes _data) external view returns (byte, bytes32. bytes32);
}
4、ERC721系列
4.1 ERC721
狀態:
定稿(Final)
提交記錄:
https://github.com/ethereum/EIPs/issues/721
標準說明:
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
推薦樣例:
1)https://www.cryptokitties.co/
2)https://github.com/OpenZeppelin/openzeppelin-solidity/tree/master/contracts/token/ERC721
ERC-721與ERC-20和ERC-223都大不相同。 它描述了一個不可互換的通證,官方簡要解釋是Non-Fungible Tokens,簡寫為NFTs,多翻譯為非同質代幣。 這意味著每個通證是完全不同的,並且每個通證對不同的使用者都有不同的價值。 理解這種通證的一個方法就是回憶CryptoKittes。 每一個數字貓都是獨立的,其價值取決於其稀缺性和使用者的購買慾。
ERC-721令牌可用於任何交易所,但通證價值是“每個通證的唯一性和稀缺性所決定的結果”。標準中規定的介面函式包括name、symbol、totalSupply、balanceOf、ownerOf、approve、takeOwnership 、 transfer 、tokenOfOwnerByIndex和tokenMetadata 。 它還定義了兩個事件: Transfer和Approval 。 Gerald Nash的 這篇文章很好地解釋了可互換性的概念。
函式介面說明:
balanceOf(address _owner):
返回由_owner 持有的NFTs的數量。
ownerOf(uint256 _tokenId):
返回tokenId代幣持有者的地址。
exists(uint256 _tokenId):
tokenId代幣是否存在,返回BOOL值;
approve(address _to, uint256 _tokenId):
授予地址_to具有_tokenId的控制權,方法成功後需觸發Approval 事件。
getApproved(uint256 _tokenId):
獲得_tokenId授權的地址;
setApprovalForAll(address _operator, bool _approved):
授予地址_operator具有所有NFTs的控制權,成功後需觸發ApprovalForAll事件。
isApprovedForAll(address _owner, address _operator):
用來查詢授權。
transferFrom(address _from, address _to, uint256 _tokenId)
不建議使用本函式,建議使用safeTransferFrom函式。
safeTransferFrom(address _from, address _to, uint256 _tokenId):
把_tokenId代幣從_from賬戶安全轉移到_to賬戶,安全是指如果目標地址為合約地址,則執行onERC721Received進行資產轉移,否則的話交易會回滾;如果目標地址為外部賬號地址,則正常轉移。
更深度分析的文章參考《【基於ERC721的區塊鏈遊戲】迷戀貓從玩耍到開發》。
4.2 ERC875
狀態:
還處於pull request下(issue)
提交記錄:
https://github.com/ethereum/EIPs/issues/875
標準說明:
推薦樣例:
https://github.com/alpha-wallet/ERC875-Example
AlphaWallet自主開發了ERC875協議族。該協議不僅會讓數字資產變得具有收藏價值,同時也能幫助現實世界中不可拆分替代、具有物權唯一性的資產上鍊,這就能為線下服務的鏈上操作提供了可能性。
雖然另一種協議ERC721也能實現token的不可置換性,但其存在需要交易雙方支付gas費用、無法簡單實現原子化交易等一些不易於使用者使用的問題。
ERC875內建了兩個密碼學協議, 一方面能夠簡單實現原子化交易(atomic swap)——直接搭建去中心化市場、降低普通使用者使用門檻,賣家無需持有以太幣,買家支付一次gas即能完成;另外一方面可以簡單打包處理大量交易。
拿基於ERC721的加密貓來說,換用ERC875協議的話,能夠實現。使用者在商家網站法幣購貓,透過MagicLink免費把貓匯入使用者的錢包,之後使用者還可以在不需要持有以太幣的情況下,透過MagicLink把貓售出或者免費轉讓,全部過程都是無中心的原子化交易。另外商家可以一次批發100只貓給分銷商。
介面函式或者變數說明
totalTickets:
inventory:
ticketIndex:
expiryTimeStamp:
owner:
admin:
transferFee:
numOfTransfers:
name:
symbol:
decimals:
Token(uint256[] numberOfTokens, string evName,uint expiry, string eventSymbol, address adminAddr):
構建函式,樣例如example: [1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15], “MJ comeback”, 1603152000. “MJC”, “0x007bEe82BDd9e866b2bd114780a47f2261C684E3″]
getDecimals():
返回代幣的小數點後位數值;
trade(uint256 expiry,uint256[] tokenIndices,uint8 v,bytes32 r,bytes32 s):
交易函式,例如:0. [3. 4], 27. “0x2C011885E2D8FF02F813A4CB83EC51E1BFD5A7848B3B3400AE746FB08ADCFBFB”, “0x21E80BAD65535DA1D692B4CEE3E740CD3282CCDC0174D4CF1E2F70483A6F4EB2″
encodeMessage(bytes12 prefix, uint value,uint expiry, uint256[] tokenIndices):
name():
返回代幣名稱;
symbol():
返回代幣表示;
getAmountTransferred():
返回已傳輸的數量;
isContractExpired():
合約是否過期;
balanceOf(address _owner):
返回賬戶餘額;
myBalance():
transfer(address _to, uint256[] tokenIndices):
資產轉賬;
transferFrom(address _from, address _to, uint256[] tokenIndices):
endContract():
結束合約;
getContractAddress():
獲取合約地址;
4.3 ERC998
狀態:
草稿(Draft)
提交記錄:
https://github.com/ethereum/EIPs/issues/998
標準說明:
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-998.md
推薦樣例:
https://github.com/mattlockyer/composables-998
不同的ERC代幣可以被相容的ERC-998代幣既代表一組相似資產(ERC-20代幣),一種獨特資產的分類(ERC-721代幣),或者內嵌於單比交易的混合體。
這個協議是以不可以替代代幣為基礎的全新複雜型數字資產。一個ERC-998代幣可以作為一個數字資產投資組合。
中心資產和輔助資產的結合
第一個使用案例是可以和不同數字資產和零件結合外加附加增值功能的中心NFT幣。增值可以透過個人花費時間和精力,或者購買來實現。
在奢侈品行業裡,這些可以作為應用於不同時尚品牌的“外表”和“包裝”。 比如說,中心的不可替代貨幣是外表,可以輔助鞋子和錢包,每一個都代表了他們自己的NFT。這一整個套裝都作為一部分組合到ERC-998代幣裡面。
單一資產的幾個組成部分
作為附加債券的一部分,單一的數字資產可以被ERC-998代幣群組所代表。因為每一個部分都是由自己的NFT被獨特的體現出來的,NFT代幣組合可以保證貨品的絕對真實性。然而,除非依附於實際商品的形式,每一個NFT都沒有自己的價值。這是一個可以附加在類似手錶,珠寶這樣價值商品上的非常強勢的防偽手段。
上圖所示為勞力士的三個元件,每個元件都有一個單獨的序列號 – 錶殼、表面和指標。單獨來看,這些部件幾乎沒有任何價值,但它們一起構成了一個真正的勞力士手錶,由一個ERC-998代幣所代表。
分組集合
通常被認為是組合的任何東西,例如一副牌,一本歷史郵票或罕見的硬幣收集等,可以在一個組合型代幣下結合在一起。因此,完整的組合可以由單個數字資產表示。
大多數奢侈品牌都有很大眾的產品,每年都會使用重新設計的型號,這些產品往往成為收藏品。在奢侈品戰略下,消費者購買經典和品牌,這些都是透過多年來產品的演變出來的。作為上圖中的示例,該品牌在三年內釋出了其第一、二、三代模型,這些模型被分組為一個組合代幣。
同時,這也更為品牌加強與老客戶的聯絡。例如,如果使用者可以透過Smart-Links這樣可組合的代幣,顯示他們對某個品牌的所有收藏品,那麼該品牌將能夠透過獨家邀請和優惠來獎勵這位客戶。
4.4 ERC1155
狀態:
草稿(Draft)
提交記錄:
https://github.com/ethereum/EIPs/issues/1155
標準說明:
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
推薦樣例:
https://enjincoin.io/
ERC-1155是一種定義token的新標準,1155是這種方法的編號。1155標準定義了一種解決上述問題的新方法。現在『物品』(可能包含ERC20的token或ERC721的token或兩者都有)可以被單一的一個合約(打包處理)來定義了。合約裡包含區別token們所需的最小量的資料。合約的狀態包含了每個token ID的配置資訊和管理收集的所有行為。ERC-1155的靈活性更強,它使得開發者可以自行選擇是批次生成某一種特定的token,還是構建不可被複制的惟一後設資料。
ERC-1155支援原子交換,“原子交換”是指不透過中介物而將一種token換成為另外一種token。
ERC-1155的最大進步就是可以融合不同token(可能是“可替換”的代幣與“不可替換”的代幣的混合體)進行“打包處理”。
函式介面說明:
name(uint256 _itemId):
symbol(uint256 _itemId):
decimals(uint256 _itemId):
totalSupply(uint256 _itemId):
balanceOf(uint256 _itemId, address _owner):
allowance(uint256 _itemId, address _owner, address _spender):
transfer(uint256[] _itemId, address[] _to, uint256[] _value):
transferFrom(uint256[] _itemId, address[] _from, address[] _to, uint256[] _value):
approve(uint256[] _itemId, address[] _spender, uint256[] _value):
increaseApproval(uint256[] _itemId, address[] _spender, uint256[] _addedValue):
decreaseApproval(uint256[] _itemId, address[] _spender, uint256[] _subtractedValue):
ownerOf(uint256 _itemId):
itemURI(uint256 _itemId):
itemByIndex(uint256 _itemId, uint256 _index):
itemOfOwnerByIndex(uint256 _itemId, address _owner, uint256 _index):
4.5 ERC1190
狀態:
還處於pull request下(issue)
提交記錄:
https://github.com/ethereum/EIPs/issues/1190
標準說明:
推薦樣例:
ERC1190的token將使每個數字物件的建立者(如藝術品或遊戲中的物品)在每次使用該物件時會自動受益,無論是下一秒還是幾年之後。
每位ERC1190 token的持證者都可以單獨持有“創造權”或“所有權”,當然也可以同時持有兩個權利。
ERC1190的三種獲益方式:
1.銷售“所有權”;
2.銷售“創造權”;
3.在固定時間內出租“所有權”。
一個數字產品的“所有權”持有者和“創造權”持有者透過以上三種方式都會自動獲得一定收益。
1. 創造者將擁有“創造權”和“所有權”
我們以網路遊戲中的“裝備”為例。
物品的建立者可以將物品及其所有權資訊嵌入到一個ERC1190 token中。
簡單來說,我在遊戲裡製造了一把劍並把他命名為“裂魂之劍”。
詳解以太坊token標準ERC1190
身為創造者的我就會擁有他的“創造權”和“所有權”。
如果我想銷售我的“裂魂之劍”那麼它的“所有權”將會被轉交給一個第三方參與者(此處我們將他定為玩家A),但是我還會保留它的“創造權”。
在這次銷售中,我一次性獲得了“所有權”帶來的收益,並會在將來的某個時刻獲得一定比例的“所有權”收益。
詳解以太坊token標準ERC1190
2. 如果“所有權”持有者再次發生轉換,創造者將會獲得收益
擁有“裂魂之劍”“所有權”的玩家可以永久持有該裝備,在遊戲裡如果這件裝備得到了更好的最佳化或者其他玩家因為某種原因喜歡上了這件裝備,那麼它的價格也必定會有所提高。
當玩家A決定銷售“裂魂之劍”的“所有權”給玩家B時,他會從中獲得高比例的收益,而擁有“創造權”的我將會獲得低比例的收益。
如:10%。(這個比例會在一開始設計該token的時候寫在協議上)每一次“所有權”的轉換,“創造權”持有者都會自動獲得售價10%的收益。
詳解以太坊token標準ERC1190
3. 如果“所有權”持有者出租了“裝備”,那麼創造者也可以獲得一定比例的租金
如果玩家B暫時不需要使用“裂魂之劍”。
他便有權將“裝備”出租給玩家C。按照規定,做為創造者的我將會獲得租金裡的10%,而這個過程也是可以無限迴圈的(任何一次有關“裝備”權益的轉換都需要支付給創造者一定比例的費用)。
其實不單單是在遊戲領域,在其它的的虛擬領域都可以進行這一活動,如影音,藝術等。人們不用再擔心複雜的交易流程和版權費問題了。
規則被寫入了智慧合約,基於區塊鏈技術,雙方的任何行為都會自動觸發後續動作。
詳解以太坊token標準ERC1190
4. 創造者銷售“創造權”
身為創造者的我有權出售“裂魂之劍”的“創造權”,並且我將會一次性的拿到所有收益,這其中的收益比銷售“所有權”所帶來的收益要高得多。
之後,新的“創造權”持有者在未來的“權益”轉換過程中會重複上面的步驟,只要他不出售自己的“創造權”,他將繼續重複獲得租金或“所有權”轉換所帶來的收益。
詳解以太坊token標準ERC1190
用一個現實世界的例子“房屋”來解釋,你擁有它的房產證並且擁有它的出租權,使用權。
你作為房產證的擁有者可以將房子的使用權出售給客人A,而客人A可以選擇將他的使用權賣給客人B或者將使用權出租給客人B。
而你依舊可以獲得一定比例的房租收益或售賣分紅,且最終房屋還是歸你所有。
當你賣掉了房產證之後才會從這個利益關係中徹底退出,之後任何的“權益”轉換也就和你沒有半毛錢關係!
函式介面:
function approve(address[] owners, uint royaltyForOwnershipTransfer, uint royaltyForRental) returns uint256;
說明:Function to initialize token and set the owner(s) and the royalty rates. Returns the unique token ID for the digital asset.
function transferCreativeLicense(address[] creativeLicenseHolders, address[] newOwners, uint256 tokenId);
說明: Function to transfer creative license of token。
function transferOwnershipLicense(address[] creativeLicenseHolders, address[] ownershipLicenseHolders, address newOwners[], uint256 tokenId);
說明:Function to transfer ownership license of token
function rentAsset(address[] creativeLicenseHolders, address[] ownershipLicenseHolders, address[] renters, uint256 tokenId);
說明:Function to rent asset
5、ERC865
狀態:
還處於pull request下(issue)
提交記錄:
https://github.com/ethereum/EIPs/issues/865
標準說明:
推薦樣例:
https://github.com/lavawallet/lava-wallet
以太坊開發者Bhaskar Sharma在Medium網站上發表了一篇文章,提出了一個在以太坊中使用對使用者更友好的代幣的提案,這一提案將允許使用者來採用去中心化應用程式(DApps)時使用代幣(tokens)來支付交易費用,而不是用以太幣ETH來支付。
他認為,以太坊區塊鏈中的費用支付問題為新手帶來了麻煩,這些費用用於支付礦工將交易打包到區塊並確保區塊鏈的安全。使用者必須認識以太坊的工作原理,這樣才能理解燃料(gas)價格和成本。使用者還需要獲得必要的以太幣來支付這兩種費用。
函式介面說明:
transferPreSigned(bytes _signature, address _to, uint256 _value, uint256 _gasPrice, uint256 _nonce):
approvePreSigned(bytes _signature, address _spender, uint256 _value, uint256 _gasPrice, uint256 _nonce):
**approveAndCallPreSigned(bytes _signature, address _spender, uint256 _value, bytes _extraData, uint256 _gasPrice, uint256 _nonce) **:
increaseApprovalPreSigned(bytes _signature, address _to, uint256 _amount, uint256 _gasPrice, uint256 _nonce):
decreaseApprovalPreSigned(bytes _signature, address _to, uint256 _amount, uint256 _gasPrice, uint256 _nonce):
revokeSignature(bytes _signature):
6、其他ERC協議
6.1 ERC165
狀態:
已定稿(Final)
提交記錄:
https://github.com/ethereum/EIPs/issues/165
標準說明:
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
ERC165定義以下功能:
1) 如何識別介面;
2) 一個智慧合約如何釋出它執行的介面;
3) 如何檢測一個智慧合約是否執行了ERC-165協議;
4) 如何檢測一個智慧合約是否執行了一個給定的介面;
7、參考
(1)以太坊官網ERC列表
(2)以太坊官網EIP提出列表