【Solidity】代币

ERC20

ERC-20 全称 “Ethereum Request for Comment 20”,是一种标准接口,用于实现代币合约。ERC20 标准定义了一组函数和事件,使得代币可以在不同的应用和平台之间互操作。

ERC20 标准接口定义了一组必须实现的函数和事件:

interface IERC20 {
    // 返回代币的总供应量
    function totalSupply() external view returns (uint);

	// 返回指定地址的代币余额
    function balanceOf(address account) external view returns (uint);

	// 返回授权给 spender 的代币数量
    function allowance(address owner, address spender) external view returns (uint);

    // 将指定数量 amount 的代币从调用者的账户转移到另一个地址 recipient
    function transfer(address recipient, uint amount) external returns (bool);

    // 授权 spender 可以从调用者账户转移的代币数量 amount
    function approve(address spender, uint amount) external returns (bool);

	// 从 sender 账户转移指定数量的代币到 recipient, 需要预先通过 approve 授权
    function transferFrom(
        address sender,
        address recipient,
        uint amount
    ) external returns (bool);
}
interface IERC20 {
	// 在代币转移时触发, 包括零值转移
    event Transfer(address indexed from, address indexed to, uint value);

    // 在调用 approve 时触发
    event Approval(address indexed owner, address indexed spender, uint value);
}

以下是一个简单的 ERC20 代币合约示例:

contract ERC20 is IERC20 {
    // 存储代币的名称、符号和小数位数
    string public name = "TestToken";
    string public symbol = "TTK";
    uint8 public decimals = 18;

    // 存储代币的总供应量
    uint public totalSupply;

    // 存储每个地址的代币余额; owner => balance
    mapping(address => uint) public balanceOf;

    // 存储每个地址对其他地址的授权额度; owner => spender => amount
    mapping(address => mapping(address => uint)) public allowance;

    // 定义两个事件, 用于记录代币转移和授权操作
    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(
        address indexed owner,
        address indexed spender,
        uint value
    );

    // 将指定数量 amount 的代币从调用者的账户转移到另一个地址 recipient
    function transfer(
        address recipient,
        uint amount
    ) external override returns (bool) {
        require(
            balanceOf[msg.sender] >= amount,
            "ERC20: transfer amount exceeds balance"
        );
        balanceOf[msg.sender] -= amount;
        balanceOf[recipient] += amount;
        emit Transfer(msg.sender, recipient, amount);
        return true;
    }

    // 授权 spender 可以从调用者账户转移的代币数量 amount
    function approve(
        address spender,
        uint amount
    ) external override returns (bool) {
        allowance[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    // 从 sender 账户转移指定数量的代币到 recipient, 需要预先通过 approve 授权
    function transferFrom(
        address sender,
        address recipient,
        uint amount
    ) external override returns (bool) {
        require(
            balanceOf[sender] >= amount,
            "ERC20: transfer amount exceeds balance"
        );
        require(
            allowance[sender][msg.sender] >= amount,
            "ERC20: transfer amount exceeds allowance"
        );
        balanceOf[sender] -= amount;
        balanceOf[recipient] += amount;
        allowance[sender][msg.sender] -= amount;
        emit Transfer(sender, recipient, amount);
        return true;
    }
}

使用 OpenZeppelin 库可以简化 ERC20 代币的实现。OpenZeppelin 提供了安全且经过审计的 ERC20 实现。

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyToken is ERC20 {
    constructor(
        string memory name,
        string memory symbol,
        uint256 initialSupply
    ) ERC20(name, symbol) {
        _mint(msg.sender, initialSupply * 10 ** uint256(decimals()));
    }
}

除了上述核心方法,你可能还听过 mint & burn。它们通常用于 ERC20 代币合约中,以增加或减少代币的总供应量。

contract ERC20 is IERC20 {
    // ...

    // 创建 amount 数量的代币, 并将其分配给指定的地址
    function mint(uint amount) external {
        totalSupply += amount;
        balanceOf[msg.sender] += amount;
        emit Transfer(address(0), msg.sender, amount);
    }

    // 销毁 amount 数量的代币
    function burn(uint amount) external {
        require(
            balanceOf[msg.sender] >= amount,
            "ERC20: burn amount exceeds balance"
        );
        totalSupply -= amount;
        balanceOf[msg.sender] -= amount;
        emit Transfer(msg.sender, address(0), amount);
    }
}



ERC721

ERC721 是以太坊上用于创建不可替代代币(NFT)的标准。与 ERC20 不同,ERC721 代币是独一无二的,每个代币都有自己的唯一标识符。

ERC721 标准定义了一组必须实现的函数和事件,使得代币可以在不同的应用和平台之间互操作。

interface IERC721 {
	// 返回某个地址拥有的代币数量
    function balanceOf(address owner) external view returns (uint256 balance);

	// 返回某个代币的所有者地址
    function ownerOf(uint256 tokenId) external view returns (address owner);

	// 安全地将代币从一个地址转移到另一个地址
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

	// 将代币从一个地址转移到另一个地址
    function transferFrom(address from, address to, uint256 tokenId) external;

	// 批准某个地址可以转移指定的代币
    function approve(address to, uint256 tokenId) external;

	// 返回被批准可以转移指定代币的地址
    function getApproved(
        uint256 tokenId
    ) external view returns (address operator);

	// 批准或撤销某个地址可以管理调用者所有的代币
    function setApprovalForAll(address operator, bool _approved) external;

	// 查询某个地址是否被批准可以管理另一个地址的所有代币
    function isApprovedForAll(
        address owner,
        address operator
    ) external view returns (bool);
}
interface IERC721 {
	// 在代币转移时触发
    event Transfer(
        address indexed from,
        address indexed to,
        uint256 indexed tokenId
    );

    // 在调用 approve 时触发
    event Approval(
        address indexed owner,
        address indexed approved,
        uint256 indexed tokenId
    );

    // 在调用 setApprovalForAll 时触发
    event ApprovalForAll(
        address indexed owner,
        address indexed operator,
        bool approved
    );
}



WETH

WETH(Wrapped Ether)是以太坊(ETH)的包装版本,它遵循 ERC-20 代币标准。由于 ETH 本身并不符合 ERC-20 标准,因此在某些去中心化应用(DApp)和去中心化金融(DeFi)平台上使用时会有一些限制。WETH 的出现解决了这个问题,使 ETH 可以在这些平台上无缝使用。

contract WETH {
    // 代币名称、符号、小数位数
    string public name = "Wrapped Ether";
    string public symbol = "WETH";
    uint8 public decimals = 18;

    // 记录每个地址的 WETH 余额
    mapping(address => uint) public balanceOf;

    // 记录存入 ETH 的事件
    event Deposit(address indexed account, uint amount);

    // 记录提取 ETH 的事件
    event Withdrawal(address indexed account, uint amount);

    // 使合约可以接受 ETH
    receive() external payable {
        deposit();
    }

    // 接受 ETH 并将其转换为 WETH
    function deposit() public payable {
        balanceOf[msg.sender] += msg.value;
        emit Deposit(msg.sender, msg.value);
    }

    // 将 WETH 转换回 ETH 并提取到调用者的地址
    function withdraw(uint amount) public {
        require(balanceOf[msg.sender] >= amount, "Insufficient balance");
        balanceOf[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
        emit Withdrawal(msg.sender, amount);
    }

    // 返回合约中存储的 ETH 总量
    function totalSupply() public view returns (uint) {
        return address(this).balance;
    }
}

我们可以直接使用 OpenZeppelin 的 ERC20 合约库来实现 WETH 合约:

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract WETH is ERC20 {
    // 记录存入 ETH 的事件
    event Deposit(address indexed account, uint amount);

    // 记录提取 ETH 的事件
    event Withdrawal(address indexed account, uint amount);

    // 初始化 WETH 合约
    constructor() ERC20("Wrapped Ether", "WETH") {}

    // 使合约可以接受 ETH
    receive() external payable {
        deposit();
    }

    // 接受 ETH 并将其转换为 WETH
    function deposit() public payable {
        _mint(msg.sender, msg.value);
        emit Deposit(msg.sender, msg.value);
    }

    // 将 WETH 转换回 ETH 并提取到调用者的地址
    function withdraw(uint amount) public {
        _burn(msg.sender, amount);
        payable(msg.sender).transfer(amount);
        emit Withdrawal(msg.sender, amount);
    }
}
  1. 部署 WETH 合约

  2. 调用 WETH 合约的 deposit 函数,设置传入的 ETH 数量,这里以 1 ETH 为例

  3. 调用 WETH 合约继承的 balanceOf 函数,传入部署 WETH 合约的地址,查看 WETH 余额

  4. 调用 WETH 合约继承的 totalSupply 函数,查看合约中存储的 ETH 总量

  5. 调用 WETH 合约的 withdraw 函数,传入提取的 WETH 数量,提取 ETH

  6. 调用 WETH 合约继承的 balanceOf 函数,查看 WETH 余额

  7. 调用 WETH 合约继承的 totalSupply 函数,查看合约中存储的 ETH 总量



  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JS.Huang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值