【Ethereum】以太坊ERC20 Token標準完整說明

什麼是ERC20 token

市面上出現了大量的用ETH作的代幣,他們都遵照REC20協議,那麼咱們須要知道什麼是REC20協議。php

概述

token表明數字資產,具備價值,可是並非都符合特定的規範。git

基於ERC20的貨幣更容易互換,而且可以在Dapps上相同的工做。github

新的標準可讓token更兼容,容許其餘功能,包括投票標記化。操做更像一個投票操做數組

Token的持有人能夠徹底控制資產,遵照ERC20的token能夠跟蹤任何人在任什麼時候間擁有多少token.基於eth合約的子貨幣,因此容易實施。只能本身去轉讓。安全

標準化很是有利,也就意味着這些資產能夠用於不一樣的平臺和項目,不然只能用在特定的場合。bash

ERC20 Token標準(Github)

序言

EIP: 20 
Title: ERC-20 Token Standard 
Author: Fabian Vogelsteller fabian@ethereum.org, Vitalik Buterin vitalik.buterin@ethereum.org 
Type: Standard 
Category: ERC 
Status: Accepted 
Created: 2015-11-19markdown

總結

token的接口標準網絡

抽象

如下標準容許在智能合約中實施標記的標記API。 該標準提供了轉移token的基本功能,並容許token被批准,以便他們能夠由另外一個在線第三方使用。app

動機

標準接口可讓Ethereum上的任何令牌被其餘應用程序從新使用:從錢包到分散式交換。函數

規則

Token

方法

注意:調用者必須處理返回falsereturns (bool success).調用者絕對不能假設返回false的狀況不存在。

name

返回這個令牌的名字,好比"MyToken".

可選 - 這種方法能夠用來提升可用性,但接口和其餘契約不能期望這些值存在。

function name() constant returns (string name)

symbol

返回令牌的符號,好比HIX.

可選 - 這種方法能夠用來提升可用性,但接口和其餘契約不能期望這些值存在。

function symbol() constant returns (string symbol)

decimals

返回token使用的小數點後幾位, 好比 8,表示分配token數量爲100000000

可選 - 這種方法能夠用來提升可用性,但接口和其餘契約不能期望這些值存在。

function decimals() constant returns (uint8 decimals)

totalSupply

返回token的總供應量。

function totalSupply() constant returns (uint256 totalSupply)

balanceOf

返回地址是_owner的帳戶的帳戶餘額。

function balanceOf(address _owner) constant returns (uint256 balance)

transfer

轉移_value的token數量到的地址_to,而且必須觸發Transfer事件。 若是_from賬戶餘額沒有足夠的令牌來支出,該函數應該被throw

建立新令牌的令牌合同應該在建立令牌時將_from地址設置爲0x0觸發傳輸事件。

注意 0值的傳輸必須被視爲正常傳輸並觸發傳輸事件。

function transfer(address _to, uint256 _value) returns (bool success)

transferFrom

從地址_from發送數量爲_value的token到地址_to,必須觸發Transfer事件。

transferFrom方法用於提取工做流,容許合同代您轉移token。這能夠用於例如容許合約代您轉讓代幣和/或以子貨幣收取費用。除了_from賬戶已經經過某種機制故意地受權消息的發送者以外,該函數**應該**throw。

注意 0值的傳輸必須被視爲正常傳輸並觸發傳輸事件。

function transferFrom(address _from, address _to, uint256 _value) returns (bool success)

approve

容許_spender屢次取回您的賬戶,最高達_value金額。 若是再次調用此函數,它將以_value覆蓋當前的餘量。

注意:爲了阻止向量攻擊,客戶端須要確認以這樣的方式建立用戶接口,即將它們設置爲0,而後將其設置爲同一個花費者的另外一個值。雖然合同自己不該該強制執行,容許向後兼容之前部署的合同兼容性

function approve(address _spender, uint256 _value) returns (bool success)

allowance

返回_spender仍然被容許從_owner提取的金額。

function allowance(address _owner, address _spender) constant returns (uint256 remaining)

Events

Transfer

當token被轉移(包括0值),必須被觸發。

event Transfer(address indexed _from, address indexed _to, uint256 _value)

Approval

當任何成功調用approve(address _spender, uint256 _value)後,必須被觸發。

event Approval(address indexed _owner, address indexed _spender, uint256 _value)

實施

在Ethereum網絡上部署了大量符合ERC20標準的令牌。 具備不一樣權衡的各類團隊已經編寫了不一樣的實施方案:從節省gas到提升安全性。

示例實現可在

在調用以前添加力0的實施「批准」了

ERC20 Token標準接口

如下是一個接口合同,聲明所需的功能和事件以符合ERC20標準:

