ERC20合约项目实践(上)

420 阅读2分钟

1.实验内容

1.给WETH合约增加 depositTo(address _toAddress) 方法,使得充值时可以选择充值地址

2.增加DepositTo事件,在调用depositTo时可以记录msg.sender, toAddress 和充值金额。比如账户A充值,实际增加的是账户B的余额,同时使用DepositTo记录下该事件

3.给WETH合约增加withdrawTo(address _toAddress,uint256 wad) 方法,使得提现到时候可以选择提现地址

4.增加WithdrawTo事件,在调用withdrawTo时可以记录msg.sender, toAddress 和提现金额。比如账户A操作提现,可以提现到账户B,同时使用WithdrawTo记录该事件

2.合约基本内容

上述的实验内容是基于ERC20合约实现,以下我会先介绍该实验合约的基础方法,后面再介绍需要新增方法。

2.1 属性

平台代币的名字,标识和精确度。

    string public name = "Wrapped ETH";
    string public symbol = "WETH";
    uint8 public decimals = 18;

2.2 事件

    //授权
    event Approval(address indexed src, address indexed guy, uint256 wad);
    //转账
    event Transfer(address indexed src, address indexed dst, uint256 wad);
    //充值
    event Deposit(address indexed dst, uint256 wad); 
    //提取
    event Withdrawal(address indexed src, uint256 wad); 

2.3 映射

   //地址 => 余额
   mapping(address => uint256) public balanceOf; 
   ////A允许B使用多少代币
   mapping(address => mapping(address => uint256)) public allowance; 

2.4 回退函数

回调函数有fallback()receive()两个函数。当消息调用合约时,合约里面没有对应的函数时,就会调用fallback函数和receive函数。当消息中有数据时调用fallback(),没有数据则调用receive()

    receive() external payable {
        deposit();
    }
    function deposit() public payable {
        balanceOf[msg.sender] += msg.value;
        emit Deposit(msg.sender, msg.value);
    }

2.5 主要方法

    //给账户充值
    function deposit() public payable {
        balanceOf[msg.sender] += msg.value;
        emit Deposit(msg.sender, msg.value);
    }
    //提现
    function withdraw(uint256 wad) public {
        require(balanceOf[msg.sender] >= wad);
        balanceOf[msg.sender] -= wad;
        msg.sender.transfer(wad);
        emit Withdrawal(msg.sender, wad);
    }

3.新增方法

  • 该方法是可以给任意地址进行充值。
    function depositTo(address _toAddress) external payable {
        uint value = msg.value;
        balanceOf[_toAddress] += value;
        emit DepositTo(msg.sender, _toAddress, value);
    }
  • 在提现时,可以选择任意地址,包括提现给其他地址和自己。对_toAddress使用payable表示该地址是可以接受代币的。
    function withdrawto(address payable _toAddress, uint256 wad) external {
        require(balanceOf[msg.sender] >= wad, "balanceOf[msg.sender] < wad");
        balanceOf[msg.sender] -= wad;
        _toAddress.transfer(wad);
        emit WithdrawalTo(msg.sender, _toAddress, wad);
    }
  • 提现可以从from地址向to地址转移
    function withdrawFrom(address from, address payable to, uint256 value) external {
        require(balanceOf[from] >= value, "balanceOf[from] < wad");
        require(allowance[from][msg.sender] >= value, "allowance[from][msg.sender] < value");
        allowance[from][msg.sender] -= value;
        balanceOf[from] -= value;
        to.transfer(value);
        emit WithdrawalFrom(msg.sender, from, to, value);
    }

4.源代码

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.7.6;

contract WETH9 {
    string public name = "Wrapped ETH";
    string public symbol = "WETH";
    uint8 public decimals = 18;

    event Approval(address indexed src, address indexed guy, uint256 wad);
    event Transfer(address indexed src, address indexed dst, uint256 wad);
    event Deposit(address indexed dst, uint256 wad);
    event Withdrawal(address indexed src, uint256 wad);
    event DepositTo(address indexed handlers, address indexed toAddress, uint value);
    event WithdrawalTo(address indexed handlers, address indexed toAddress, uint value);
    event WithdrawalFrom(address indexed handlers, address indexed from, address indexed to, uint value);

    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    receive() external payable {
        deposit();
    }

    function deposit() public payable {
        balanceOf[msg.sender] += msg.value;
        emit Deposit(msg.sender, msg.value);
    }

    function depositTo(address _toAddress) external payable {
        uint value = msg.value;
        balanceOf[_toAddress] += value;
        emit DepositTo(msg.sender, _toAddress, value);
    }

    function withdraw(uint256 wad) public {
        require(balanceOf[msg.sender] >= wad);
        balanceOf[msg.sender] -= wad;
        msg.sender.transfer(wad);
        emit Withdrawal(msg.sender, wad);
    }
    //在提现时,可以选择任意地址。
    function withdrawto(address payable _toAddress, uint256 wad) external {
        require(balanceOf[msg.sender] >= wad, "balanceOf[msg.sender] < wad");
        balanceOf[msg.sender] -= wad;
        _toAddress.transfer(wad);
        emit WithdrawalTo(msg.sender, _toAddress, wad);
    }

    function withdrawFrom(address from, address payable to, uint256 value) external {
        require(balanceOf[from] >= value, "balanceOf[from] < wad");
        require(allowance[from][msg.sender] >= value, "allowance[from][msg.sender] < value");
        allowance[from][msg.sender] -= value;
        balanceOf[from] -= value;
        to.transfer(value);
        emit WithdrawalFrom(msg.sender, from, to, value);
    }

    function totalSupply() public view returns (uint256) {
        return address(this).balance;
    }

    function approve(address guy, uint256 wad) public returns (bool) {
        allowance[msg.sender][guy] = wad;
        emit Approval(msg.sender, guy, wad);
        return true;
    }

    function transfer(address dst, uint256 wad) public returns (bool) {
        return transferFrom(msg.sender, dst, wad);
    }

    function transferFrom(
        address src,
        address dst,
        uint256 wad
    ) public returns (bool) {
        require(balanceOf[src] >= wad);
        if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) {
            require(allowance[src][msg.sender] >= wad);
            allowance[src][msg.sender] -= wad;
        }
        balanceOf[src] -= wad;
        balanceOf[dst] += wad;

        emit Transfer(src, dst, wad);
        return true;
    }
}