Solidity語法基礎學習
十、實戰專案(二):
3.專案實操:
ERC20 代幣實戰
①轉賬篇
總髮行量函式
totalSupply() return(uint256)
·回傳代幣的發行總量
·使用狀態變數uint256_totalSupply來儲存
賬戶餘額查詢函式
Balance0f(address) returns(uint256)
·給定一個賬戶(address),回傳該賬戶擁有的代幣餘額(uint256)
·使用mapping來儲存:
·mapping(address => uint256) _balance;
轉賬函式
Transfer(address,uint256) returns(bool);
·呼叫者“msg.sender”,轉移“amount”數量的代幣給特定賬戶“to”
·成功時回傳true,反之,回傳false
·有些檢查需要做:
·amount是否超過餘額
·是否轉移給address 0x0代表銷燬的意思
轉賬事件
event Transfer(
address indexed from,
address indexed to,
uint256 value,
);
·當發生代幣轉移時,必須觸發此事件,即使轉移的數量為“0”也是
②授權篇
授權餘額查詢函式
allowance(address owner,address spender) returns(uint256);
·給定兩個賬戶(address),回傳“owner”授權給“spender”的額度(uint256)
·使用mapping來儲存:
·mapping(address =>
·mapping(address => uint256) _allowance;
注:mapping查詢節省燃料
授權函式
approve(address spender,uint256 amount) returns(bool);
·呼叫者“msg.sender”,授權“amount”數量的代幣額度給第三方賬戶“spender”
·成功時回傳true,反之,回傳false
授權事件
event Approval(
address indexed owner,
address indexed spender,
uint256 value,
);
·當授權額度時,必須觸發此事件,即使數量為“0”也要觸發
③花別人的錢
從第三方賬戶轉賬的函式
transferFrom(address from,address to,uint256 amount);
·呼叫者(msg.sender)從代幣持有者(from)轉賬給接收者(to)“amount”數量的代幣
·其中:
·需檢查呼叫者是否擁有足夠的額度可用
·轉賬時要檢查持有者是否足夠的餘額
·轉賬時需要同時減少額度
4.補充概念:
ERC20代幣實戰
元資料(metadata)
鑄造(mint)與銷燬(burn)篇
ERC20 Meta介面
Interface IERCMetadata{……}
interface IERC20Metadata{
function name() public view returns(string memory);
function symbol() public view returns(string memory);
function decimals() public view returns(uint8);
}
代幣名稱
function name() public view returns(string memory);
·回傳一個字元,代表這個代幣的名稱
·儲存是以string來儲存
·通常在constructor的時候就給定
代幣的簡稱/縮寫/象徵
function symbol() public view returns(string memory);
·回傳一個字串,代表這個代幣的簡稱
·Ethereum(name)→ETH(symbol)
·Apple(name)→AAPL(symbol)
·儲存時以string來儲存
·通常在constructor的時候就給定
代幣小數點位置
function decimals() public view returns(uint8);
·回傳一個uint8,代表這個代幣的小數點位置
·這個函式只用來顯示用
·decimals=3,則balance=1234,在顯示為1.234
·基本上代幣都會把decimals設定為18
·這是因為最開始就是設計的18,後來因為人類天性,能抄就抄
·1ether=1018wei
·1token=1018uint => decimals=18
ERC20輔助函式
鑄造(mint)與銷燬(burn)
interface IERC20{
function mint(address account,uin256 amount);
function burn(address account,uint256 amount);
}
鑄造新代幣
function mint(address account,uint256 amount);
·鑄造,即“無中生有”
·只有合約擁有者或者特殊許可權的人才能呼叫
·他同時也是一種轉賬,由address 0x0轉到目標賬號(account)
·由於是轉賬,因此也要觸發“Transfer”事件
銷燬代幣
function burn(address account,uint256 account);
·銷燬,即“迴歸虛無”
·可以根據使用情況決定誰可以呼叫
·若只有合約擁有者可以呼叫,則通常會有account引數,用來銷燬特定人的代幣
·若任何人都可以呼叫,則不會有account引數,用來銷燬特定人的代幣
·若任何人都可以呼叫,則不會有account引數,主要目的是請求呼叫者(msg.sender)銷燬自己的代幣同時也是一種轉賬,由account/msg.sender轉到address 0x0
·由於是轉賬,因此也要觸發“Transfer”事件
Example:示例程式碼
//SPDX-License-Identifier:MIT
pragma solidity ^0.8.17;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner,address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balance0f(address account) external view returns (uint256);
function allowance(address owner,address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transfer(address to, uint amount) external returns (bool);
function trnasferFrom(address from, address to, uint256 amount) external returns (bool);
}
contract ERC20 is IERC20 {
uint _totalSupply;//定義一個數
mapping(address => uint256) _balance;//定義了一個賬號
mapping(address => mapping(address => uint256)) _allowance;
//查詢授權額度
function allowance(address owner, address spender) public view returns (uint256) {
return _allowance[owner][spender];//返回自己和第三方
}
function _approve(address owner, address spender, uint256 amount) internal {
_allowance[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
//授權
function approve(address spender, uint256 amount) public returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
//發行代幣,啟動最初代幣
constructor () {
_balance[msg.sender] = 10000;
_totalSupply = 10000;
}
function totalSupply() public view returns (uint256) {
//回傳總髮行量
return _totalSupply;
}
function balance0f(address account) public view returns (uint256) {
//回傳查詢餘額
return _balance[account];
}
function _transfer(address from, address to, uint256 amount) internal {
uint256 myBalance = _balance[from];
require(myBalance >= amount,"No money to transfer!");//已經沒錢轉賬了
require(to != address(0),"Transfer to address 0");//不準轉賬到地址0
_balance[from] = myBalance - amount;//我的賬戶總額計算
_balance[to] = _balance[to] + amount;//你的賬戶怎麼計算
emit Transfer(from, to, amount);
}
//實現轉賬功能
function transfer(address to, uint256 amount) public returns (bool) {
_transfer(msg.sender, to , amount);
return true;
}
//檢查額度花人家的錢
function trnasferFrom(address from, address to, uint256 amount) external returns (bool) {
uint256 myAllowance = _allowance[from] [msg.sender];
require(myAllowance >= amount,"ERROR:myAllowance < amount"); //我們允許的額度是否小於了他花的額度
_approve(from, msg.sender, myAllowance - amount);//花去以後是否允許的額度有減少
_transfer(from, to, amount);
//檢查花銷是否從原來賬戶轉移到被授權者賬戶
return true;
}
}