// https://github.com/ethereum/EIPs/issues/20 contract ERC20 { function totalSupply() constant returns (uint totalSupply); function balanceOf(address _owner) constant returns (uint balance); function transfer(address _to, uint _value) returns (bool success); function transferFrom(address _from, address _to, uint _value) returns (bool success); function approve(address _spender, uint _value) returns (bool success); function allowance(address _owner, address _spender) constant returns (uint remaining); event Transfer(address indexed _from, address indexed _to, uint _value); event Approval(address indexed _owner, address indexed _spender, uint _value); }

 

大部分Ethereum主要標記符合ERC20標準。

一些令牌包括描述令牌合同的進一步信息:

string public constant name = "Token Name"; string public constant symbol = "SYM"; uint8 public constant decimals = 18; // 大部分都是18

如何工做?

如下是令牌合約的一個片斷,用於演示令牌合約如何維護Ethereum賬戶的令牌餘額

contract TokenContractFragment {

     // Balances 保存地址的餘額 mapping(address => uint256) balances; // 賬戶的全部者批准將金額轉入另外一個賬戶 mapping(address => mapping (address => uint256)) allowed; // 特定賬戶的餘額是多少? function balanceOf(address _owner) constant returns (uint256 balance) { return balances[_owner]; //從數組中取值 } // 將餘額從全部者賬戶轉移到另外一個賬戶 function transfer(address _to, uint256 _amount) returns (bool success) { //判斷條件 發送者餘額>=要發送的值 發送的值>0 接收者餘額+發送的值>接收者的餘額 if (balances[msg.sender] >= _amount && _amount > 0 && balances[_to] + _amount > balances[_to]) { balances[msg.sender] -= _amount; //發送者的餘額減小 balances[_to] += _amount; //接收者的餘額增長 return true; } else { return false; } } // 發送 _value 數量的token從地址 _from 到 地址 _to // transferFrom方法用於提取工做流程,容許合同以您的名義發送令牌,例如「存入」到合同地址和/或以子貨幣收取費用; 該命令應該失敗,除非_from賬戶經過某種機制故意地受權消息的發送者; 咱們提出這些標準化的API來批准: function transferFrom( address _from, address _to, uint256 _amount ) returns (bool success) { //和上面同樣的校驗規則 if (balances[_from] >= _amount && allowed[_from][msg.sender] >= _amount && _amount > 0 && balances[_to] + _amount > balances[_to]) { balances[_from] -= _amount; allowed[_from][msg.sender] -= _amount; //減小發送者的批准量 balances[_to] += _amount; return true; } else { return false; } } // 容許_spender屢次退出您的賬戶,直到_value金額。 若是再次調用此函數,它將以_value覆蓋當前的餘量。 function approve(address _spender, uint256 _amount) returns (bool success) { allowed[msg.sender][_spender] = _amount; //覆蓋當前餘量 return true; } }

 

token餘額

假設token合約內有兩個持有者

  • 0x1111111111111111111111111111111111111111有100個單位
  • 0x2222222222222222222222222222222222222222有200個單位

那麼這個合約的balances結構就會存儲下面的內容

balances[0x1111111111111111111111111111111111111111] = 100 balances[0x2222222222222222222222222222222222222222] = 200

 

那麼,balanceOf(...)就會返回下面的結果

tokenContract.balanceOf(0x1111111111111111111111111111111111111111) 將會返回 100 tokenContract.balanceOf(0x2222222222222222222222222222222222222222) 將會返回 200

轉移token的餘額

若是0x1111111111111111111111111111111111111111想要轉移10個單位給0x2222222222222222222222222222222222222222,那麼0x1111111111111111111111111111111111111111會執行下面的函數

tokenContract.transfer(0x2222222222222222222222222222222222222222, 10)

 

token合約的transfer(...)方法將會改變balances結構中的信息

balances[0x1111111111111111111111111111111111111111] = 90 balances[0x2222222222222222222222222222222222222222] = 210

 

balanceOf(...)調用就會返回下面的信息

tokenContract.balanceOf(0x1111111111111111111111111111111111111111) 將會返回 90 tokenContract.balanceOf(0x2222222222222222222222222222222222222222) 將會返回 210

從token餘額批准和轉移

若是0x1111111111111111111111111111111111111111想要批准0x2222222222222222222222222222222222222222傳輸一些token到0x2222222222222222222222222222222222222222,那麼0x1111111111111111111111111111111111111111會執行下面的函數

tokenContract.approve(0x2222222222222222222222222222222222222222, 30)

而後allowed(這裏官方文檔寫的是approve,很明顯是錯的)結構就會存儲下面的內容

tokenContract.allowed[0x1111111111111111111111111111111111111111][0x2222222222222222222222222222222222222222] = 30

若是0x2222222222222222222222222222222222222222想要晚點轉移token從0x1111111111111111111111111111111111111111到他本身,0x2222222222222222222222222222222222222222將要執行transferFrom(...)函數

tokenContract.transferFrom(0x1111111111111111111111111111111111111111, 20)

balances的信息就會變成下面的

tokenContract.balances[0x1111111111111111111111111111111111111111] = 70 tokenContract.balances[0x2222222222222222222222222222222222222222] = 230

而後allowed就會變成下面的內容

tokenContract.allowed[0x1111111111111111111111111111111111111111][0x2222222222222222222222222222222222222222] = 10

0x2222222222222222222222222222222222222222仍然能夠從0x1111111111111111111111111111111111111111轉移10個單位。

tokenContract.balanceOf(0x1111111111111111111111111111111111111111) will return 70 tokenContract.balanceOf(0x2222222222222222222222222222222222222222) will return 230

簡單修復的token合約

如下是一個樣本令牌合同,固定供應量爲1000000單位,最初分配給合同全部者:

pragma solidity ^0.4.8; // ---------------------------------------------------------------------------------------------- // Sample fixed supply token contract // Enjoy. (c) BokkyPooBah 2017. The MIT Licence. // ---------------------------------------------------------------------------------------------- // ERC Token Standard #20 Interface // https://github.com/ethereum/EIPs/issues/20 contract ERC20Interface { // 獲取總的支持量 function totalSupply() constant returns (uint256 totalSupply); // 獲取其餘地址的餘額 function balanceOf(address _owner) constant returns (uint256 balance); // 向其餘地址發送token function transfer(address _to, uint256 _value) returns (bool success); // 從一個地址想另外一個地址發送餘額 function transferFrom(address _from, address _to, uint256 _value) returns (bool success); //容許_spender從你的帳戶轉出_value的餘額,調用屢次會覆蓋可用量。某些DEX功能須要此功能 function approve(address _spender, uint256 _value) returns (bool success); // 返回_spender仍然容許從_owner退出的餘額數量 function allowance(address _owner, address _spender) constant returns (uint256 remaining); // token轉移完成後出發 event Transfer(address indexed _from, address indexed _to, uint256 _value); // approve(address _spender, uint256 _value)調用後觸發 event Approval(address indexed _owner, address indexed _spender, uint256 _value); } //繼承接口後的實例 contract FixedSupplyToken is ERC20Interface { string public constant symbol = "FIXED"; //單位 string public constant name = "Example Fixed Supply Token"; //名稱 uint8 public constant decimals = 18; //小數點後的位數 uint256 _totalSupply = 1000000; //發行總量 // 智能合約的全部者 address public owner; // 每一個帳戶的餘額 mapping(address => uint256) balances; // 賬戶的全部者批准將金額轉入另外一個賬戶。從上面的說明咱們能夠得知allowed[被轉移的帳戶][轉移錢的帳戶] mapping(address => mapping (address => uint256)) allowed; // 只能經過智能合約的全部者才能調用的方法 modifier onlyOwner() { if (msg.sender != owner) { throw; } _; } // 構造函數 function FixedSupplyToken() { owner = msg.sender; balances[owner] = _totalSupply; } function totalSupply() constant returns (uint256 totalSupply) { totalSupply = _totalSupply; } // 特定帳戶的餘額 function balanceOf(address _owner) constant returns (uint256 balance) { return balances[_owner]; } // 轉移餘額到其餘帳戶 function transfer(address _to, uint256 _amount) returns (bool success) { if (balances[msg.sender] >= _amount && _amount > 0 && balances[_to] + _amount > balances[_to]) { balances[msg.sender] -= _amount; balances[_to] += _amount; Transfer(msg.sender, _to, _amount); return true; } else { return false; } } //從一個帳戶轉移到另外一個帳戶,前提是須要有容許轉移的餘額 function transferFrom( address _from, address _to, uint256 _amount ) returns (bool success) { if (balances[_from] >= _amount && allowed[_from][msg.sender] >= _amount && _amount > 0 && balances[_to] + _amount > balances[_to]) { balances[_from] -= _amount; allowed[_from][msg.sender] -= _amount; balances[_to] += _amount; Transfer(_from, _to, _amount); return true; } else { return false; } } //容許帳戶從當前用戶轉移餘額到那個帳戶,屢次調用會覆蓋 function approve(address _spender, uint256 _amount) returns (bool success) { allowed[msg.sender][_spender] = _amount; Approval(msg.sender, _spender, _amount); return true; } //返回被容許轉移的餘額數量 function allowance(address _owner, address _spender) constant returns (uint256 remaining) { return allowed[_owner][_spender]; } }

注意的是,最後的例子中allowed限定的第二維的參數是調用者的轉移數量,而開始的例子是接收者的數量。

參考資料

相關文章
相關標籤/搜索