3分钟Solidity: 8.5 ERC20

25 阅读4分钟

欢迎订阅专栏3分钟Solidity--智能合约--Web3区块链技术必学

如需获取本内容的最新版本,请参见 Cyfrin.io 上的ERC20(代码示例)

任何遵循ERC20标准的合约都是ERC20代币。

ERC-20引入了可替代Token(代币)的标准,换句话说,它们具有使每个Token(代币)与另一个Token(代币)完全相同(在类型和价值上)的属性。例如,ERC-20,Token(代币)的行为与ETH相同,这意味着任意1个遵循ERC-20规则的Token(代币)与所有其他所有Token(代币)是平等和相同的。

ERC20代币提供以下功能:

  • 转移代币
  • 允许他人代表代币持有者转移代币

以下是ERC20的接口。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount)
        external
        returns (bool);
    function allowance(address owner, address spender)
        external
        view
        returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount)
        external
        returns (bool);
}

ERC20代币合约示例。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import "./IERC20.sol";

contract ERC20 is IERC20 {
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(
        address indexed owner, address indexed spender, uint256 value
    );

    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;
    string public name;
    string public symbol;
    uint8 public decimals;

    constructor(string memory _name, string memory _symbol, uint8 _decimals) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
    }

    function transfer(address recipient, uint256 amount)
        external
        returns (bool)
    {
        balanceOf[msg.sender] -= amount;
        balanceOf[recipient] += amount;
        emit Transfer(msg.sender, recipient, amount);
        return true;
    }

    function approve(address spender, uint256 amount) external returns (bool) {
        allowance[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount)
        external
        returns (bool)
    {
        allowance[sender][msg.sender] -= amount;
        balanceOf[sender] -= amount;
        balanceOf[recipient] += amount;
        emit Transfer(sender, recipient, amount);
        return true;
    }

    function _mint(address to, uint256 amount) internal {
        balanceOf[to] += amount;
        totalSupply += amount;
        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal {
        balanceOf[from] -= amount;
        totalSupply -= amount;
        emit Transfer(from, address(0), amount);
    }

    function mint(address to, uint256 amount) external {
        _mint(to, amount);
    }

    function burn(address from, uint256 amount) external {
        _burn(from, amount);
    }
}

创建你自己的ERC20代币

使用Open Zeppelin可以非常轻松地创建你自己的ERC20代币。

这里有一个示例

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import "./ERC20.sol";

contract MyToken is ERC20 {
    constructor(string memory name, string memory symbol, uint8 decimals)
        ERC20(name, symbol, decimals)
    {
        // Mint 100 tokens to msg.sender
        // Similar to how
        // 1 dollar = 100 cents
        // 1 token = 1 * (10 ** decimals)
        _mint(msg.sender, 100 * 10 ** uint256(decimals));
    }
}

代币交换合约

以下是一个示例合约 TokenSwap,用于将一个 ERC20 代币兑换为另一个 ERC20 代币。

该合约将通过调用以下功能实现代币交换:

transferFrom(address sender, address recipient, uint256 amount)

该操作会将 amount数量的代币从 sender转账至 recipient

要使 transferFrom执行成功,sender必须满足以下条件:

  • 账户余额需大于 amount数量的代币
  • 在 TokenSwap调用 transferFrom之前,已通过调用 approve授权 TokenSwap提取 amount数量的代币
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import "./IERC20.sol";

/*
如何交换代币

1.  Alice拥有100个AliceCoin代币,这是一种ERC20代币。
2.  Bob拥有100个BobCoin代币,这也是一种ERC20代币。
3.  Alice和Bob想用10个AliceCoin交换20个BobCoin。
4.  Alice或Bob部署TokenSwap合约
5.  Alice授权TokenSwap合约从AliceCoin中提取10个代币
6.  Bob授权TokenSwap合约从BobCoin中提取20个代币
7.  Alice或Bob调用TokenSwap.swap()方法
8.  Alice和Bob成功完成了代币交换。
*/

contract TokenSwap {
    IERC20 public token1;
    address public owner1;
    uint256 public amount1;
    IERC20 public token2;
    address public owner2;
    uint256 public amount2;

    constructor(
        address _token1,
        address _owner1,
        uint256 _amount1,
        address _token2,
        address _owner2,
        uint256 _amount2
    ) {
        token1 = IERC20(_token1);
        owner1 = _owner1;
        amount1 = _amount1;
        token2 = IERC20(_token2);
        owner2 = _owner2;
        amount2 = _amount2;
    }

    function swap() public {
        require(msg.sender == owner1 || msg.sender == owner2, "Not authorized");
        require(
            token1.allowance(owner1, address(this)) >= amount1,
            "代币1的授权额度过低"
        );
        require(
            token2.allowance(owner2, address(this)) >= amount2,
            "代币2限额过低"
        );

        _safeTransferFrom(token1, owner1, owner2, amount1);
        _safeTransferFrom(token2, owner2, owner1, amount2);
    }

    function _safeTransferFrom(
        IERC20 token,
        address sender,
        address recipient,
        uint256 amount
    ) private {
        bool sent = token.transferFrom(sender, recipient, amount);
        require(sent, "Token transfer failed");
    }
}

Remix Lite 尝试一下