Migrate to Simple Config
The LayerZero Simple Config Generator provides a streamlined approach to configuring your OApp connections across supported VMs (EVM, Solana, etc.). This guide will help you migrate from manual configuration to the Simple Config approach.
Current Support: The Simple Config Generator currently supports EVM chains and Solana. Aptos support is not yet available.
Why Migrate to Simple Config?
The Simple Config Generator offers several advantages over manual configuration:
- Reduced complexity: Fewer configuration parameters to manage
- Automatic bidirectional connections: Define one pathway, get both directions
- Built-in best practices: Uses recommended DVN and executor configurations
- Cross-VM compatibility: Works seamlessly with EVM chains, Solana, and other supported VMs
- Less error-prone: Automated configuration generation reduces manual errors
- VM-agnostic: Same configuration approach works across different virtual machines
Before Migration: Manual Configuration
In the traditional manual approach, you would need to:
- Define each connection direction separately
- Manually specify send and receive libraries
- Configure ULN settings for each direction
- Set up executor configurations
- Define enforced options for each pathway
- Handle VM-specific configurations separately
Here's an example of manual configuration for EVM chains:
connections: [
// ETH <--> ARB PATHWAY: START
{
from: ethereumContract,
to: arbitrumContract,
},
{
from: arbitrumContract,
to: ethereumContract,
},
// ETH <--> ARB PATHWAY: END
];
// Then define config settings for each direction
connections: [
{
from: ethereumContract,
to: arbitrumContract,
config: {
sendLibrary: contractsConfig.ethereum.sendLib302,
receiveLibraryConfig: {
receiveLibrary: contractsConfig.ethereum.receiveLib302,
gracePeriod: BigInt(0),
},
sendConfig: {
executorConfig: {
maxMessageSize: 10000,
executor: contractsConfig.ethereum.executor,
},
ulnConfig: {
confirmations: BigInt(15),
requiredDVNs: [
contractsConfig.ethereum.horizenDVN,
contractsConfig.ethereum.polyhedraDVN,
contractsConfig.ethereum.lzDVN,
],
optionalDVNs: [],
optionalDVNThreshold: 0,
},
},
receiveConfig: {
ulnConfig: {
confirmations: BigInt(20),
requiredDVNs: [
contractsConfig.ethereum.lzDVN,
contractsConfig.ethereum.horizenDVN,
contractsConfig.ethereum.polyhedraDVN,
],
optionalDVNs: [],
optionalDVNThreshold: 0,
},
},
enforcedOptions: [
{
msgType: 1,
optionType: ExecutorOptionType.LZ_RECEIVE,
gas: 65000,
value: 0,
},
{
msgType: 2,
optionType: ExecutorOptionType.LZ_RECEIVE,
gas: 65000,
value: 0,
},
{
msgType: 2,
optionType: ExecutorOptionType.COMPOSE,
index: 0,
gas: 50000,
value: 0,
},
],
},
},
// Repeat for the reverse direction...
];
After Migration: Simple Config
With the Simple Config Generator, the same configuration becomes much simpler and works across all VMs:
import {ExecutorOptionType} from '@layerzerolabs/lz-v2-utilities';
import {OAppEnforcedOption, OmniPointHardhat} from '@layerzerolabs/toolbox-hardhat';
import {EndpointId} from '@layerzerolabs/lz-definitions';
import {generateConnectionsConfig} from '@layerzerolabs/metadata-tools';
const ethereumContract: OmniPointHardhat = {
eid: EndpointId.ETHEREUM_V2_MAINNET,
contractName: 'MyOFT',
};
const arbitrumContract: OmniPointHardhat = {
eid: EndpointId.ARBITRUM_V2_MAINNET,
contractName: 'MyOFT',
};
const EVM_ENFORCED_OPTIONS: OAppEnforcedOption[] = [
{
msgType: 1,
optionType: ExecutorOptionType.LZ_RECEIVE,
gas: 65000,
value: 0,
},
];
export default async function () {
const connections = await generateConnectionsConfig([
[
ethereumContract, // Chain A contract
arbitrumContract, // Chain B contract
[['LayerZero Labs'], []], // [ requiredDVN[], [ optionalDVN[], threshold ] ]
[15, 20], // [A to B confirmations, B to A confirmations]
[EVM_ENFORCED_OPTIONS, EVM_ENFORCED_OPTIONS], // Chain A enforcedOptions, Chain B enforcedOptions
],
]);
return {
contracts: [{contract: ethereumContract}, {contract: arbitrumContract}],
connections,
};
}
Migration Steps
1. Install Required Dependencies
pnpm add -D @layerzerolabs/metadata-tools
2. Update Your Configuration File
- EVM Chains Only
- EVM + Solana
Replace your manual layerzero.config.ts
with the Simple Config approach:
import {ExecutorOptionType} from '@layerzerolabs/lz-v2-utilities';
import {OAppEnforcedOption, OmniPointHardhat} from '@layerzerolabs/toolbox-hardhat';
import {EndpointId} from '@layerzerolabs/lz-definitions';
import {generateConnectionsConfig} from '@layerzerolabs/metadata-tools';
// Define your contracts
const contractA: OmniPointHardhat = {
eid: EndpointId.CHAIN_A_ENDPOINT_ID,
contractName: 'YourContract',
};
const contractB: OmniPointHardhat = {
eid: EndpointId.CHAIN_B_ENDPOINT_ID,
contractName: 'YourContract',
};
// Define enforced options (gas settings for destination chain execution)
const EVM_ENFORCED_OPTIONS: OAppEnforcedOption[] = [
{
msgType: 1,
optionType: ExecutorOptionType.LZ_RECEIVE,
gas: 80000,
value: 0,
},
];
export default async function () {
const connections = await generateConnectionsConfig([
[
contractA, // Chain A contract
contractB, // Chain B contract
[['LayerZero Labs'], []], // [ requiredDVN[], [ optionalDVN[], threshold ] ]
[1, 1], // [A to B confirmations, B to A confirmations]
[EVM_ENFORCED_OPTIONS, EVM_ENFORCED_OPTIONS], // Chain A enforcedOptions, Chain B enforcedOptions
],
]);
return {
contracts: [{contract: contractA}, {contract: contractB}],
connections,
};
}
For EVM + Solana configurations:
import {ExecutorOptionType} from '@layerzerolabs/lz-v2-utilities';
import {OAppEnforcedOption, OmniPointHardhat} from '@layerzerolabs/toolbox-hardhat';
import {EndpointId} from '@layerzerolabs/lz-definitions';
import {generateConnectionsConfig} from '@layerzerolabs/metadata-tools';
const evmContract: OmniPointHardhat = {
eid: EndpointId.ETHEREUM_V2_MAINNET,
contractName: 'MyOFT',
};
const solanaContract: OmniPointHardhat = {
eid: EndpointId.SOLANA_V2_MAINNET,
address: 'YourSolanaAddress', // Required for Solana contracts
};
const EVM_ENFORCED_OPTIONS: OAppEnforcedOption[] = [
{
msgType: 1,
optionType: ExecutorOptionType.LZ_RECEIVE,
gas: 80000,
value: 0,
},
];
const SOLANA_ENFORCED_OPTIONS: OAppEnforcedOption[] = [
{
msgType: 1,
optionType: ExecutorOptionType.LZ_RECEIVE,
gas: 200000,
value: 2039280, // SPL token account rent value in lamports
},
];
export default async function () {
const connections = await generateConnectionsConfig([
[
evmContract, // EVM contract
solanaContract, // Solana contract
[['LayerZero Labs'], []], // [ requiredDVN[], [ optionalDVN[], threshold ] ]
[1, 1], // [EVM to Solana confirmations, Solana to EVM confirmations]
[SOLANA_ENFORCED_OPTIONS, EVM_ENFORCED_OPTIONS], // Solana enforcedOptions, EVM enforcedOptions
],
]);
return {
contracts: [{contract: evmContract}, {contract: solanaContract}],
connections,
};
}
3. Update Your Deployment Scripts
Replace your manual wire commands with the Simple Config approach:
- EVM Only
- EVM + Solana
npx hardhat lz:oapp:wire --oapp-config layerzero.config.ts
# Initialize Solana config (first time only)
npx hardhat lz:oft:solana:init-config --oapp-config layerzero.config.ts
# Wire all connections
npx hardhat lz:oapp:wire --oapp-config layerzero.config.ts
Key Differences
Aspect | Manual Config | Simple Config |
---|---|---|
Connection Definition | Define each direction separately | Define once, get bidirectional |
DVN Configuration | Manual specification | Automated with metadata |
Executor Setup | Manual configuration | Automated with metadata |
Library Selection | Manual specification | Automated with metadata |
VM-Specific Handling | Separate configs per VM | Unified approach |
Configuration Length | 100+ lines per pathway | ~20 lines per pathway |
Error Prone | High (manual configuration) | Low (automated generation) |
Configuration Parameters Explained
Custom Metadata: For advanced use cases, you can provide custom metadata by passing a fetchMetadata
function to generateConnectionsConfig
. This allows you to extend the default metadata with custom DVNs and executors.
Pathway Definition
[
contractA, // Source chain contract
contractB, // Destination chain contract
[['LayerZero Labs'], []], // DVN configuration
[15, 20], // Confirmations for each direction
[optionsA, optionsB], // Enforced options for each direction
];
DVN Configuration
[['LayerZero Labs'], []]; // [ requiredDVN[], [ optionalDVN[], threshold ] ]
- Required DVNs: Must verify the message for it to be considered valid
- Optional DVNs: Additional verifiers (with threshold) for enhanced security
Confirmations
[15, 20]; // [A to B confirmations, B to A confirmations]
The number of block confirmations to wait before considering a message verified.
Enforced Options
const EVM_ENFORCED_OPTIONS: OAppEnforcedOption[] = [
{
msgType: 1, // Message type (1 = OFT, 2 = OApp)
optionType: ExecutorOptionType.LZ_RECEIVE, // Option type
gas: 80000, // Gas limit for destination execution
value: 0, // Value to send (usually 0)
},
];
VM-Specific Considerations
EVM Chains
- Use
contractName
for contract identification - Gas values represent actual gas units
- Value is typically 0
Solana
- Use
address
for contract identification (required) - Gas values represent compute units
- Value represents lamports (typically 2039280 for SPL token account rent)
Aptos Support: Aptos is not yet supported by the Simple Config Generator. Use manual configuration for Aptos integrations.
Migration Checklist
- Install
@layerzerolabs/metadata-tools
- Update
layerzero.config.ts
to use Simple Config format - Define your contract objects with correct EIDs
- Configure enforced options for your use case
- Set appropriate DVN requirements
- Handle VM-specific requirements (
address
for Solana contract objects) - Test by running
npx hardhat lz:oapp:wire --oapp-config layerzero.config.ts
(if there were no config changes, there should be no transactions to be submitted)
Troubleshooting
Common Issues
- Missing Dependencies: Ensure
@layerzerolabs/metadata-tools
is installed - Incorrect EndpointId: Verify you are using the correct Endpoint ID (if using Endpoint V2, the constant name should include
V2
) - VM-Specific Requirements: Remember to specify
address
for Solana contracts andvalue
for enforced optionsmsgType
1 when sending to Solana. - Gas Estimation: Profile your contracts to set appropriate gas limits
Getting Help
If you encounter issues during migration:
- Check the Simple Config documentation
- Review the examples in devtools
- Consult VM-specific documentation.
The Simple Config Generator significantly reduces the complexity of LayerZero configuration while maintaining the same functionality and security guarantees as manual configuration.