如何以簡單的方式創建 ERC20 代幣

已發表: 2022-03-11

本文的目標是演示如何在盡可能短的時間內創建 ERC20 代幣。

讓我們從基礎開始:什麼是 ERC20 代幣?

近年來,ERC20 代幣規範已成為以太坊代幣的事實標準。 換句話說,目前大多數以太坊合約都符合 ERC20。 本文將詳細介紹如何創建自己的以太坊代幣,但在開始之前,讓我們仔細看看 ERC20 標準。

ERC20 代幣說明

是什麼讓 ERC20 代幣如此有吸引力和成功? 有幾個因素在起作用:

  1. 正如您將在本教程中看到的那樣,ERC20 令牌簡單且易於部署。
  2. ERC20 標準解決了一個重大問題,因為基於區塊鏈的市場和加密錢包需要一套單一的標準化命令來與它們管理的代幣範圍進行通信。 這包括不同代幣之間的交互規則,以及代幣購買規則。
  3. 它是第一個提供以太坊代幣標準化的流行規範。 它絕不是第一個,但由於它的流行,它很快成為了行業標準。

就像其他以太坊代幣一樣,ERC20 代幣被實現為智能合約,並以去中心化的方式在以太坊虛擬機 (EVM) 上執行。

Solidity:智能合約編程語言

以太坊智能合約是用 Solidity 編寫的。 雖然有替代語言,但幾乎沒有人將它們用於此目的。 Solidity 類似於 JavaScript,所以如果你對 JavaScript,甚至 Java 和其他類似 C 的語言有一定的了解,你應該可以毫不費力地弄清楚 Solidity 中的一段代碼,甚至在你真正掌握 Solidity 足以使用之前它。

這就是樂趣的開始,因為您應該能夠立即開始創建一個簡單的 ERC20 合約。 這是一項簡單的任務,非常簡單,本文將演示如何在一小時內編寫和部署 ERC20 代幣。

我們將在此演示中創建的代幣將是一個簡單的 ERC20 實現,沒有太多的花里胡哨。 但是,我在現實世界中看到了許多類似的簡單令牌,而且它們往往做得很好。

ERC20 通證標準概述

什麼是 ERC20?

簡而言之,ERC20 標准定義了一組由所有 ERC20 代幣實現的功能,以便與其他合約、錢包或市場集成。 這組功能相當簡短和基本。

 function totalSupply() public view returns (uint256); function balanceOf(address tokenOwner) public view returns (uint); function allowance(address tokenOwner, address spender) public view returns (uint); function transfer(address to, uint tokens) public returns (bool); function approve(address spender, uint tokens) public returns (bool); function transferFrom(address from, address to, uint tokens) public returns (bool);

ERC20 功能允許外部用戶(例如加密錢包應用程序)找出用戶的餘額,並在獲得適當授權的情況下將資金從一個用戶轉移到另一個用戶。

智能合約定義了兩個特別定義的事件:

 event Approval(address indexed tokenOwner, address indexed spender, uint tokens); event Transfer(address indexed from, address indexed to, uint tokens);

當用戶被授予從帳戶中提取代幣的權利時,以及代幣實際轉移後,這些事件將被調用或發出

除了標準的 ERC20 功能外,許多 ERC20 代幣還具有附加字段,有些已成為 ERC20 標準的事實上的一部分,如果不是書面形式,那麼實際上是在實踐中。 以下是此類字段的一些示例。

 string public constant name; string public constant symbol; uint8 public constant decimals;

以下是關於 ERC20 和 Solidity 命名法的幾點:

  • 可以在合約本身之外訪問public功能
  • view基本上意味著不變,即合約的內部狀態不會被函數改變
  • event是 Solidity 允許客戶端(例如您的應用程序前端)在合同中的特定事件時收到通知的方式

如果您已經具備基本的 Java/JavaScript 技能,那麼大多數 Solidity 語言結構都應該是清楚的。

在 Solidity 中編寫 ERC20 代幣

穩固的 ERC20 代幣

現在我們已經概述了基礎知識並解釋了創建 ERC20 代幣需要什麼,是時候開始編寫一些邏輯了。

首先,我們需要定義兩個映射對象。 這是關聯或鍵/值數組的 Solidity 概念:

 mapping(address => uint256) balances; mapping(address => mapping (address => uint256)) allowed;

表達式mapping(address => uint256)定義了一個關聯數組,其鍵是address類型——一個用於表示帳戶地址的數字,其值是uint256類型——一個 256 位整數,通常用於存儲代幣餘額。

