---
# System prepended metadata

title: Solidity ERC20 Practice
tags: [Block Chain]

---

###### tags: `Block Chain`

# Solidity ERC20 Practice

## [ERC20](https://eips.ethereum.org/erc) 

### Must 
```solidity=
// 返回代幣的總供應量
function totalSupply() public view returns (uint256)
// 返回該帳戶此代幣的餘額
function balanceOf(address _owner) public view returns (uint256 balance)
// 轉移代幣至_to地址，觸發Transfer event & throw error
function transfer(address _to, uint256 _value) public returns (bool success)
// 從_from轉移代幣至_to地址，觸發Transfer event & throw error
function transferForm(address _from,address _to, uint256 _value) public returns (bool success)
// 批准提領數，設置_spender可提取的代幣數量 
function approve(address _spender, uint256 _value) public returns (bool success) 
// 返回_owner批准_spender的提取數量
function allowance(address _owner, address _spender) public view returns(uint256 remaining)
```

### Option
```solidity=
// 返回代幣名稱 
function name() public view returns (string)
// 返回代幣的符號 ex: etheteum->eth
function symbol() public view returns (string)
// 返回代幣使用的小數點位數
function decimals() public view returns (uint8)
```

### Event
```solidity=
// 轉移事件，代幣轉移時都必須觸發，包含0值轉移，創建代幣時也須觸發事件，_from設置為0x000
event function Transfer(address indexed _from, address indexed _to, uint256 _value)
// 成功事件，任何成功的調用都要觸發
event function Approval(address indexed _onwer, address indexed _spender,uint256 _value)

```

```solidity=
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.14;

contract Token {
    // Token 名字 (幣的名字)11
    string public name = "Anonymous Mask Token";
    // 暱稱
    string public symbol = "AMT";
    // 使用的小數點位
    uint8 decimals = 5;

    // Event
    // 轉移事件，代幣轉移時都必須觸發，包含0值轉移，創建代幣時也須觸發事件，_from設置為0x000
    event  Transfer(address indexed _from, address indexed _to, uint256 _value);
    // 成功事件，任何成功的調用都要觸發
    event  Approval(address indexed _onwer, address indexed _spender,uint256 _value);


    //返回該帳戶此代幣的餘額，帳號餘額map like map[address]uin256 in golang
    mapping (address => uint256) public balanceOf;

    // A地址允許B地址提取的代幣數量
    // 返回_owner批准_spender的提取數量
    mapping (address => mapping(address => uint256)) public allowance;

    // 代幣總數，返回代幣的總供應量，此種寫法包含宣告變數及產生簡單的get func
    uint256 public totalSupply;
    /*
    效用同此
        uint256 totalSupply;
        function totalSupply() public view returns (uint256){
            return totalSupply;
        }
    */
    
    // 轉移代幣至_to地址，觸發Transfer event & throw error
    function transfer(address _to, uint256 _value) public returns (bool success){
        return transferFrom(msg.sender,_to,_value);
    }

    // 從_from轉移代幣至_to地址，觸發Transfer event & throw error
    function transferFrom(address _from,address _to, uint256 _value) public returns (bool success){
        // 檢查from有無足夠代幣，沒有的話throw error 
        require(balanceOf[_from] >= _value,"not enough token!");


        // 確認當前呼叫合約者是否為from
        if (msg.sender != _from) {
            // 此情況為第三者要轉移from地址的代幣到to
            // 確認from授予msg.sender的提領代幣數量有無大於此次轉移顆數
            require(allowance[_from][msg.sender] >= _value);
        }

        balanceOf[_from] -= _value;
        balanceOf[_to] += _value;

	    emit Transfer(_from,_to,_value);

        return true;
    }
    // 批准提領數，設置_spender可提取的代幣數量 
    function approve(address _spender, uint256 _value) public returns (bool success) {
        // @ msg.sender => 合約呼叫者
        // @ _spender => 提領者
        // msg.sender 允許 _spender 提領 value 顆 AMT
        allowance[msg.sender][_spender] = _value;

        // 觸發事件
	    emit Approval(msg.sender,_spender,_value);

        return true;
    }

    // 造幣
    function mint(address _to,uint value) public {
        
        balanceOf[msg.sender] = value;
        totalSupply += value;
        emit Transfer(address(0),_to,value);
    }
    

}
```


{%hackmd theme-dark %}