@layerzerolabs/toolbox-hardhat
v0.6.0
Published
One-stop-shop for developing LayerZero applications using hardhat
Downloads
2,123
Readme
Installation
yarn add @layerzerolabs/toolbox-hardhat
pnpm add @layerzerolabs/toolbox-hardhat
npm install @layerzerolabs/toolbox-hardhat
Configuration
1. Add @layerzerolabs/toolbox-hardhat
to your config
To use @layerzerolabs/toolbox-hardhat
you will need to import it in your hardhat
config file.
TypeScript (hardhat.config.ts)
import "@layerzerolabs/toolbox-hardhat";
JavaScript (hardhat.config.js)
require("@layerzerolabs/toolbox-hardhat");
2. Connect your networks
LayerZero deploys EndpointV2
contracts on all supported chains. These contracts are identified by their endpoint ID (eid
for short).
In order to wire your contracts, @layerzerolabs/toolbox-hardhat
needs to know the mapping between the networks defined in your hardhat
config and the endpoint ID.
Previously we required your network names to exactly match the names we use. In order to be more flexible, we decided to switch this more explicit, albeit more verbose configuration.
Head to your hardhat
config to set the eid
↔︎ network
mapping.
TypeScript (hardhat.config.ts)
import { HardhatUserConfig } from "hardhat/types";
import { EndpointId } from "@layerzerolabs/lz-definitions";
const config: HardhatUserConfig = {
// ...
networks: {
fuji: {
eid: EndpointId.AVALANCHE_V2_TESTNET,
url: "https://api.avax-test.network/ext/bc/C/rpc",
// ...
},
mainnet: {
eid: EndpointId.ETHEREUM_V2_MAINNET,
url: "https://eth.llamarpc.com",
},
},
};
export default config;
JavaScript (hardhat.config.js)
const { EndpointId } = require("@layerzerolabs/lz-definitions");
const config = {
// ...
networks: {
fuji: {
eid: EndpointId.AVALANCHE_V2_TESTNET,
url: "https://api.avax-test.network/ext/bc/C/rpc",
// ...
},
mainnet: {
eid: EndpointId.ETHEREUM_V2_MAINNET,
url: "https://eth.llamarpc.com",
},
},
};
module.exports = config;
3. Configure your LayerZero OApp Config
To use the lz:oapp:wire
task you must first fill out your layerzero.config
file.
LayerZero configuration:
contracts
: A conditionally required array of LayerZero Contracts.contract
: A LayerZero Contract, defines theeid
along with either thecontractName
or theaddress
.eid
: A number, defines the LayerZero Endpoint Identifier.contractName
: The contract name. An optional parameter. It should be provided only if the contract was deployed using hardhat-deploy and the deployment information is located in the deployments folder.address
: The contract address. An optional parameter. It should be provided if the contracts are not located in the deployments folder.
connections
: A conditionally required array of LayerZero Connections defining the configuration between two LayerZero contracts.from
: A LayerZero Contract, defines thefrom
contract. This sets the peerfrom -> to
.to
: A LayerZero Contract, defines theto
contract. This sets the peerfrom -> to
.- Note: Both
from
andto
are optional; you are not required to connect all pathways. However,from
andto
must be defined to setconfig
.
- Note: Both
config
: An optional LayerZero Config, defines a configuration between two contracts.sendLibrary
: An optional string, defines the Send Library Address.receiveLibraryConfig
: An optional LayerZero Receive Library Config, defines the receiveLibrary and gracePeriod.receiveLibrary
: A string, defines the Receive Library Address.gracePeriod
: A number, defines Grace Period.
receiveLibraryTimeoutConfig
: An optional LayerZero Receive Library Timeout Config, defines the lib and expiry.lib
: A string, defines the Receive Library Address.expiry
: A number, defines the block timestamp the Receive Library will expire.
sendConfig
: An optional LayerZero Send Config, defines the executorConfig and ulnConfig.executorConfig
: A LayerZero Executor Config, defines the maxMessageSize and executor.maxMessageSize
: A number, defines the maxMessageSize.executor
: A string, defines the Executor Address.
ulnConfig
: An optional LayerZero ULN Config Object, defines the confirmations, optionalDVNThreshold, requiredDVNs, and optionalDVNs.confirmations
: A number, defines the Block Confirmations.optionalDVNThreshold
: A number, defines the Optional DVN Threshold.requiredDVNs
: An array of strings, defines the Required DVNs.optionalDVNs
: An array of strings, defines the Optional DVNs.
receiveConfig
: An optional LayerZero Receive Config, defines the ulnConfig.ulnConfig
: A LayerZero ULN Config Object, defines the confirmations, optionalDVNThreshold, requiredDVNs, and optionalDVNs.confirmations
: A number, defines the Block Confirmations.optionalDVNThreshold
: A number, defines the Optional DVN Threshold.requiredDVNs
: A array of strings, defines the Required DVNs.optionalDVNs
: A array of strings, defines the Optional DVNs.
enforcedOptions
: An optional array of LayerZero Enforced Options, defines the msgType and optionType.msgType
: A number, defines a user defined msgType for the OAppoptionType
: A number, defines type of Enforced Option.LZ_RECEIVE
: Enforced option type 1gas
: A number, defines gas for Option Type LZ_RECEIVE.value
: A number, defines value for Option Type LZ_RECEIVE.
NATIVE_DROP
: Enforced option type 2amount
: A number, defines amount for Option Type NATIVE_DROP.receiver
: A string, defines the receiver address for Option Type NATIVE_DROP.
COMPOSE
: Enforced option type 3index
: A number, defines the index of the composable calls for Option Type COMPOSE.gas
: A number, defines gas for the composable calls for Option Type COMPOSE.value
: A number, defines value for the composable calls for Option Type COMPOSE.
ORDERED
: Enforced option type 4
For example:
TypeScript (layerzero.config.ts)
import {
OAppOmniGraphHardhat,
OmniPointHardhat,
} from "@layerzerolabs/ua-devtools-evm-hardhat";
import { EndpointId } from "@layerzerolabs/lz-definitions";
import { ExecutorOptionType } from "@layerzerolabs/lz-v2-utilities";
const sepoliaContract: OmniPointHardhat = {
eid: EndpointId.SEPOLIA_V2_TESTNET,
contractName: "MyOApp",
};
const fujiContract: OmniPointHardhat = {
eid: EndpointId.AVALANCHE_V2_TESTNET,
contractName: "MyOApp",
};
const graph: OAppOmniGraphHardhat = {
contracts: [
{
contract: fujiContract,
},
{
contract: sepoliaContract,
},
],
connections: [
{
// Sets the peer `from -> to`. Optional, you do not have to connect all pathways.
from: fujiContract,
to: sepoliaContract,
// Optional Configuration
config: {
// Optional Send Library
sendLibrary: "0x0000000000000000000000000000000000000000",
// Optional Receive Library Configuration
receiveLibraryConfig: {
receiveLibrary: "0x0000000000000000000000000000000000000000",
gracePeriod: BigInt(0),
},
// Optional Receive Library Timeout Configuration
receiveLibraryTimeoutConfig: {
lib: "0x0000000000000000000000000000000000000000",
expiry: BigInt(0),
},
// Optional Send Configuration
sendConfig: {
executorConfig: {
maxMessageSize: 99,
executor: "0x0000000000000000000000000000000000000000",
},
ulnConfig: {
confirmations: BigInt(42),
requiredDVNs: [],
optionalDVNs: [
"0x0000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000",
],
optionalDVNThreshold: 2,
},
},
// Optional Receive Configuration
receiveConfig: {
ulnConfig: {
confirmations: BigInt(42),
requiredDVNs: [],
optionalDVNs: [
"0x0000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000",
],
optionalDVNThreshold: 2,
},
},
// Optional Enforced Options Configuration
enforcedOptions: [
{
msgType: 1,
optionType: ExecutorOptionType.LZ_RECEIVE,
gas: 200000,
value: 1,
},
{
msgType: 1,
optionType: ExecutorOptionType.NATIVE_DROP,
amount: 1,
receiver: "0x0000000000000000000000000000000000000000",
},
{
msgType: 2,
optionType: ExecutorOptionType.COMPOSE,
index: 0,
gas: 200000,
value: 1,
},
{
msgType: 2,
optionType: ExecutorOptionType.COMPOSE,
index: 1,
gas: 300000,
value: 1,
},
],
},
},
],
};
export default graph;
Usage
Tasks
This package comes with several hardhat
tasks to speed up your workflow. In order to prevent name collisions, these have been prefixed with lz:
:
lz:oapp:wire
Wires the individual OApp
contracts together, calling setPeer
.
pnpm hardhat lz:oapp:wire