Skip to main content
Version: Endpoint V2 Docs

Configuring Contracts

For each contract in your config file, you can configure the following:

FromOApp.transferOwnership(newOwner)
FromOApp.setPeer(dstEid, peer)
FromOApp.setEnforcedOptions()
EndpointV2.setSendLibrary(OApp, dstEid, newLib)
EndpointV2.setReceiveLibrary(OApp, dstEid, newLib, gracePeriod)
EndpointV2.setReceiveLibraryTimeout(OApp, dstEid, lib, gracePeriod)
EndpointV2.setConfig(OApp, sendLibrary, sendConfig)
EndpointV2.setConfig(OApp, receiveLibrary, receiveConfig)
EndpointV2.setDelegate(delegate)

Adding Configurations

To configure your OApp, you will need to change your layerzero.config.ts for your desired pathways.

Initializing Config

You can initialize your OApp configurations by running:

npx hardhat lz:oapp:config:init --contract-name DEPLOYMENT_NAME --oapp-config CONFIG_FILE_NAME

This will auto-populate the provided config file, or create the file if the path does not exist, with the current LayerZero default configurations as a placeholder.

For example, running:

npx hardhat lz:oapp:config:init --contract-name MyOApp --oapp-config testnet.layerzero.config.ts

will create a new file in my directory with the correct type interface:

contracts/
deploy/
test/
foundry.toml
hardhat.config.ts
layerzero.config.ts
testnet.layerzero.config.ts <-----
caution

Make sure the DEPLOYMENT_NAME exists in your ./deployments folder, otherwise the task will fail.


Head to the layerzero.config.ts and scroll down to module.exports.

As explained previously, the CLI Toolkit organizes your configurations on a per-pathway basis:

module.exports = {
// Define the contracts to be deployed on each network
// Each contract is associated with a specific blockchain.
contracts: [
{
contract: sepoliaContract,
},
{
contract: bscContract,
},
],
// Define the pathway between each contract.
// This allows for cross-chain communication using LayerZero.
connections: [
{
from: bscContract,
to: sepoliaContract,
},
{
from: sepoliaContract,
to: bscContract,
},
],
};

To add a specific pathway configuration, add a config: {} to your connection:

module.exports = {
// Define the contracts to be deployed on each network
// Each contract is associated with a specific blockchain.
contracts: [
{
contract: sepoliaContract,
},
{
contract: bscContract,
},
],
// Define the pathway between each contract.
// This allows for cross-chain communication using LayerZero.
connections: [
{
from: bscContract,
to: sepoliaContract,
config: {},
},
{
from: sepoliaContract,
to: bscContract,
},
],
};

Each pathway contains a config, containing multiple configuration structs for changing how your OApp sends and receives messages, specifically for the chain your OApp is sending from:

NameTypeDescription
sendLibraryAddressThe message library used for configuring all sent messages from this chain. (e.g., SendUln302.sol)
receiveLibraryConfigStructA struct containing the receive message library address (e.g., ReceiveUln302.sol), and an optional BigInt, gracePeriod, the time to wait before updating to a new MessageLib version during version migration. Controls how the from chain receives messages.
receiveLibraryTimeoutConfigStructAn optional param, defining when the old receive library (lib) will expire (expiry) during version migration.
sendConfigStructControls how the OApp sends from this pathway, containing two more structs: executorConfig and ulnConfig (DVNs).
receiveConfigStructControls how the OApp (from) receives messages, specifically the ulnConfig (DVNs).
enforcedOptionsStructControls the minimum destination gas sent to the destination, per message type (e.g., _lzReceive, lzCompose, etc.) in your OApp.
tip

When adding a config, consider that connections moves in a bidirectional, two-way path:

  • The sendConfig applies to all message sent from Chain A and received by the to address, Chain B.

  • The receiveConfig applies to all messages received by Chain A (from), sent from Chain B (the to contract).

For example, this config: {} applies only to how the bscContract sends messages to the sepoliaContract, and how the bscContract receives messages from the sepoliaContract.

Adding sendLibrary

Every configuration should start by adding a sendLibrary.

connections: [
{
// Sets the peer `from -> to`. Optional, you do not have to connect all pathways.
from: bscContract,
to: sepoliaContract,
// Optional Configuration
config: {
// Required Send Library Address on BSC
sendLibrary: "0x0000000000000000000000000000000000000000",
},
},
],

When running lz:oapp:wire, this will call EndpointV2:

