> ## Documentation Index
> Fetch the complete documentation index at: https://docs.layerzero.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate to Simple Config

> Use Migrate to Simple Config with LayerZero V2. Developer tools for building and debugging omnichain applications. LayerZero enables crosschain messaging.

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.

<Note>
  **Current Support**: The Simple Config Generator currently supports EVM chains and Solana. Aptos support is not yet available.
</Note>

<Warning>
  **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](/v2/deployments/dvn-addresses) before wiring. See the [Integration Checklist](/v2/tools/integration-checklist#set-security-and-executor-configurations-on-every-pathway) for production DVN guidance.
</Warning>

## 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
* **Streamlined defaults**: Sensible structure for DVN and executor configuration that you must review and override per pathway (see Warning below)
* **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:

1. Define each connection direction separately
2. Manually specify send and receive libraries
3. Configure ULN settings for each direction
4. Set up executor configurations
5. Define enforced options for each pathway
6. Handle VM-specific configurations separately

Here's an example of manual configuration for EVM chains:

```typescript wrap theme={null}
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:

```typescript wrap theme={null}
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', '<SECONDARY_DVN>'], []], // [ 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

```bash wrap theme={null}
pnpm add -D @layerzerolabs/metadata-tools
```

### 2. Update Your Configuration File

<Tabs>
  <Tab title="EVM Chains Only">
    Replace your manual `layerzero.config.ts` with the Simple Config approach:

    ```typescript wrap theme={null}
    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', '<SECONDARY_DVN>'], []], // [ 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,
      };
    }
    ```
  </Tab>

  <Tab title="EVM + Solana">
    For EVM + Solana configurations:

    ```typescript wrap theme={null}
    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', '<SECONDARY_DVN>'], []], // [ 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,
      };
    }
    ```
  </Tab>
</Tabs>

### 3. Update Your Deployment Scripts

Replace your manual wire commands with the Simple Config approach:

<CodeGroup>
  ```bash wrap EVM Only theme={null}
  npx hardhat lz:oapp:wire --oapp-config layerzero.config.ts
  ```

  ```bash wrap EVM + Solana theme={null}
  # 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
  ```
</CodeGroup>

## 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

<Note>
  **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.
</Note>

### Pathway Definition

```typescript wrap theme={null}
[
  contractA, // Source chain contract
  contractB, // Destination chain contract
  [['LayerZero Labs', '<SECONDARY_DVN>'], []], // DVN configuration
  [15, 20], // Confirmations for each direction
  [optionsA, optionsB], // Enforced options for each direction
];
```

### DVN Configuration

```typescript wrap theme={null}
[['LayerZero Labs', '<SECONDARY_DVN>'], []]; // [ 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

```typescript wrap theme={null}
[15, 20]; // [A to B confirmations, B to A confirmations]
```

The number of block confirmations to wait before considering a message verified.

### Enforced Options

```typescript wrap theme={null}
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)

<Note>
  **Aptos Support**: Aptos is not yet supported by the Simple Config Generator. Use manual configuration for Aptos integrations.
</Note>

## 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

1. **Missing Dependencies**: Ensure `@layerzerolabs/metadata-tools` is installed
2. **Incorrect EndpointId**: Verify you are using the correct Endpoint ID (if using Endpoint V2, the constant name should include `V2`)
3. **VM-Specific Requirements**: Remember to specify `address` for Solana contracts and `value` for enforced options `msgType` 1 when sending to Solana.
4. **Gas Estimation**: Profile your contracts to set appropriate gas limits

### Getting Help

If you encounter issues during migration:

1. Check the [Simple Config documentation](/v2/tools/simple-config)
2. Review the [examples in devtools](https://github.com/LayerZero-Labs/devtools/tree/main/examples)
3. 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.
