衆所周知,以太坊在現階段最大的應用就是令牌發行,而在以太坊中有不少類型的令牌,最著名的當屬ERC20了,可是對於其餘幾種令牌類型,可能還有一些朋友不知道,因此最近規劃了一個系列,就是以太坊標準令牌系列。javascript
目前市面上,凡是基於以太坊的令牌,在交易所上線交易的均是ERC20令牌,那麼今天咱們就來聊聊ERC20令牌的標準方案吧。java
在基於以太坊發行令牌時,若是各個令牌發行方都使用自有標準去發行令牌,那對於錢包開發者以及交易所對接成本是極其高昂了,由於他們須要爲每一種令牌去獨立進行對接,爲了下降錢包開發者以及交易所的對接成本,以太坊社區制定了一個關於令牌的發行標準。編程
該標準中主要包含了,令牌的轉移,地址餘額的獲取等方法。app
一個令牌的合約,通常須要令牌的發行量,每一個地址的餘額,令牌的轉移等方法, 而ERC20標準就是將這些最經常使用又是必不可少的方法,對此進行標準化,方便開發者進行令牌合約的開發,也方便錢包開發者以及交易所對接成本降到最低。函數
其中,定義了三類,方法、屬性、事件。post
下面介紹這些標準方法:ui
function totalSupply() constant returns (uint256 totalSupply)
方法
該方法用於獲取令牌總髮行量spa
function balanceOf(address _owner) constant returns (uint256 balance)
方法
該方法用於獲取地址 _owner
的令牌餘額日誌
function transfer(address _to, uint256 _value) returns (bool success)
方法
該方法用於將調用令牌合約的地址中的_value
個令牌轉給_to
地址code
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
方法
該方法用於從_from
地址中發送_value
個令牌給_to
地址。
當你但願可以使用其餘智能合約控制你的令牌轉移,則可使用transferFrom
方法,而使用transferFrom
方法有一個前提條件,那就是須要調用者須要獲得 _from
地址的受權,才能夠進行令牌轉移的操做。而如何進行受權,咱們接下來會介紹。
function approve(address _spender, uint256 _value) returns (bool success)
方法
容許 _spender
地址從你的帳戶中轉移 _value
個令牌到任何地方。
當你設置了一個 _value
以後,_spender
地址能夠分任何屢次將令牌進行轉移,直至_value
爲0.
function allowance(address _owner, address _spender) constant returns (uint256 remaining)
方法
獲取 _owner
地址受權給 _spender
地址能夠轉移的令牌的餘額。
事件是EVM內置的日誌功能,並且在DAPP中,咱們能夠經過JS來監聽事件的回調。在ERC-20令牌中,定義瞭如下事件:
event Transfer(address indexed _from, address indexed _to, uint256 _value)
當進行令牌轉移時,須要觸發調用該事件。其中記錄了令牌發送者_from
,令牌接受者_to
,令牌發送量_value
.
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
當進行受權時,須要觸發調用該事件,其中記錄了受權者_owner
,被受權者_spender
,受權令牌量_value
經過以上的標準,咱們能夠了解到一個遵照ERC20令牌標準的令牌合約須要實現的方法,如下是經過規範實現的一個ERC20令牌的接口。
contract EIP20Interface { ///////////////////////////// 方法 /////////////////////////////////// // 獲取令牌發行量 // 注意:constant的修飾符是提示該方法中不能進行變量的修改。 // 但編譯器不會強制校驗。 // @return uint256 totalSupply 總髮行量 function totalSupply() constant returns (uint256 totalSupply) // 獲取指定地址 // @param address _owner 想要獲取的地址 // @return uint256 balance 令牌餘額 function balanceOf(address _owner) public view returns (uint256 balance); // 從`msg.sender`中發送`_value`個令牌給`_to` // @param address _to 接收令牌的地址 // @param uint256 _value 發送的令牌數量 // @return bool success 發送令牌成功狀態 function transfer(address _to, uint256 _value) public returns (bool success); // 從`_from`地址發送`_value`令牌到`_to`地址 // 須要知足條件,須要被`_from`地址受權給`msg.sender` // @param address _from 發送者地址 // @param address _to 接收者地址 // @param uint256 _value 發送的令牌數量 // @return bool success 發送令牌成功狀態 function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); // `msg.sender`受權`_spender`地址能夠任意轉移`_value`數量的令牌 // @param address _spender 被受權發送令牌的地址 // @param uint256 _value 受權發送令牌的數量 // @return bool success 受權成功狀態 function approve(address _spender, uint256 _value) public returns (bool success); /// @param _owner The address of the account owning tokens /// @param _spender The address of the account able to transfer the tokens /// @return Amount of remaining tokens allowed to spent // 獲取被受權限額 // @param address _owner 令牌全部者的帳戶 // @param address _spender 令牌被受權者帳戶 // @return uint256 remaining 剩餘可發送的令牌數量 function allowance(address _owner, address _spender) public view returns (uint256 remaining); ///////////////////////////// 事件 /////////////////////////////////// // 令牌轉移事件 當發生令牌的轉移時,須要調用該事件 event Transfer(address indexed _from, address indexed _to, uint256 _value); // 受權轉移事件 當進行受權時,須要觸發該事件 event Approval(address indexed _owner, address indexed _spender, uint256 _value); }
在標準的基礎上,有不少代碼的實現方法,好比有的在代碼中實現空投,有的在實現鎖定,有的實現挖礦等等,可是最常規的實現已經有了官方的實現代碼,也有不少組織實現了一些範例,若是沒有定製化的地方,徹底能夠直接採用這些代碼去建立ERC20令牌。
示例代碼:
pragma solidity ^0.4.18; contract ERC20 { // 定義一個mapping 存儲各個地址的令牌 mapping (address => uint256) public balances; // 定義一個mapping 存儲受權詳情 mapping (address => mapping (address => uint256)) public allowed; // 如下參數非必須,可是儘可能添加,大多數錢包會經過此獲取相關信息 // 令牌發行總量 uint256 public totalSupply; // 令牌名稱,如 OmiseGO string public name; // 支持的小數位數 // 由於在EVM中對浮點數的支持不好,在令牌的建立中直接採用整數 // 而後經過該字段進行小數的處理 uint8 public decimals; // 令牌簡稱,如 OMG string public symbol; // 令牌合約的構造函數 // 在solidity中,和合約名稱一致的方法爲構造函數,在第一次建立合約時,僅執行一次。 function ERC20( uint256 _totalSupply, // 令牌建立總量 string _name, // 令牌名稱 uint8 _decimals, // 支持小數位數 string _symbol // 令牌簡稱 ) public { // 給建立者帳戶初始化令牌 balances[msg.sender] = _totalSupply; // 設置令牌發行量 totalSupply = _totalSupply; // 設置令牌名稱 name = _name; // 設置令牌支持小數位數 decimals = _decimals; // 設置令牌簡稱 symbol = _symbol; } /** * 獲取令牌總髮行量 * @return uint256 totalSupply 發行總量 */ function totalSupply() constant returns (uint256 totalSupply) { return totalSupply; } /** * 轉移令牌 * @param address _to 令牌接收者地址 * @param uint256 _value 發送令牌數量 * @return bool success 發送成功狀態 */ function transfer(address _to, uint256 _value) public returns (bool success) { // 判斷髮送者餘額是否充足 require(balances[msg.sender] >= _value); // 從發送者餘額中減去`_value`數量的令牌 balances[msg.sender] -= _value; // 給接收者帳戶中添加`_value`數量的令牌 balances[_to] += _value; // 記錄令牌轉移的事件 Transfer(msg.sender, _to, _value); return true; } /** * 轉移令牌(受權) * @param address _from 令牌發送者地址 * @param address _to 令牌接收者地址 * @param uint256 _value 令牌發送數量 * @return bool success 方法執行狀態 */ function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { // 其中`msg.sender`是合約方法調用者的地址 // 獲取`_from`地址受權給`msg.sender`地址的可轉移令牌餘額 uint256 allowance = allowed[_from][msg.sender]; // 判斷`_from`地址餘額是否充足以及受權轉移令牌是否充足 require(balances[_from] >= _value && allowance >= _value); // 從`_from`地址減去`_value`數量的令牌 balances[_from] -= _value; // 從受權餘額中減去`_value`數量的令牌 allowed[_from][msg.sender] -= _value; // 給`_to`地址添加`_value`數量的令牌 balances[_to] += _value; // 記錄轉移令牌的事件 Transfer(_from, _to, _value); return true; } /** * 獲取`_owner`地址的令牌餘額 * @param address _owner 要獲取餘額的地址 * @return uint256 balance 返回`_owner`地址的餘額 */ function balanceOf(address _owner) public view returns (uint256 balance) { return balances[_owner]; } /** * 受權令牌轉移方法 * @param address _spender 被受權地址 * @param uint256 _value 受權可轉移的數量 * @return bool success 方法執行狀態 */ function approve(address _spender, uint256 _value) public returns (bool success) { // `msg.sender`受權`_spender`地址轉移`_value`數量的令牌 allowed[msg.sender][_spender] = _value; // 記錄受權事件 Approval(msg.sender, _spender, _value); return true; } /** * 獲取被受權的令牌餘額 * @param address _owner 受權地址 * @param address _spender 被受權地址 * @return uint256 remaining 可轉移的令牌餘額 */ function allowance(address _owner, address _spender) public view returns (uint256 remaining) { return allowed[_owner][_spender]; } }
大多數在交易所交易的令牌的合約代碼就這麼簡單,其實每個方法拆分開來都是最簡單的編程代碼,而核心的處理都被EVM進行了封裝,以太坊在令牌發行方面確實極大的解放了人類,簡單幾十行代碼就能夠發行一個令牌。ERC20令牌又被成爲同質化令牌,就是每一個令牌都是一致的,沒法區分,而市場上如今冒出了不少以太貓,以太狗的遊戲,而這裏面也是使用以太坊的令牌來實現的,可是他們選擇的不是ERC20令牌,而是被成爲非同質化的令牌,被稱爲ERC721令牌。
下期,咱們一塊兒來聊非同質化令牌ERC721。
喜歡,不要說話,掃我~