Introduction
LayerZero enables seamless communication between different blockchain networks. With LayerZero, you can have an interaction on one blockchain (say, Ethereum) automatically trigger a reaction on another (like Arbitrum), all without relying on a central authority to relay that trigger. This guide will walk you through the process of setting up and using a simplified OApp contract to send messages across chains.Prerequisites
Before getting started, make sure you have:- Node.js and NPM installed
- Basic understanding of Solidity and smart contracts
- Testnet funds for deploying contracts
Creating an OApp
Project Setup
LayerZero providescreate-lz-oapp, a CLI Toolkit designed to streamline the process of building, testing, deploying and configuring omnichain applications (OApps).
create-lz-oapp is an npx package that creates a Node.js project with both the Hardhat and Foundry development frameworks installed, allowing developers to build from any LayerZero Contract Standards.
To start, create a new project:
OApp as your example starting point when prompted and a package manager of your choice.
This will initialize a repo with example contracts, crosschain unit tests for sample contracts, custom LayerZero configuration files, deployment scripts, and more.
OApp Smart Contract
Review theMyOApp.sol contract to see how it implements the OApp contract standard.
No need to change anything in this file at this point, but it’s good to know how sending and receiving messages works.
Configuration
Update yourhardhat.config.ts file to include the networks you want to deploy to:
.env.example file to .env and update it with needed configurations:
PRIVATE_KEY. RPC URLs are optional, but strongly recommended. If you don’t provide them, public RPCs will be used, but public RPCs can be unreliable or slow, leading to long waiting times for transactions to be confirmed or, at worst, cause your transactions to fail.
Deploying Contracts
Before deploying, fund the address you’re deploying from with the corresponding chains’ native tokens. In this case, you need to have AVAX on Avalanche and POL on Polygon testnets. Deploy your contracts using the LayerZero CLI:hardhat.config.ts according to instructions above, you should have two networks already selected (amoy-tesnet and avalanche-testnet).
If everything is set up correctly, you should see output similar to this:
MyOApp contract is now deployed to both networks.
Deployer and deployed contract addresses will be different for your project.
Note the deployed contract addresses, we will need them later.
Configuration and wiring
Now we are ready to connect (wire) the contracts across chains. For that, we need to configure thelayerzero.config.ts file to tell which chains should be wired and able to talk to each other. In our case, it’s only two chains, but you can have as many as you want.
Modify your layerzero.config.ts file to include the chains you deployed to:
Sending Your First Message
Now, you need to prepare a transaction that sends a message across the configured LayerZero channel. Using the contract instance that you deployed on Avalanche, you will call thesend function on the contract, providing the required parameters: the source network, destination network and the message.
To make it easier, let’s create a hardhat task to do that.
Create a new file tasks/sendMessage.ts and add the following code:
hardhat.config.ts file:
Verifying Receipts
The message will be stored in thedata variable of the MyOApp contract on the destination chain. Remember how we set the data variable to "Nothing received yet." in the MyOApp.sol contract?
data variable will be updated on the destination chain with the message we sent.
We can verify this by calling the data getter function on the MyOApp contract on the destination chain, but first, let’s have a look at the transaction on the LayerZero Scan.
Click on the LayerZero Scan link in the output of the transaction to get all the details of the message we just sent.
There’s a lot of useful information here. Let’s focus on a few key details:
- Status: The transaction status is
Delivered. If you’re checking the status of the message immediately after sending it, it might still be inInflightstatus. Just wait a few seconds and it should be automatically updated. - Message Payload: All the parameters of our crosschain message are included here, including the message itself, encoded as bytes.
- Transaction Fee: This is how much we paid to send the message crosschain.
- OApp Configuration: This is the configuration of the
MyOAppcontract both on the source and destination chains. We used a lot of the default configurations, but you can customize them to your needs later on. - Destination Omnichain Application: This is the address of the
MyOAppcontract on the destination chain. You can click on the globe icon next to it to see the contract on the destination chain.
data variable of the MyOApp contract.
We’re on Polygon Amoy, and we have successfully received the message from Avalanche Fuji. Mission accomplished!
Important Notes
- Always ensure you have sufficient gas tokens on both source and destination chains
- Double check endpoint IDs and contract addresses when setting peers
- Monitor LayerZero Scan for message status
Next Steps
You have now successfully set up and used a simplified OApp contract to send a message across two different blockchains using LayerZero. This guide serves as a foundational example of the capabilities of LayerZero’s crosschain messaging. From here, you can explore more advanced features and build more complex omnichain applications.Explore Contract Standards
- Omnichain Token: Create an Omichain Fungible Token that works across chains.
- Omnichain NFT: Build an Omnichain Non-Fungible Token (ONFT) collection that works across chains.
- Omnichain Read: Read external state from other chains and perform calculations, using LayerZero Read.