智能合约开发、测试、部署全流程(实操篇)

  • 木西
  • 发布于 2天前
  • 阅读 333

前言本文主要对hardhat框架实操的介绍,通过一个简单的智能合约案例,用handhat把开发、测试、部署全流程过一遍。前期准备构建工具:hardhat前端技术栈:React+Ethersjs+Web3UIKit钱包:MetaMask合约层:Solidityehterscan区

前言

本文主要对hardhat框架实操的介绍,通过一个简单的智能合约案例,用handhat把开发、测试、部署全流程过一遍。

前期准备

  • 构建工具:hardhat
  • 前端技术栈:React+Ethersjs+Web3UI Kit
  • 钱包:MetaMask
  • 合约层:Solidity
  • ehterscan区块链浏览器<br>

    开始

    项目构建

    # 合约部分
    # 创建空文件夹
    mkdir Web3
    # 进入工程目录中
    cd Web3
    # 项目初始化
    npm init
    # 安装hardhat
    npm install --save-dev hardhat
    # hardhat框架初始化选择项目模板
    npx hardhat init
    # 下载项目插件
    npm install --save-dev @nomicfoundation/hardhat-toolbox
    # 运行校验
    # 在工程目录下创建文件前端工程目录
    # &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;
    # 前端部分
    # 创建一个dapp项目用于编写前端程序
    create-react-app dapp
    # 进入dapp文件夹
    cd dapp
    # 安装相应的包
    # ethers与合约交互
    # @web3uikit/core @web3uikit/web3 @web3uikit/icons 钱包相关包
    npm install  xxx

    项目目录结构介绍

    web3
    |_contracts//智能合约目录
    |_test//合约测试目录
    |_scripts//合约部署目录
    |_artifacts//编译合约自动生成
    |___build-info
    |___contracts//前端调用合约生成的json文件
    |_ignition//
    |_cache//
    |_deploy//部署合约文件目录
    |_tasts//自定任务简化流程
    |_front_end//前端项目工程目录
    |_hardhat.config.js//hardhat配置文件
    |_helper-hardhat-config.js//hardhat集中常用变量汇总文件
    |_package.json//工程目录

    Hardhat常用指令

    # 获取所有指令
    npx hardhat
    # 获取区块网络节点
    npx hardhat node
    # 编译合约
    npx hardhat compile
    # 清除缓存并删除所有工件
    npx hardhat clean
    # 测试合约
    npx hardhat test
    # 部署合约
    npx hardhat run scripts/xx.js 
    # 控制台
    npx hardhat console
    # 查看所有指令
    npx hardhat 

    合约开发

    
    // SPDX-License-Identifier: MIT
    // Compatible with OpenZeppelin Contracts ^5.0.0
    pragma solidity ^0.8.22;
    import {ERC20} from  "@openzeppelin/contracts/token/ERC20/ERC20.sol"
    import {ERC20Burnable} from  "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; 
    import {ERC20Permit} from  "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; 
    import {Ownable} from  "@openzeppelin/contracts/access/Ownable.sol";
    contract MyToken is ERC20, ERC20Burnable, Ownable, ERC20Permit {
    constructor(address initialOwner)
    ERC20("MyToken", "MTK")
    Ownable(initialOwner)
    ERC20Permit("MyToken")
    {
    _mint(msg.sender, 1000 * 10 ** decimals());
    }
    //铸造方法
    function mint(address to, uint256 amount) public onlyOwner {
    _mint(to, amount);
    }
    }
    /**
  • 合约说明:
  • 使用openzeppelin库快速构建一个具备铸造和销毁的ERC20标准的代币合约
  • 代币名称 MyToken,符号 MTK,总量:1000MTK
  • 方法:铸造,销毁,转账,授权... */
    # 合约编译

    编译合约指令

    npx hardhat compile

    # 合约测试

    合约测试指令

    npx hardhat test

    # 合约测试样例
    说明:hardhat框架集成了chai测试的工具

    const { ethers,getNamedAccounts,deployments} = require("hardhat"); const {assert,expect } = require("chai"); let firstAccount; let nft; // 部署合约 beforeEach(async function () { firstAccount = (await getNamedAccounts()).firstAccount; await deployments.fixture(["all"]); nft=await ethers.getContract("MyNFT",firstAccount); }); // 测试单元 参数说明:测试单元命名 describe("xxx", async () => { it("mint nft", async function () { await nft.safeMint(firstAccount); let owner=await nft.ownerOf(0); expect(owner).to.equal(firstAccount); }); //......... });

