前面提到,我最近在看 Web3,这不记录下最近看到的好玩的。
忘了在哪里看到的一句话,Web3 这个东西,刚看时让人摸不到头脑的点在于,你很难知道要用哪些东西去组装,去哪里拿数据。
比如都说区块链人人可访问,我要到哪里看到它?毕竟看得见的东西更让人心安。
给俺瞧瞧。
我到哪里去看区块链上的数据?不给你 区块链浏览器
这个关键词,大概很难知晓。
一个经常会看到的疑问是如何与合约交互,比如,合约里存了一个字符串,我现在要将其展示到页面上,如何搞?
这玩意是去中心化的呀,没有一个 API 地址让你去连呀,于是就迷茫了。。。
。。。
。。。
。。。
其实 Web3 里的很多东西,就是一张纸,没啥,与智能合约交互其实就是要和节点交互,但维护全节点也太难受了。
那么就换一种方案就是使用别人维护的节点,其实就是连接轻节点提供商,比如 MetaMask 或者 Alchemy,当然了,这里有去中心化的取舍了。
废话说完了,进入正题。
通过使用 Hardhat Alchemy Solidity 来走一下智能合约开发部署流程。
- Hardhat 创建项目
- 实现一个 Hello World 智能合约
- mocha 来测试合约
- 如何将合约部署到区块网络
- 如何验证已经部署的合约
1. 环境搭建
前提条件,前端常用的环境 node 就不多说了。
打开 Hardhat 官网,照着文档一把梭,把它当成一个帮你创建合约项目的一个脚手架就完了。
https://hardhat.org/
注意,Hardhat 更新很快,一些教程可能不是很准确,没事看看官网文档就好了。
npx hardhat
下面是执行时终端输出:
cemcoe@cemcoe MINGW64 ~/workplace/web3gogogo/contracts (main)
$ npx hardhat
Need to install the following packages:
hardhat
Ok to proceed? (y) y
888 888 888 888 888
888 888 888 888 888
888 888 888 888 888
8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888
888 888 "88b 888P" d88" 888 888 "88b "88b 888
888 888 .d888888 888 888 888 888 888 .d888888 888
888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.
888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888
Welcome to Hardhat v2.10.2
? What do you want to do? ...
> Create a JavaScript project
Create a TypeScript project
Create an empty hardhat.config.js
Quit
选择 Create a JavaScript project
,并回车。注意,按照输出,这里还需要装点东西:
cemcoe@cemcoe MINGW64 ~/workplace/web3gogogo/contracts (main)
$ npx hardhat
Need to install the following packages:
hardhat
Ok to proceed? (y) y
888 888 888 888 888
888 888 888 888 888
888 888 888 888 888
8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888
888 888 "88b 888P" d88" 888 888 "88b "88b 888
888 888 .d888888 888 888 888 888 888 .d888888 888
888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.
888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888
Welcome to Hardhat v2.10.2
√ What do you want to do? · Create a JavaScript project
√ Hardhat project root: · C:\Users\cemcoe\workplace\web3gogogo\contracts
√ Do you want to add a .gitignore? (Y/n) · y
You need to install these dependencies to run the sample project:
npm install --save-dev "hardhat@^2.10.2" "@nomicfoundation/hardhat-toolbox@^1.0.1"
Project created
See the README.md file for some example tasks you can run
Give Hardhat a star on Github if you're enjoying it!
https://github.com/NomicFoundation/hardhat
听话,按照它说的做,把依赖都装上:
npm install --save-dev "hardhat@^2.10.2" "@nomicfoundation/hardhat-toolbox@^1.0.1"
基本环境就好了,可以开心写合约玩了。
2. 看下目录
哦,天呀,小宝贝,打开目录看一下吧。
国际惯例,写个 HelloWorld 先。
到 contracts 目录下按照 Lock.sol 来画 HelloWorld,这个文件要尽可能简单,现在的重点在于合约的编译部署和验证。
合约大概长这样:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract HelloWorld {
string public _string = "Hello, World! My Name is cemcoe!";
}
好了,合约不用管了,毕竟不是本文的重点。
3. 写个测试
下面为合约写个测试,不同于前端,合约的安全是重重重重点,毕竟里面存的是资产,测试就不能少了。
https://hardhat.org/hardhat-runner/docs/guides/test-contracts
这里测试是 Chai 和 Mocha 提供的能力,需要注意的是 chai 仅仅是一个assertion library,不是JavaScript test framework。
下面代码中的 describe 以及 it 并不是由 chai 提供的,所以在 chai 的官网你是找不到这俩货的,我在 chai 的官网找半天it。。。
到 test 下创建同名文件来测试一下合约,测试写完那就运行一下。
主要是下面的代码没有 mocha 的影子,但其实 Hardhat 的文档里有提到。
const {
time,
loadFixture,
} = require("@nomicfoundation/hardhat-network-helpers");
const { expect } = require("chai");
// chai 仅仅是一个assertion library,不是JavaScript test framework
// 下面describe以及it并不是由chai提供的,所以在chai的官网你是找不到这俩货的
// https://mochajs.org/
// 比起简单的语法,上面的认知还是蛮重要的
describe("HelloWorld", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshot in every test.
async function deployOneYearLockFixture() {
// Contracts are deployed using the first signer/account by default
const [owner] = await ethers.getSigners();
const CONTRACT = await ethers.getContractFactory("HelloWorld");
const contract = await CONTRACT.deploy();
return { contract, owner };
}
describe("Deployment", function () {
it("Should set the right string", async function () {
const { contract } = await loadFixture(deployOneYearLockFixture);
expect(await contract._string()).to.equal(
"Hello, World! My Name is cemcoe!"
);
});
});
});
运行一下测试脚本
$ npx hardhat test ./test/0.HelloWorld.test.js
Compiled 3 Solidity files successfully
HelloWorld
Deployment
✔ Should set the right string (3150ms)
1 passing (3s)
bingo,测试完成。
4. 部署到测试网络
目前为止,其实一直是关上门称王称霸,现在将合约发布到测试网络吧。
这里要找一个服务商,帮忙上链,什么,你不想要中间商,嗯,把握重点吧伙计。
到这里 https://www.alchemy.com/ 注册一个账号拿到key,并将相应信息配置到hardhat.config.js
文件中,像下面这样:
networks: {
goerli: {
url: GOERLI_URL,
accounts: [PRIVATE_KEY],
},
polygonMumbai: {
url: process.env.MUMBAI_URL,
accounts: [process.env.PRIVATE_KEY],
},
optimismGoerli: {
url: OPTIMISM_GOERLI_URL,
accounts: [PRIVATE_KEY],
},
},
当然,我这里用了一下 dotenv 来存敏感信息,为了体验编译部署流程可以直接写死在文件中。
你可以只配置一个网络,比如 polygonMumbai,其中 MUMBAI_URL 是申请的URL,而 PRIVATE_KEY 是你钱包地址的私钥,做好自己的风险控制,别把自己存有资产的钱包密钥泄露。
配置文件搞好以后就来写一个部署脚本好了。其实很简单。
const hre = require("hardhat");
async function main() {
const CONTRACT = await hre.ethers.getContractFactory("HelloWorld");
const contract = await CONTRACT.deploy();
await contract.deployed();
console.log(`contract deployed to ${contract.address}`);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
核心代码就三句。。。
配置文件和部署脚本都写好以后就可以开始部署了。
npx hardhat run scripts/0.HelloWorld.deploy.js --network polygonMumbai
$ npx hardhat run scripts/0.HelloWorld.deploy.js --network polygonMumbai
Compiled 1 Solidity file successfully
contract deployed to 0x8487Ec50f29d1d36Cb422d6f45AA1ef38Cd2bBA2
5. 验证合约
验证合约的目的是让合约代码在区块浏览器上可读。
和部署合约类似要先写一下申请账号,再配置文件,然后运行脚本,一步一步来。
先到对应的区块浏览器去申请key,这里是 https://mumbai.polygonscan.com/
然后将key配置到hardhat.config.js文件中。
etherscan: {
apiKey: {
goerli: process.env.ETHERSCAN_API_KEY,
polygonMumbai: process.env.POLYGONSCAN_API_KEY,
// optimismGoerli 不在默认配置中
optimismGoerli: "abc",
},
},
当然了,仍然是按需配置,需要什么网络就到对应的区块浏览器去拿key再配置进去。
有了key,配置文件,再加上部署的合约的地址,就可以验证合约了。
npx hardhat verify --network polygonMumbai 0x8487Ec50f29d1d36Cb422d6f45AA1ef38Cd2bBA2
一条龙完成。
$ npx hardhat verify --network polygonMumbai 0x8487Ec50f29d1d36Cb422d6f45AA1ef38Cd2bBA2
Nothing to compile
Successfully submitted source code for contract
contracts/0.HelloWorld.sol:HelloWorld at 0x8487Ec50f29d1d36Cb422d6f45AA1ef38Cd2bBA2
for verification on the block explorer. Waiting for verification result...
Successfully verified contract HelloWorld on Etherscan.
https://mumbai.polygonscan.com/address/0x8487Ec50f29d1d36Cb422d6f45AA1ef38Cd2bBA2#code
注意, goerli 或其它网络验证合约时,因网络原因会出现 Error in plugin @nomiclabs/hardhat-etherscan: Failed to send contract verification request. 的情况。
$ npx hardhat verify --network goerli 0x7520A14646eF8d8123e88937DcB39604E8E70CeA
Nothing to compile
Error in plugin @nomiclabs/hardhat-etherscan: Failed to send contract verification request.
Endpoint URL: https://api-goerli.etherscan.io/api
Reason: Connect Timeout Error