Skip to main content
Version: Endpoint V2

Adding Networks

When working with a LayerZero project, it searches for the closest hardhat.config.ts and layerzero.config.ts files starting from the Current Working Directory. This file normally lives in the root of your project.

This guide shows how to add a new EVM network to your existing LayerZero project.

Example scenario: You have an OFT deployed on Optimism Sepolia and Base Sepolia, and want to add Arbitrum Sepolia to your mesh.

Existing networks in your mesh:

  • Optimism Sepolia (EID: 40232)
  • Base Sepolia (EID: 40245)

Network being added:

  • Arbitrum Sepolia (EID: 40231)

You will:

  • Update hardhat.config.ts with the new network's LayerZero Endpoint ID (EID) and RPC
  • Deploy your contract to the new network
  • Update layerzero.config.ts to declare the contract and connections
  • Wire peers and apply configuration across pathways

1) Add the network to hardhat.config.ts

Add an entry with the LayerZero Endpoint ID, RPC URL, and your deployer accounts. Here's the diff showing what to add:

// hardhat.config.ts
import { EndpointId } from '@layerzerolabs/lz-definitions'

export default {
networks: {
// Existing networks
'optimism-sepolia': {
eid: EndpointId.OPTSEP_V2_TESTNET,
url: process.env.RPC_URL_OPT_SEPOLIA || 'https://optimism-sepolia.gateway.tenderly.co',
accounts,
},
'base-sepolia': {
eid: EndpointId.BASSEP_V2_TESTNET,
url: process.env.RPC_URL_BASE_SEPOLIA || 'https://sepolia.base.org',
accounts,
},

+ 'arbitrum-sepolia': {
+ eid: EndpointId.ARBSEP_V2_TESTNET,
+ url: process.env.RPC_URL_ARB_SEPOLIA || 'https://sepolia-rollup.arbitrum.io/rpc',
+ accounts,
+ },
},
}
info

The only notable change from a standard hardhat.config.ts setup is the inclusion of a LayerZero Endpoint ID.

For hardhat specific questions, refer to the Hardhat Configuration documentation.

tip

The npx package uses @layerzerolabs/lz-definitions to enable you to reference both V1 and V2 Endpoints. Make sure if your project uses LayerZero V2 to select the V2 Endpoint (i.e., eid: EXAMPLE_V2_MAINNET).

2) Deploy your contract to the new network

Use the CLI to deploy your contract to the added network. You can deploy interactively or target a specific network.

# Interactive (select networks and tags when prompted)
pnpm hardhat lz:deploy

# Or target a specific network (example name from step 1)
# pnpm hardhat deploy --network arbitrum-sepolia --tags MyOFT

3) Add the new contract and connections to layerzero.config.ts

Specify which contracts should be connected on a per pathway basis and set the security stack values:

// layerzero.config.ts
import {EndpointId} from '@layerzerolabs/lz-definitions';
import {ExecutorOptionType} from '@layerzerolabs/lz-v2-utilities';
import {TwoWayConfig, generateConnectionsConfig} from '@layerzerolabs/metadata-tools';
import {OAppEnforcedOption, OmniPointHardhat} from '@layerzerolabs/toolbox-hardhat';

+ const arbitrumSepoliaContract: OmniPointHardhat = {
+ eid: EndpointId.ARBSEP_V2_TESTNET,
+ contractName: 'MyOFT',
+ };

const optimismSepoliaContract: OmniPointHardhat = {
eid: EndpointId.OPTSEP_V2_TESTNET,
contractName: 'MyOFT',
};

const baseSepoliaContract: OmniPointHardhat = {
eid: EndpointId.BASSEP_V2_TESTNET,
contractName: 'MyOFT',
};

// For this example's simplicity, we will use the same enforced options values for sending to all chains
// For production, you should ensure `gas` is set to the correct value through profiling the gas usage of calling OApp._lzReceive(...) on the destination chain
// To learn more, read https://docs.layerzero.network/v2/concepts/applications/oapp-standard#execution-options-and-enforced-settings
const EVM_ENFORCED_OPTIONS: OAppEnforcedOption[] = [
{
msgType: 1,
optionType: ExecutorOptionType.LZ_RECEIVE,
gas: 80000,
value: 0,
},
];

