日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

web3 solidity 基础 ERC20 大白话搞懂

發布時間:2023/12/20 编程问答 63 豆豆
生活随笔 收集整理的這篇文章主要介紹了 web3 solidity 基础 ERC20 大白话搞懂 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、什么是標準什么是ERC20標準

ERC20 是 eth 的一個標準,怎么理解標準一詞呢?

標準是大家遵循的一個協議,根據這個協議大家都知道該怎么去做,例如去吃飯的時候人多,你就需要排隊,然后去窗口跟阿姨說你要吃什么,阿姨就會幫你打;若你不準守這個標準,直接沖進后廚,翻開泔水,大喊著我要吃飯…這個時候就完全背離了這個標準,所以被趕走了。

以上所述以開玩笑的方式講述了什么是標準,所以在我們要使用 ERC20 標準完成這個標準的結果時,就需要遵守這個標準。

ERC20 是以太坊上的一種代幣合約標準,你要實現這個代幣或者說你要發個幣那么就得給這個代幣一個名字、怎么轉賬、總量、授權 等這些功能(標準),否則別人拿你的幣都不能轉賬,難道就是看嘛,所以標準我們得實現。

具體標準我們可以看這個:https://eips.ethereum.org/EIPS/eip-20

以上的標準簡而言之就是實現一些接口就可以了,以下是一個標準的ERC20標準:

// SPDX-License-Identifier:MIT pragma solidity 0.8.17; interface IERC20 {//發行的代幣總量function totalSupply() external view returns (uint256);//某地址余額function balanceOf(address account) external view returns (uint256);//從當前賬戶對某個地址轉amount的錢function transfer(address account, uint256 amount) external returns (bool);//授權某個賬戶可以用你的錢(用多少錢是指定的)function approve(address spender, uint256 amount) external returns (bool);//你授權的賬戶還可以有多少你授權的錢可以用function allowance(address owner, address spender) external view returns (uint256);//授權用戶的轉賬方法,只針對授權用戶使用function transferFrom(address from,address to,uint256 amount) external returns (bool);//轉賬時觸發轉賬事件event Transfer(address indexed from, address indexed to, uint256 value);//授權時觸發授權事件event Approval(address indexed owner, address indexed spender, uint256 value); }

用文字列出來,那么這些接口方法就包括:

  • 代幣總量 totalSupply
  • 某地址余額 balanceOf
  • 轉賬 transfer
  • 授權 approve
  • 查看授權賬戶余額 allowance
  • 授權用戶轉賬 transferFrom
  • 轉賬事件 Transfer
  • 授權事件Approval

二、簡單 ERC20標準實現

2.1 父合約

實現 ERC20 標準首先我們創建一個合約,在合約中將第一點的接口作為父合約之后我們將其繼承:

// SPDX-License-Identifier:MIT pragma solidity 0.8.17; interface IERC20 {//發行的代幣總量function totalSupply() external view returns (uint256);//某地址余額function balanceOf(address account) external view returns (uint256);//從當前賬戶對某個地址轉amount的錢function transfer(address account, uint256 amount) external returns (bool);//授權某個賬戶可以用你的錢(用多少錢是指定的)function approve(address spender, uint256 amount) external returns (bool);//你授權的賬戶還可以有多少你授權的錢可以用function allowance(address owner, address spender) external view returns (uint256);//授權用戶的轉賬方法,只針對授權用戶使用function transferFrom(address from,address to,uint256 amount) external returns (bool);//轉賬時觸發轉賬事件event Transfer(address indexed from, address indexed to, uint256 value);//授權時觸發授權事件event Approval(address indexed owner, address indexed spender, uint256 value); }

2.2 創建合約

接著編寫一個合約叫做 BitCoinDemo:

contract BitCoinDemo is IERC20{}

2.3 代幣名稱、總量、余額等狀態變量編寫

接下來是不是應該到我們需要用到一些變量來存儲這個代幣名稱、總量以及余額了?

此時創建一個變量用來存儲一個地址與余額的關系,那么使用 map 類型的數據:

//余額 mapping(address => uint256)public balances;

那么接下來就是對應的總量了:

//總量 uint256 public total = 100000000;

那么就還有你的代幣全名、簡稱和小數了:

//代幣名 string public constant name = "1BITCOINERC20DEMO"; //簡稱 string public constant symbol = "1BitCoin"; //小數點 uint8 public constant decimals = 18;

其中小數點位置我們為 18就好,一般都是寫18。

當然,你這些內容都可以在合約部署的時候再傳入,在這里我就簡單編寫了。

