// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "hardhat/console.sol";
//ERC20 同質化代幣,每個代幣的本質或性質都是相同
//ETH 是原生代幣,它不是ERC20代幣,它們兩是不能協同工作。所以需要將ETH轉換成WETH(ERC20)
//ERC20 必須實現相應的介面(規範),參見 https://eips.ethereum.org/EIPS/eip-20
//totalSupply 代幣發行總供應量,它即可以固定不變,又可以根據業務需求而改變
//totalSupply 代幣發行總供應量是否可變,取決於合約是否存在mint或burn函式/方法
//balanceOf(owner) 獲取某個賬戶的餘額,所有賬戶餘額的總和必須等於totalSupply
//approve 授權一定數量的代幣給第三方/交易所/代理人。注意,是授權而不是傳送代幣給第三方
//approve 必須包含3個引數,Owner:誰授權代幣給第三方,Spender:第三方/交易所/代理人,Amount:授權數額
//allowance 儲存approve方法的3項資料
//transfer 轉賬,接收2個引數,from:msg.sender; to:轉入; amount:金額
//transferFrom 轉賬,接收3個引數,from:轉出; to:轉入; amount:金額
//transfer與transferFrom使用場景不一樣,transfer用在本合約轉賬,transferFrom用在第三方/去中心交易所/代理人
//event Approval與Transfer 將交易等日誌資訊寫入區塊鏈,非常重要
//V1
interface IERC20V1 {
event Approval(address indexed owner ,address indexed spender ,uint256 amount);
event Transfer(address indexed from ,address indexed to ,uint256 amount);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
//對應狀態變數totalSupply 代幣發行總供應量
function totalSupply() external view returns(uint256);
//balanceOf(owner) 獲取某個賬戶的餘額
function balanceOf(address owner) external view returns(uint256);
//approve 授權一定數量的代幣給第三方/交易所/代理人
function approve(address spender, uint amount) external returns (bool);
//allowance 儲存approve方法的3項資料
function allowance(address owner, address spender) external view returns (uint256);
function transfer(address to, uint amount) external returns(bool);
function transferFrom(address from, address to,uint amount) external returns(bool);
}
contract ERC20V1 is IERC20V1 {
string public constant name = "XingZheChain";
string public constant symbol = "XZC";
uint8 public constant decimals = 18;
//totalSupply 代幣發行總供應量
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
address public _owner;
mapping(address => mapping(address => uint256)) public allowance;
constructor(uint256 _initTotalSupply){
_owner = msg.sender;
//預挖給建立者代幣
mint(msg.sender,_initTotalSupply);
}
modifier onlyOwner() {
require(_owner == msg.sender,"Ownable:caller is not the owner");
_;
}
//挖掘出新代幣以及挖給那個地址
//合約建立者呼叫
function mint(address to ,uint256 amount) public onlyOwner {
totalSupply = totalSupply += amount;
balanceOf[to] = balanceOf[to] += amount;
}
//燃燒自己的代幣
function burn(uint256 amount) public {
address from = msg.sender;
balanceOf[from] = balanceOf[from] -= amount;
totalSupply = totalSupply -= amount;
}
function _approve(address owner, address spender, uint amount) private {
allowance[owner][spender] = amount;
emit Approval(owner ,spender ,amount);
}
function approve(address spender, uint amount) external returns(bool) {
_approve(msg.sender, spender, amount);
return true;
}
function _transfer(address from, address to,uint amount) private {
balanceOf[from] = balanceOf[from] -= amount;
balanceOf[to] = balanceOf[to] += amount;
emit Transfer(from ,to ,amount);
}
function transfer(address to, uint amount) external returns(bool){
_transfer(msg.sender, to, amount);
return true;
}
function transferFrom(address from, address to,uint amount) external returns(bool){
uint256 currentAllowance = allowance[from][msg.sender];
require(currentAllowance >= amount,"ERC20: insufficient allowance");
allowance[from][msg.sender] = currentAllowance -= amount;
//console.log("msg.sender ->",address(msg.sender));
_transfer(from ,to ,amount);
return true;
}
}
//建議去中心化交易所
contract Dex {
address public erc20V1;
constructor(address _erc20V1){
erc20V1 = _erc20V1;
}
function transferFromTo(address to ,uint amount) external {
IERC20V1(erc20V1).transferFrom(msg.sender ,to ,amount);
}
function transferTo(address to,uint amount) external {
IERC20V1(erc20V1).transfer(to,amount);
}
}