Solidity 以太坊智能合约标准-ERC20(2023版)

ERC20标准接口

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);

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

可以看到ERC20由5个function函数和2个event构成;

构成解析:

  • totalSupply(): token的总量,总发行量
  • balanceOf() :某个账户地址上的余额
  • transfer() : 发送token,转账
  • allowance() :额度、配额、津贴,owner授权给spender余额
  • approve() : 批准给某个地址一定数量的token(授予额度、授予津贴)
  • transferFrom(): 提取approve授予的token(提取额度、提取津贴),针对授权进行转账
  • Transfer() : token转移事件,转账
  • Approval() :额度批准事件,授权

下面我们来举个例子,首先是接口代码:

// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.7;

interface IERC20 {
    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 account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256 remaining);
    function approve(address spender, uint256 amount) external returns (bool);
    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);

}

这里的name(),symbol(),decimals()(精度)都是可选项而不是必选项;

我们需要将这些函数正之后的继承中全部实现;

合约示例代码:

// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.7;

import "./IERC20.sol";

contract ERC20 is IERC20{
    string ercName; 
    string ercSymbol;
    uint8 ercDecimal;
    uint256 ercTotalSupply;
    mapping(address=>uint256) ercBalances;     //自定义账本;
    mapping(address=>mapping(address=>uint256))ercAllowance;    //授权转账额度;

    address public owner;

    constructor(string memory _name,string memory _sym,uint8 _decimals){
        ercName = _name;
        ercSymbol = _sym;
        ercDecimal = _decimals;
        owner = msg.sender;
//        ercTotalSupply=21000000;
//        ercBalances[owner]=ercTotalSupply;

    }

    function mint(address _to,uint256 _value)public{       //挖矿或者空投;
        require(msg.sender==owner);
        require(address(0)!=_to);
        require(_value>0);

        ercBalances[_to]+=_value;
        ercTotalSupply += _value;

        emit Transfer(address(0), _to, _value);

    }                                

    function name() override external view returns (string memory){
        return ercName;

    }
    function symbol() override external view returns(string memory){
        return ercSymbol;

    }
    function decimals() override external view returns(uint8){        //精度
        return ercDecimal;
    }
    function totalSupply() override external view returns (uint256){
        return ercTotalSupply;

    }
    function balanceOf(address account) override external view returns (uint256){
        return ercBalances[account];

    }
    function transfer(address recipient, uint256 amount) override external returns (bool){
        require(amount>0,"amount must >0");
        require(address(0)!=recipient,"recipient address is zero");
        require(ercBalances[msg.sender]>=amount,"user' balance not enough");

        ercBalances[msg.sender]-=amount;
        ercBalances[recipient]+=amount;

        emit Transfer(msg.sender, recipient, amount);
        return true;

    }
    function allowance(address owner, address spender)override external view returns (uint256 remaining){
        remaining = ercAllowance[owner][spender];

    }
    function approve(address spender, uint256 amount) external returns (bool){
        //委托人->被委托人->value
        require(amount>0,"amount must >0");
        require(spender!=address(0),"spender is a zero address");
        require(ercBalances[msg.sender]>=amount,"user's balance not enough");

        ercAllowance[msg.sender][spender]=amount;
        emit Approval(msg.sender, spender, amount);
        return true;

    }
    function transferFrom(address sender, address recipient, uint256 amount)override external returns (bool){
        require(ercBalances[sender]>=amount);
        require(ercAllowance[sender][msg.sender]>=amount);
        require(amount>0);
        require(address(0)!=recipient);
        ercBalances[sender]-=amount;
        ercBalances[recipient]+=amount;
        ercAllowance[sender][msg.sender]-=amount;

        emit Transfer(msg.sender, recipient, amount);
        return true;

    }
}

注意事项:

  • 只要是涉及到token的转移,都需要使用emit激活事件;
  • approve函数涉及到mapping的二次映射需要注意;
  • allowance()主要是查看owner授权给spender的额度;
  • 如果没有经过owner的授权,spender无法进行transferFrom()转账;
  • 该例子还涉及到了空投(挖矿)函数,由该函数来决定token的发行量,token最初的地址来源于黑洞地址;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Solidity中,可以通过使用智能合约来实现ERC20代币的锁仓与释放。以下是一个简单的锁仓合约示例: ``` pragma solidity ^0.8.0; import "./IERC20.sol"; import "./SafeMath.sol"; contract TokenVesting { using SafeMath for uint256; address public beneficiary; uint256 public cliff; uint256 public start; uint256 public duration; uint256 public released; IERC20 public token; constructor( address _beneficiary, uint256 _cliff, uint256 _duration, address _token ) public { require(_beneficiary != address(0)); require(_cliff <= _duration); beneficiary = _beneficiary; cliff = _cliff; duration = _duration; start = block.timestamp; token = IERC20(_token); } function release() public { uint256 unreleased = releasableAmount(); require(unreleased > 0); released = released.add(unreleased); token.transfer(beneficiary, unreleased); } function releasableAmount() public view returns (uint256) { return vestedAmount().sub(released); } function vestedAmount() public view returns (uint256) { uint256 currentBalance = token.balanceOf(address(this)); uint256 totalBalance = currentBalance.add(released); if (block.timestamp < start.add(cliff)) { return 0; } else if (block.timestamp >= start.add(duration)) { return totalBalance; } else { return totalBalance.mul(block.timestamp.sub(start)).div(duration); } } } ``` 在这个合约中,当创建合约时,需要传入受益人地址、锁仓期、释放期、代币地址等信息。锁仓期结束后,受益人可以通过调用 `release()` 函数来释放锁仓代币。如果释放函数被调用,但是当前时间还没有到达释放期,则会抛出异常。 为了保证代币不能被提前释放,合约还实现了 cliff 的概念,即在锁仓期结束之前,代币不能被释放。当 cliff 结束之后,代币将按照线性方式释放,直到释放期结束。 需要注意的是,以上示例只是一个简单的锁仓合约示例,实际生产环境中需要更加严格地考虑各种情况和安全性问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值