安装 Node.js 从官网下载安装包)
admin 发布于 2026-02-16 10:51
频道:默认分类
阅读:43
从零开始:以太坊ERC20代币开发详解**
以太坊作为全球领先的智能合约平台,其上发行的代币数量庞大,其中ERC20标准是最具影响力和广泛应用的代币标准之一,ERC20定义了一套统一的接口和规则,使得不同的代币可以在以太坊生态中无缝交互,例如在交易所交易、钱包存储、DeFi协议中使用等,本文将详细讲解ERC20代币的开发流程,包括核心概念、标准接口、智能合约编写、测试、部署以及注意事项。
什么是ERC20
ERC20是“Ethereum Request for Comments 20”的缩写,即以太坊改进建议第20号,它不是一个具体的代币,而是一个技术标准,规定了以太坊上同质化代币(Fungible Token,即每个代币完全相同,可以互换)应遵循的规范,遵循ERC20标准的代币,其行为具有一致性,可以被各种以太坊钱包、交易所和应用识别和支持。
ERC20核心接口与事件
ERC20标准定义了必须实现的接口(函数)和推荐实现的事件,这些是开发ERC20代币合约的基础。
核心接口函数:
function name() public view returns (string): 返回代币的名称,"MyToken"。
function symbol() public view returns (string): 返回代币的符号,"MTK",通常2-3个字符。
function decimals() public view returns (uint8): 返回代币的小数位数,用于计算精度,18位小数意味着1个代币等于 10^18 个最小单位(wei类似)。
function totalSupply() public view returns (uint256): 返回代币的总供应量。
function balanceOf(address _owner) public view returns (uint256): 返回指定地址 _owner 拥有的代币数量。
function transfer(address _to, uint256 _value) public returns (bool): 将调用者(msg.sender)的 _value 数量代币转移到地址 _to,成功返回 true。
function transferFrom(address _from, address _to, uint256 _value) public returns (bool): 从地址 _from 转移 _value 数量代币到地址 _to,调用者需要有来自 _from 的足够授权(通过 approve)。
function approve(address _spender, uint256 _value) public returns (bool): 授权地址 _spender 可以调用 transferFrom 从调用者(msg.sender)处转移最多 _value 数量的代币。
function allowance(address _owner, address _spender) public view returns (uint256): 返回地址 _spender 被授权从地址 
e>_owner 处转移的代币数量。
推荐事件:
event Transfer(address indexed from, address indexed to, uint256 value): 当代币发生转移时触发(包括铸造和销毁)。from 为零地址表示铸造,to 为零地址表示销毁。
event Approval(address indexed owner, address indexed spender, uint256 value): 当 approve 函数被调用时触发,授权额度发生变化。
开发环境准备
在开始编写ERC20代币合约之前,需要准备以下开发环境:
- Node.js and npm/yarn: JavaScript运行时环境和包管理器。
- Truffle: 一个流行的以太坊开发框架,用于编译、测试和部署智能合约。
- Ganache: 一本本地的以太坊区块链,用于快速开发和测试,可以立即生成测试账户和提供以太坊。
- MetaMask: 一个浏览器钱包插件,用于与以太坊区块链交互,管理账户,以及在测试网上部署和测试合约。
- Solidity: 以太坊智能合约的编程语言,需要安装Solidity编译器(solc)。
安装步骤(简述):
npm install -g truffle
# 安装 Ganache (从官网下载桌面应用或命令行版本)
# 安装 MetaMask (浏览器扩展商店)
编写ERC20代币智能合约
我们可以使用Truffle提供的ERC20合约模板,或者从OpenZeppelin库导入经过审计的ERC20实现,后者更安全可靠。
使用OpenZeppelin库(推荐)
OpenZeppelin提供了一套安全的、标准化的智能合约组件,包括ERC20代币。
-
初始化项目:
mkdir my-erc20-token
cd my-erc20-token
npm init -y
npm install @openzeppelin/contracts
-
编写合约: 在 contracts/ 目录下创建 MyToken.sol 文件。
// 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) {
// 在部署时,向msg.sender(部署者)铸造1000000个代币,18位小数
_mint(msg.sender, 1000000 * 10**decimals());
}
}
SPDX-License-Identifier: 指定许可证。
pragma solidity ^0.8.20; 指定Solidity编译器版本。
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 导入OpenZeppelin的ERC20合约。
contract MyToken is ERC20; 声明我们的合约继承自ERC20。
constructor: 构造函数,在合约部署时调用,我们在这里设置了代币的名称和符号,并通过 _mint 函数向部署者铸造初始代币。_mint 是ERC20合约内部提供的铸造函数。
编译合约
在项目根目录下运行:
truffle compile
如果成功,会在 build/contracts/ 目录下生成编译后的JSON文件(ABI和字节码)。
测试合约
测试是确保智能合约正确性和安全性的重要环节。
-
编写测试脚本: 在 test/ 目录下创建 myToken.test.js 文件(使用JavaScript或TypeScript)。
const MyToken = artifacts.require("MyToken");
contract("MyToken", (accounts) => {
it("should put 1000000 MyToken in the first account", async () => {
const myTokenInstance = await MyToken.deployed();
const balance = await myTokenInstance.balanceOf(accounts[0]);
assert.equal(balance.toString(), "1000000000000000000000000", "1000000 tokens weren't in the first account");
});
it("should transfer tokens correctly", async () => {
const myTokenInstance = await MyToken.deployed();
const sender = accounts[0];
const receiver = accounts[1];
const amount = web3.utils.toWei("100", "ether"); // 假设decimals是18
// 检查初始余额
let senderBalance = await myTokenInstance.balanceOf(sender);
let receiverBalance = await myTokenInstance.balanceOf(receiver);
assert.equal(senderBalance.toString(), "1000000000000000000000000");
assert.equal(receiverBalance.toString(), "0");
// 转移
await myTokenInstance.transfer(receiver, amount);
// 检查转移后余额
senderBalance = await myTokenInstance.balanceOf(sender);
receiverBalance = await myTokenInstance.balanceOf(receiver);
assert.equal(senderBalance.toString(), "999900000000000000000000");
assert.equal(receiverBalance.toString(), "100000000000000000000");
});
});
-
运行测试:
truffle test
部署合约
部署合约到以太坊网络(可以是本地Ganache、测试网如Goerli或Sepolia,或主网)。
-
配置Truffle: 在 truffle-config.js (或 truffle.js) 中配置网络。
require('dotenv').config(); // 使用.env文件管理私钥等敏感信息
const { MNEMONIC, INFURA_API_KEY } = process.env;
module.exports = {
networks: {
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
goerli: {
provider: () => new HDWalletProvider(MNEMONIC, `https://goerli.infura.io/v