2.4 構造函數給自己好多錢

接著,我們可以編寫一個構造函數,將即將我們要創建的代幣給與當前合約的創建者:

constructor() {balances[msg.sender] = total; }

畢竟這個關系就是某個地址又多少余額,那么我總量是 total,那不就是給當前創建合約的人所有余額就好了。

2.5 實現 totalSupply() 方法

接著開始實現 totalSupply() 方法,我們只需要返回當前合約的總量即可,那么就可以寫成:

//返回總量 function totalSupply()override public view returns (uint256) {return total; }

記得,一定要寫 override,畢竟是父接口的方法重寫。

2.6 實現 轉賬 方法

既然我有了幣,那么接下來就應該有一個轉賬方法,我們實現 transfer 方法:

//轉賬代幣 function transfer(address account, uint256 amount) public override returns (bool) {require(balances[msg.sender]>amount);//判斷錢夠不夠balances[msg.sender] = balances[msg.sender]-amount;//原賬戶減去給自己balances[account] = balances[account]+amount;//給別人賬戶加上轉賬的錢emit Transfer(msg.sender, account, amount);//響應這個事件return true; }

以上的轉賬方法很簡單,接收兩個參數,一個是你要轉給誰的賬戶 account,還有一個你要轉多少錢 amount,最后返回 bool 是否轉賬成功

在方法中首先判斷錢是否足夠,夠的話就給原賬戶減去轉出去的錢,別人賬戶加上轉出去的錢就ok了。

2.7 查看余額

既然已經轉賬到別人賬戶了,那么此時還需要對應的查看一下別人的余額,那么此時就實現 balanceOf 方法:

//余額查看 function balanceOf(address account)override public view returns (uint256) {return balances[account]; }

直接返回那個 balances 的映射結果就得到余額了。

2.8 指定授權賬戶

授權賬戶需要一個 map 來存儲,但是跟之前的 map 不太一樣,如下:

//授權用戶及余額 mapping(address => mapping (address => uint256)) appbalances;

為啥要這樣寫這個 map 呢?那是因為你授權肯定是 A賬戶 授權給了 B賬戶 多少錢,所以此時就是兩個 address,最外層的 address 就是授權人,這個授權人下的 address 就是授權給的某人,二 對應的 uint256 數據則是授權的金額,方法如下:

//授權方法 function approve(address spender, uint256 amount)override public returns (bool) {appbalances[msg.sender][spender] = amount;emit Approval(msg.sender, spender, amount);return true; }

以上這個方法呢 spender 就是需要授權給的地址,amount 就是給這個地址授權的金額數量,那么 appbalances[msg.sender][spender] = amount; 就表示在這個 appbalances 授權金額 map 中添加一個記錄,msg.sender 是我自己的地址,那意思就是我自己授權給了 spender 一個金額,這個金額是 amount。

隨后再用 emit 觸發一個事件。

2.9 指定授權賬戶

查看授權賬戶余額也很簡單了,傳入兩個地址,一個地址是授權人,另一個是被授權人,返回對應的 appbalances 數據,那么就得到值了,那么這個方法編寫如下:

//查看授權賬戶余額 function allowance(address owner, address spender)override public view returns (uint) {return appbalances[owner][spender]; }

2.10 授權用戶的專用轉賬方法

授權用戶是有一個專用的轉賬方法的,畢竟這兩者存儲的結構都不一樣,那么此時就實現最后一個需要實現的授權用戶的轉賬方法:

//授權用戶的轉賬方法 function transferFrom(address from, address to, uint256 amount)override public returns (bool) {require(amount <= balances[from]);require(amount <= appbalances[from][msg.sender]);balances[from] = balances[from]-amount;appbalances[from][msg.sender] = appbalances[from][msg.sender]-amount;balances[to] = balances[to]+amount;emit Transfer(from, to, amount);return true; }

以上代碼中的第一行,為啥要判斷 balances 非授權用戶的余額呢?那是因為我授權給你的錢那也是我的錢,那么肯定我的錢都不夠,你肯定也不夠了。要注意這個關系,是授權而不是轉賬給你。

知道以后那就明白為什么要寫 require(amount <= balances[from]); 了,那么判斷完授權用戶的余額后開始判斷被授權用戶的余額是否足夠,足夠了就繼續往下走。

首先得從授權賬戶的余額里面扣除要支出的部分 balances[from] = balances[from]-amount;,接著再從被授權的人那里扣除支出部分 appbalances[from][msg.sender] = appbalances[from][msg.sender]-amount;;有些同學可能會問不是已經從授權賬戶扣除了為什么還要從被授權賬戶扣除呢?這是因為這是被授權用戶發起的支出,而不是授權賬戶發起的支出,所以被授權賬戶要減去已經授權的余額。