// LayerZero/V2/protocol/contracts/interfaces/IMessageLibManager.sol

function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external;

Each MessageLib contains the available configuration options for the protocol, and so must be set by the application owner to prevent unintended updates.

info

You should use the sendLibrary address for the chain you're sending from (i.e., SendUln302.sol on BSC).

info

The MessageLib Registry is append only, meaning that old Message Libraries will always be available for OApps. Locking your Library is only necessary to prevent updates.

Adding receiveLibrary

Every configuration should also add a receiveLibrary. Similar to the sendLibrary, the OApp owner must also set the Receive Library to ensure that your configured application settings will be locked.

To do this, add a receiveLibraryConfig:

connections: [
{
// Sets the peer `from -> to`. Optional, you do not have to connect all pathways.
from: bscContract,
to: sepoliaContract,
// Optional Configuration
config: {
// Required Send Library Address on BSC
sendLibrary: "0x0000000000000000000000000000000000000000",
receiveLibraryConfig: {
// Required Receive Library Address on BSC
receiveLibrary: "0x0000000000000000000000000000000000000000",
// Optional Grace Period for Switching Receive Library Address on BSC
gracePeriod: BigInt(0),
},
// Optional Receive Library Timeout for when the Old Receive Library Address will no longer be valid on BSC
receiveLibraryTimeoutConfig: {
lib: "0x0000000000000000000000000000000000000000",
expiry: BigInt(0),
},
},
},
],

The Receive Library also provides two additional parameters to help future-proof OApp's for migrating MessageLib versions:

  • gracePeriod: the time to wait before updating to a new MessageLib version during version migration. If the grace period is 0, it will delete the timeout configuration.

  • expiry: the time at which messages in-flight from the old library will be considered invalid. This is mainly for handling messages that are in-flight during the migration.

In most cases, setting the gracePeriod to 0 will be sufficient.

When running lz:oapp:wire, this config will call EndpointV2:

// LayerZero/V2/protocol/contracts/interfaces/IMessageLibManager.sol

function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external;

function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _gracePeriod) external;

Adding sendConfig

Your sendConfig controls what DVN addresses and Executor addresses should be paid to verify and execute when a message is sent.

info

Each DVN and Executor contains both on-chain and off-chain component. When sending a message, you pay the DVNs and Executors contracts on the source chain, and they relay the message to the equivalent contracts on the destination chain.

For your sendConfig, use the DVNs and Executor contract addresses on the same chain as your sending OApp.

tip

DVNs only need to be the same for a given pathway.

You can have one set of DVNs verifying transactions from Arbitrum to Base and Base to Arbitrum, and a separate set of DVNs verifying transactions from Arbitrum to Avalanche and Avalanche to Arbitrum.

connections: [
{
// Sets the peer `from -> to`. Optional, you do not have to connect all pathways.
from: bscContract,
to: sepoliaContract,
// Optional Configuration
config: {
// Required Send Library Address on BSC
sendLibrary: "0x0000000000000000000000000000000000000000",
// Required Receive Library Config
receiveLibraryConfig: {
// Required Receive Library Address on BSC
receiveLibrary: "0x0000000000000000000000000000000000000000",
// Optional Grace Period for Switching Receive Library Address on BSC
gracePeriod: BigInt(0),
},
// Optional Receive Library Timeout for when the Old Receive Library Address will no longer be valid on BSC
receiveLibraryTimeoutConfig: {
lib: "0x0000000000000000000000000000000000000000",
expiry: BigInt(0),
},
// Optional Send Configuration
// @dev Controls how the `from` chain sends messages to the `to` chain.
sendConfig: {
executorConfig: {
maxMessageSize: 10000,
// The configured Executor address on BSC
executor: "0x0000000000000000000000000000000000000000",
},
ulnConfig: {
// The number of block confirmations to wait on BSC before emitting the message from the source chain (BSC).
confirmations: BigInt(0),
// The address of the DVNs you will pay to verify a sent message on the source chain (BSC).
// The destination tx will wait until ALL `requiredDVNs` verify the message.
requiredDVNs: [],
// The address of the DVNs you will pay to verify a sent message on the source chain (BSC).
// The destination tx will wait until the configured threshold of `optionalDVNs` verify a message.
optionalDVNs: [
"0x_POLYHEDRA_DVN_ADDRESS_ON_BSC",
"0x_LAYERZERO_DVN_ADDRESS_ON_BSC",
],
// The number of `optionalDVNs` that need to successfully verify the message for it to be considered Verified.
optionalDVNThreshold: 2,
},
},
},
},
],

