智能合約開發學習—實踐 ERC20
這裡整理之前上課的筆記,都是入門級別一共 4 章,分別如下:
講那麼多,還是看個實際的例子比較有感覺
所謂得 ERC 是 Ethereum Request for Comments 的縮寫,是被同意後的 EIP 演變而來的
EIP 是 Ethereum Improvement Proposals 的縮寫,顧名思義就是提案,提案給 eth 社群經審查確定實作後就成為 ERC
而 EIP-20 的標題是 Token standard,就是以太幣的標準
interfaces
EIP-20 的文件有明定要實現標準接口如下
- totalSupply
- 返回此 contract 的 token 最大值
function totalSupply() public view returns (uint256)
- balanceOf
- 返回傳入 owner 的 balance
function balanceOf(address _owner) public view returns (uint256 balance)
- transfer
- 進行移轉,當 caller 的 balance 不夠時要丟出例外
function transfer(address _to, uint256 _value) public returns (bool success)
- transferFrom
- 用在提款流程,允許合約代表你進行 token 移轉,如果
_from
沒有授權合約的話要拋出例外 function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
- 用在提款流程,允許合約代表你進行 token 移轉,如果
- approve
- 允許
_spender
從你的帳戶中多次提款,最大值為_value
,每次呼叫都會複寫掉_value
function approve(address _spender, uint256 _value) public returns (bool success)
- 允許
- allowance
- 返回
_spender
剩餘可以從_owner
中提出的 token 數量 function allowance(address _owner, address _spender) public view returns (uint256 remaining)
- 返回
- (event) Transfer
- 當發生移轉時必須被 trigger,就算是 0 也是
event Transfer(address indexed _from, address indexed _to, uint256 _value)
- (event) Approve
- 在呼叫
approve(address _spender, uint256 _value)
必須被 trigger event Approval(address indexed _owner, address indexed _spender, uint256 _value)
- 在呼叫
implementation
- 開發環境
這裡是用 Remix IDE 進行開發,不用煩惱本地環境配置的問題,如何使用它串接 metamask 請參考本文底部的 references
- ERC20.sol
//SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
// ----------------------------------------------------------------------------
// EIP-20: ERC-20 Token Standard
// https://eips.ethereum.org/EIPS/eip-20
// -----------------------------------------
interface ERC20Interface {
function totalSupply() external view returns (uint);
function balanceOf(address tokenOwner) external view returns (uint balance);
function transfer(address to, uint tokens) external returns (bool success);
function allowance(address tokenOwner, address spender) external view returns (uint remaining);
function approve(address spender, uint tokens) external returns (bool success);
function transferFrom(address from, address to, uint tokens) external returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
contract Cryptos is ERC20Interface{
string public name = "Cryptos";
string public symbol = "CRPT";
uint public decimals = 0; //18 is very common
uint public override totalSupply;
address public founder;
mapping(address => uint) public balances;
// balances[0x1111...] = 100;
mapping(address => mapping(address => uint)) allowed;
// allowed[0x111][0x222] = 100;
constructor(){
totalSupply = 1000000;
founder = msg.sender;
balances[founder] = totalSupply;
}
function balanceOf(address tokenOwner) public view override returns (uint balance){
return balances[tokenOwner];
}
function transfer(address to, uint tokens) public override returns(bool success){
require(balances[msg.sender] >= tokens);
balances[to] += tokens;
balances[msg.sender] -= tokens;
emit Transfer(msg.sender, to, tokens);
return true;
}
function allowance(address tokenOwner, address spender) view public override returns(uint){
return allowed[tokenOwner][spender];
}
function approve(address spender, uint tokens) public override returns (bool success){
require(balances[msg.sender] >= tokens);
require(tokens > 0);
allowed[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
return true;
}
function transferFrom(address from, address to, uint tokens) public override returns (bool success){
require(allowed[from][msg.sender] >= tokens);
require(balances[from] >= tokens);
balances[from] -= tokens;
allowed[from][msg.sender] -= tokens;
balances[to] += tokens;
emit Transfer(from, to, tokens);
return true;
}
}
references
發佈時間
2023-3-18