// Add pathways to connect your new network with existing networks
+ const pathways: TwoWayConfig[] = [
+ [
+ arbitrumSepoliaContract, // New network contract
+ optimismSepoliaContract, // Existing network 1
+ [['LayerZero Labs'], []], // [ requiredDVN[], [ optionalDVN[], threshold ] ]
+ [15, 15], // [A to B confirmations, B to A confirmations]
+ [EVM_ENFORCED_OPTIONS, EVM_ENFORCED_OPTIONS], // Chain B enforcedOptions, Chain A enforcedOptions
+ ],
+ [
+ arbitrumSepoliaContract, // New network contract
+ baseSepoliaContract, // Existing network 2
+ [['LayerZero Labs'], []], // [ requiredDVN[], [ optionalDVN[], threshold ] ]
+ [15, 15], // [A to B confirmations, B to A confirmations]
+ [EVM_ENFORCED_OPTIONS, EVM_ENFORCED_OPTIONS], // Chain C enforcedOptions, Chain A enforcedOptions
+ ],
+ // ... existing pathways between your current networks
+ ];
export default async function () {
// Generate the connections config based on the pathways
const connections = await generateConnectionsConfig(pathways);
return {
contracts: [
+ {contract: arbitrumSepoliaContract},
{contract: optimismSepoliaContract},
{contract: baseSepoliaContract},
],
connections,
};
}

You can refer to defaults with the Defaults Checker.

4) Wire peers and apply configuration

Set peers, libraries, DVN/Executor settings, and enforced options per your layerzero.config.ts.

When delegate and owner are your local EOA (not recommended):

pnpm hardhat lz:oapp:wire --oapp-config layerzero.config.ts

When delegate and owner are Multisigs:

pnpm hardhat lz:oapp:wire --oapp-config layerzero.config.ts --output-filename wiring-txns.json
  • --output-filename will generate a JSON file with the list of transactions rather than submitting the transactions for execution directly
  • When asked to preview txns, you can choose Y or just terminate the process immediately, as at this point, the JSON file would have already been generated. If asked "Would you like to submit the required transactions?", respond with N to terminate the process.
  • View the generated JSON at wiring-txns.json to view the txns data that need execution
  • Import them into your Multisig for execution

5) Verify connections and configuration

# Check peers
pnpm hardhat lz:oapp:peers:get --oapp-config layerzero.config.ts

# Check pathway config
pnpm hardhat lz:oapp:config:get --oapp-config layerzero.config.ts

Checking Pathway Configurations

To check your OApp's current configuration, you can run:

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

This command will output a table with 3 columns:

  1. Custom OApp Config: your layerzero.config.ts configuration changes, with null values for unchanged parameters.

  2. Default OApp Config: the default LayerZero configuration for the pathway.

  3. Active OApp Config: the combination of your customized and default parameters, i.e., the active configuration.