This will call EndpointV2.setConfig:

// LayerZero/V2/protocol/contracts/interfaces/IMessageLibManager.sol

struct SetConfigParam {
uint32 eid;
uint32 configType;
bytes config;
}

function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external;

The Executor and ULN configType and config:

// LayerZero/V2/messagelib/contracts/uln/uln302/SendUln302.sol

uint32 internal constant CONFIG_TYPE_EXECUTOR = 1;
uint32 internal constant CONFIG_TYPE_ULN = 2;
// LayerZero/V2/messagelib/contracts/uln/SendLibBase.sol

struct ExecutorConfig {
uint32 maxMessageSize;
address executor;
}
// LayerZero/V2/messagelib/contracts/uln/UlnBase.sol

struct UlnConfig {
uint64 confirmations;
// we store the length of required DVNs and optional DVNs instead of using DVN.length directly to save gas
uint8 requiredDVNCount; // 0 indicate DEFAULT, NIL_DVN_COUNT indicate NONE (to override the value of default)
uint8 optionalDVNCount; // 0 indicate DEFAULT, NIL_DVN_COUNT indicate NONE (to override the value of default)
uint8 optionalDVNThreshold; // (0, optionalDVNCount]
address[] requiredDVNs; // no duplicates. sorted an an ascending order. allowed overlap with optionalDVNs
address[] optionalDVNs; // no duplicates. sorted an an ascending order. allowed overlap with requiredDVNs
}

Adding receiveConfig

The receive configuration controls what DVN addresses your OApp expects to have verified the message in-flight.

tip

For example, if BSC is receiving messages from Sepolia, you should use the DVN contract addresses on BSC for each DVN provider you have in your sendConfig.

connections: [
{
// Sets the peer `from -> to`. Optional, you do not have to connect all pathways.
from: bscContract,
to: sepoliaContract,
// Optional Configuration
config: {
// Required Send Library Address on BSC
sendLibrary: "0x0000000000000000000000000000000000000000",
// Required Receive Library Config
receiveLibraryConfig: {
// Required Receive Library Address on BSC
receiveLibrary: "0x0000000000000000000000000000000000000000",
// Optional Grace Period for Switching Receive Library Address on BSC
gracePeriod: BigInt(0),
},
// Optional Receive Library Timeout for when the Old Receive Library Address will no longer be valid on BSC
receiveLibraryTimeoutConfig: {
lib: "0x0000000000000000000000000000000000000000",
expiry: BigInt(0),
},
// Optional Send Configuration
// @dev Controls how the `from` chain sends messages to the `to` chain.
sendConfig: {
executorConfig: {
maxMessageSize: 99,
// The configured Executor address on BSC
executor: "0x0000000000000000000000000000000000000000",
},
ulnConfig: {
// The number of block confirmations to wait on BSC before emitting the message from the source chain (BSC).
confirmations: BigInt(42),
// The address of the DVNs you will pay to verify a sent message on the source chain (BSC).
// The destination tx will wait until ALL `requiredDVNs` verify the message.
requiredDVNs: [],
// The address of the DVNs you will pay to verify a sent message on the source chain (BSC).
// The destination tx will wait until the configured threshold of `optionalDVNs` verify a message.
optionalDVNs: [
"0x_POLYHEDRA_DVN_ADDRESS_ON_BSC",
"0x_LAYERZERO_DVN_ADDRESS_ON_BSC",
],
// The number of `optionalDVNs` that need to successfully verify the message for it to be considered Verified.
optionalDVNThreshold: 2,
},
},
// Optional Receive Configuration
// @dev Controls how the `from` chain receives messages from the `to` chain.
receiveConfig: {
ulnConfig: {
// The number of block confirmations to expect from the `to` chain (Sepolia).
confirmations: BigInt(42),
// The address of the DVNs your `receiveConfig` expects to receive verifications from on the `from` chain (BSC).
// The `from` chain's OApp will wait until the configured threshold of `requiredDVNs` verify the message.
requiredDVNs: [],
// The address of the `optionalDVNs` you expect to receive verifications from on the `from` chain (BSC).
// The destination tx will wait until the configured threshold of `optionalDVNs` verify the message.
optionalDVNs: [
"0x_POLYHEDRA_DVN_ADDRESS_ON_BSC",
"0x_LAYERZERO_DVN_ADDRESS_ON_BSC",
],
// The number of `optionalDVNs` that need to successfully verify the message for it to be considered Verified.
optionalDVNThreshold: 2,
},
},
},
},
],

