在区块链和加密货币的世界里,创建一种属于自己的代币似乎是一件遥不可及的、只有专业开发者才能完成的高难度任务,但实际上,借助以太坊智能平台和Solidity编程语言,任何人都可以通过编写几行代码来发行一个功能完备的代币,这个过程不仅是学习区块链开发的绝佳实践,也是许多去中心化应用和社区治理项目的基础。

本文将带你一步步走过创建以太坊代币的全过程,并提供一份可以直接部署和使用的完整代码,我们将以最流行的ERC-20代币标准为例,这是以太坊上所有 fungible(可互换)代币的黄金标准,包括USDT、LINK等知名代币都遵循此标准。


第一步:准备工作——环境搭建

在开始编写代码之前,你需要准备好以下工具:

  1. 代码编辑器:如 VS Code,并安装 Solidity 插件,它提供语法高亮和自动补全功能,能极大提升编码体验。
  2. 以太坊钱包:如 MetaMask,你需要一个钱包来与以太坊网络交互,以及支付部署智能合约时所需的 gas 费。
  3. 开发环境:我们使用 Remix IDE,这是一个基于网页的集成开发环境,无需在本地安装任何软件,非常适合初学者,你只需在浏览器中访问 remix.ethereum.org 即可。

第二步:深入理解ERC-20标准

ERC-20标准定义了一套接口,即一套必须实现的方法和事件,一个完全符合ERC-20标准的代币,必须包含以下核心元素:

  • 状态变量

    • name: 代币名称,如 "My Awesome Token"。
    • symbol: 代币符号,如 "MAT",通常为2-3个字母。
    • decimals: 代币精度,通常为18,表示代币可以分割到小数点后18位。
    • totalSupply: 代币总供应量。
    • balances: 一个映射,记录每个地址拥有的代币数量。
    • allowances: 一个映射,记录一个地址被授权从另一个地址转移多少代币(用于交易所或第三方合约)。
  • 事件

    • Transfer(address from, address to, uint256 value): 当代币被转移时触发。
    • Approval(address owner, address spender, uint256 value): 当授权额度被设置时触发。
  • 函数

    • transfer(address to, uint256 amount): 向指定地址转移代币。
    • approve(address spender, uint256 amount): 授权一个地址可以动用你的代币。
    • transferFrom(address from, address to, uint256 amount): 从被授权的地址转移代币(通常由交易所调用)。
    • balanceOf(address account): 查询指定地址的代币余额。
    • allowance(address owner, address spender): 查询授权额度。

第三步:编写完整的ERC-20代币智能合约

下面是一份完整、可直接使用的ERC-20代币智能合约代码,它包含了所有必要的功能,并添加了一些注释以帮助你理解每一部分的作用。

在Remix IDE中,创建一个新文件(MyToken.sol),然后将以下代码完整复制进去。

// SPDX-License-Identifier: MIT
// 这是一个标准的许可证标识符,告诉别人你的代码是在MIT许可下发布的。
pragma solidity ^0.8.20;
/**MyToken
 * @dev 这是一个标准的 ERC-20 代币合约,名为 "My Awesome Token",符号为 "MAT"。
 * 它实现了所有必需的接口功能,包括代币的铸造(创建初始供应量)和转移。
 */
contract MyToken {
    // --- 状态变量 ---
    string public name;       // 代币全称
    string public symbol;     // 代币符号
    uint8 public decimals;    // 代币精度,18是标准
    uint256 public totalSupply; // 代币总供应量
    // balances[address] = 该地址拥有的代币数量
    mapping(address => uint256) public balances;
    // allowances[owner][spender] = owner授权给spender的代币数量
    mapping(address => mapping(address => uint256)) public allowances;
    // --- 事件 ---
    // 当代币被成功转移时触发
    event Transfer(address indexed from, add
随机配图
ress indexed to, uint256 value); // 当授权额度被设置或修改时触发 event Approval(address indexed owner, address indexed spender, uint256 value); // --- 构造函数 --- /** * @dev 合约部署时执行的函数,用于初始化代币的基本信息。 * 我们创建一个初始供应量,并将其发送给合约的部署者(msg.sender)。 * @param _name 代币名称 * @param _symbol 代币符号 * @param _initialSupply 初始供应量(注意:这是基础单位的数量,如果精度是18,则1000代表 1000 * 10^18) */ constructor(string memory _name, string memory _symbol, uint256 _initialSupply) { name = _name; symbol = _symbol; decimals = 18; totalSupply = _initialSupply * (10 ** uint256(decimals)); // 根据精度调整总供应量 balances[msg.sender] = totalSupply; // 将所有代币分配给合约部署者 emit Transfer(address(0), msg.sender, totalSupply); // 触发Transfer事件,从0地址(创世)转移到部署者 } // --- ERC-20 标准函数 --- /** * @dev 获取一个地址的代币余额 * @param account 要查询的地址 * @return 该地址拥有的代币数量 */ function balanceOf(address account) public view returns (uint256) { return balances[account]; } /** * @dev �授权一个地址可以动用你的代币 * @param spender 被授权的地址 * @param amount 授权的数量 * @return 成功时返回true */ function approve(address spender, uint256 amount) public returns (bool) { _approve(msg.sender, spender, amount); return true; } /** * @dev 从你的账户向另一个地址转移代币 * @param to 接收代币的地址 * @param amount 转移的数量 * @return 成功时返回true */ function transfer(address to, uint256 amount) public returns (bool) { _transfer(msg.sender, to, amount); return true; } /** * @dev 从被授权的地址转移代币(通常由第三方合约调用) * @param from 转出代币的地址 * @param to 接收代币的地址 * @param amount 转移的数量 * @return 成功时返回true */ function transferFrom(address from, address to, uint256 amount) public returns (bool) { // 首先检查授权额度是否足够 uint256 currentAllowance = allowances[from][msg.sender]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); // 更新授权额度 unchecked { allowances[from][msg.sender] = currentAllowance - amount; } // 执行实际的转移 _transfer(from, to, amount); return true; } /** * @dev �回一个地址对另一个地址的授权额度 * @param owner 授权方 * @param spender 被授权方 * @return 授权数量 */ function allowance(address owner, address spender) public view returns (uint256) { return allowances[owner][spender]; } // --- 内部函数 (Internal Functions) --- /** * @dev 内部函数:执行代币转移的核心逻辑 * @param from 转出地址 * @param to 接收地址 * @param amount 转移数量 */ function _transfer(address from, address to, uint256 amount) internal { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); require(balances[from] >= amount, "ERC20: transfer amount exceeds balance"); balances[from] -= amount; balances[to] += amount; emit Transfer(from, to, amount); } /** * @dev 内部函数:执行授权的核心逻辑 * @param owner 授权方 * @param spender 被授权方 * @param amount 授权数量 */ function _approve(address owner, address spender, uint256 amount) internal { require(owner != address(0), "ERC20: approve from the zero