本文最后更新于 2024-03-31,本文发布时间距今超过 90 天, 文章内容可能已经过时。最新内容请以官方内容为准

ERC20 Contract built

Requrirement 📂

完善合约,实现以下功能:

  1. 设置 Token 名称(name):“BaseERC20”
  2. 设置 Token 符号(symbol):“BERC20”
  3. 设置 Token 小数位 decimals:18
  4. 设置 Token 总量(totalSupply):100,000,000
  5. 允许任何人查看任何地址的 Token 余额(balanceOf)
  6. 允许 Token 的所有者将他们的 Token 发送给任何人(transfer);转帐超出余额时抛出异常 (require),并显示错误消息“ERC20: transfer amount exceeds balance”。
  7. 允许 Token 的所有者批准某个地址消费他们的一部分 Token(approve)
  8. 允许任何人查看一个地址可以从其它账户中转账的代币数量(allowance)
  9. 允许被授权的地址消费他们被授权的 Token 数量(transferFrom);
  10. 转帐超出余额时抛出异常 (require),异常信息:“ERC20: transfer amount exceeds balance”
  11. 转帐超出授权数量时抛出异常 (require),异常消息:“ERC20: transfer amount exceeds allowance”。

⚠️ 注意

在编写合约时,需要遵循 ERC20 标准,此外也需要考虑到安全性,确保转账和授权功能在任何时候都能正常运行无误。

代码模板中已包含基础框架,只需要在标记为“Write your code here”的地方编写你的代码。不要去修改已有内容!

💯 希望你能用一段优雅高效安全的代码,完成这个挑战。

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


contract BaseERC20 {
    string public name; 
    string public symbol; 
    uint8 public decimals; 

    uint256 public totalSupply; 

    mapping (address => uint256) balances; 

    mapping (address => mapping (address => uint256)) allowances; 

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    constructor() public {
        // write your code here
        // set name,symbol,decimals,totalSupply
        balances[msg.sender] = totalSupply;  
    }

    function balanceOf(address _owner) public view returns (uint256 balance) {
        // write your code here
    }

    function transfer(address _to, uint256 _value) public returns (bool success) {
        // write your code here


        emit Transfer(msg.sender, _to, _value);  
        return true;   
    }

    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        // write your code here

        
        emit Transfer(_from, _to, _value); 
        return true; 
    }

    function approve(address _spender, uint256 _value) public returns (bool success) {
        // write your code here


        emit Approval(msg.sender, _spender, _value); 
        return true; 
    }

    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {   
        // write your code here     

    }
}

Implementation ✍️

完善后的智能合约代码:

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

contract BaseERC20 {
    string public name = "BaseERC20";
    string public symbol = "BERC20";
    uint8 public decimals = 18;

    uint256 public totalSupply = 100000000 * (10 ** uint256(decimals));

    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowances;

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    constructor() {
        balances[msg.sender] = totalSupply;
    }

    function balanceOf(address _owner) public view returns (uint256 balance) {
        return balances[_owner];
    }

    function transfer(address _to, uint256 _value) public returns (bool success) {
        require(balances[msg.sender] >= _value, "ERC20: transfer amount exceeds balance");
        balances[msg.sender] -= _value;
        balances[_to] += _value;
        emit Transfer(msg.sender, _to, _value);
        return true;
    }

    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(balances[_from] >= _value, "ERC20: transfer amount exceeds balance");
        require(allowances[_from][msg.sender] >= _value, "ERC20: transfer amount exceeds allowance");
        balances[_to] += _value;
        balances[_from] -= _value;
        allowances[_from][msg.sender] -= _value;
        emit Transfer(_from, _to, _value);
        return true;
    }

    function approve(address _spender, uint256 _value) public returns (bool success) {
        allowances[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
        return allowances[_owner][_spender];
    }
}

explanation 🤯

basic logic 🛠️

  1. 在构造函数中初始化了 Token 的名称、符号、小数位数以及总供应量,并将全部 Token 分配给合约的创建者。
  2. balanceOf 函数允许任何人查看指定地址的 Token 余额。
  3. transfer 函数允许 Token 的所有者将他们的 Token 发送给其他人。如果转账金额超过了发送者的余额,将会抛出异常并显示错误信息。
  4. approve 函数允许 Token 的所有者批准另一个地址消费他们的一部分 Token。
  5. allowance 函数允许任何人查看一个地址可以从其他账户中转账的代币数量。
  6. transferFrom 函数允许被授权的地址消费他们被授权的 Token 数量。如果转账金额超过了余额或者授权数量,将会抛出相应的异常。

code explanation 💻

1. 状态变量和事件

  • name, symbol, decimals: 这些状态变量分别存储代币的名称、符号和最小小数位数。它们在合约创建时被初始化,并且不可更改。
  • totalSupply: 存储代币的总供应量。这里通过乘以10 ** uint256(decimals)来确保总供应量符合指定的小数位数。
  • balances: 这是一个映射,用于存储每个地址的代币余额。
  • allowances: 这是一个嵌套映射,用于存储一个地址授权给另一个地址的代币数量。

事件TransferApproval用于记录代币转移和授权操作,它们是 ERC20 标准的一部分,可以被区块链浏览器和钱包用来更新用户界面和显示交易历史。

2. 构造函数

构造函数在合约创建时执行一次。它初始化代币的名称、符号、小数位数和总供应量,并将所有代币分配给合约的创建者。

3. balanceOf 函数

这个函数允许任何人查询特定地址的代币余额。它返回一个uint256类型的余额值。

4. transfer 函数

这个函数允许代币的所有者发送代币给其他地址。它执行以下步骤:

  • 检查发送者的余额是否足够进行转账。
  • 如果足够,从发送者余额中减去转账金额。
  • 将转账金额加到接收者的余额上。
  • 发出一个Transfer事件,记录这次代币转移。

如果余额不足,它将抛出一个异常,显示错误信息“ERC20: transfer amount exceeds balance”。

5. transferFrom 函数

这个函数允许一个地址使用另一个地址授权的代币进行转账。它执行以下步骤:

  • 检查发送者的余额是否足够。
  • 检查发送者授权给调用者的代币数量是否足够。
  • 如果都足够,从发送者余额中减去转账金额,并从发送者授权给调用者的代币数量中减去相同的金额。
  • 将转账金额加到接收者的余额上。
  • 发出一个Transfer事件,记录这次代币转移。

如果余额不足或授权数量不足,它将抛出相应的异常。

6. approve 函数

这个函数允许代币的所有者授权另一个地址消费他们的一部分代币。它执行以下步骤:

  • 设置指定地址的授权金额。
  • 发出一个Approval事件,记录这次授权操作。

7. allowance 函数

这个函数允许任何人查询一个地址可以从另一个地址转账的代币数量。它返回一个uint256类型的授权金额。

通过这些函数,该智能合约实现了 ERC20 代币标准的核心功能,包括代币的转移、授权和余额查询。
这些功能是构建基于以太坊的去中心化应用(DApps)和进行代币经济活动的基础。