This will set the receiveConfig in EndpointV2.setConfig:

// LayerZero/V2/messagelib/contracts/uln/UlnBase.sol

struct UlnConfig {
uint64 confirmations;
// we store the length of required DVNs and optional DVNs instead of using DVN.length directly to save gas
uint8 requiredDVNCount; // 0 indicate DEFAULT, NIL_DVN_COUNT indicate NONE (to override the value of default)
uint8 optionalDVNCount; // 0 indicate DEFAULT, NIL_DVN_COUNT indicate NONE (to override the value of default)
uint8 optionalDVNThreshold; // (0, optionalDVNCount]
address[] requiredDVNs; // no duplicates. sorted an an ascending order. allowed overlap with optionalDVNs
address[] optionalDVNs; // no duplicates. sorted an an ascending order. allowed overlap with requiredDVNs
}

Adding enforcedOptions

You can specify both a minimum destination gas and msg.value that users must pay for both your contract's lzReceive and `lzCompose logic to execute as intended.

The CLI Toolkit enables you to configure your message options in a human-readable format, provided that your OApp has added an Enforced Option Message Type.

info

The Omnichain Fungible Token (OFT) Standard by default already has Enforced Options added to the contract, with two message types available:

// @dev execution types to handle different enforcedOptions
uint16 internal constant SEND = 1; // a standard token transfer via lzReceive
uint16 internal constant SEND_AND_CALL = 2; // a token transfer, followed by a composable call via lzCompose
connections: [
{
// Sets the peer `from -> to`. Optional, you do not have to connect all pathways.
from: bscContract,
to: sepoliaContract,
// Optional Configuration
config: {
// Required Send Library Address on BSC
sendLibrary: "0x0000000000000000000000000000000000000000",
receiveLibraryConfig: {
// Required Receive Library Address on BSC
receiveLibrary: "0x0000000000000000000000000000000000000000",
// Optional Grace Period for Switching Receive Library Address on BSC
gracePeriod: BigInt(0),
},
// Optional Receive Library Timeout for when the Old Receive Library Address will no longer be valid on BSC
receiveLibraryTimeoutConfig: {
lib: "0x0000000000000000000000000000000000000000",
expiry: BigInt(0),
},
// Optional Send Configuration
// @dev Controls how the `from` chain sends messages to the `to` chain.
sendConfig: {
executorConfig: {
maxMessageSize: 99,
// The configured Executor address on BSC
executor: "0x0000000000000000000000000000000000000000",
},
ulnConfig: {
// The number of block confirmations to wait on BSC before emitting the message from the source chain (BSC).
confirmations: BigInt(42),
// The address of the DVNs you will pay to verify a sent message on the source chain (BSC).
// The destination tx will wait until ALL `requiredDVNs` verify the message.
requiredDVNs: [],
// The address of the DVNs you will pay to verify a sent message on the source chain (BSC).
// The destination tx will wait until the configured threshold of `optionalDVNs` verify a message.
optionalDVNs: [
"0x_POLYHEDRA_DVN_ADDRESS_ON_BSC",
"0x_LAYERZERO_DVN_ADDRESS_ON_BSC",
],
// The number of `optionalDVNs` that need to successfully verify the message for it to be considered Verified.
optionalDVNThreshold: 2,
},
},
// Optional Receive Configuration
// @dev Controls how the `from` chain receives messages from the `to` chain.
receiveConfig: {
ulnConfig: {
// The number of block confirmations to expect from the `to` chain (Sepolia).
confirmations: BigInt(42),
// The address of the DVNs your `receiveConfig` expects to receive verifications from on the `from` chain (BSC).
// The `from` chain's OApp will wait until the configured threshold of `requiredDVNs` verify the message.
requiredDVNs: [],
// The address of the `optionalDVNs` you expect to receive verifications from on the `from` chain (BSC).
// The destination tx will wait until the configured threshold of `optionalDVNs` verify the message.
optionalDVNs: [
"0x_POLYHEDRA_DVN_ADDRESS_ON_BSC",
"0x_LAYERZERO_DVN_ADDRESS_ON_BSC",
],
// The number of `optionalDVNs` that need to successfully verify the message for it to be considered Verified.
optionalDVNThreshold: 2,
},
},
// Optional Enforced Options Configuration
// @dev Controls how much gas to use on the `to` chain, which the user pays for on the source `from` chain.
enforcedOptions: [
{
msgType: 1, // depending on OAppOptionType3
optionType: ExecutorOptionType.LZ_RECEIVE,
gas: 65000, // gas limit in wei for EndpointV2.lzReceive
value: 0, // msg.value in wei for EndpointV2.lzReceive
},
{
msgType: 1,
optionType: ExecutorOptionType.NATIVE_DROP,
amount: 0, // amount of native gas token in wei to drop to receiver address
receiver: "0x0000000000000000000000000000000000000000",
},
{
msgType: 2,
optionType: ExecutorOptionType.LZ_RECEIVE,
index: 0,
gas: 65000, // gas limit in wei for EndpointV2.lzReceive
value: 0, // msg.value in wei for EndpointV2.lzReceive
},
{
msgType: 2,
optionType: ExecutorOptionType.COMPOSE,
index: 0, // index of EndpointV2.lzCompose message
gas: 50000, // gas limit in wei for EndpointV2.lzCompose
value: 0, // msg.value in wei for EndpointV2.lzCompose
},
],
},
},
],