# 合约部署指令

部署合约

说明:部署一个在scripts目录下的deploy.js 网络节点

network-name可以在hardhat.json中配置网络:localhost,

npx hardhat run scripts/xxx.js --network <network-name>

例如

npx hardhat run scripts/deploy.js or npx hardhat run scripts/deploy.js --network localhost//指定网络

# 合约部署样例1

直接在scripts目录下编写部署脚本

const { ethers } = require("hardhat");

async function main() { const [deployer] = await ethers.getSigners();//获取网络节点账号 // console.log(deployer) console.log("Deploying contracts with the account:", deployer.address); const MyToken = await ethers.getContractFactory("MyToken");//获取合约 console.log(MyToken)//获取合约实例 const myToken = await MyToken.deploy();//部署合约 console.log("Token address:", myToken.target);//打印合约地址

} main().then(()=>{ process.exit(0) }).catch((err)=>{ console.error(err) process.exit(1) });

使用指令

npx hardhat run scripts/xxx.js --network 指定网络节点

# 合约部署样例2

在deploy目录下部署脚本(推荐此操作)

使用hardhat部署插件hardhat-deploy

1 在配置文件hardhat.confing.js中引入插件

require("hardhat-deploy"); require("@nomicfoundation/hardhat-ethers"); require("hardhat-deploy-ethers");

在deploy目录下的部署文件:

// module.exports = async (hre) => { // const getNamedAccounts = hre.getNamedAccounts // const deployments = hre.deployments // } const { network } =require("hardhat");

module.exports = async ({getNamedAccounts,deployments}) => { const firstAccount = (await getNamedAccounts()).firstAccount;//获取节点1 const secondAccount = (await getNamedAccounts()).secondAccount;//获取节点2 const {deploy}= deployments//获取部署实例 //部署合约 const FundMe= await deploy("FundMe",{ from: firstAccount,//节点 args: [xx,xxx],//要传的参数xx,xxx log: true,//是否打印log //waitConfirmations: confirmations,//等待的区块数 }) //验证合约是否成功的部署的链上 await hre.run("verify:verify", { address: FundMe.address, constructorArguments: [xx,xxx],//合约要传的参数xx,xxx }); } module.exports.tags = ["all","fundme"];//在执行部署指令时可选参数

例如

npx hardhat deploy --tag fundme or all

等同于

npx hardhat run scripts/funfme.js

# 自定义task样例

说明

文件目录

tasks |_deploy_nft.js |index.js | deploy_tonken.js

deploy_nft.js代码如下

const {task} = require("hardhat/config");//hardhat集成的插件 //参数说明,deploy-nft是指令名 task("deploy-fundme", "deploy-fundme").setAction(async (taskArgs, hre) => { const FundMeFactory = await ethers.getContractFactory("MyNFT");//获取合约 const fundMe = await FundMeFactory.deploy(300);//部署需要传递的参数 await fundMe.waitForDeployment();//几个区块 console.log(address : ${fundMe.target}) if(hre.network.config.chainId == 11155111 && process.env.ETHERSCAN_API_KEY){ console.log("Waiting for 5 confirmations") await fundMe.deploymentTransaction().wait(5) //等待5个区块交易完成 await verifyFundMe(fundMe.target, [300]) }else{ console.log("verification skipped..") }

}); async function verifyFundMe(factoryAddr,args){ await hre.run("verify:verify", { address: factoryAddr, constructorArguments: [50], }); } exports.default = {};

