前言本文通过OpenZeppelin与ethers.js打通前端与合约,实现ERC20代币的一键发行,完成最小可行闭环。前置准备启动自定义网络:ganache把账号导入钱包中使用hardhat构建编写,编译合约OpenZeppelin简化合约开发表格总结:
本文通过 OpenZeppelin 与 ethers.js 打通前端与合约,实现 ERC20 代币的一键发行,完成最小可行闭环。
前置准备
- 启动自定义网络:ganache 把账号导入钱包中
- 使用hardhat构建编写,编译合约
- OpenZeppelin简化合约开发
- 表格总结:
工具 | 作用 | 一条命令 |
---|---|---|
Ganache | 本地测试链 | ganache-cli |
Hardhat | 编译 | npx hardhat compile |
MetaMask | 浏览器钱包 | 把 Ganache 私钥导入即可 |
合约说明:基于ERC20实现标准代币,不设权限所有账号都可以发布自己的代币
// 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,
uint256 totalSupply
) ERC20(name, symbol) {
_mint(msg.sender, totalSupply * 10 ** decimals());
}
}
编译说明:编译合约生成代币xx.json文件,用于前端部分使用
编译指令:npx hardhat compile
编译说明:执行此指令会生成新的文件夹《contracts》在此文件中找到对应的json文件
前端使用:例如:/contracts/MyToken.sol/MyToken.json,把MyToken.json导入到前端项目中
补充说明:关于hardhat相关的内容可以查看作者写的另一篇文章《智能合约开发、测试、部署全流程(实操篇)》
一键发币核心代码
import { useRouter } from "expo-router";
import { abi, bytecode } from "@/abi/MyToken.json";//合约编译生成的.json
import * as ethers from 'ethers';
const provider = new ethers.providers.Web3Provider(window.ethereum);
const router=useRouter();//路由
const deploy = async () => {
await provider.send('eth_requestAccounts', []); // 唤起钱包
const signer = await provider.getSigner();
const factory = new ethers.ContractFactory(abi, bytecode, signer);
console.log(factory)
const contract = await factory.deploy(name,symbol,supply);
await contract.deployed();
console.log("tokenAddress",contract.address);
console.log(contract)
if(contract.address){
//部署成功后进行后续操作 例如:
router.push({
pathname:"/home/addToken",
params:{
address:contract.address
}
})
}
}
合约交互核心代币
# 代币部署成功后,查看代币基本信息,以及调用代币事件
import { useRouter,useLocalSearchParams } from "expo-router";
import { abi, bytecode } from "@/abi/MyToken.json";//合约编译生成的.json
import * as ethers from 'ethers';
import { useState } from 'react';
//读取代币基本信息
const { address } = useLocalSearchParams();//合约地址
const [TokenName,setTokenName]=useState('');
const [TokenSymbol,setTokenSymbol]=useState('');
const [TokenDecimals,setTokenDecimals]=useState(0);
const [TokenTotalSupply,setTokenTotalSupply]=useState(0);
const tokenDetailFn= async ()=>{
const provider = new ethers.providers.Web3Provider(window.ethereum);
// await provider.send('eth_requestAccounts', []); // 唤起钱包
// const signer = await provider.getSigner();
const contract = new ethers.Contract(address as string, abi, provider);
const name = await contract.name();
const symbol = await contract.symbol();
const decimals = await contract.decimals();
const totalSupply = await contract.totalSupply();
const totalReadable = ethers.utils.formatUnits(totalSupply, decimals);//代币单位转换
console.log(name,symbol,decimals,totalReadable)
setTokenName(name);
setTokenSymbol(symbol);
setTokenDecimals(decimals);
setTokenTotalSupply(Number(totalReadable));
//也可以调用合约的事件:如下表
}
代币事件列表 | 事件 | 触发时机 | 参数 |
---|---|---|---|
Transfer |
发生代币转移(transfer 、transferFrom 成功时) |
from , to , value |
|
Approval |
授权额度被更新(approve /permit 成功时) |
owner , spender , value |
<div style="display:flex; gap:8px;flex-wrap:wrap;"> <img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/66935bb0cb4940b6ad69be20c23e3699~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyo6KW_:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjQzNjE3MzQ5Njg0NTU0OSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1756484768&x-orig-sign=Qgb0%2FLM5CjbG34LSePKSpRCa8bw%3D" alt="图1转存失败,建议直接上传图片文件" width="200"> <img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/8b130810ece34f4389b9f81dc0ada6b0~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyo6KW_:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjQzNjE3MzQ5Njg0NTU0OSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1756484808&x-orig-sign=8spVTkO5aqtcM7IkVCbqpWeOkoI%3D" alt="图1转存失败,建议直接上传图片文件" width="200"> <img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/7b4d3a688aff466abd579c8bb74d1142~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyo6KW_:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjQzNjE3MzQ5Njg0NTU0OSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1756484954&x-orig-sign=%2Bpj9a1fz0x6XrhZR2Nplh9Y4NF4%3D" alt="图1转存失败,建议直接上传图片文件" width="200"> <img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/b17cd5c3b5d1496ba2dbc65268962fd5~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyo6KW_:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjQzNjE3MzQ5Njg0NTU0OSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1756485114&x-orig-sign=0sBofQqW3fkc59Gz6aLcq%2Fin274%3D" alt="图1转存失败,建议直接上传图片文件" width="200"> <img src="https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/ee03bb0fe1084b1c96ef0cc514a6fda5~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyo6KW_:q75.awebp?policy=eyJ2bSI6MywidWlkIjoiMjQzNjE3MzQ5Njg0NTU0OSJ9&rk3s=e9ecf3d6&x-orig-authkey=f32326d3454f2ac7e96d3d06cdbb035152127018&x-orig-expires=1756484881&x-orig-sign=oVEjdcK2lV1HmyTW6N31bo7bky4%3D" alt="图1转存失败,建议直接上传图片文件" width="200"> </div>
以上就是实现 ERC20 代币的一键发行,完成最小可行闭环,如果想进一步完善可以补充权限管理、白名单、Mint 策略等高级功能。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!