第一個映射對象balances將保存每個所有者帳戶的代幣餘額。

第二個映射對象allowed將包括所有獲准從給定賬戶提款的賬戶以及每個賬戶允許的提款金額。

如您所見,allowed mapping 的 value 字段本身就是一個映射繪圖帳戶地址到其批准的提款金額。

這些映射連同所有其他合約字段將存儲在區塊鏈中,並將被挖掘,從而將更改傳播到所有網絡用戶節點。

區塊鏈存儲成本高昂,您的合約用戶需要以一種或另一種方式付費。 因此,您應該始終嘗試最小化存儲大小並寫入區塊鏈。

現在我們已經有了所需的數據結構,我們可以開始將 ERC20 邏輯實際寫入適當的函數中。

設置 ICO 代幣數量

我們如何設置 ICO 代幣的數量? 好吧,有很多方法可以設置 ICO 代幣的最大數量,這個問題本身可能值得進行長時間的討論。

為了我們 ECR20 教程的需要,我們將使用最簡單的方法:在合約創建時設置代幣總量,並最初將它們全部分配給“合約所有者”,即部署智能合約的賬戶:

 uint256 totalSupply_; constructor(uint256 total) public { totalSupply_ = total; balances[msg.sender] = _totalSupply; }

構造函數是以太坊在部署合約後立即自動調用的特殊函數。 它通常用於使用合約部署帳戶傳遞的參數初始化令牌的狀態。

msg是由以太坊本身聲明和填充的全局變量。 它包含執行合同的重要數據。 我們在這裡使用的字段: msg.sender包含執行當前合約功能的以太坊賬戶。

只有部署賬戶才能進入合約的構造函數。 當合約啟動時,該函數將可用代幣分配給“合約所有者”賬戶。

獲取總代幣供應量

function totalSupply() public view returns (uint256) { return totalSupply_; }

此函數將返回此合約分配的所有代幣的數量,無論所有者如何。

獲取所有者的代幣餘額

function balanceOf(address tokenOwner) public view returns (uint) { return balances[tokenOwner]; }

balanceOf將返回由其所有者地址標識的帳戶的當前代幣餘額。

將代幣轉移到另一個賬戶

function transfer(address receiver, uint numTokens) public returns (bool) { require(numTokens <= balances[msg.sender]); balances[msg.sender] = balances[msg.sender] — numTokens; balances[receiver] = balances[receiver] + numTokens; emit Transfer(msg.sender, receiver, numTokens); return true; }

顧名思義, transfer函數用於將numTokens數量的代幣從所有者的餘額轉移到另一個用戶或receiver的餘額。 轉讓所有者是msg.sender即執行該功能的人,這意味著只有令牌的所有者才能將它們轉讓給其他人。

Solidity 斷言謂詞的方式是require 。 在這種情況下,轉賬賬戶有足夠的餘額來執行轉賬。 如果require語句失敗,事務會立即回滾,不會將任何更改寫入區塊鏈。

就在退出之前,該函數觸發 ERC20 事件Transfer允許註冊的偵聽器對其完成做出反應。

批准代表提取代幣

此功能最常用於代幣市場場景。

 function approve(address delegate, uint numTokens) public returns (bool) { allowed[msg.sender][delegate] = numTokens; emit Approval(msg.sender, delegate, numTokens); return true; }

approve的作用是允許所有者,即msg.sender批准委託賬戶——可能是市場本身——從他的賬戶中提取代幣並將它們轉移到其他賬戶。

如您所見,此功能用於所有者在市場上提供代幣的場景。 它允許市場在不等待事先批准的情況下完成交易。

在執行結束時,此函數會觸發Approval事件。

獲取批准提款的代幣數量

function allowance(address owner, address delegate) public view returns (uint) { return allowed[owner][delegate]; }

此函數將所有者當前批准的代幣數量返回給特定代表,如approve函數中設置的那樣。

委託代幣轉移

transferFrom函數是我們之前討論過的approve函數的對等點。 它允許獲准提款的代表將所有者資金轉移到第三方賬戶。

 function transferFrom(address owner, address buyer, uint numTokens) public returns (bool) { require(numTokens <= balances[owner]); require(numTokens <= allowed[owner][msg.sender]); balances[owner] = balances[owner] — numTokens; allowed[owner][msg.sender] = allowed[from][msg.sender] — numTokens; balances[buyer] = balances[buyer] + numTokens; Transfer(owner, buyer, numTokens); return true; }

