- Omnichain Application (OApp): the base contract standard for omnichain messaging and configuration.
-
Omnichain Fungible Token (OFT): an extension of
OAppbuilt for handling and supporting omnichainERC20transfers. -
Omnichain Non-Fungible Token (ONFT): an extension built for handling and supporting omnichain
ERC721transfers.
-
OAppSender._lzSend: internal function that callsEndpointV2.sendto send a message asbytes. -
OAppReceiver._lzReceive: internal function that delivers the encoded message asbytesafter theExecutorcallsEndpointV2.lzReceive.
Example Omnichain Application
TheOApp Standard contains both a send and receive interface.
This code snippet is already implemented in the Remix example below. Simply review this code to understand how it works internally.
OAppSender and OAppReceiver work together for sending and receiving any arbitrary data to supported destination chains.
OAppSender.sol
Open in Remix What is Remix?OAppReceiver.sol
Open in Remix What is Remix?Prerequisites
- You should first be familiar with writing and deploying contracts to your desired blockchains. This involves understanding the specific smart contract language and the deployment process for those chains.
- A wallet set up and funded for the chains you’ll be working with.
Deploying Your Contracts
We’ll deploy the Source Contract onSepolia, and the Destination Contract on Optimism Sepolia:
This example can be used with any EVM-compatible blockchain that LayerZero supports.
-
Open MetaMask and select the
Ethereum Sepolianetwork. Make sure you have native gas in the wallet connected. -
In Remix under the Deploy & Run Transactions tab, select
Injected Provider - MetaMaskin the Environment list. - Under the Deploy section, fill in the Endpoint Address for your current chain.
Sepolia Endpoint Address
Optimism Sepolia Endpoint Address
- Click deploy, follow the MetaMask prompt to confirm the transaction, and wait for the contract address to appear under Deployed Contracts.
- Repeat the above steps for any other chains you plan to deploy to and connect.
Connecting Your Contracts
To connect your OApp deployments together, you will need to callsetPeer on both the Ethereum Sepolia and Optimism Sepolia OApp.
The function takes 2 arguments: _eid, the destination endpoint ID for the chain our other OApp contract lives on, and _peer, the destination OApp contract address in bytes32 format.
setPeer on SourceOApp, take the DestinationOApp address and call OApp.addressToBytes32. Use the returned output as the _peer.
Your _peer should look something like this: 0x0000000000000000000000000a3ecc421699e2eb7f53584d07165d95721a4ca7.
By default, the OApp standard inherits OAppReceiver which uses this peer inside lzReceive to enforce that the sender is the expected origin address.
Pass the address of your destination contract as a
bytes32 value, as well as the destination endpoint ID.
-
To send to Ethereum Sepolia, the Endpoint ID is:
40161. -
To send to Optimism Sepolia, the Endpoint ID is:
40232.
Estimating Fees
The LayerZero Protocol gas fees can vary based on your source chain,DVNs, Executor, and amount of native gas token you request in _options, so you should estimate fees before sending your first transaction.
The OApp.quote function invokes an internal OAppSender._quote to estimate the fees associated with a particular LayerZero transaction using four inputs:
-
_dstEid: This is the identifier of the destination chain’s endpoint where the transaction is intended to go. -
_message: This is the arbitrary message you intend to send to your destination chain and contract. -
_options: A bytes array that contains serialized execution options that tell the protocol the amount of gas to for the Executor to send when callinglzReceive, as well as other function call related settings. -
_payInLzToken: A boolean which determines whether to return the fee estimate in the native gas token or in ZRO token.
In this tutorial, you will deliver
50000 wei for the lzReceive call by passing 0x0003010011010000000000000000000000000000c350 as your _options. You will be quoted 50000 wei on the source chain, which the Executor will convert to the destination gas token and use in the call. See Message Execution Options for all possible execution settings.Sending Your Message
To use thesend function, simply input a string into the message field that you wish to send to your destination chain.
Contract A
Remember to pass thequote in Remix under VALUE to pay the gas fees on the source and destination, as well as for the Security Stack and Executor who verify and execute the messages. Then call SourceOApp.send!
Contract B
Your message may take a few minutes to appear in the destination block explorer, depending on which chains you deploy to.Tracking Your Message
Finally, let’s see what’s happening in our transaction. Take your transaction hash and paste it into: https://testnet.layerzeroscan.com/ You should seeStatus: Delivered, confirming your message has been delivered to its destination using LayerZero.
Congrats, you just sent your first omnichain message! 🥳