┌────────────────────┬─────────────────────────────────────────────────────────────────┬───────────────────────────────────────────────────────────────────────────────┬───────────────────────────────────────────────────────────────────────────────┐
│ │ Custom OApp Config │ Default OApp Config │ Active OApp Config │
├────────────────────┼─────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ localNetworkName │ bsc_testnet │ bsc_testnet │ bsc_testnet │
├────────────────────┼─────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ remoteNetworkName │ sepolia │ sepolia │ sepolia │
├────────────────────┼─────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ sendLibrary │ 0x0000000000000000000000000000000000000000 │ 0x55f16c442907e86D764AFdc2a07C2de3BdAc8BB7 │ 0x55f16c442907e86D764AFdc2a07C2de3BdAc8BB7 │
├────────────────────┼─────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ receiveLibrary │ 0x0000000000000000000000000000000000000000 │ 0x188d4bbCeD671A7aA2b5055937F79510A32e9683 │ 0x188d4bbCeD671A7aA2b5055937F79510A32e9683 │
├────────────────────┼─────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ sendUlnConfig │ ┌──────────────────────┬───┐ │ ┌──────────────────────┬────────────────────────────────────────────────────┐ │ ┌──────────────────────┬────────────────────────────────────────────────────┐ │
│ │ │ confirmations │ 0 │ │ │ confirmations │ 5 │ │ │ confirmations │ 5 │ │
│ │ ├──────────────────────┼───┤ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │
│ │ │ requiredDVNs │ │ │ │ requiredDVNs │ ┌───┬────────────────────────────────────────────┐ │ │ │ requiredDVNs │ ┌───┬────────────────────────────────────────────┐ │ │
│ │ ├──────────────────────┼───┤ │ │ │ │ 0 │ 0x0eE552262f7B562eFcED6DD4A7e2878AB897d405 │ │ │ │ │ │ 0 │ 0x0eE552262f7B562eFcED6DD4A7e2878AB897d405 │ │ │
│ │ │ optionalDVNs │ │ │ │ │ └───┴────────────────────────────────────────────┘ │ │ │ │ └───┴────────────────────────────────────────────┘ │ │
│ │ ├──────────────────────┼───┤ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │
│ │ │ optionalDVNThreshold │ 0 │ │ │ optionalDVNs │ │ │ │ optionalDVNs │ │ │
│ │ └──────────────────────┴───┘ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │
│ │ │ │ optionalDVNThreshold │ 0 │ │ │ optionalDVNThreshold │ 0 │ │
│ │ │ └──────────────────────┴────────────────────────────────────────────────────┘ │ └──────────────────────┴────────────────────────────────────────────────────┘ │
├────────────────────┼─────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ sendExecutorConfig │ ┌────────────────┬────────────────────────────────────────────┐ │ ┌────────────────┬────────────────────────────────────────────┐ │ ┌────────────────┬────────────────────────────────────────────┐ │
│ │ │ executor │ 0x0000000000000000000000000000000000000000 │ │ │ executor │ 0x31894b190a8bAbd9A067Ce59fde0BfCFD2B18470 │ │ │ executor │ 0x31894b190a8bAbd9A067Ce59fde0BfCFD2B18470 │ │
│ │ ├────────────────┼────────────────────────────────────────────┤ │ ├────────────────┼────────────────────────────────────────────┤ │ ├────────────────┼────────────────────────────────────────────┤ │
│ │ │ maxMessageSize │ 0 │ │ │ maxMessageSize │ 10000 │ │ │ maxMessageSize │ 10000 │ │
│ │ └────────────────┴────────────────────────────────────────────┘ │ └────────────────┴────────────────────────────────────────────────────┘ │ └────────────────┴────────────────────────────────────────────────────┘ │
├────────────────────┼─────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ receiveUlnConfig │ ┌──────────────────────┬───┐ │ ┌──────────────────────┬────────────────────────────────────────────────────┐ │ ┌──────────────────────┬────────────────────────────────────────────────────┐ │
│ │ │ confirmations │ 0 │ │ │ confirmations │ 2 │ │ │ confirmations │ 2 │ │
│ │ ├──────────────────────┼───┤ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │
│ │ │ requiredDVNs │ │ │ │ requiredDVNs │ ┌───┬────────────────────────────────────────────┐ │ │ │ requiredDVNs │ ┌───┬────────────────────────────────────────────┐ │ │
│ │ ├──────────────────────┼───┤ │ │ │ │ 0 │ 0x0eE552262f7B562eFcED6DD4A7e2878AB897d405 │ │ │ │ │ │ 0 │ 0x0eE552262f7B562eFcED6DD4A7e2878AB897d405 │ │ │
│ │ │ optionalDVNs │ │ │ │ │ └───┴────────────────────────────────────────────┘ │ │ │ │ └───┴────────────────────────────────────────────┘ │ │
│ │ ├──────────────────────┼───┤ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │
│ │ │ optionalDVNThreshold │ 0 │ │ │ optionalDVNs │ │ │ │ optionalDVNs │ │ │
│ │ └──────────────────────┴───┘ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │ ├──────────────────────┼────────────────────────────────────────────────────┤ │
│ │ │ │ optionalDVNThreshold │ 0 │ │ │ optionalDVNThreshold │ 0 │ │
│ │ │ └──────────────────────┴────────────────────────────────────────────────────┘ │ └──────────────────────┴────────────────────────────────────────────────────┘ │
└────────────────────┴─────────────────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────┘

Specifying Pathway Configurations

For more specific configurations on a per pathway basis, review the Configuring Pathways page.