deploy_token.js代码同上简单修改代码即可

index.js如下

exports.deployfundme=require("./deploy_nft.js") exports.interactfundme=require("./deploy_token.js") 把自定task引入hardhat.config.js中 require(./tasks);

可以通过npx hardhat 查看是否生成

导入成功后

可以在控制台面板中的AVAILABLE TASKS查看到

deploy-token

npx hardhat deploy-fundme --network xxx //如果有参数传递就后面跟参数 键名 键值

deploy-nft

同上修改一下关键参数即可

# hardhat.config.js文件配置

require("@nomicfoundation/hardhat-toolbox"); require("@nomicfoundation/hardhat-verify");//验证合约 // require("@chainlink/env-enc").config();//可以采用此包对.env常量进行加密处理 require("dotenv").config();//读取.env的内容 require("./tasks");//自定义task,作用主要快加高效的执行自定指令,便于高效的开发。 //引入部署插件 require("hardhat-deploy"); require("@nomicfoundation/hardhat-ethers"); require("hardhat-deploy-ethers"); //读取env的常量 process.env.PRIVATE_KEY = process.env.PRIVATE_KEY; process.env.PRIVATE_KEY_1 = process.env.PRIVATE_KEY_1; process.env.ALCHEMY_API_KEY = process.env.ALCHEMY_API_KEY; process.env.ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY; module.exports = { solidity: "0.8.27", defaultNetwork: "hardhat", mocha: { timeout: 300000//设置mocha的超时时间为300秒,解决集成测试时间不够问题 }, networks: { // localhost: { // url:'http://127.0.0.1:8545/', // chainId: 31337, // }, sepolia: { url: https://sepolia.infura.io/v3/${process.env.ALCHEMY_API_KEY}, accounts: [process.env.PRIVATE_KEY,process.env.PRIVATE_KEY_1], chainId: 11155111 }, },//网络节点设置 etherscan: { apiKey: { sepolia: process.env.ETHERSCAN_API_KEY } },//设置 Etherscan API 密钥的,用于与 Etherscan 服务进行交互 sourcify: { enabled: true },//启动 Hardhat 插件 @nomicfoundation/hardhat-verify,用户验证部署在以太坊区块链上的智能合约的源代码 namedAccounts: { firstAccount: { default: 0 }, secondAccount: { default: 1 } },//通过名字获取区块节点 gasReporter: { enabled: false,//控制gas报告的显示 } };

# 前端调用合约

前端主要通过Ethers.js或者Web3.js和合约进行交互。

关于Ehers.js库的使用。

  • Provider:提供者
  • Signer:签名者
  • Contract:用于合约的获取
  • 其他(单位转换,)

    前端获取合约

    import myToken from "../json/MyToken.json";//不是之后生成的json文件 import { ethers } from "ethers"; const provider = new ethers.JsonRpcProvider();//获取provider let TokenAddress="0x......"//合约地址 let signer=await provider.signer();//获取签名

    获取合约 参数:合约地址 合约abi,签名如果是signer可读写,provider可读

    const contractWETH = new ethers.Contract(TokenAddress, myToken.abi, signer);

    获取合约后进行交互操作

    # 插件篇

    推荐工具

    hardhat-deploy合约部署相关的插件

    hardhat-gas-reporter部署合约后会生成一个gas费的报告文件

    
    # 总结 
    以上就是使用hardhat构建工具,把编写的智能合约从开发,测试,部署上链的整个流程。
  • 使用内嵌测试包chai,快速验证合约的可行性;
  • 使用到了hardhat-deploy插件,实现快速部署合约;
  • 使用@nomicfoundation/hardhat-verify,验证合约是否成功上链;
  • 以及合约部署gas费消耗分析报告hardhat-gas-reporter。便于优化合约;
  • 通过自定task,提高开发效率;
  • 开发中还会用到预言机chainlink相关的方法
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
木西
木西
江湖只有他的大名,没有他的介绍。