函數啟動時的兩個require語句用於驗證交易是否合法,即所有者有足夠的代幣可以轉移,並且委託人已經批准(至少) numTokens可以撤回。

除了將numTokens金額從所有者轉移到買方之外,此函數還從受託人的津貼中減去numTokens 。 這基本上允許具有給定津貼的代表將其分成幾個單獨的提款,這是典型的市場行為。

我們可以在這裡停下來,並有一個有效的 ERC20 實施。 但是,我們想要更進一步,因為我們想要一個工業實力代幣。 這要求我們使我們的代碼更安全一些,儘管我們仍然能夠保持令牌相對簡單,即使不是基本的。

SafeMath Solidity 庫

SafeMath是一個 Solidity 庫,旨在處理已知的黑客破壞合約的一種方式:整數溢出攻擊。 在這種攻擊中,黑客通過傳遞將使相關整數超過其最大值的參數來強制合約使用不正確的數值。

Solidity 中的 Safemath 庫:插圖

SafeMath通過在執行算術運算之前測試溢出來防止這種情況發生,從而消除了溢出攻擊的危險。 該庫非常小,因此對合約大小的影響很小,不會產生任何性能和存儲成本損失。

讓我們將SafeMath添加到我們的代碼中:

 library SafeMath { // Only relevant functions function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a — b; } function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } }

SafeMath使用assert語句來驗證傳遞參數的正確性。 如果assert失敗,函數執行將立即停止,所有區塊鏈更改都將回滾。

接下來,讓我們添加以下語句,將庫引入 Solidity 編譯器:

using SafeMath for uint256;

然後,我們用 SafeMath 函數替換一開始使用的簡單算法:

 balances[msg.sender] = balances[msg.sender].sub(numTokens); balances[receiver] = balances[receiver].add(numTokens); balances[buyer] = balances[buyer].add(numTokens); balances[owner] = balances[owner].sub(numTokens);

打包在一起

在 Solidity 中,智能合約的功能和事件被包裝到一個稱為合約的實體中,您可以將其默默地轉換為“區塊鏈類”。 下面是我們創建的 ERC20 兼容合約,包括我們的代碼要點。 名稱和符號字段可以隨意更改。 大多數令牌將十進制值保持為 18,因此我們將這樣做。

以太坊合約部署

是時候將我們的合約部署到區塊鏈上了。 部署後,我們的合約將轉移到參與網絡的所有節點。 對合約所做的任何和所有更改都將傳播到所有參與節點。

以太坊開發人員通常使用 Truffle 等部署工具。 對於本文的有限需求,即使是 Truffle 也太過分了,一個名為 Remix 的簡單在線工具就足夠了。

要使用它,您需要在瀏覽器上安裝 MetaMask 插件和一個 Rinkeby(以太坊測試網絡)帳戶,其中至少包含一些 Rinkeby Ether。 這些都是比較簡單的步驟,所以我們不會詳細介紹。

如果您沒有,請前往 MetaMask 和 Rinkeby 獲取下載鏈接並獲得明確的安裝和使用說明。

現在我們已經準備好所有構建塊,我們將前往 Remix 並將上面的代碼(包括 pragma 行和 SafeMath 庫)粘貼到在線編輯器中。

然後,我們將跳轉到右側名為“ Run ”的第二個選項卡,然後單擊“ Deploy ”。 將出現一個 MetaMask 彈出窗口,要求我們確認交易。 當然,我們會批准。

圖片替代文字

  • 綠框:確保你在 Rinkeby
  • 藍色框:設置您的總代幣供應量
  • 紅框:部署!

要點:https://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be#file-basicerc20-sol

恭喜! 您剛剛部署了您的第一個 ERC20 代幣,就像真正的以太坊專業人士一樣。 正如所承諾的那樣,該令牌簡單輕巧,功能齊全,符合 ERC20 標準,並受 MathSafe 保護。 它已準備好在整個區塊鏈中購買、支付和轉移。

這就是智能合約的全部內容嗎?

不,甚至沒有接近,因為我們的簡短演示幾乎沒有觸及表面,只涉及智能合約開發的一個方面。

智能合約可能要復雜得多,具體取決於您的業務邏輯、用戶交互的建模、是否允許鑄造和銷毀代幣、您在合約中引入的生命週期更改、對管理員級別功能的需求,這通常伴隨著管理員授權的一組功能,等等。 你得到圖片。

不過,如果您可以復制我們在這裡所做的工作,那將是擴展您的知識並在必要時轉向更複雜的合同的堅實基礎。