This will call OApp.setEnforcedOptions assuming your OApp has inherited from OAppOptionsType3.sol:

// LayerZero/V2/oapp/contracts/oapp/interfaces/IOAppOptionsType3.sol

struct EnforcedOptionParam {
uint32 eid; // Endpoint ID
uint16 msgType; // Message Type
bytes options; // Additional options
}

function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) external;

Review the Transaction Pricing section and the Execution Options to better understand how you should add your execution gas settings.

Adding delegate

// layerzero.config.ts

contracts: [
{
contract: sepolia,
config: {
delegate: '0x0000000000000000000000000000000000000000',
},
},
{
contract: bsc,
config: {
delegate: '0x0000000000000000000000000000000000000000',
},
},
];

Adding owner

// layerzero.config.ts

contracts: [
{
contract: sepolia,
config: {
owner: '0x0000000000000000000000000000000000000000',
},
},
{
contract: bsc,
config: {
owner: '0x0000000000000000000000000000000000000000',
},
},
];

To transfer ownership, you will need to run a separate command:

npx hardhat lz:ownable:transfer-ownership --oapp-config layerzero.config.ts
caution

Once you transfer ownership, you can no longer call OApp.setDelegate and OApp.setEnforcedOptions. You should ensure all other configurations have been set to your liking before transferring ownership.

Final Config

Your final config may have different settings, but should define the following parameters:

connections: [
{
// Sets the peer `from -> to`. Optional, you do not have to connect all pathways.
from: bscContract,
to: sepoliaContract,
// Optional Configuration
config: {
// Required Send Library Address on BSC
sendLibrary: "0x0000000000000000000000000000000000000000",
receiveLibraryConfig: {
// Required Receive Library Address on BSC
receiveLibrary: "0x0000000000000000000000000000000000000000",
// Optional Grace Period for Switching Receive Library Address on BSC
gracePeriod: BigInt(0),
},
// Optional Receive Library Timeout for when the Old Receive Library Address will no longer be valid on BSC
receiveLibraryTimeoutConfig: {
lib: "0x0000000000000000000000000000000000000000",
expiry: BigInt(0),
},
// Optional Send Configuration
// @dev Controls how the `from` chain sends messages to the `to` chain.
sendConfig: {
executorConfig: {
maxMessageSize: 10000,
// The configured Executor address on BSC
executor: "0x0000000000000000000000000000000000000000",
},
ulnConfig: {
// The number of block confirmations to wait on BSC before emitting the message from the source chain (BSC).
confirmations: BigInt(0),
// The address of the DVNs you will pay to verify a sent message on the source chain (BSC).
// The destination tx will wait until ALL `requiredDVNs` verify the message.
requiredDVNs: [],
// The address of the DVNs you will pay to verify a sent message on the source chain (BSC).
// The destination tx will wait until the configured threshold of `optionalDVNs` verify a message.
optionalDVNs: [
"0x_POLYHEDRA_DVN_ADDRESS_ON_BSC",
"0x_LAYERZERO_DVN_ADDRESS_ON_BSC",
],
// The number of `optionalDVNs` that need to successfully verify the message for it to be considered Verified.
optionalDVNThreshold: 2,
},
},
// Optional Receive Configuration
// @dev Controls how the `from` chain receives messages from the `to` chain.
receiveConfig: {
ulnConfig: {
// The number of block confirmations to expect from the `to` chain (Sepolia).
confirmations: BigInt(0),
// The address of the DVNs your `receiveConfig` expects to receive verifications from on the `from` chain (BSC).
// The `from` chain's OApp will wait until the configured threshold of `requiredDVNs` verify the message.
requiredDVNs: [],
// The address of the `optionalDVNs` you expect to receive verifications from on the `from` chain (BSC).
// The destination tx will wait until the configured threshold of `optionalDVNs` verify the message.
optionalDVNs: [
"0x_POLYHEDRA_DVN_ADDRESS_ON_BSC",
"0x_LAYERZERO_DVN_ADDRESS_ON_BSC",
],
// The number of `optionalDVNs` that need to successfully verify the message for it to be considered Verified.
optionalDVNThreshold: 2,
},
},
// Optional Enforced Options Configuration
// @dev Controls how much gas to use on the `to` chain, which the user pays for on the source `from` chain.
enforcedOptions: [
{
msgType: 1,
optionType: ExecutorOptionType.LZ_RECEIVE,
gas: 60000,
value: 0,
},
{
msgType: 1,
optionType: ExecutorOptionType.NATIVE_DROP,
amount: 0,
receiver: "0x0000000000000000000000000000000000000000",
},
{
msgType: 2,
optionType: ExecutorOptionType.LZ_RECEIVE,
index: 0,
gas: 60000,
value: 1,
},
{
msgType: 2,
optionType: ExecutorOptionType.COMPOSE,
index: 0,
gas: 50000,
value: 0,
},
],
},
},
],

