ERC20代币学习与合约编写

Posted bfengj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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,同时写了一些代码,对于代币以及合约的继承的理解更深了。

开发者涨薪指南 48位大咖的思考法则、工作方式、逻辑体系

以上是关于ERC20代币学习与合约编写的主要内容,如果未能解决你的问题,请参考以下文章

Solidity-ERC20代币的锁仓与释放-1

ERC20 代币转移到智能合约

我的网页上的 Solidity 众筹功能失败,但直接发送时成功,但成功交易时不发送 ERC20

如何与已部署的 ERC20 代币与另一个智能合约进行交互?

以太坊私链部署erc20_usdt代币

使用智能合约存取erc20代币