接下來就直接導 balances 中為獲得方添加余額即可,記住這個金額不是授權金額,所以直接 balances 進行添加即可。

最后響應一個事件及解決。

2.11 完整代碼

那么此時的完整代碼如下:

// SPDX-License-Identifier:MIT pragma solidity 0.8.17; interface IERC20 {//發行的代幣總量function totalSupply() external view returns (uint256);//某地址余額function balanceOf(address account) external view returns (uint256);//從當前賬戶對某個地址轉amount的錢function transfer(address account, uint256 amount) external returns (bool);//授權某個賬戶可以用你的錢(用多少錢是指定的)function approve(address spender, uint256 amount) external returns (bool);//你授權的賬戶還可以有多少你授權的錢可以用function allowance(address owner, address spender) external view returns (uint256);//授權用戶的轉賬方法,只針對授權用戶使用function transferFrom(address from,address to,uint256 amount) external returns (bool);//轉賬時觸發轉賬事件event Transfer(address indexed from, address indexed to, uint256 value);//授權時觸發授權事件event Approval(address indexed owner, address indexed spender, uint256 value); }contract BitCoinDemo is IERC20{//余額mapping(address => uint256)public balances;//總量uint256 public total = 10000000000000000;//代幣名string public constant name = "1BITCOINERC20DEMO";//簡稱string public constant symbol = "1BitCoin";//小數點uint8 public constant decimals = 18;//授權用戶及余額mapping(address => mapping (address => uint256)) appbalances;constructor() {balances[msg.sender] = total;}//返回總量function totalSupply()override public view returns (uint256) {return total;}//轉賬代幣function transfer(address account, uint256 amount) public override returns (bool) {require(balances[msg.sender]>amount);//判斷錢夠不夠balances[msg.sender] = balances[msg.sender]-amount;//原賬戶減去給自己balances[account] = balances[account]+amount;//給別人賬戶加上轉賬的錢emit Transfer(msg.sender, account, amount);//響應這個事件return true;}//余額查看function balanceOf(address account)override public view returns (uint256) {return balances[account];}//授權方法function approve(address spender, uint256 amount)override public returns (bool) {appbalances[msg.sender][spender] = amount;emit Approval(msg.sender, spender, amount);return true;}//查看授權賬戶余額function allowance(address owner, address spender)override public view returns (uint) {return appbalances[owner][spender];}//授權用戶的轉賬方法function transferFrom(address from, address to, uint256 amount)override public returns (bool) {require(amount <= balances[from]);require(amount <= appbalances[from][msg.sender]);balances[from] = balances[from]-amount;appbalances[from][msg.sender] = appbalances[from][msg.sender]-amount;balances[to] = balances[to]+amount;emit Transfer(from, to, amount);return true;} }

三、新增功能

3.1 增發鑄幣

此時我們還可以對合約增加一些新的功能,例如鑄幣功能。你可以理解為鑄幣就是對代幣進行增發(不是增頭發),通過鑄幣可以創造出更多的代幣,但是在代幣總量上我們需要對其進行增加,否則你的發行跟實際記錄不符,這樣你的合約將會不可信。

//增發 function mint(address account, uint256 amount) external virtual {total += amount;balances[account] += amount;emit Transfer(address(0), account, amount); }

以上是一個增發方法,通過傳入增發后代幣增加的賬戶地址,以及一個增發量,再到方法內對總量進行增加,并且記錄增發的代幣存儲到哪一個賬戶之中,當然也要響應一個對應的交易事件(你也可以再搞一個增發事件)。

3.2 代幣銷毀

既然有了代幣增發,那就來一個代幣銷毀。代表銷毀可以銷毀指定賬戶的代幣,當然你也可以設定為只有“owner”賬戶,最開始存儲的賬戶代幣都行,在此只是做一個示例。

//銷毀 function burn(address account, uint256 amount) external virtual {require(balances[account] >= amount, "burn error");balances[account] = balances[account] - amount;total -= amount;emit Transfer(account, address(0), amount); }

代幣銷毀的方式跟增發的方式相反,當然還需要判斷你指定的賬戶的余額否大于或等于需要銷毀的量,接著就是往對應的 balances 里面去減去對應的 amount 了,總量也要對應的減去值,最后觸發一個 Transfer 事件。

