在区块链开发领域,创建代币并实现其交易功能是常见的需求。本文将引导你逐步构建一个代币承销商去中心化应用(dApp),实现代币的买卖功能。
环境准备与项目初始化
首先需要搭建开发环境。我们将使用 scaffold-eth 项目作为基础框架。
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项目包含以下核心目录:
hardhat-ts: 智能合约代码及部署配置services: The Graph 协议配置subgraph: 数据处理设置vite-app-ts: 前端用户界面
启动应用需要运行三个命令:
yarn chain: 启动本地区块链yarn deploy: 编译部署合约yarn start: 启动前端应用
访问 http://localhost:3000 即可查看应用界面。如需重新部署,可使用 yarn deploy --reset 命令。
创建 ERC20 代币合约
理解 ERC20 标准
ERC20 是以太坊上同质化代币的标准接口,定义了代币的基本功能和交互方式。标准要求实现以下核心方法:
totalSupply(): 返回代币总供应量balanceOf(address _owner): 查询地址余额transfer(address _to, uint256 _value): 代币转账transferFrom(address _from, address _to, uint256 _value): 授权转账approve(address _spender, uint256 _value): 授权操作allowance(address _owner, address _spender): 查询授权额度
使用 OpenZeppelin 库
OpenZeppelin 提供了经过安全审计的合约库,极大简化了开发过程。我们使用其 ERC20 实现来创建代币合约。
pragma solidity >=0.8.0 <0.9.0;
// SPDX-License-Identifier: MIT
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
contract YourToken is ERC20 {
constructor() ERC20('Gold', 'GLD') {
_mint(msg.sender, 1000 * 10 ** 18);
}
}这段代码创建了名为 "Gold"、符号为 "GLD" 的代币,并向部署者铸造 1000 个代币。
部署与验证
部署脚本位于 packages/hardhat-ts/deploy/00_deploy_your_token.ts。部署后可通过前端界面验证代币余额和转账功能。
👉 查看实时部署工具
构建承销商合约:购买功能
承销商合约允许用户用 ETH 购买代币。核心功能包括:
- 设置兑换比例(如 1 ETH = 100 GLD)
- 实现 payable 的
buyTokens函数 - 添加代币购买事件记录
- 实现仅所有者可调用的资金提取功能
pragma solidity >=0.8.0 <0.9.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import './YourToken.sol';
contract Vendor is Ownable {
YourToken yourToken;
uint256 public tokensPerEth = 100;
event BuyTokens(address buyer, uint256 amountOfEth, uint256 amountOfTokens);
constructor(address tokenAddress) {
yourToken = YourToken(tokenAddress);
}
function buyTokens() payable public {
require(msg.value > 0, "Not enough ether");
uint256 amountOfTokens = msg.value * tokensPerEth;
uint256 tokenBalance = yourToken.balanceOf(address(this));
require(tokenBalance >= amountOfTokens, "Not enough tokens");
bool sent = yourToken.transfer(msg.sender, amountOfTokens);
require(sent, "Failed to transfer token");
emit BuyTokens(msg.sender, msg.value, amountOfTokens);
}
function withdraw() public onlyOwner {
uint256 balance = address(this).balance;
require(balance > 0, "No ether to withdraw");
(bool sent, ) = msg.sender.call{value: balance}("");
require(sent, "Failed to withdraw balance");
}
}部署时需要将代币转移到承销商合约并设置所有权:
const yourToken = await ethers.getContract('YourToken', deployer);
const vendor = await ethers.getContract('Vendor', deployer);
await yourToken.transfer(vendor.address, ethers.utils.parseEther('1000'));
await vendor.transferOwnership('0x169841AA3024cfa570024Eb7Dd6Bf5f774092088');实现代币回购功能
回购功能允许用户将代币卖回换取 ETH。由于合约不能直接接收代币,需要使用 ERC20 的授权机制。
理解授权机制
ERC20 标准的 approve 和 transferFrom 函数协同工作:
- 用户调用
approve(spender, amount)授权合约处理其代币 - 合约调用
transferFrom(user, contract, amount)转移代币
event SellTokens(address seller, uint256 amountOfTokens, uint256 amountOfETH);
function sellTokens(uint256 amountToSell) public {
require(amountToSell > 0, "Amount must be greater than 0");
uint256 userBalance = yourToken.balanceOf(msg.sender);
require(userBalance >= amountToSell, "Not enough tokens");
uint256 amountOfEthNeeded = amountToSell / tokensPerEth;
require(amountOfEthNeeded <= address(this).balance, "Not enough ether");
bool sent = yourToken.transferFrom(msg.sender, address(this), amountToSell);
require(sent, "Failed to transfer tokens");
(bool ethSent, ) = msg.sender.call{value: amountOfEthNeeded}("");
require(ethSent, "Failed to send ether");
emit SellTokens(msg.sender, amountToSell, amountOfEthNeeded);
}部署到测试网络
将合约部署到 Rinkeby 测试网络需要:
- 修改配置中的网络设置为 "rinkeby"
- 获取测试 ETH 从水龙头
- 部署合约到测试网
部署成功后,可以在 Etherscan 上查看合约状态和交易记录。
前端部署与合约验证
部署前端应用
使用 Surge.sh 可以免费部署前端应用:
yarn build
yarn surge验证合约源码
在 Etherscan 上验证合约代码增加透明度:
- 获取 Etherscan API 密钥
- 配置验证命令
- 运行验证流程
验证成功后,合约页面会显示验证标志,用户可查看源代码。
常见问题
什么是 ERC20 标准?
ERC20 是以太坊上同质化代币的标准接口,规定了代币合约必须实现的基本函数和事件,确保不同代币之间的互操作性。包括余额查询、转账功能和授权机制等核心功能。
为什么需要承销商合约?
承销商合约提供了代币与主流货币(如 ETH)之间的兑换机制,为代币创造流动性。它实现了买卖功能,让用户能够方便地获取和处置代币,是许多 DeFi 应用的基础组件。
如何确保合约安全?
使用经过审计的 OpenZeppelin 库、实现正确的访问控制、进行充分的测试以及在测试网上部署验证都是确保合约安全的重要措施。避免自己实现标准功能可减少潜在漏洞。
测试网部署有什么好处?
测试网部署允许在不消耗真实资金的情况下验证合约功能、测试用户界面和评估用户体验。这是区块链应用开发流程中不可或缺的环节,确保主网部署前的稳定性。
合约验证为什么重要?
合约验证让用户能够查看部署的源代码,建立信任关系。它透明化合约逻辑,让社区可以审计代码,是去中心化应用获得采纳的重要步骤,也是最佳实践的一部分。
👉 探索更多部署策略
总结
通过本教程,你学会了如何创建 ERC20 代币、实现承销商合约的买卖功能、部署到测试网络以及验证合约代码。这些技能是区块链开发的基础,为你构建更复杂的去中心化应用奠定了坚实基础。
掌握这些概念后,你可以进一步探索流动性池、自动化做市商等高级主题,继续在区块链开发领域深入学习和实践。