1. 程式人生 > >【Ethereum】以太坊ERC20 Token標準完整說明

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

編寫 function 接收 auth uil abi reat 存在 clas

什麽是ERC20 token

市面上出現了大量的用ETH做的代幣,他們都遵守REC20協議,那麽我們需要知道什麽是REC20協議。

概述

token代表數字資產,具有價值,但是並不是都符合特定的規範。

基於ERC20的貨幣更容易互換,並且能夠在Dapps上相同的工作。

新的標準可以讓token更兼容,允許其他功能,包括投票標記化。操作更像一個投票操作

Token的持有人可以完全控制資產,遵守ERC20的token可以跟蹤任何人在任何時間擁有多少token.基於eth合約的子貨幣,所以容易實施。只能自己去轉讓。

標準化非常有利,也就意味著這些資產可以用於不同的平臺和項目,否則只能用在特定的場合。

ERC20 Token標準(Github)

序言

EIP: 20
Title: ERC-20 Token Standard
Author: Fabian Vogelsteller [email protected], Vitalik Buterin [email protected]
Type: Standard
Category: ERC
Status: Accepted
Created: 2015-11-19

總結

token的接口標準

抽象

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

動機

標準接口可以讓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到提高安全性。

示例實現可在

  • https://github.com/ConsenSys/Tokens/blob/master/contracts/StandardToken.sol
  • https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/StandardToken.sol

在調用之前添加力0的實施“批準”了

  • https://github.com/Giveth/minime/blob/master/contracts/MiniMeToken.sol

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限定的第二維的參數是調用者的轉移數量,而開始的例子是接收者的數量。

參考資料

  • http://themerkle.com/what-is-the-erc20-ethereum-token-standard/
  • https://github.com/ethereum/EIPs/pull/610
  • https://github.com/ethereum/EIPs/issues/20
  • https://theethereum.wiki/w/index.php/ERC20_Token_Standard
  • https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
  • https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
  • https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit#heading=h.m9fhqynw2xvt

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