在此我們可以看到我們通過 發送方或者是接收方 為 0 地址表示銷毀和增加,發送方為 0 地址則是增發,接收方為 0 地址則是銷毀。

四、優化合約

通過以上的最基礎的 ERC20 合約內容大概已經明白了怎么玩了,接下來我們為其新增一點內容,循序漸進感覺挺棒。

4.1 增發及銷毀條件

增發及銷毀條件需要滿足是否是合約的 owner 調用,否則任意一個人都可以增發和銷毀就亂套了,在此我們增加對應的 require:

require(owner==msg.sender,"sender error");

在此我們還需要創建一個狀態變量存儲當前的 owner:

address owner; owner=msg.sender;

4.2 銷毀代幣優化

銷毀代幣之前是隨便一個賬戶指定了就可以銷毀那個賬戶代幣,這明顯就不對,不然我的錢就非常不安全了,在此我們設置只能夠銷毀自己的代碼:

還需要把多余的參數刪除喲。

4.3 完整代碼

其他情況就增加判斷是否是 0 地址就ok了,畢竟本篇文章只是介紹基礎的 ERC20,并不是做一個“完善”的ERC20 合約:

接著我們部署完畢后(測試網)導入代幣:

接著我們來個增發,輸入地址和增加量:

等待交易完成:

現在錢多多了,并且使 Mint 方法發送的。

在測試一下銷毀:


銷毀成功:

基本上都操作正常:

最終代碼完整如下:

// SPDX-License-Identifier:MIT pragma solidity 0.8.17; interface IERC20 {//發行的代幣總量function totalSupply() external view returns (uint256);//某地址余額function balanceOf(address account) external view returns (uint256);//從當前賬戶對某個地址轉amount的錢function transfer(address account, uint256 amount) external returns (bool);//授權某個賬戶可以用你的錢(用多少錢是指定的)function approve(address spender, uint256 amount) external returns (bool);//你授權的賬戶還可以有多少你授權的錢可以用function allowance(address owner, address spender) external view returns (uint256);//授權用戶的轉賬方法,只針對授權用戶使用function transferFrom(address from,address to,uint256 amount) external returns (bool);//轉賬時觸發轉賬事件event Transfer(address indexed from, address indexed to, uint256 value);//授權時觸發授權事件event Approval(address indexed owner, address indexed spender, uint256 value); }contract BitCoinDemo is IERC20{//余額mapping(address => uint256)public balances;//總量uint256 public total = 10000000000000000;//代幣名string public constant name = "1BITCOINERC20DEMO";//簡稱string public constant symbol = "1BitCoin";//小數點uint8 public constant decimals = 18;//授權用戶及余額mapping(address => mapping (address => uint256)) appbalances;//擁有者address owner;constructor() {owner=msg.sender;balances[msg.sender] = total;}//返回總量function totalSupply()override public view returns (uint256) {return total;}//轉賬代幣function transfer(address account, uint256 amount) public override returns (bool) {require(account==address(0),"sender error");require(balances[msg.sender]>amount);//判斷錢夠不夠balances[msg.sender] = balances[msg.sender]-amount;//原賬戶減去給自己balances[account] = balances[account]+amount;//給別人賬戶加上轉賬的錢emit Transfer(msg.sender, account, amount);//響應這個事件return true;}//余額查看function balanceOf(address account)override public view returns (uint256) {return balances[account];}//授權方法function approve(address spender, uint256 amount)override public returns (bool) {require(spender==address(0),"sender error");appbalances[msg.sender][spender] = amount;emit Approval(msg.sender, spender, amount);return true;}//查看授權賬戶余額function allowance(address owner, address spender)override public view returns (uint) {return appbalances[owner][spender];}//授權用戶的轉賬方法function transferFrom(address from, address to, uint256 amount)override public returns (bool) {require(amount <= balances[from]);require(amount <= appbalances[from][msg.sender]);require(to==address(0),"sender error");balances[from] = balances[from]-amount;appbalances[from][msg.sender] = appbalances[from][msg.sender]-amount;balances[to] = balances[to]+amount;emit Transfer(from, to, amount);return true;}//增發function mint(address account, uint256 amount) external virtual {require(owner==msg.sender,"sender error");total += amount;balances[account] += amount;emit Transfer(address(0), account, amount);}//銷毀function burn(uint256 amount) external virtual {require(owner==msg.sender,"sender error");require(balances[owner] >= amount, "burn error");balances[owner] = balances[owner] - amount;total -= amount;emit Transfer(owner, address(0), amount);} }

總結

以上是生活随笔為你收集整理的web3 solidity 基础 ERC20 大白话搞懂的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。