Applying Changes

Wiring your contracts will set the peer address for your OApp or OFT and initialize the desired configuration in your layerzero.config.ts. If unfamiliar with this concept, review the OApp Quickstart.

Wiring Contracts

The CLI Tool makes this one step easier by enabling you to wire and configure your contract pathways with a single command:

$ npx hardhat lz:oapp:wire --oapp-config layerzero.config.ts

Before wiring your contracts, you should review your layerzero.config.ts to ensure that you have specified accurately the configuration you want to set.

Wiring your contracts will set the peer address for your OApp or OFT and initialize the desired configuration in your layerzero.config.ts. If unfamiliar with this concept, review the OApp Quickstart.

The CLI Tool makes this one step easier by enabling you to wire and configure your contract pathways with a single command:

$ npx hardhat lz:oapp:wire --oapp-config layerzero.config.ts

Before wiring your contracts, you should review your layerzero.config.ts to ensure that you have specified accurately the configuration you want to set.

Checking setPeers

To check if your contracts have correctly been set to communicate with one another, you can run:

npx hardhat lz:oapp:peers:get --oapp-config layerzero.config.ts

Checking Pathway config

To confirm your OApp's configuration has been set as intended, you can run:

$ npx hardhat lz:oapp:config:get --oapp-config layerzero.config.ts

Checking executor

To see your OApp's configured executor, you can run:

npx hardhat lz:oapp:config:get:executor

Checking enforcedOptions

To see your OApp's configured execution gas has been set as intended, you can run:

npx hardhat lz:oapp:enforced-opts:get --oapp-config layerzero.config.ts

Checking Pathway defaults

To see what the default configuration is for any pathway, run:

npx hardhat lz:oapp:config:get --oapp-config layerzero.config.ts

Wiring via Gnosis Safe

If your contracts are owned by a gnosis multisig wallet, you must define the multisig's safeUrl and safeAddress per chain in your hardhat.config.ts file to enable the submission of wire transactions for multisig approval.

Step 1: Configure your gnosis

In your hardhat config, add safeConfig to your networks, with your specific safeUrl and safeAddress mapped accordingly:

// hardhat.config.ts

networks: {
// Include configurations for other networks as needed
fuji: {
/* ... */
// Network-specific settings
safeConfig: {
safeUrl: 'http://something',
safeAddress: 'address'
}
}
}

Step 2: Use your safe config

When wiring, pass the --safe flag in your wire command.

$ npx hardhat lz:oapp:wire --oapp-config layerzero.config.ts --safe

This command initiates the wiring process under the multisig setup, pushing transactions to the specified multisig wallet for necessary approvals.

note

Ensure your development tools are up to date to utilize this feature, as it relies on the latest versions of the required dependencies.