> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/eco/eco-routes/llms.txt
> Use this file to discover all available pages before exploring further.

# LayerZero Integration

> LayerZeroProver implementation using V2 endpoints

LayerZeroProver integrates with LayerZero V2 endpoints to prove intent fulfillment across chains. It implements the `ILayerZeroReceiver` interface to receive cross-chain messages.

## Contract Overview

Location: `contracts/prover/LayerZeroProver.sol`

```solidity contracts/prover/LayerZeroProver.sol theme={null}
contract LayerZeroProver is ILayerZeroReceiver, MessageBridgeProver, Semver {
    string public constant PROOF_TYPE = "LayerZero";
    address public immutable ENDPOINT;
}
```

## Constructor

From `LayerZeroProver.sol:57-74`:

```solidity contracts/prover/LayerZeroProver.sol theme={null}
constructor(
    address endpoint,
    address delegate,
    address portal,
    bytes32[] memory provers,
    uint256 minGasLimit
) MessageBridgeProver(portal, provers, minGasLimit)
```

### Parameters

<ParamField path="endpoint" type="address">
  Address of the local LayerZero V2 endpoint contract
</ParamField>

<ParamField path="delegate" type="address">
  Address authorized to configure LayerZero settings (configs, paths, etc.)
</ParamField>

<ParamField path="portal" type="address">
  Address of the Portal contract that manages rewards
</ParamField>

<ParamField path="provers" type="bytes32[]">
  Array of trusted prover addresses on other chains (as bytes32 for cross-VM compatibility)
</ParamField>

<ParamField path="minGasLimit" type="uint256">
  Minimum gas limit for cross-chain messages. Defaults to 200,000 if zero.
</ParamField>

<Note>
  The constructor automatically sets the delegate on the LayerZero endpoint (line 73):

  ```solidity theme={null}
  ILayerZeroEndpointV2(endpoint).setDelegate(delegate);
  ```
</Note>

## Prove Function

Inherited from `MessageBridgeProver.sol:112-117`:

```solidity contracts/prover/MessageBridgeProver.sol theme={null}
function prove(
    address sender,
    uint64 domainID,
    bytes calldata encodedProofs,
    bytes calldata data
) external payable only(PORTAL);
```

