Skip to main content
For each contract in your config file, you can configure the following:

Adding Configurations

To configure your OApp, you will need to change your layerzero.config.ts for your desired pathways.
Production deployments should use multiple required DVNs from independent operators. The examples below use <SECONDARY_DVN> as a placeholder so the config does not silently resolve to a single-DVN configuration. Replace it with a real DVN name from DVN Addresses before wiring. See the Integration Checklist for production DVN guidance.
LayerZero’s CLI makes use of the @layerzerolabs/metadata-tools package, which allows for a human readable layerzero.config.ts file. Here’s how to use it:
  1. Install metadata-tools: pnpm add -D @layerzerolabs/metadata-tools
  2. Create a new LZ config file named layerzero.config.ts (or edit your existing one) in the project root and use the examples below as a starting point:
    • The above examples contains a minimal mesh with only one pathway (two chains) for demonstration purposes. You are able to add as many pathways as you need into the connections param, via generateConnectionsConfig.
  3. Run the wire command:
The wire command will process all the transactions required to connect the pathways specified in the config file. If you change anything in the config, run the command again. 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:
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.
When running lz:oapp:wire, this will call EndpointV2:
Each MessageLib contains the available configuration options for the protocol, and so must be set by the application owner to prevent unintended updates.
You should use the sendLibrary address for the chain you’re sending from (i.e., SendUln302.sol on BSC).
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:
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:

Adding sendConfig

Your sendConfig controls what DVN addresses and Executor addresses should be paid to verify and execute when a message is sent.
Each DVN and Executor contains both onchain 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.
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.
This will call EndpointV2.setConfig:
The Executor and ULN configType and config:

Adding receiveConfig

The receive configuration controls what DVN addresses your OApp expects to have verified the message in-flight.
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.
This will set the receiveConfig in EndpointV2.setConfig:

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 Options.
The Omnichain Fungible Token (OFT) Standard by default already has Enforced Options added to the contract, with two message types available:
This will call OApp.setEnforcedOptions assuming your OApp has inherited from OAppOptionsType3.sol:

Adding delegate

Adding owner

To transfer ownership, you will need to run a separate command:
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.

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.

Wiring Contracts

The CLI Tool makes this one step easier by enabling you to wire and configure your contract pathways with a single command:
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. The CLI Tool makes this one step easier by enabling you to wire and configure your contract pathways with a single command:
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:

Checking Pathway config

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

Checking executor

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

Checking enforcedOptions

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

Checking Pathway defaults

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

Wiring via Safe multisig

If your contracts are owned by a Safe 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. safeUrl refers to the URL of the Safe Transaction Service for a given network. For the endpoints deployed by Safe themselves on popular networks, you can find the URLs in the Safe Transaction Service API Reference.

Step 1: Configure your Safe multisig

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

Step 2: Use your safe config

When wiring, pass the --safe flag in your wire command.
This command initiates the wiring process under the multisig setup, pushing transactions to the specified multisig wallet for necessary approvals.
Ensure your development tools are up to date to utilize this feature, as it relies on the latest versions of the required dependencies.