本文将带你用 scaffold-eth 框架,完成三种关键操作:创建 ERC20 代币、编写承销商合约、搭建 Web3 前端。流程覆盖本地环境到 Rinkeby 测试链、Surge 前端托管以及 Etherscan 合约验证,保证你能在 2 小时内跑完完整流程。
核心关键词:ERC20、代币承销商、Solidity、Hardhat、dApp、Web3、智能合约部署、Rinkeby、Scaffold-eth
一、环境准备:三条命令跑起完整开发链
1.1 克隆模板并安装依赖
git clone https://github.com/scaffold-eth/scaffold-eth-typescript-challenges.git \
challenge-2-token-vendor
cd challenge-2-token-vendor
git checkout challenge-2-token-vendor
yarn install项目结构一目了然:
packages/
├── hardhat-ts # Hardhat 合约逻辑
├── services # The Graph 配置
├── subgraph # 子图相关
└── vite-app-ts # React 前端⚠️ 篇幅所限,本篇不展开 The Graph 教程,关注核心路径即可。
1.2 一键启动三条并行终端
| 终端 # | 命令 | 作用 |
|---|---|---|
| T1 | yarn chain | 用 Hardhat 启本地链条 |
| T2 | yarn deploy | 编译 & 部署 + 初始化数据 |
| T3 | yarn start | 打开 React 前端 localhost:3000 |
本地环境完成后,浏览器就能看到「扫把 + 水龙头」界面,右上角连 MetaMask 一把梭。
1.3 小坑提示
如果合约逻辑改动后需要 重新上线,只需 yarn deploy --reset,其余终端保持不动。
二、快速发行 ERC20 代币
2.1 ERC20 方法一览
ERC20 是同质化通证标准,最常用的 6 个方法:
// 元数据
string public name;
string public symbol;
uint8 public decimals = 18;
// 核心逻辑
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);2.2 使用 OpenZeppelin 加速开发
不用重复造轮子,直接继承 ERC20.sol:
// packages/hardhat-ts/contracts/YourToken.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract YourToken is ERC20 {
constructor() ERC20("Gold", "GLD") {
// 铸造 1000 * 10^18 枚 GLD 给部署者
_mint(msg.sender, 1000 * 10 ** 18);
}
}👉 看看 OpenZeppelin ERC20 底层 _mint 实现细节,帮你理解发行流程
2.3 部署脚本
packages/hardhat-ts/deploy/00_deploy_your_token.ts
...
const yourToken = await ethers.getContract("YourToken", deployer);
// 把 1000 GLD 转到测试账户,方便前端调试
await yourToken.transfer("YOUR_WALLET", ethers.utils.parseEther("1000"));
...三、承销商合约:让用户用 ETH 买/卖你的 GLD
3.1 设计兑换比例与函数
| 参数 | 说明 |
|---|---|
tokensPerEth=100 | 1 ETH 兑换 100 GLD |
buyTokens() | 可接收 ETH,计算 GLD,并转账 |
withdraw() | 合约所有者提走 ETH |
sellTokens(uint256 amount) | 回购逻辑 |
购买代币核心代码
function buyTokens() external payable {
require(msg.value > 0, "Eth too low");
uint256 buyAmount = msg.value * tokensPerEth;
require(yourToken.balanceOf(address(this)) >= buyAmount, "Not enough tokens");
yourToken.transfer(msg.sender, buyAmount);
emit BuyTokens(msg.sender, msg.value, buyAmount);
}提现权限
function withdraw() external onlyOwner {
(bool sent,) = payable(owner()).call{ value: address(this).balance }("");
require(sent, "Withdraw failed");
}3.2 deploy 脚本:同时给承销商转账 GLD
// packages/hardhat-ts/deploy/01_deploy_vendor.ts
...
const vendor = await ethers.getContract("Vendor", deployer);
await yourToken.transfer(vendor.address, ethers.utils.parseEther("1000"));
await vendor.transferOwnership("YOUR_WALLET");3.3 本地验证 checklist
- 浏览器访问
http://localhost:3000/debug - 查看 Vendor 合约是否有 1000 GLD
- 用 0.1 ETH 购买 10 GLD(前端 Buy Token 输入框)
- 刷新后用户地址余额正确变化
- 合约所有者点击 Withdraw,余额归零
四、开放回购:用户把 GLD 卖回给合约
4.1 流程解析
用户必须先 approve 承销商权限,承销商再 transferFrom 用户 → 合约,最后给用户转 ETH:
| 步骤 | 说明 |
|---|---|
| 1. approve | 用户:承销商合约地址,额度 10 GLD |
| 2. sellTokens | 用户:输入 10 GLD 调用 sellTokens |
| 3. transferFrom | 合约:把 10 GLD 转到自身 |
| 4. send ETH | 合约:给用户转回 0.1 ETH |
4.2 sellTokens 实现
function sellTokens(uint256 amountToSell) external {
require(amountToSell > 0, "Zero tokens");
require(yourToken.balanceOf(msg.sender) >= amountToSell, "Insufficient user tokens");
uint256 ethAmount = amountToSell / tokensPerEth;
require(address(this).balance >= ethAmount, "Vendor has no eth");
bool sent = yourToken.transferFrom(msg.sender, address(this), amountToSell);
require(sent, "transferFrom failed");
(bool ethSent,) = msg.sender.call{value: ethAmount}("");
require(ethSent, "Send ETH failed");
emit SellTokens(msg.sender, amountToSell, ethAmount);
}前端验证:
- Debug 页面
approve -> sellTokens一条龙。 - 测试链子有余额的话,ETH/GLD 会秒速互换。
五、冲 Rinkeby 测试网
.env填入已领到测试 ETH 的私钥hardhat.config.ts把defaultNetwork切到"rinkeby"yarn deploy一键部署
部署完成会给出两个地址:GLD 代币 & 承销商合约,直接 Etherscan 浏览器实时查看。
六、上线前端:2 分钟用 Surge 托管
yarn build
yarn surge按提示登录或注册 Surge,系统会自动将 dist/ 推送到 your-domain.surge.sh,同学们直接扫码即可体验。
七、Etherscan 合约验证
合约验证后会在页面出现蓝色徽章,增加公信力:
pnpm add -D @nomiclabs/hardhat-etherscanhardhat.config.ts追加etherscan: { apiKey: "YOUR_KEY" }- 运行
yarn hardhat verify <CONTRACT_ADDRESS> <CONSTRUCTOR_ARGS> --network rinkeby
两条命令分别执行,刷新浏览器即能看到「Contract Source Code Verified」。
常见疑问 FAQ
Q1:为什么本地 MetaMask 提示余额不足?
A:Hardhat 自带私钥 0xf39... 为首富,确保 MetaMask 切换到该账户即可。
Q2:承销商无 ETH 如何测试 sellTokens?
A:T1 里 Hardhat 网络已包含 10000 个 ETH。只要从 faucet 拿 1 个送到 Vendor 合约即可。
Q3:approve 遗忘额度怎么查?
A:前端 Debug 页面点击「Allowance」,填 owner + spender 即可实时查询。
Q4:合约能否在一台机器上部署多次?
A:本地 Hardhat 每次默认重置链,多次 deploy --reset 会产生全新地址,但历史链数据消失。
Q5:如何把手滑发的错误代币救回?
A:只能让合约所有者对合约再调用 transfer 倒出代币,所以 千万勿直接转给合约地址。
Q6:主网迁移只需改动哪些配置?
A:网络切换 + API key + 真实 ETH 外,无需改业务逻辑,其他步骤与测试网一致。
🎯 最后一步:交卷
登入 speedrunethereum.com,选择「Token Vendor」挑战,粘贴:
- 前端访问地址 👉
https://your-domain.surge.sh - Vendor 合约地址 & 代码仓库链接
恭喜你!你已完整掌握 代币发行 → 承销商合约 → Web3 前端 → 主网迁移 的「蒲公英式」全流程。把项目扔进简历或 DAO 提案,都能在一众开发者中闪闪发光。