<Warning>
  The `domainID` parameter uses **LayerZero Endpoint IDs (EIDs)**, which are NOT the same as chain IDs. Consult [LayerZero V2 documentation](https://docs.layerzero.network/v2) for endpoint ID mappings.
</Warning>

### Data Parameter Structure

The `data` parameter must be ABI-encoded as an `UnpackedData` struct (from `LayerZeroProver.sol:19-24`):

```solidity contracts/prover/LayerZeroProver.sol theme={null}
struct UnpackedData {
    bytes32 sourceChainProver; // Address of prover on source chain
    bytes options;             // LayerZero message options
    uint256 gasLimit;          // Gas limit for execution
}
```

**Encoding example:**

```solidity theme={null}
bytes memory data = abi.encode(
    UnpackedData({
        sourceChainProver: bytes32(uint256(uint160(sourceProverAddress))),
        options: "",  // Or custom LayerZero options
        gasLimit: 250000
    })
);
```

<Note>
  Gas limits below `MIN_GAS_LIMIT` (200,000) are automatically increased to the minimum (from `LayerZeroProver.sol:190-192`).
</Note>

## Message Dispatch

Internal dispatch implementation from `LayerZeroProver.sol:133-156`:

```solidity contracts/prover/LayerZeroProver.sol theme={null}
function _dispatchMessage(
    uint64 domainID,
    bytes calldata encodedProofs,
    bytes calldata data,
    uint256 fee
) internal override {
    UnpackedData memory unpacked = _unpackData(data);
    
    ILayerZeroEndpointV2.MessagingParams memory params = _formatLayerZeroMessage(
        domainID,
        encodedProofs,
        unpacked
    );
    
    ILayerZeroEndpointV2(ENDPOINT).send{value: fee}(
        params,
        msg.sender  // refund address
    );
}
```

### Message Formatting

From `LayerZeroProver.sol:239-267`:

```solidity contracts/prover/LayerZeroProver.sol theme={null}
function _formatLayerZeroMessage(
    uint64 domainID,
    bytes calldata encodedProofs,
    UnpackedData memory unpacked
) internal pure returns (ILayerZeroEndpointV2.MessagingParams memory params) {
    // Validate domain ID fits in uint32
    if (domainID > type(uint32).max) {
        revert DomainIdTooLarge(domainID);
    }
    params.dstEid = uint32(domainID);
    
    // Use source chain prover as recipient
    params.receiver = unpacked.sourceChainProver;
    params.message = encodedProofs;
    
    // Use provided options or create default with gas limit
    params.options = unpacked.options.length > 0
        ? unpacked.options
        : abi.encodePacked(
            uint16(3),              // option type for gas limit
            unpacked.gasLimit       // gas amount
        );
    params.payInLzToken = false;
}
```

## Message Reception

From `LayerZeroProver.sol:85-98`:

```solidity contracts/prover/LayerZeroProver.sol theme={null}
function lzReceive(
    Origin calldata origin,
    bytes32 /* guid */,
    bytes calldata message,
    address /* executor */,
    bytes calldata /* extraData */
) external payable override only(ENDPOINT) {
    if (origin.sender == bytes32(0)) {
        revert MessageSenderCannotBeZeroAddress();
    }
    
    _handleCrossChainMessage(origin.sender, message);
}
```

The `lzReceive()` function:

1. Validates call is from the LayerZero endpoint
2. Validates sender address is non-zero
3. Checks sender is whitelisted
4. Extracts chain ID from message prefix
5. Processes intent proofs

## Additional LayerZero Methods

### Allow Initialize Path

From `LayerZeroProver.sol:105-110`:

```solidity contracts/prover/LayerZeroProver.sol theme={null}
function allowInitializePath(
    Origin calldata origin
) external view override returns (bool) {
    return isWhitelisted(origin.sender);
}
```

Checks if a cross-chain path should be allowed based on sender whitelist.

### Next Nonce

From `LayerZeroProver.sol:117-123`:

```solidity contracts/prover/LayerZeroProver.sol theme={null}
function nextNonce(
    uint32 /* srcEid */,
    bytes32 /* sender */
) external pure override returns (uint64) {
    return 0;  // We don't track nonces
}
```

## Fee Calculation

From `LayerZeroProver.sol:166-176`:

```solidity contracts/prover/LayerZeroProver.sol theme={null}
function fetchFee(
    uint64 domainID,
    bytes calldata encodedProofs,
    bytes calldata data
) public view override returns (uint256) {
    UnpackedData memory unpacked = _unpackData(data);
    return _fetchFee(domainID, encodedProofs, unpacked);
}
```

Internal implementation (from `LayerZeroProver.sol:202-221`):

```solidity contracts/prover/LayerZeroProver.sol theme={null}
function _fetchFee(
    uint64 domainID,
    bytes calldata encodedProofs,
    UnpackedData memory unpacked
) internal view returns (uint256) {
    ILayerZeroEndpointV2.MessagingParams memory params = _formatLayerZeroMessage(
        domainID,
        encodedProofs,
        unpacked
    );
    
    ILayerZeroEndpointV2.MessagingFee memory fee = ILayerZeroEndpointV2(
        ENDPOINT
    ).quote(params, address(this));
    
    return fee.nativeFee;
}
```

## Usage Example

```solidity theme={null}
// On destination chain (e.g., Optimism)
address lzProver = 0x...;  // LayerZeroProver on Optimism
uint64 sourceEid = 30101;  // LayerZero EID for Ethereum

// Prepare proof data
bytes32[] memory intentHashes = new bytes32[](1);
intentHashes[0] = intentHash;

// Encode additional data
bytes memory data = abi.encode(
    ILayerZeroProver.UnpackedData({
        sourceChainProver: bytes32(uint256(uint160(ethereumProverAddress))),
        options: "",  // Use default options
        gasLimit: 250000
    })
);

// Calculate fee
uint256 fee = IProver(lzProver).fetchFee(
    sourceEid,
    encodedProofs,
    data
);

// Send proof (called by Inbox contract)
IProver(lzProver).prove{value: fee}(
    msg.sender,
    sourceEid,
    encodedProofs,
    data
);
```

## Endpoint ID Reference

<Warning>
  Always check [LayerZero's official endpoint ID registry](https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts) for accurate endpoint IDs. These are NOT chain IDs.
</Warning>

Common V2 endpoint IDs (verify before use):

| Chain    | Chain ID | LayerZero V2 EID |
| -------- | -------- | ---------------- |
| Ethereum | 1        | 30101            |
| Optimism | 10       | 30111            |
| Polygon  | 137      | 30109            |
| Arbitrum | 42161    | 30110            |
| Base     | 8453     | 30184            |

## Security Considerations

### Whitelist Validation

Only whitelisted prover addresses can send proof messages. This is validated in `_handleCrossChainMessage()` from `MessageBridgeProver.sol:81-82`:

```solidity contracts/prover/MessageBridgeProver.sol theme={null}
if (!isWhitelisted(messageSender)) {
    revert UnauthorizedIncomingProof(messageSender);
}
```

### Delegate Configuration

The delegate address has full control over LayerZero configurations. Set this carefully during deployment.

### Gas Limit Enforcement

The contract enforces a minimum gas limit (from `LayerZeroProver.sol:190-192`):

```solidity contracts/prover/LayerZeroProver.sol theme={null}
if (unpacked.gasLimit < MIN_GAS_LIMIT) {
    unpacked.gasLimit = MIN_GAS_LIMIT;
}
```

## Related Contracts

* [BaseProver](/bridges/overview#common-base-functionality) - Base proving functionality
* [MessageBridgeProver](/bridges/overview#common-prove-function) - Message bridge base contract
* [Inbox](/api/inbox) - Intent fulfillment and proving
