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

# Design Patterns & Extensions

> Each design pattern functions as a distinct omnichain building block, capable of being used independently or in conjunction with. LayerZero enables secure...

Each design pattern functions as a distinct omnichain building block, capable of being used independently or in conjunction with others.

| Message Pattern                       | Description                                                                                                                             |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| [ABA](#aba)                           | a nested send call from Chain A to Chain B that sends back again to the source chain (`A` -> `B` -> `A`)                                |
| [Batch Send](#batch-send)             | a single send that calls multiple destination chains                                                                                    |
| [Composed](#composed)                 | a message that transfers from a source to destination chain and calls an external contract (`A` -> `B1` -> `B2`)                        |
| [Composed ABA](#composed-aba)         | transfers data from a source to destination, calls an external contract, and then calls back to the source (`A` -> `B1` -> `B2` -> `A`) |
| [Message Ordering](#message-ordering) | enforce the ordered delivery of messages on execution post verification                                                                 |
| [Rate Limit](#rate-limiting)          | rate limit the number of `send` calls for a given amount of `messages` or `tokens` transferred                                          |

<br />

This modularity allows for the seamless integration and combination of patterns to suit specific developer requirements.

## ABA

**AB** messaging refers to a one way send call from a source to destination blockchain.

<img src="https://mintcdn.com/layerzero/MzSiOdXt8xlDlEr4/images/learn/ABLight.svg?fit=max&auto=format&n=MzSiOdXt8xlDlEr4&q=85&s=26159ac201830230d42dbab6e67168a9" alt="Diagram showing simple AB messaging pattern: a one-way send call from source chain A to destination chain B via LayerZero" className="block dark:hidden" width="1920" height="517" data-path="images/learn/ABLight.svg" />

<img src="https://mintcdn.com/layerzero/MzSiOdXt8xlDlEr4/images/learn/ABDark.svg?fit=max&auto=format&n=MzSiOdXt8xlDlEr4&q=85&s=57ee89cb8ac22fcdd3d6ba916d27f750" alt="Diagram showing simple AB messaging pattern: a one-way send call from source chain A to destination chain B via LayerZero" className="hidden dark:block" width="1920" height="517" data-path="images/learn/ABDark.svg" />

In the [Getting Started Guide](../getting-started), we use this design pattern to send a string from Chain A to store on Chain B (`A` -> `B`).

The **ABA** message pattern extends this simple logic by nesting another `_lzSend` call within the destination contract's `_lzReceive` function. You can think of this as a ping-pong style call, pinging a destination chain and ponging back to the original source (`A` -> `B` -> `A`).

<img src="https://mintcdn.com/layerzero/MzSiOdXt8xlDlEr4/images/learn/ABAlight.svg?fit=max&auto=format&n=MzSiOdXt8xlDlEr4&q=85&s=fa52c0d952ad24d9efa642bee4da991c" alt="Diagram showing ABA messaging pattern: a ping-pong style call where Chain A sends to Chain B, which then sends back to Chain A (A → B → A)" className="block dark:hidden" width="1920" height="517" data-path="images/learn/ABAlight.svg" />

<img src="https://mintcdn.com/layerzero/MzSiOdXt8xlDlEr4/images/learn/ABAdark.svg?fit=max&auto=format&n=MzSiOdXt8xlDlEr4&q=85&s=2fa451ae74341533b88351949651fce8" alt="Diagram showing ABA messaging pattern: a ping-pong style call where Chain A sends to Chain B, which then sends back to Chain A (A → B → A)" className="hidden dark:block" width="1920" height="517" data-path="images/learn/ABAdark.svg" />

<br />

This is particularly useful when actions on one blockchain depend on the state or confirmation of another, such as:

* **Conditional Execution of Contracts**: A smart contract on chain A will only execute a function if a condition on chain B is met. It sends a message to chain B to check the condition and then receives a confirmation back before proceeding.

* **Omnichain Data Feeds**: A contract on Chain A can fetch data from the destination (Chain B) to complete a process back on the source.

* **Crosschain Authentication**: A user or contract might authenticate on chain A, ping chain B to process something that requires this authentication, and then receive back a token or confirmation that the process was successful.

### Code Example

This pattern demonstrates **vertical composability**, where the nested message contains both handling for the message receipt, as well as additional logic for a subsequent call that must all happen within one atomic transaction.

```solidity wrap theme={null}
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

import { OApp, MessagingFee, Origin } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
import { OAppOptionsType3 } from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OAppOptionsType3.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title ABA contract for demonstrating LayerZero messaging between blockchains.
 * @notice THIS IS AN EXAMPLE CONTRACT. DO NOT USE THIS CODE IN PRODUCTION.
 * @dev This contract showcases a PingPong style call (A -> B -> A) using LayerZero's OApp Standard.
 */
contract ABA is OApp, OAppOptionsType3 {

    /// @notice Last received message data.
    string public data = "Nothing received yet";

    /// @notice Message types that are used to identify the various OApp operations.
    /// @dev These values are used in things like combineOptions() in OAppOptionsType3.
    uint16 public constant SEND = 1;
    uint16 public constant SEND_ABA = 2;

    /// @notice Emitted when a return message is successfully sent (B -> A).
    event ReturnMessageSent(string message, uint32 dstEid);

    /// @notice Emitted when a message is received from another chain.
    event MessageReceived(string message, uint32 senderEid, bytes32 sender);

     /// @notice Emitted when a message is sent to another chain (A -> B).
    event MessageSent(string message, uint32 dstEid);

    /// @dev Revert with this error when an invalid message type is used.
    error InvalidMsgType();

    /**
     * @dev Constructs a new PingPong contract instance.
     * @param _endpoint The LayerZero endpoint for this contract to interact with.
     * @param _owner The owner address that will be set as the owner of the contract.
     */
    constructor(address _endpoint, address _owner) OApp(_endpoint, _owner) Ownable(msg.sender) {}

    function encodeMessage(string memory _message, uint16 _msgType, bytes memory _extraReturnOptions) public pure returns (bytes memory) {
        // Get the length of _extraReturnOptions
        uint256 extraOptionsLength = _extraReturnOptions.length;

        // Encode the entire message, prepend and append the length of extraReturnOptions
        return abi.encode(_message, _msgType, extraOptionsLength, _extraReturnOptions, extraOptionsLength);
    }

    /**
     * @notice Returns the estimated messaging fee for a given message.
     * @param _dstEid Destination endpoint ID where the message will be sent.
     * @param _msgType The type of message being sent.
     * @param _message The message content.
     * @param _extraSendOptions Gas options for receiving the send call (A -> B).
     * @param _extraReturnOptions Additional gas options for the return call (B -> A).
     * @param _payInLzToken Boolean flag indicating whether to pay in LZ token.
     * @return fee The estimated messaging fee.
     */
    function quote(
        uint32 _dstEid,
        uint16 _msgType,
        string memory _message,
        bytes calldata _extraSendOptions,
        bytes calldata _extraReturnOptions,
        bool _payInLzToken
    ) public view returns (MessagingFee memory fee) {
        bytes memory payload = encodeMessage(_message, _msgType, _extraReturnOptions);
        bytes memory options = combineOptions(_dstEid, _msgType, _extraSendOptions);
        fee = _quote(_dstEid, payload, options, _payInLzToken);
    }


    /**
     * @notice Sends a message to a specified destination chain.
     * @param _dstEid Destination endpoint ID for the message.
     * @param _msgType The type of message to send.
     * @param _message The message content.
     * @param _extraSendOptions Options for sending the message, such as gas settings.
     * @param _extraReturnOptions Additional options for the return message.
     */
    function send(
        uint32 _dstEid,
        uint16 _msgType,
        string memory _message,
        bytes calldata _extraSendOptions, // gas settings for A -> B
        bytes calldata _extraReturnOptions // gas settings for B -> A
    ) external payable {
        // Encodes the message before invoking _lzSend.
        require(bytes(_message).length <= 32, "String exceeds 32 bytes");

        if (_msgType != SEND && _msgType != SEND_ABA) {
            revert InvalidMsgType();
        }

        bytes memory options = combineOptions(_dstEid, _msgType, _extraSendOptions);

        _lzSend(
            _dstEid,
            encodeMessage(_message, _msgType, _extraReturnOptions),
            options,
            // Fee in native gas and ZRO token.
            MessagingFee(msg.value, 0),
            // Refund address in case of failed source message.
            payable(msg.sender)
        );

        emit MessageSent(_message, _dstEid);
    }

    function decodeMessage(bytes calldata encodedMessage) public pure returns (string memory message, uint16 msgType, uint256 extraOptionsStart, uint256 extraOptionsLength) {
        extraOptionsStart = 256;  // Starting offset after _message, _msgType, and extraOptionsLength
        string memory _message;
        uint16 _msgType;

        // Decode the first part of the message
        (_message, _msgType, extraOptionsLength) = abi.decode(encodedMessage, (string, uint16, uint256));

        return (_message, _msgType, extraOptionsStart, extraOptionsLength);
    }

    /**
     * @notice Internal function to handle receiving messages from another chain.
     * @dev Decodes and processes the received message based on its type.
     * @param _origin Data about the origin of the received message.
     * @param message The received message content.
     */
    function _lzReceive(
        Origin calldata _origin,
        bytes32 /*guid*/,
        bytes calldata message,
        address,  // Executor address as specified by the OApp.
        bytes calldata  // Any extra data or options to trigger on receipt.
    ) internal override {

        (string memory _data, uint16 _msgType, uint256 extraOptionsStart, uint256 extraOptionsLength) = decodeMessage(message);
        data = _data;

        if (_msgType == SEND_ABA) {

            string memory _newMessage = "Chain B says goodbye!";

            bytes memory _options = combineOptions(_origin.srcEid, SEND, message[extraOptionsStart:extraOptionsStart + extraOptionsLength]);

            _lzSend(
                _origin.srcEid,
                abi.encode(_newMessage, SEND),
                // Future additions should make the data types static so that it is easier to find the array locations.
                _options,
                // Fee in native gas and ZRO token.
                MessagingFee(msg.value, 0),
                // Refund address in case of failed send call.
                // @dev Since the Executor makes the return call, this contract is the refund address.
                payable(address(this))
            );

            emit ReturnMessageSent(_newMessage, _origin.srcEid);
        }

        emit MessageReceived(data, _origin.srcEid, _origin.sender);
    }


    receive() external payable {}

}
```

<Info>
  This message pattern can also be considered an ABC type call (`A` -> `B` -> `C`), as the nested `_lzSend` can send to any new destination chain.
</Info>

## Batch Send

The **Batch Send** design pattern, where a single transaction can initiate multiple `_lzSend` calls to various destination chains, is highly efficient for operations that need to propagate an action across several blockchains simultaneously.

<img src="https://mintcdn.com/layerzero/MzSiOdXt8xlDlEr4/images/learn/BatchSendLight.svg?fit=max&auto=format&n=MzSiOdXt8xlDlEr4&q=85&s=57095138f498ea83fc8f8614a846b8b3" alt="Diagram showing Batch Send pattern: a single transaction from Chain A initiating multiple _lzSend calls to Chains B, C, and D simultaneously" className="block dark:hidden" width="1920" height="517" data-path="images/learn/BatchSendLight.svg" />

<img src="https://mintcdn.com/layerzero/MzSiOdXt8xlDlEr4/images/learn/BatchSendDark.svg?fit=max&auto=format&n=MzSiOdXt8xlDlEr4&q=85&s=b220135c00ff58f4e29a34bc64e1f1c0" alt="Diagram showing Batch Send pattern: a single transaction from Chain A initiating multiple _lzSend calls to Chains B, C, and D simultaneously" className="hidden dark:block" width="1920" height="517" data-path="images/learn/BatchSendDark.svg" />

This can significantly reduce the operational overhead associated with performing the same action multiple times on different blockchains. It streamlines omnichain interactions by bundling them into a single transaction, making processes more efficient and easier to manage for example:

* **Simultaneous Omnichain Updates**: When a system needs to update the same information across multiple chains (such as a change in governance parameters or updating oracle data), Batch Send can propagate the updates in one go.

* **DeFi Strategies**: For DeFi protocols that operate on multiple chains, rebalancing liquidity pools or executing yield farming strategies can be done in batch to maintain parity across ecosystems.

* **Aggregated Omnichain Data Posting**: Oracles or data providers that supply information to smart contracts on multiple chains can use Batch Send to post data such as price feeds, event outcomes, or other updates in a single transaction.

### Code Example

```solidity wrap theme={null}
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

import { OApp, MessagingFee, Origin } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
import { OAppOptionsType3 } from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OAppOptionsType3.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title BatchSend contract for demonstrating multiple outbound crosschain calls using LayerZero.
 * @notice THIS IS AN EXAMPLE CONTRACT. DO NOT USE THIS CODE IN PRODUCTION.
 * @dev This contract showcases how to send multiple crosschain calls with one source function call using LayerZero's OApp Standard.
 */
contract BatchSend is OApp, OAppOptionsType3 {
    /// @notice Last received message data.
    string public data = "Nothing received yet";

    /// @notice Message types that are used to identify the various OApp operations.
    /// @dev These values are used in things like combineOptions() in OAppOptionsType3 (enforcedOptions).
    uint16 public constant SEND = 1;

    /// @notice Emitted when a message is received from another chain.
    event MessageReceived(string message, uint32 senderEid, bytes32 sender);

    /// @notice Emitted when a message is sent to another chain (A -> B).
    event MessageSent(string message, uint32 dstEid);

    /// @dev Revert with this error when an invalid message type is used.
    error InvalidMsgType();

    /**
     * @dev Constructs a new BatchSend contract instance.
     * @param _endpoint The LayerZero endpoint for this contract to interact with.
     * @param _owner The owner address that will be set as the owner of the contract.
     */
    constructor(address _endpoint, address _owner) OApp(_endpoint, _owner) Ownable(msg.sender) {}

    function _payNative(uint256 _nativeFee) internal override returns (uint256 nativeFee) {
        if (msg.value < _nativeFee) revert NotEnoughNative(msg.value);
        return _nativeFee;
    }

    /**
     * @notice Returns the estimated messaging fee for a given message.
     * @param _dstEids Destination endpoint ID array where the message will be batch sent.
     * @param _msgType The type of message being sent.
     * @param _message The message content.
     * @param _extraSendOptions Extra gas options for receiving the send call (A -> B).
     * Will be summed with enforcedOptions, even if no enforcedOptions are set.
     * @param _payInLzToken Boolean flag indicating whether to pay in LZ token.
     * @return totalFee The estimated messaging fee for sending to all pathways.
     */
    function quote(
        uint32[] memory _dstEids,
        uint16 _msgType,
        string memory _message,
        bytes calldata _extraSendOptions,
        bool _payInLzToken
    ) public view returns (MessagingFee memory totalFee) {
        bytes memory encodedMessage = abi.encode(_message);

        for (uint i = 0; i < _dstEids.length; i++) {
            bytes memory options = combineOptions(_dstEids[i], _msgType, _extraSendOptions);
            MessagingFee memory fee = _quote(_dstEids[i], encodedMessage, options, _payInLzToken);
            totalFee.nativeFee += fee.nativeFee;
            totalFee.lzTokenFee += fee.lzTokenFee;
        }
    }

    function send(
        uint32[] memory _dstEids,
        uint16 _msgType,
        string memory _message,
        bytes calldata _extraSendOptions // gas settings for A -> B
    ) external payable {
        if (_msgType != SEND) {
            revert InvalidMsgType();
        }

        // Calculate the total messaging fee required.
        MessagingFee memory totalFee = quote(_dstEids, _msgType, _message, _extraSendOptions, false);
        require(msg.value >= totalFee.nativeFee, "Insufficient fee provided");

        // Encodes the message before invoking _lzSend.
        bytes memory _encodedMessage = abi.encode(_message);

        uint256 totalNativeFeeUsed = 0;
        uint256 remainingValue = msg.value;

        for (uint i = 0; i < _dstEids.length; i++) {
            bytes memory options = combineOptions(_dstEids[i], _msgType, _extraSendOptions);
            MessagingFee memory fee = _quote(_dstEids[i], _encodedMessage, options, false);

            totalNativeFeeUsed += fee.nativeFee;
            remainingValue -= fee.nativeFee;

            // Ensure the current call has enough allocated fee from msg.value.
            require(remainingValue >= 0, "Insufficient fee for this destination");

            _lzSend(
                _dstEids[i],
                _encodedMessage,
                options,
                fee,
                payable(msg.sender)
            );

            emit MessageSent(_message, _dstEids[i]);
        }
    }

    /**
     * @notice Internal function to handle receiving messages from another chain.
     * @dev Decodes and processes the received message based on its type.
     * @param _origin Data about the origin of the received message.
     * @param message The received message content.
     */
    function _lzReceive(
        Origin calldata _origin,
        bytes32 /*guid*/,
        bytes calldata message,
        address, // Executor address as specified by the OApp.
        bytes calldata // Any extra data or options to trigger on receipt.
    ) internal override {
        string memory _data = abi.decode(message, (string));
        data = _data;

        emit MessageReceived(data, _origin.srcEid, _origin.sender);
    }
}
```

## Composed

A composed message refers to an application that invokes the Endpoint method, `sendCompose`, to deliver a composed call to a destination contract via `lzCompose`.

<img src="https://mintcdn.com/layerzero/MzSiOdXt8xlDlEr4/images/learn/Composed-Light.svg?fit=max&auto=format&n=MzSiOdXt8xlDlEr4&q=85&s=3917355397da56862d784598420f6e0c" alt="Diagram showing Composed messaging pattern: message sent from Chain A to contract B1 on Chain B, which then calls sendCompose to deliver a composed call to contract B2 via lzCompose (A → B1 → B2)" className="block dark:hidden" width="1920" height="517" data-path="images/learn/Composed-Light.svg" />

<img src="https://mintcdn.com/layerzero/MzSiOdXt8xlDlEr4/images/learn/Composed-Dark.svg?fit=max&auto=format&n=MzSiOdXt8xlDlEr4&q=85&s=38ab6dbf2d791462d654d55dd9846c7a" alt="Diagram showing Composed messaging pattern: message sent from Chain A to contract B1 on Chain B, which then calls sendCompose to deliver a composed call to contract B2 via lzCompose (A → B1 → B2)" className="hidden dark:block" width="1920" height="517" data-path="images/learn/Composed-Dark.svg" />

This pattern demonstrates **horizontal composability**, which differs from vertical composability in that the external call is now containerized as a new message packet; enabling the application to ensure that certain receipt logic remains separate from the external call itself.

<Info>
  Since each composable call is created as a separate message packet via `lzCompose`, this pattern can be extended for as many steps as your application needs (`B1` -> `B2` -> `B3`, etc).
</Info>

<br />

This pattern can be particularly powerful for orchestrating complex interactions and processes on the destination chain that need contract logic to be handled in independent steps, such as:

* **Omnichain DeFi Strategies**: A smart contract could trigger a token transfer on the destination chain and then automatically interact with a DeFi protocol to lend, borrow, provide liquidity, stake, etc. executing a series of financial strategies across chains.

* **NFT Interactions**: An NFT could be transferred to another chain, and upon arrival, it could trigger a contract to issue a license, register a domain, or initiate a subscription service linked to the NFT's ownership.

* **DAO Coordination**: A DAO could send funds to another chain's contract and compose a message to execute specific DAO-agreed upon investments or funding of public goods.

<br />

### Composing an OApp

There are 3 relevant contract interactions when composing an OApp:

1. **Source OApp**: the OApp sending a crosschain message via `_lzSend` to a destination.

2. **Destination OApp(s)**: the OApp receiving a crosschain message via `_lzReceive` and calling `sendCompose`.

3. **Composed Receiver(s)**: the contract interface implementing business logic to handle receiving a composed message via `lzCompose`.

### Sending Message

The sending OApp is **required** to pass specific [Composed Message Execution Options](#composed-message-execution-options) (more on this below) for the `sendCompose` call, but is **not required** to pass any input parameters for the call itself (however this pattern may be useful depending on what arbitrary action you wish to trigger when composing).

For example, this `send` function packs the destination `_composedAddress` for the destination OApp to decode and use for the actual composed call.

```solidity wrap theme={null}
/// @notice Sends a message from the source to destination chain.
/// @param _dstEid Destination chain's endpoint ID.
/// @param _message The message to send.
/// @param _composedAddress The contract you wish to deliver a composed call to.
/// @param _options Message execution options (e.g., for sending gas to destination).
function send(
    uint32 _dstEid,
    string memory _message,
    address _composedAddress, // the destination contract implementing ILayerZeroComposer
    bytes calldata _options
) external payable returns(MessagingReceipt memory receipt) {
    // Encodes the message before invoking _lzSend.
    bytes memory _payload = abi.encode(_message, _composedAddress);
    receipt = _lzSend(
        _dstEid,
        _payload,
        _options,
        // Fee in native gas and ZRO token.
        MessagingFee(msg.value, 0),
        // Refund address in case of failed source message.
        payable(msg.sender)
    );
}
```

### Sending Compose

The receiving OApp invokes the LayerZero Endpoint's `sendCompose` method as part of your OApp's `_lzReceive` business logic.

The `sendCompose` method takes the following inputs:

1. `_to`: the contract implementing the [`ILayerZeroComposer`](https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/packages/layerzero-v2/evm/protocol/contracts/interfaces/ILayerZeroComposer.sol) receive interface.

2. `_guid`: the global unique identifier of the source message (provided standard by `lzReceive`).

3. `_index`: the index of the composed message (used for pricing different gas execution amounts along different composed legs of the transaction).

```solidity wrap theme={null}
/// @dev the Oapp sends the lzCompose message to the endpoint
/// @dev the composer MUST assert the sender because anyone can send compose msg with this function
/// @dev with the same GUID, the Oapp can send compose to multiple _composer at the same time
/// @dev authenticated by the msg.sender
/// @param _to the address which will receive the composed message
/// @param _guid the message guid
/// @param _message the message
function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external {
    // must have not been sent before
    if (composeQueue[msg.sender][_to][_guid][_index] != NO_MESSAGE_HASH) revert Errors.ComposeExists();
    composeQueue[msg.sender][_to][_guid][_index] = keccak256(_message);
    emit ComposeSent(msg.sender, _to, _guid, _index, _message);
}
```

This means that when a packet is received (`_lzReceive`) by the Destination OApp, it will send (`sendCompose`) a new composed packet via the destination LayerZero Endpoint.

```solidity wrap theme={null}
/// @dev Called when data is received from the protocol. It overrides the equivalent function in the parent contract.
/// Protocol messages are defined as packets, comprised of the following parameters.
/// @param _origin A struct containing information about where the packet came from.
/// @param _guid A global unique identifier for tracking the packet.
/// @param payload Encoded message.
function _lzReceive(
    Origin calldata _origin,
    bytes32 _guid,
    bytes calldata payload,
    address,  // Executor address as specified by the OApp.
    bytes calldata  // Any extra data or options to trigger on receipt.
) internal override {
    // Decode the payload to get the message
    (string memory _message, address _composedAddress) = abi.decode(payload, (string, address));
    // Storing data in the destination OApp
    data = _message;
    // Send a composed message[0] to a composed receiver
    endpoint.sendCompose(_composedAddress, _guid, 0, payload);
}
```

<Info>
  The above `sendCompose` call hardcodes `_index` to `0` and simply forwards the same `payload` as `_lzReceive` to `lzCompose`, however these inputs can also be dynamically adjusted depending on the number and type of composed calls you wish to make.
</Info>

#### Composed Message Execution Options

You can decide both the `_gas` and `msg.value` that should be used for the composed call(s), depending on the type and quantity of messages you intend to send.

Your configured Executor will use the `_options` provided in the original `_lzSend` call to determine the gas limit and amount of `msg.value` to include per message `_index`:

```javascript wrap theme={null}
// addExecutorLzComposeOption(uint16 _index, uint128 _gas, uint128 _value)
Options.newOptions()
  .addExecutorLzReceiveOption(50000, 0)
  .addExecutorComposeOption(0, 30000, 0)
  .addExecutorComposeOption(1, 30000, 0);
```

It's important to remember that gas costs may vary depending on the destination chain. For example, all new Ethereum transactions cost `21000` wei, but other chains may have lower or higher opcode costs, or entirely different gas mechanisms.

You can read more about generating `_options` and the role of `_index` in [Message Execution Options](../configuration/options#lzcompose-option).

### Receiving Compose

The destination must implement the `ILayerZeroComposer` interface to handle receiving the composed message.

From there, you can decide any additional composed business logic to execute within `lzCompose`, as shown below:

```solidity wrap theme={null}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import { ILayerZeroComposer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroComposer.sol";

/// @title ComposedReceiver
/// @dev A contract demonstrating the minimum ILayerZeroComposer interface necessary to receive composed messages via LayerZero.
contract ComposedReceiver is ILayerZeroComposer {

    /// @notice Stores the last received message.
    string public data = "Nothing received yet";

    /// @notice Store LayerZero addresses.
    address public immutable endpoint;
    address public immutable oApp;

    /// @notice Constructs the contract.
    /// @dev Initializes the contract.
    /// @param _endpoint LayerZero Endpoint address
    /// @param _oApp The address of the OApp that is sending the composed message.
    constructor(address _endpoint, address _oApp) {
        endpoint = _endpoint;
        oApp = _oApp;
    }

    /// @notice Handles incoming composed messages from LayerZero.
    /// @dev Decodes the message payload and updates the state.
    /// @param _oApp The address of the originating OApp.
    /// @param /*_guid*/ The globally unique identifier of the message.
    /// @param _message The encoded message content.
    function lzCompose(
        address _oApp,
        bytes32 /*_guid*/,
        bytes calldata _message,
        address,
        bytes calldata
    ) external payable override {
        // Perform checks to make sure composed message comes from correct OApp.
        require(_oApp == oApp, "!oApp");
        require(msg.sender == endpoint, "!endpoint");

        // Decode the payload to get the message
        (string memory message, ) = abi.decode(_message, (string, address));
        data = message;
    }
}
```

### Further Reading

For more advanced implementations of `sendCompose` and `lzCompose`:

* Review the [`OmniCounter.sol`](https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/packages/layerzero-v2/evm/oapp/contracts/oapp/examples/OmniCounter.sol#L43) for sending composed messages to the same OApp implementation.

* Read the [OFT Composing](../oft/oft-patterns-extensions#composed-oft) section to see how to implement composed business logic into your OFTs.

## Composed ABA

The **Composed ABA** design pattern enables sophisticated omnichain communication by allowing for an operation to be performed as part of the receive logic on the destination chain (`B1`), a follow-up action or call containerized as an independent step within `lzCompose` (`B2`), which then sends back to the source chain (`A`).

<img src="https://mintcdn.com/layerzero/MzSiOdXt8xlDlEr4/images/learn/ComposedABAlight.svg?fit=max&auto=format&n=MzSiOdXt8xlDlEr4&q=85&s=2fe8c732ca9706b667cebb39eca60e75" alt="Diagram showing Composed ABA pattern: Chain A sends to B1, B1 calls lzCompose to B2, and B2 sends back to Chain A (A → B1 → B2 → A), enabling multi-step crosschain workflows" className="block dark:hidden" width="1920" height="517" data-path="images/learn/ComposedABAlight.svg" />

<img src="https://mintcdn.com/layerzero/MzSiOdXt8xlDlEr4/images/learn/ComposedABAdark.svg?fit=max&auto=format&n=MzSiOdXt8xlDlEr4&q=85&s=6f961a2878cc72e959ea75fce9f1b012" alt="Diagram showing Composed ABA pattern: Chain A sends to B1, B1 calls lzCompose to B2, and B2 sends back to Chain A (A → B1 → B2 → A), enabling multi-step crosschain workflows" className="hidden dark:block" width="1920" height="517" data-path="images/learn/ComposedABAdark.svg" />

<Info>
  This message pattern can also be considered a Composed ABC type call (`A` -> `B1` -> `B2` -> `C`), as the nested `_lzSend` can send to any new destination chain.
</Info>

<br />

This pattern demonstrates a complex, multi-step, process across blockchains where each step requires its own atomic logic to execute without depending on separate execution logic. Here are some use cases that could benefit from a Composed ABA design pattern:

* **Omnichain Data Verification**: Chain A sends a request to chain B to verify a set of data. Once verified, a contract on chain B executes an action based on this data and sends a signal back to chain A to either proceed with the next step or record the verification.

* **Omnichain Collateral Management**: When collateral on chain A is locked or released, a corresponding contract on chain B could be called to issue a loan or unlock additional funds. Confirmation of the action is then sent back to chain A to complete the process.

* **Multi-Step Contract Interaction for Games and Collectibles**: In a gaming scenario, an asset (like an NFT) could be sent from chain A to B, triggering a contract on B that could unlock a new level or feature in a game, with a confirmation or reward then sent back to chain A.

## Message Ordering

See [Message Ordering](../../../concepts/message-ordering) under Core Concepts for details.

## Rate Limiting

The `RateLimiter.sol` is used to control the number of crosschain messages that can be sent within a certain time window, ensuring that the OApp is not spammed by too many transactions at once. It's particularly useful for:

* **Preventing Denial of Service Attacks**: By setting thresholds on the number of messages that can be processed within a given timeframe, the `RateLimiter` acts as a safeguard against DoS attacks, where malicious actors might attempt to overload an OApp with a flood of transactions. This protection ensures that the OApp remains accessible and functional for legitimate users, even under attempted attacks.

* **Regulatory Compliance**: Some applications may need to enforce limits to comply with legal or regulatory requirements.

The `RateLimiter` is only useful under specific application use cases. It will not be necessary for most OApps and can even be counterproductive for more generic applications:

* **Low Traffic Applications**: If your application doesn't expect high volumes of traffic, implementing a rate limiter might be unnecessary overhead.

* **Critical Systems Requiring Immediate Transactions**: For systems where transactions need to be processed immediately without delay, rate limiting could hinder performance.

### Installation

To begin working with LayerZero contracts, you can install the [OApp npm package](https://www.npmjs.com/package/@layerzerolabs/oapp-evm?activeTab=code) to an existing project:

```
npm install @layerzerolabs/oapp-evm
```

### Usage

Import the `RateLimiter.sol` contract into your OApp contract file and inherit the contract:

```solidity wrap theme={null}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;

import { OApp } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
import { RateLimiter } from "@layerzerolabs/oapp-evm/contracts/oapp/utils/RateLimiter.sol";

contract MyOApp is OApp, RateLimiter {
    // ...contract
}
```

#### Initializing Rate Limits

In the constructor of your contract, initialize the rate limits using `_setRateLimits` with an array of `RateLimitConfig` structs.

**Example:**

```solidity wrap theme={null}
constructor(
    RateLimitConfig[] memory _rateLimitConfigs,
    address _lzEndpoint,
    address _delegate
) OApp(_lzEndpoint, _delegate) {
    _setRateLimits(_rateLimitConfigs);
}
// ...Rest of contract code
```

**`RateLimitConfig` Struct:**

```solidity wrap theme={null}
struct RateLimitConfig {
    uint32 dstEid; // destination endpoint ID
    uint256 limit; // arbitrary limit of messages/tokens to transfer
    uint256 window; // window of time before limit resets
}
```

#### Setting Rate Limits

Provide functions to set or update rate limits dynamically. This can include a function to adjust individual or multiple rate limits and a mechanism to authorize who can make these changes (typically restricted to the contract owner or a specific role).

```solidity wrap theme={null}
/**
 * @dev Sets the rate limits based on RateLimitConfig array. Only callable by the owner or the rate limiter.
 * @param _rateLimitConfigs An array of RateLimitConfig structures defining the rate limits.
 */
function setRateLimits(
    RateLimitConfig[] calldata _rateLimitConfigs
) external {
    if (msg.sender != rateLimiter && msg.sender != owner()) revert OnlyRateLimiter();
    _setRateLimits(_rateLimitConfigs);
}
```

#### Checking Rate Limits During Send Calls

Before processing transactions, use `_outflow` to ensure the transaction doesn't exceed the set limits. This function should be called in any transactional functions, such as message passing or token transfers.

#### Message Passing

```solidity wrap theme={null}
function send(
    uint32 _dstEid,
    string memory _message,
    bytes calldata _options
) external payable {
    // highlight-next-line
    _outflow(_dstEid, 1); // updating the rate limit per message sent
    bytes memory _payload = abi.encode(_message); // Encodes message as bytes.
    _lzSend(
        _dstEid, // Destination chain's endpoint ID.
        _payload, // Encoded message payload being sent.
        _options, // Message execution options (e.g., gas to use on destination).
        MessagingFee(msg.value, 0), // Fee struct containing native gas and ZRO token.
        payable(msg.sender) // The refund address in case the send call reverts.
    );
}
```

#### Token Transfers

```solidity wrap theme={null}
/**
 * @dev Checks and updates the rate limit before initiating a token transfer.
 * @param _amountLD The amount of tokens to be transferred.
 * @param _minAmountLD The minimum amount of tokens expected to be received.
 * @param _dstEid The destination endpoint identifier.
 * @return amountSentLD The actual amount of tokens sent.
 * @return amountReceivedLD The actual amount of tokens received.
 */
function _debit(
    address _from,
    uint256 _amountLD,
    uint256 _minAmountLD,
    uint32 _dstEid
) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) {
    // highlight-next-line
    _outflow(_dstEid, _amountLD);
    return super._debit(_from, _amountLD, _minAmountLD, _dstEid);
}
```
