Hardhat
Hardhat 是一个编译、部署、测试和调试以太坊应用的开发环境。
Hardhat 内置了 Hardhat 网络,这是一个专为开发设计的本地以太坊网络。主要功能有 Solidity 调试,跟踪调用堆栈、console.log()和交易失败时的明确错误信息提示等。
code
1、quick start
a、编译合约
yarn hardhat compile
如果您创建了 TypeScript 项目,此任务还将使用 TypeChain 生成 TypeScript 绑定。
要强制编译,您可以使用 --force
参数,或运行 npx hardhat clean
来清除缓存并删除工件。
测试合约
b、部署合约
[TODO] 💖https://hardhat.org/ignition/docs/getting-started#overview
yarn hardhat run scripts/deploy.ts
c、hardhat 网络
默认情况下,Hardhat 将在启动时启动一个新的内存中 Hardhat 网络实例。还可以以独立方式运行 Hardhat Network,以便外部客户端可以连接到它。这可以是钱包、Dapp 前端或脚本。
yarn hardhat node
在本地网络上部署
yarn hardhat run scripts/deploy.ts --network localhost
d、验证合约
https://hardhat.org/hardhat-runner/docs/guides/verifying
https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify
2、配置
a、cli
help
yarn hardhat help
--network
--network localhost
--network hardhat
--network sepolia
b、hardhat.config.js
config, plugins and custom tasks
https://hardhat.org/hardhat-runner/docs/config#configuration
Hardhat 的配置文件将始终在任何任务之前运行,因此您可以使用它与其他工具集成,例如导入 @babel/register
。
3、任务和脚本 tasks & scripts
a、任务
https://hardhat.org/hardhat-runner/docs/advanced/create-task
import { task } from 'hardhat/config';
task('accounts', 'Prints the list of accounts', async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
});
yarn hardhat accounts
它的第一个参数是任务的名称,我们在命令行中使用它来运行它。第二个参数是任务的描述,当您使用 npx hardhat help
时会打印该描述。
第三个参数是一个异步函数,在运行任务时执行。它接收两个参数:
带有任务参数的对象。我们还没有定义任何。
Hardhat 运行时环境或 HRE,包含 Hardhat 及其插件的所有功能。您还可以找到在任务执行期间注入到 global
命名空间中的所有属性。
带参数 addParam
import { task } from 'hardhat/config';
task('balance', "Prints an account's balance")
.addParam('account', "The account's address")
.setAction(async (taskArgs, hre) => {
const balance = await hre.ethers.provider.getBalance(taskArgs.account);
console.log(hre.ethers.utils.formatEther(balance), 'ETH');
});
yarn hardhat balance --help
Usage: hardhat [GLOBAL OPTIONS] balance --account <STRING>
OPTIONS:
--account The account's address
balance: Prints an account's balance
可选参数 addOptionalParam
task('hello', 'Prints a greeting')
.addOptionalParam('greeting', 'The greeting to print', 'Hello, World!')
.setAction(async ({ greeting }) => console.log(greeting));
yarn hardhat hello
# Hello, World!
yarn hardhat hello --greeting foo
# foo
子任务 subtask
import { task, subtask } from 'hardhat/config';
task('hello-world', 'Prints a hello world message').setAction(async (taskArgs, hre) => {
await hre.run('print', { message: 'Hello, World!' });
});
subtask('print', 'Prints a message')
.addParam('message', 'The message to print')
.setAction(async taskArgs => {
console.log(taskArgs.message);
});
b、脚本
https://hardhat.org/hardhat-runner/docs/advanced/scripts
scripts/accounts.ts
import { ethers } from 'hardhat';
async function main() {
const accounts = await ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
}
main().catch(error => {
console.error(error);
process.exitCode = 1;
});
yarn hardhat run scripts/accounts.ts
4、hre
https://hardhat.org/hardhat-runner/docs/advanced/hardhat-runtime-environment
5、console
6、typescript
不使用 cli,直接使用ts-node
yarn ts-node --files scripts/accounts.ts
This can also be enabled with TS_NODE_FILES=true
7、Hardhat Ignition
https://hardhat.org/ignition/docs/guides/creating-modules
Hardhat Ignition 是一个用于在以太坊上部署智能合约的声明式系统。它使您能够定义要部署的智能合约实例以及要在其上运行的任何操作。通过接管部署和执行,Harhat Ignition 可让您专注于项目,而不是陷入部署细节中。
a、start
引入
import '@nomicfoundation/hardhat-ignition-ethers';
模块(module)定义&部署
ignition/modules
import { buildModule } from '@nomicfoundation/hardhat-ignition/modules';
export default buildModule('Apollo', m => {
const apollo = m.contract('Rocket', ['Saturn V']);
m.call(apollo, 'launch', []);
return { apollo };
});
yarn hardhat ignition deploy ignition/modules/Apollo.ts --network localhost
将创建一个 ignition/deployments/chain-31337
文件夹。这包含有关您的部署的所有详细信息。 Hardhat Ignition 使用此数据从错误中恢复、恢复修改后的部署等等。
b、创建模块
部署合约 m.contract
const token = m.contract('Token', ['My Token', 'TKN', 18]);
const bar = m.contract('ReceivesETH', [], {
value: 1_000_000_000n, // 1gwei
});
使用现有合约 m.contractAt
const existingToken = m.contractAt('Token', '0x...');
调用合约 m.call
m.call(token, "transfer", [receiver, amount]);
m.call(myContract, "receivesEth" [], {
value: 1_000_000_000n, // 1gwei
});
从合约中读取值 m.staticCall
如果您需要调用合约中的 view
或 pure
函数来检索值,您可以使用 m.staticCall
来完成
const balance = m.staticCall(token, 'balanceOf', [address]);
从 Future 执行期间发出的事件中读取值 ❓
const transfer = m.call(token, 'transfer', [receiver, amount]);
const value = m.readEventArgument(transfer, 'Transfer', '_value');
发送 ETH 或数据到账户 ❓
const send = m.send('SendingEth', address, 1_000_000n);
const send = m.send('SendingData', address, undefined, '0x16417104');
部署一个库 ❓
const myLib = m.library('MyLib');
8、[The Graph]
The Graph 是捕捉区块链事件并提供一个查询事件的 GraphQL 接口,可以方便的 跟踪数据的变化
https://thegraph.com/docs/zh/quick-start/
graph init tg-02 tg-02 --protocol ethereum --network sepolia --abi "./ignition/deployments/chain-11155111/artifacts/MTOKEN#SimpleToken.json" --from-contract 0xF887Ac1b01439475bD75904359A4CB741E640b93 --start-block 5441889 --studio
graph auth --studio
graph codegen && graph build
graph deploy --studio tg-01
-
Run
graph auth
to authenticate with your deploy key. -
Type
cd tg-02
to enter the subgraph. -
Run
yarn deploy
to deploy the subgraph.
在 Goerli 部署一个合约,并调用触发事件。
创建定义数据索引的 Subgraph。
部署 Subgraph 到 TheGraph,实现数据索引。
在前端 DApp 中查询索引数据。
当对子图进行更改时,将主要使用三个文件:
-
清单(subgraph.yaml)--清单定义子图将索引哪些数据源。
-
模式(schema.graphql)--GraphQL 模式定义从子图中检索到的数据。
-
AssemblyScript 映射(mapping.ts)--将数据源中的数据转换为模式中定义的实体的代码。
[contract.ts]
$ graph codegen
$ graph build
$ graph auth --studio <DEPLOY_KEY>
$ graph deploy --studio <SUBGRAPH_SLUG>