以下是 ERC20 的應用,中心化交易所

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

// 運算過程中溢出(公開的類)
library SafeMath {
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        assert(c >= b);
        return c;
    }
}

interface IERC20 {
    // 獲取地址
    function getAddress() external view returns (address);

    // 返回當前存在的Token的總單位。ERC20Token可以有固定或可變的供應量。
    function totalSupply() external view returns (uint256);

    // 根據地址獲取餘額(Token)
    function balanceOf(address account) external view returns (uint256);

    // 從哪到哪交易轉帳 recpient 接收地址
    function transfer(address recipient, uint256 amount)
        external
        returns (bool);

		// 給定一個所有者地址和一個消費者地址,返回該消費者被批准從所有者的取款的剩餘金額。
    // 他能重我們的帳戶滑走多少錢
    function allowance(address owner, address spender)
        external
        view
        returns (uint256);

    // 先批准,在滑轉 approve ->allowance
    function approve(
        address owner,
        address spender,
        uint256 amount
    ) external returns (bool);

    // sender 發送者, recipient 接收者
    function transferFrom(
        address sender,
        address recipient,
        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 ERC20Basic is IERC20 {
    // 代幣名稱
    string public constant name = "ERC20-TestToken";
    // 代幣簡稱
    string public constant symbol = "ERC-TTK";
    uint8 public constant decimals = 18;
    // 帳戶
    mapping(address => uint256) balances;
    // 二維錢
    mapping(address => mapping(address => uint256)) allowed;
    // ether  10*18 多少代幣
    uint256 totalSupply_ = 10 ether;

    using SafeMath for uint256;

    // 構造函數
    constructor() {
        // 發行了多少錢給創建人(建立合約的人)
        balances[msg.sender] = totalSupply_;
    }

    function getAddress() public view override returns (address) {
        return address(this);
    }

    function totalSupply() public view override returns (uint256) {
        return totalSupply_;
    }

    // 獲取餘額
    function balanceOf(address tokenOwner)
        public
        view
        override
        returns (uint256)
    {
        return balances[tokenOwner];
    }

    // receiver 接收的人
    function transfer(address receiver, uint256 numTokens)
        public
        override
        returns (bool)
    {
        require(numTokens >= balances[msg.sender]);
        // 轉出去的人
        balances[msg.sender] = balances[msg.sender].sub(numTokens);
        // 接收的人
        balances[receiver] = balances[receiver].add(numTokens);
        emit Transfer(msg.sender, receiver, numTokens);
        return true;
    }

    function approve(
        address owner,
        address delegate,
        uint256 numTokens
    ) public override returns (bool) {
        // owner 底下的delegate允許滑走多少錢
        allowed[owner][delegate] = numTokens;
        emit Approval(owner, delegate, numTokens);
        return true;
    }

    function allowance(address owner, address delegate)
        public
        view
        override
        returns (uint256)
    {
        return allowed[owner][delegate];
    }

    // owner 傳出去 buyer 接收者 多少錢
    function transferFrom(
        address owner,
        address buyer,
        uint256 numTokens
    ) public override returns (bool) {
        require(numTokens <= balances[owner]);
        require(numTokens <= allowed[owner][msg.sender]);

        balances[owner] = balances[owner].sub(numTokens);
        allowed[owner][buyer] = allowed[owner][buyer].sub(numTokens);
        balances[buyer] = balances[buyer].add(numTokens);
        emit Transfer(owner, buyer, numTokens);
        return true;
    }
}

// 中心化交易所
contract DEX {
    event Bought(uint256 amount);
    event Sold(uint256 amount);

    IERC20 public token;

    constructor() {
        token = new ERC20Basic();
    }

    function buy() public payable {
        uint256 amountTobuy = msg.value; // 買多少
        // 合約多少錢
        uint256 dexBalance = token.balanceOf(address(this)); //合約多少錢
        require(amountTobuy > 0, "You need to send some Ether");
        require(amountTobuy <= dexBalance, "Not enough tokens in the reserve");
        token.transfer(msg.sender, amountTobuy);
        emit Bought(amountTobuy);
    }

    function sell(uint256 amount) public {
        require(amount > 0, "You need to sell at laeast some tokens");
        uint256 allowance = token.allowance(msg.sender, address(this));
        require(allowance >= amount, "Check the token allowance");
        token.transferFrom(msg.sender, address(this), amount);
        emit Sold(amount);
    }

    function getDexBalance() public view returns (uint256) {
        return token.balanceOf(address(this));
    }

    // 現在這個人的代幣有多少
    function getOwnerBalance() public view returns (uint256) {
        return token.balanceOf(msg.sender);
    }

    function getAdress() public view returns (address) {
        return address(this);
    }

    function getTokenAddress() public view returns (address) {
        return token.getAddress();
    }

    function getTotalSupply() public view returns (uint256) {
        return token.totalSupply();
    }

    function getSenderAddress() public view returns (address) {
        return address(msg.sender);
    }

    function getAllowance() public view returns (uint256) {
        uint256 allowance = token.allowance(msg.sender, address(this));
        return allowance;
    }

    function approve(uint256 amount) public returns (bool) {
        bool isApprove = token.approve(msg.sender, address(this), amount);
        return isApprove;
    }
}
  1. library SafeMath 這部分是防止計算中溢出(通常別人已經寫好不用再自己寫)
  2. 可以看到其實 IERC20是 interface 所以我們就是實作他的方法即可。
  3. 注意發現IERC20 各 function的修飾詞是external [ 只有內部可調用]
  4. 所以會有一個實現的地方 contract ERC20Basic is IERC20

20.ERC721

有任何問題可反饋: [email protected]