ERC20代币学习与合约编写

前言

今天刷Ethernaut遇到了一道ERC20的题目,考虑到自己还没有实际用过ERC20,以及它的编写,就花了一个晚上写了点代码,可以发现自己的币。

简介

也许你经常看到ERC20和代币一同出现, ERC20是以太坊定义的一个代币标准。
要求我们在实现代币的时候必须要遵守的协议,如指定代币名称、总量、实现代币交易函数等,只有支持了协议才能被以太坊钱包支持。

登链社区关于ERC20的API规范:
代币标准
还有github的英文版标准:
代币标准

编写代码

规范中也推荐了几个比较好的实现实例:
实例,我就是学习了这些实例,然后自己编写了一遍。
ERC20Interface.sol

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

interface ERC20Interface {
     

    
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8 );
    function totalSupply() external view returns (uint256 );
    function balanceOf(address _owner) external view returns (uint256 balance);
    function transfer(address _to, uint256 _value) external returns (bool success);
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
    function approve(address _spender, uint256 _value) external returns (bool success);
    function allowance(address _owner, address _spender) external view returns (uint256 remaining);
    

}

接口函数,这些函数的原型也都是上面的代币标准中摘录下来的。对于每个函数的用途也都做了解释。
然后就是继承接口并编写ERC20.sol

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

import "./ERC20Interface.sol";

contract ERC20 is ERC20Interface{
     
    string public _name = "Feng";
    string public _symbol = "FENG";
    uint8 public _decimals = 18;  // 18 是建议的默认值
    uint256 public _totalSupply;
    
    mapping (address => uint256) public _balanceOf;
    mapping (address => mapping (address => uint256)) _allowance;
    
    
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    
    
    function name() public view virtual override returns (string memory){
     
        return _name;
    }
    function symbol() public view virtual override returns (string memory){
     
        return _symbol;
    }
    function decimals() public view virtual override returns (uint8 ){
     
        return _decimals;
    }
    function totalSupply() public view virtual override returns (uint256 ){
     
        return _totalSupply;
    }
    function balanceOf(address _owner) public  view virtual override returns (uint256 balance){
     
        balance = _balanceOf[_owner];
    }
    function _transfer(address _from, address _to, uint256 _value) internal virtual {
     
        require(_from != address(0));
        require(_to != address(0));
        require(_balanceOf[_from] >= _value);
        _balanceOf[msg.sender]-=_value;
        _balanceOf[_to]+=_value;
        emit Transfer(_from, _to, _value);
    }
    function _approve(address _owner, address _spender, uint256 _value) internal virtual {
     
        require(_owner != address(0));
        require(_spender != address(0)); 
        _allowance[_owner][_spender] = _value;
        emit Approval(_owner, _spender, _value);
    }
    function transfer(address _to, uint256 _value) public virtual override returns (bool success){
     
        _transfer(msg.sender, _to, _value);
        success = true;
    }
    function transferFrom(address _from, address _to, uint256 _value) public virtual override returns (bool success){
     
        _transfer(_from, _to, _value);
        uint256 allowanceNum = _allowance[_from][_to];
        require(allowanceNum >= _value);
        _approve(_from, _to, allowanceNum - _value);
        success = true;
    }
    function approve(address _spender, uint256 _value) public virtual override returns (bool success){
     
        _approve(msg.sender, _spender, _value);
        success = true;
    }
    function allowance(address _owner, address _spender) public view virtual override returns (uint256 remaining){
     
        return _allowance[_owner][_spender];
    }
    function _mint(address _account, uint256 _value) internal virtual{
     
        require(_account != address(0));
        _totalSupply += _value;
        _balanceOf[_account] += _value;
        emit Transfer(address(0), _account, _value);
    }
    
}

其中也会多出来一些函数是接口中没有的,例如_mint,是铸币函数。
再自己写一个Fun.sol来用一下自己写的代币玩玩:

//SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.0;

import "./ERC20.sol";
contract Fun is ERC20{
     
    address public owner;
    constructor() payable  {
     
        owner = msg.sender;
    }
    modifier onlyOwner(){
     
        require(msg.sender == owner);
        _;
    }
    function mint(address _account, uint _value) public onlyOwner{
     
        _mint(_account, _value);
    }
    function getMoney() public {
     
        uint value = uint(keccak256(abi.encodePacked(block.timestamp))) % 10;
        _mint(msg.sender, value);
    }
}

即可使用了。需要注意那个_decimals = 18,即有18位小数,因此一般的transfer这样的,如果value传1,其实是0.000000000000000001 FENG,因此如果是1 FENG的话,value得是1000000000000000000

总结

学习了一下ERC20,同时写了一些代码,对于代币以及合约的继承的理解更深了。

你可能感兴趣的:(区块链)