从零到一:手把手实现代币承销商 dApp 全流程

·

本文将带你用 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 一键启动三条并行终端

终端 #命令作用
T1yarn chain用 Hardhat 启本地链条
T2yarn deploy编译 & 部署 + 初始化数据
T3yarn 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=1001 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

  1. 浏览器访问 http://localhost:3000/debug
  2. 查看 Vendor 合约是否有 1000 GLD
  3. 用 0.1 ETH 购买 10 GLD(前端 Buy Token 输入框)
  4. 刷新后用户地址余额正确变化
  5. 合约所有者点击 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);
}

前端验证:


五、冲 Rinkeby 测试网

  1. .env 填入已领到测试 ETH 的私钥
  2. hardhat.config.tsdefaultNetwork 切到 "rinkeby"
  3. yarn deploy 一键部署

部署完成会给出两个地址:GLD 代币 & 承销商合约,直接 Etherscan 浏览器实时查看。


六、上线前端:2 分钟用 Surge 托管

yarn build
yarn surge

按提示登录或注册 Surge,系统会自动将 dist/ 推送到 your-domain.surge.sh,同学们直接扫码即可体验。


七、Etherscan 合约验证

合约验证后会在页面出现蓝色徽章,增加公信力:

  1. pnpm add -D @nomiclabs/hardhat-etherscan
  2. hardhat.config.ts 追加 etherscan: { apiKey: "YOUR_KEY" }
  3. 运行 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」挑战,粘贴:

👉 立即浏览官方评分标准,确保拿满所有彩蛋

恭喜你!你已完整掌握 代币发行 → 承销商合约 → Web3 前端 → 主网迁移 的「蒲公英式」全流程。把项目扔进简历或 DAO 提案,都能在一众开发者中闪闪发光。