-
oapp::oapp(main OApp interface and example usage) -
oapp::oapp_compose(handles composable message logic) -
oapp::oapp_core(contains core utilities such as sending messages, quoting fees, setting config/delegates/peers) -
oapp::oapp_receive(handles low-level message reception logic) -
oapp::oapp_store(internal persistent storage and admin/delegate logic)
Overview
A LayerZero OApp (Omnichain Application) is a contract/module that can:- Send and Receive messages across chains
- Optionally Compose messages (which is a feature to re-enter the OApp with new logic after a message is processed)
- Quote fees for sending crosschain messages
- Manage Admin and Delegate roles for secure crosschain interactions
Key Components
-
Sending Messages: Uses the
lz_sendfunction fromoapp::oapp_core. -
Quoting Fees: Uses
lz_quotefromoapp::oapp_core. -
Receiving Messages: Handled by
lz_receiveinoapp::oapp_receiveand overridden into your OApp’s logic. -
Composing Messages: Enabled by
lz_composeinoapp::oapp_compose. -
Admin/Delegate Permissions: Managed through
oapp::oapp_coreand stored inoapp::oapp_store.
Main OApp Module (oapp::oapp)
The main OApp Module defines entry functions that an application developer can call (for example, to send or quote crosschain messages).
This contract can house your custom logic for receiving messages (though the base code is handled in oapp_receive, you can add extra handling via lz_receive_impl).
Key Points
example_message_senderis a reference entry function. Developers can create their own, based on the same pattern, to send a message crosschain.lz_receive_implis the function that your OApp can override/extend with your custom “on-message” logic.
oapp::oapp_core and oapp::oapp_store to make its job easier.
OApp Core Module (oapp::oapp_core)
The Core Module provides lower-level helper functions to send messages, quote fees, manage OApp configuration, handle admin or delegate actions, and keep track of enforced configuration options.
-
lz_send: Calls the underlying LayerZero Endpoint to perform crosschain message sending. -
lz_quote: Returns the quote for fees needed to send the message in the native gas token or ZRO if enabled. -
Peer Management: The concept of peers (i.e., the paired OApp addresses) is captured by
set_peer(...),has_peer(...), etc. per blockchain pathway (i.e., from Aptos to ETH). -
Admin & Delegate: Functions like
transfer_admin,set_delegate,assert_authorized, etc. manage who can update the OApp configuration or call certain restricted functions. -
Enforced Options: By default, the system can enforce specific message options (like certain gas limits, native gas drops, etc.) for sending to specific destination pathways. This is done via
get_enforced_optionsandcombine_options.
OApp Receive Module (oapp::oapp_receive)
When a crosschain message arrives on Aptos, the OApp’s configured Executor will route the call into this module’s lz_receive or lz_receive_with_value.
This module then calls lz_receive_impl in your main oapp::oapp (or whichever module is designated).
-
The configured Executor contract on Aptos calls
lz_receive(...)on your OApp. -
The message is checked to see if it was sent from an authorized peer (i.e. checking if
senderis one of your OApp’s configured peers). -
The function
lz_receive_implis invoked from your main OApp module to perform any final business logic.
Compose Module (oapp::oapp_compose)
“Compose” is a LayerZero feature that allows an OApp to schedule a subsequent call to itself after a message is processed.
In EVM, this is typically invoked via specialized calls to the Endpoint contract in the child OApp’s lzReceive implementation, and delivered to a contract which implements ILayerZeroComposer.sol.
In Aptos Move, oapp::oapp_compose includes the logic to handle the composition of messages after they are cleared or to initiate them from the local OApp.
lz_compose_impl if your OApp truly needs the advanced external call style logic after a crosschain message has been received.
Internal Store Module (oapp::oapp_store)
The internal store manages the global OApp state:
- The OApp’s own address
- The current Admin and Delegate addresses
- A table of recognized Peers (paired addresses from other chains)
- A table of enforced messaging options
move_to<T>(account, T { ... }). This module sets up a global OAppStore resource at @oapp.
Functions like has_peer(), set_peer(), get_delegate(), etc., let the other modules read and write data in a structured manner.
Putting It All Together
-
Initialization
-
On “init”, the modules are registered with the
endpoint_v2contract. -
The OApp store (
oapp::oapp_store::OAppStore) is created at the address@oapp.
-
On “init”, the modules are registered with the
-
Configuration
-
You set up your Admin address and optional Delegate if you want certain calls (e.g.
set_send_library,skip,burn, ornilify) to be callable by someone other than the admin. -
You set peers by calling
set_peer(account, remote_eid, remote_peer_address).
-
You set up your Admin address and optional Delegate if you want certain calls (e.g.
-
Sending a Message
-
Call your custom send function (like
example_message_sender) from your main OApp module, which internally callslz_send. - Under the hood, the endpoint collects the message, your fees, and orchestrates crosschain delivery.
-
Call your custom send function (like
-
Receiving a Message
-
The LayerZero Executor calls
oapp::oapp_receive::lz_receive -
This function automatically calls
lz_receive_implin youroapp::oapp. - You handle the message payload or any FungibleAsset that might have come along with it.
-
The LayerZero Executor calls
-
Optional: Composing
-
If you want advanced functionality that re-calls the OApp after clearing, implement
lz_compose_implinoapp::oapp_compose. - Typically only needed for specialized re-entrancy or bridging flows.
-
If you want advanced functionality that re-calls the OApp after clearing, implement
Customizing for Your Own OApp
-
Rename your main modules if desired (e.g., from
oapp::oapptooapp::my_app). Update the friend usage accordingly. -
Implement your own send/receive logic in
oapp::oappentry functions. -
Override
lz_receive_implto process the crosschain message data (e.g., parse the vector bytes). -
Implement or skip the
lz_compose_implinoapp_composeif your OApp doesn’t need composition logic. - Manage your OApp’s admin and delegate roles carefully. The admin can set local storage options (like peers), while the delegate can call endpoint-level changes (like DVNs, Executors, Message Libraries).
Conclusion
The Aptos Move OApp Standard mirrors the LayerZero V2 OApp Contract Standard on EVM and Solana by:- Splitting crosschain responsibilities into send, receive, and optional compose modules.
- Offering a straightforward pattern for quoting fees, paying them, and optionally paying them in the ZRO token.
- Enforcing the same security patterns around admin/delegates, ensuring that the correct roles handle the correct privileges.
- Providing a strong separation of concerns in well-structured modules to keep your OApp’s logic clean and maintainable.