以太坊ERC20代币开发教程,从零开始创建你的第一个代币

在区块链世界中,代币是数字资产的重要载体,而ERC20(Ethereum Request for Comments 20)是以太坊上最标准、应用最广泛的代币技术标准,它定义了一套统一的接口规范,使得代币可以在以太坊生态中无缝流转、交易和被钱包、交易所等工具识别,无论是初学者还是开发者,掌握ERC20代币开发都是进入区块链领域的重要一步,本文将带你从零开始,手把手教你开发一个符合ERC20标准的代币,涵盖环境搭建、代码编写、测试到部署的全流程。

ERC20标准核心规范

在开始开发前,我们需要先理解ERC20的核心要求,ERC20标准定义了以下必须实现的接口函数事件

必需接口函数

  1. name():返回代币全称(如 "USD Coin")。
  2. symbol():返回代币符号(如 "USDC")。
  3. decimals():返回代币精度(小数位数,通常为18)。
  4. totalSupply():返回代币总供应量。
  5. balanceOf(address owner):查询指定地址的代币余额。
  6. transfer(address to, uint256 amount):向指定地址转移代币。
  7. transferFrom(address from, address to, uint256 amount):从指定地址转移代币(需授权)。
  8. allowance(address owner, address spender):查询授权额度。
  9. approve(address spender, uint256 amount):授权第三方地址转移代币。

必需事件

  1. Transfer(address indexed from, address indexed to, uint256 value):代币转移时触发。
  2. Approval(address indexed owner, address indexed spender, uint256 value):授权时触发。

开发环境准备

在编写ERC20代币之前,我们需要搭建以下开发环境:

安装Node.js和npm

ERC20代币通常使用Solidity语言编写,而Solidity的开发依赖Node.js环境,从nodejs官网下载并安装LTS版本(建议v16+),安装完成后可通过终端运行以下命令验证:

node -v  # 查看Node.js版本
npm -v   # 查看npm版本

安装Hardhat

Hardhat是一个以太坊开发环境,支持编译、测试、部署Solidity合约,功能强大且易于上手,通过以下命令安装:

npm init -y  # 初始化npm项目
npm install --save-dev hardhat

安装完成后,在项目目录下运行:

npx hardhat  # 初始化Hardhat项目

根据提示选择"Create a JavaScript project"(JavaScript项目),并确认安装依赖(如@nomicfoundation/hardhat-toolbox)。

安装OpenZeppelin合约库

OpenZeppelin是一个开源的智能合约库,提供了经过审计的ERC20标准实现,可直接复用,避免重复造轮子和安全漏洞,安装命令:

npm install @openzeppelin/contracts

编写ERC20代币合约

创建合约文件

在Hardhat项目中,合约文件通常存放在contracts/目录下,创建一个名为MyToken.sol的文件:

touch contracts/MyToken.sol

编写合约代码

打开MyToken.sol,编写以下代码(基于OpenZeppelin的ERC20实现):

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
    constructor(string memory name, string memory symbol) ERC20(name, symbol) {
        // 初始供应量:1亿代币,18位小数(ERC20默认)
        _mint(msg.sender, 100000000 * 10**decimals());
    }
}

代码解析

  • SPDX-License-Identifier: MIT:声明MIT开源协议(可选但推荐)。
  • pragma solidity ^0.8.20:指定Solidity编译器版本(0.8.20及以上,兼容性较好)。
  • import "@openzeppelin/contracts/token/ERC20/ERC20.sol":导入OpenZeppelin的ERC20标准合约。
  • contract MyToken is ERC20:定义MyToken合约,继承自ERC20,自动实现所有ERC20接口。
  • constructor:构造函数,在合约部署时调用。_mint()是ERC20库中的内部函数,用于向部署地址(msg.sender)铸造代币,100000000 * 10**decimals()确保代币精度正确(如18位小数时,实际供应量为1亿*10^18)。

编译和测试合约

编译合约

在终端运行以下命令编译合约:

npx hardhat compile

编译成功后,合约的ABI(应用二进制接口)和字节码会生成在artifacts/contracts/MyToke

随机配图
n.sol/MyToken.json中,这是后续部署和交互的关键文件。

编写测试脚本

测试是确保合约安全性的重要环节,在test/目录下创建myToken.test.js文件(JavaScript测试):

const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("MyToken", function () {
    let MyToken;
    let myToken;
    let owner;
    let addr1;
    let addr2;
    beforeEach(async function () {
        // 获取合约实例
        MyToken = await ethers.getContractFactory("MyToken");
        // 部署合约(参数为name和symbol)
        myToken = await MyToken.deploy("My Token", "MTK");
        await myToken.deployed();
        // 获取测试账户
        [owner, addr1, addr2] = await ethers.getSigners();
    });
    it("Should set the right name and symbol", async function () {
        expect(await myToken.name()).to.equal("My Token");
        expect(await myToken.symbol()).to.equal("MTK");
    });
    it("Should assign the initial supply to the owner", async function () {
        const ownerBalance = await myToken.balanceOf(owner.address);
        expect(ownerBalance).to.equal(100000000 * 10**18); // 1亿代币
    });
    it("Should transfer tokens between accounts", async function () {
        // owner转账1000代币给addr1
        await myToken.transfer(addr1.address, 1000 * 10**18);
        const addr1Balance = await myToken.balanceOf(addr1.address);
        expect(addr1Balance).to.equal(1000 * 10**18);
        // addr1转账500代币给addr2
        await myToken.connect(addr1).transfer(addr2.address, 500 * 10**18);
        const addr2Balance = await myToken.balanceOf(addr2.address);
        expect(addr2Balance).to.equal(500 * 10**18);
    });
    it("Should allow approved user to transferFrom", async function () {
        // owner授权addr1使用1000代币
        await myToken.approve(addr1.address, 1000 * 10**18);
        const allowance = await myToken.allowance(owner.address, addr1.address);
        expect(allowance).to.equal(1000 * 10**18);
        // addr1通过transferFrom从owner账户转移500代币给addr2
        await myToken.connect(addr1).transferFrom(owner.address, addr2.address, 500 * 10**18);
        const addr2Balance = await myToken.balanceOf(addr2.address);
        expect(addr2Balance).to.equal(500 * 10**18);
    });
});
  • 验证代币名称和符号是否正确。
  • 验证初始供应量是否正确分配给部署者。
  • 测试普通转账功能。
  • 测试授权和transferFrom功能。

运行测试:

npx hardhat test

如果所有测试通过,说明合约逻辑正确。

部署合约到以太坊网络

选择网络

ERC20代币可部署到以太坊主网、测试网(如Goerli、Sepolia)或本地网络(如Hardhat Network),这里以本地Hardhat Network为例,无需消耗真实ETH。

配置部署脚本

scripts/目录下创建deploy.js文件:

async function main() {
    // 获取合约工厂
    const MyToken = await ethers.getContractFactory("MyToken");
    // 部署合约(参数为name和symbol)
    const myToken = await MyToken.deploy("My Token", "MTK");
    // 等待部署完成
    await my

本文由用户投稿上传,若侵权请提供版权资料并联系删除!