— вводить
— асинхронная функция
— Требования к действиям задачи
— Определение параметров
— Ограничения на позиционные параметры
— Валидации типов
— Переопределение задач
— Подзадачи
— учебники по hardhat , hardhat 教程
— Контакт 联系方式
— введение
В этом руководстве мы рассмотрим создание задач в Hardhat, которые являются основным компонентом, используемым для автоматизации.
Задача — это асинхронная функция JavaScript с некоторыми связанными метаданными. Эти метаданные используются Hardhat для автоматизации некоторых действий. Разбор аргументов, валидация и справочные сообщения — все это берется на себя.
Все, что вы можете сделать в Hardhat, определяется как задача. Действия по умолчанию, которые поставляются из коробки, являются встроенными задачами, и они реализованы с использованием тех же API, которые доступны вам как пользователю.
Чтобы увидеть текущие задачи, доступные в вашем проекте, запустите npx hardhat
:
$ npx hardhat
Hardhat version 2.9.10
Usage: hardhat [GLOBAL OPTIONS] <TASK> [TASK OPTIONS]
GLOBAL OPTIONS:
--config A Hardhat config file.
--emoji Use emoji in messages.
--help Shows this message, or a task's help if its name is provided
--max-memory The maximum amount of memory that Hardhat can use.
--network The network to connect to.
--show-stack-traces Show stack traces.
--tsconfig A TypeScript config file.
--verbose Enables Hardhat verbose logging
--version Shows hardhat's version.
AVAILABLE TASKS:
check Check whatever you need
clean Clears the cache and deletes all artifacts
compile Compiles the entire project, building all artifacts
console Opens a hardhat console
flatten Flattens and prints contracts and their dependencies
help Prints this message
node Starts a JSON-RPC server on top of Hardhat Network
run Runs a user-defined script after compiling the project
test Runs mocha tests
To get help for a specific task run: npx hardhat help [task]
Вы можете создавать дополнительные задачи, которые будут появляться в этом списке. Например, вы можете создать задачу для сброса состояния среды разработки, или для взаимодействия с вашими контрактами, или для упаковки вашего проекта.
Давайте рассмотрим процесс создания задачи для взаимодействия с умным контрактом.
Задачи в Hardhat — это асинхронные функции JavaScript, которые получают доступ к среде выполнения Hardhat, которая раскрывает свою конфигурацию и параметры, а также программный доступ к другим задачам и любым объектам плагинов, которые могут быть внедрены.
Для нашего примера мы будем использовать @nomicfoundation/hardhat-toolbox
, который включает библиотеку ethers.js для взаимодействия с нашими контрактами.
npm install --save-dev @nomicfoundation/hardhat-toolbox
Код создания задач может находиться в hardhat.config.js
, или как там называется ваш файл конфигурации. Это хорошее место для создания простых задач. Если ваша задача сложнее, то вполне допустимо разделить код на несколько файлов и требовать
их из конфигурационного файла.
(Если вы пишете плагин для Hardhat, который добавляет задачу, их также можно создавать из отдельного пакета npm. Узнайте больше о создании задач с помощью плагинов в разделе Создание плагинов).
Конфигурационный файл всегда выполняется при запуске, прежде чем произойдет что-либо еще. Полезно помнить об этом. Мы загрузим набор инструментов Hardhat и добавим в него наш код создания задачи.
В этом учебнике мы создадим задачу для получения баланса счета из терминала. Это можно сделать с помощью API конфигурации Hardhat, который доступен в глобальной области видимости hardhat.config.js
:
require("@nomicfoundation/hardhat-toolbox");
task("balance", "Prints an account's balance").setAction(async () => {});
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.9",
};
После сохранения файла вы должны иметь возможность увидеть задачу в Hardhat:
$ npx hardhat
Hardhat version 2.9.10
Usage: hardhat [GLOBAL OPTIONS] <TASK> [TASK OPTIONS]
GLOBAL OPTIONS:
--config A Hardhat config file.
...
AVAILABLE TASKS:
balance Prints an account's balance
check Check whatever you need
clean Clears the cache and deletes all artifacts
...
To get help for a specific task run: npx hardhat help [task]
Теперь давайте реализуем нужную нам функциональность. Нам нужно получить адрес учетной записи от пользователя. Мы можем сделать это, добавив параметр в нашу задачу:
task("balance", "Prints an account's balance")
.addParam("account", "The account's address")
.setAction(async () => {});
Когда вы добавляете параметр к задаче, Hardhat будет обрабатывать ее справочные сообщения за вас:
$ npx hardhat help balance
Hardhat version 2.9.10
Usage: hardhat [GLOBAL OPTIONS] balance --account <STRING>
OPTIONS:
--account The account's address
balance: Prints an account's balance
For global options help run: hardhat help
Теперь давайте узнаем баланс счета. Среда выполнения Hardhat будет доступна в глобальной области видимости. Используя плагин Hardhat ether.js, который входит в состав Hardhat Toolbox, мы получим доступ к экземпляру ethers.js:
task("balance", "Prints an account's balance")
.addParam("account", "The account's address")
.setAction(async (taskArgs) => {
const balance = await ethers.provider.getBalance(taskArgs.account);
console.log(ethers.utils.formatEther(balance), "ETH");
});
Наконец, мы можем запустить его:
$ npx hardhat balance --account 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
10000.0 ETH
И вот она, ваша первая полнофункциональная задача Hardhat, позволяющая легко взаимодействовать с блокчейном Ethereum.
— асинхронная функция
Вы можете создавать свои собственные задачи в файле hardhat.config.js
. API Config будет доступен в глобальной среде, с функциями для определения задач. Вы также можете импортировать API с помощью require("hardhat/config")
, если вы предпочитаете сохранять явную форму и использовать преимущества автозаполнения вашего редактора.
Создание задачи осуществляется вызовом функции task
. Она вернет объект TaskDefinition
, который можно использовать для определения параметров задачи.
Самая простая задача, которую можно определить, это
task(
"hello",
"Prints 'Hello, World!'",
async function (taskArguments, hre, runSuper) {
console.log("Hello, World!");
}
);
Первый аргумент task
— это имя задачи. Второй — ее описание, которое используется для печати справочных сообщений в CLI. Третий — асинхронная функция, принимающая следующие аргументы:
-
taskArguments
— объект с разобранными CLI аргументами задачи. В данном случае это пустой объект. -
hre
— среда выполнения Hardhat. -
runSuper
имеет значение только в том случае, если вы переопределяете существующую задачу, о чем мы узнаем далее. Его цель — позволить вам запустить действие исходной задачи.
Определение аргументов действия необязательно. Hardhat Runtime Environment и runSuper
также будут доступны в глобальной области видимости. Мы можем переписать нашу задачу «hello» таким образом:
task("hello", "Prints 'Hello, World!'", async () => {
console.log("Hello, World!");
});
— Требования к действиям задач
Единственным требованием к написанию задачи является то, что Promise
, возвращаемый ее действием, не должен разрешаться до завершения всех запущенных ею асинхронных процессов.
Это пример задачи, действие которой не удовлетворяет этому требованию:
task("BAD", "This task is broken", async () => {
setTimeout(() => {
throw new Error(
"This task's action returned a promise that resolved before I was thrown"
);
}, 1000);
});
Эта другая задача использует Promise
для ожидания таймаута:
task("delayed-hello", "Prints 'Hello, World!' after a second", async () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Hello, World!");
resolve();
}, 1000);
});
});
Ручное создание Promise
может показаться сложным, но вам не придется этого делать, если вы будете придерживаться API на основе async
/await
и Promise
. Например, вы можете использовать пакет npm delay
для обещанной версии setTimeout
.
— Определение параметров
Задачи Hardhat могут получать именованные параметры со значением (например, --parameter-name parameterValue
), флаги без значения (например, --flag-name
), позиционные параметры или вариативные параметры. Вариативные параметры действуют подобно остальным параметрам JavaScript. Функция Config API task
возвращает объект с методами для определения всех этих параметров. После определения параметров Hardhat берет на себя контроль над разбором параметров, их проверкой и печатью справочных сообщений.
Добавление необязательного параметра к задаче hello
может выглядеть следующим образом:
task("hello", "Prints a greeting'")
.addOptionalParam("greeting", "The greeting to print", "Hello, World!")
.setAction(async ({ greeting }) => console.log(greeting));
И будет выполняться с помощью npx hardhat hello --greeting Hola
.
— Ограничения позиционных параметров
Позиционным и переменным параметрам не обязательно присваивать имена, они имеют обычные ограничения языка программирования:
- Позиционный параметр не может следовать за переменным.
- Обязательные/необходимые параметры не могут следовать за необязательными.
Несоблюдение этих ограничений приведет к возникновению исключения при загрузке Hardhat.
— Валидации типов
Hardhat заботится о проверке и разборе значений, предоставленных для каждого параметра. Вы можете объявить тип параметра, и Hardhat получит строки CLI и преобразует их в нужный вам тип. Если преобразование не удастся, он выведет сообщение об ошибке, объясняющее причину.
Ряд типов доступен в API Config через объект types
. Этот объект внедряется в глобальную область видимости перед обработкой вашего hardhat.config.js
, но вы также можете импортировать его явно с помощью const { types } = require("hardhat/config")
и воспользоваться преимуществами автозаполнения вашего редактора.
Примером задачи, определяющей тип для одного из своих параметров, может служить следующее
task("hello", "Prints 'Hello' multiple times")
.addOptionalParam(
"times",
"The number of times to print 'Hello'",
1,
types.int
)
.setAction(async ({ times }) => {
for (let i = 0; i < times; i++) {
console.log("Hello");
}
});
Вызов этой задачи с npx hardhat hello --times notanumber
приведет к ошибке.
— Переопределение задач
Определение задачи с тем же именем, что и существующая, отменяет существующую задачу. Это полезно для изменения или расширения поведения встроенных задач и задач, предоставляемых плагинами.
Переопределение задач работает так же, как переопределение методов при расширении класса. Вы можете задать собственное действие, которое может вызывать переопределенное действие. Единственным ограничением при переопределении задач является то, что вы не можете добавлять или удалять параметры.
Порядок переопределения задач важен, поскольку действия могут вызывать только непосредственно переопределенное определение, используя функцию runSuper
.
Переопределение встроенных задач — это отличный способ настройки и расширения Hardhat. Чтобы узнать, какие задачи следует переопределить, посмотрите на src/builtin-tasks.
— Функция runSuper
runSuper
— это функция, доступная для переопределения действий задачи. Она может быть получена в качестве третьего аргумента задачи или использоваться непосредственно из глобального объекта.
Эта функция работает подобно ключевому слову JavaScript super
: она вызывает ранее определенное действие задачи.
Если задача не переопределяет предыдущее определение задачи, то вызов runSuper
приведет к ошибке. Чтобы проверить, приведет ли вызов к ошибке, можно использовать поле boolean
runSuper.isDefined
.
Функция runSuper
получает один необязательный аргумент: объект с аргументами задачи. Если этот аргумент не указан, будут использованы те же аргументы задачи, которые были получены вызывающим ее действием.
— Подзадачи
Создание задач с большим количеством логики затрудняет их расширение или настройку. Создание нескольких небольших и сфокусированных задач, вызывающих друг друга, — лучший способ расширения. Если вы разработаете свои задачи таким образом, пользователи, которые хотят изменить только небольшой аспект, смогут переопределить одну из ваших подзадач.
Например, задача compile
реализована как конвейер из нескольких задач. Она просто вызывает такие подзадачи, как compile:get-source-paths
, compile:get-dependency-graph
и compile:build-artifacts
. Мы рекомендуем обозначать промежуточные задачи префиксом их основной задачи и двоеточием.
Чтобы избежать загромождения справочных сообщений большим количеством промежуточных задач, вы можете определить их с помощью функции API конфигурации subtask
. Функция subtask
работает почти так же, как task
. Единственное отличие заключается в том, что задачи, определенные с ее помощью, не будут включены в справочные сообщения.
Для запуска подзадачи или любой другой задачи можно использовать функцию run
. Она принимает два аргумента: имя запускаемой задачи и объект с ее аргументами.
Это пример запуска подзадачи:
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);
});
— hardhat Tutorials , hardhat 教程
CN 中文 Github hardhat 教程 : github.com/565ee/hardhat_CN
CN 中文 CSDN hardhat 教程 : blog.csdn.net/wx468116118
EN 英文 Github hardhat Tutorials : github.com/565ee/hardhat_EN
— Контакт 联系方式
Домашняя страница : 565.ee
GitHub : github.com/565ee
Электронная почта : 565.eee@gmail.com
Facebook : facebook.com/565.ee
Twitter : twitter.com/565_eee
Telegram : t.me/ee_565