Skip to main content
Version: Endpoint V2 Docs

Read CLI Setup Guide

To start leveraging LayerZero Read (lzRead), LayerZero offers CLI examples that streamline the setup and configuration process, similar to the standard CLI examples provided for other LayerZero functionalities.

Using the Read CLI

To begin using lzRead, follow the steps below. These instructions utilize the same commands as the standard setup for OApps but include minor adjustments specific to configuring read capabilities.

Create Your lzRead Repo

Run the following command to create a new LayerZero OApp with read capabilities enabled:

LZ_ENABLE_READ_EXAMPLE=1 npx create-lz-oapp@latest

This command initializes a new project with the necessary configurations to support lzRead. The project creation wizard will guide you through selecting a template and setting up your development environment.

✔ Where do you want to start your project? … ./my-lz-read-oapp
✔ Which example would you like to use as a starting point? › OApp Read
✔ What package manager would you like to use in your project? › pnpm

This will set up a repository with example contracts, cross-chain unit tests for read operations, custom LayerZero read configuration files, deployment scripts, and more.

Follow the normal setup process defined above (adding networks to your hardhat.config.ts, adding your MNEMONIC or PRIVATE_KEY to .env, etc.)

// hardhat.config.ts
import { EndpointId } from '@layerzerolabs/lz-definitions';

networks: {
ethereum: {
eid: EndpointId.ETHEREUM_V2_MAINNET,
url: process.env.RPC_URL_ETHEREUM,
accounts,
},
arbitrum: {
eid: EndpointId.ARBITRUM_V2_MAINNET,
url: process.env.RPC_URL_ARBITRUM,
accounts,
},
polygon: {
eid: EndpointId.POLYGON_V2_MAINNET,
url: process.env.RPC_URL_POLYGON,
accounts,
},
},

Refer to the LayerZero Endpoint Addresses to ensure the networks you add have deployed endpoints.

To see a list of available commands, run npx hardhat:

lz:read:resolve-command             Task for debugging read commands
lz:oapp-read:wire Wire LayerZero Read OApp
lz:oapp-read:config:get Get Read OApp configuration
lz:oapp-read:config:init Initialize Read OApp configuration
lz:oapp-read:config:get:channel Get information of read channels for networks

Each command serves a specific purpose in managing and configuring your lzRead setup.

All of the standard CLI methods available in the LayerZero CLI Setup Guide can also be found in this newly initialized project. Take some time to familiarize yourself with the project commands and layout.

In general each of the lzRead CLI methods have been modified from the base CLI, so all lz:oapp: and lz:oapp:read methods should behave similarly.

Configure LayerZero Config

Unlike standard OApp configurations, lzRead requires specific settings in the layerzero.config.ts file. Instead of configuring connections, you'll focus solely on defining contracts and read channels:

// layerzero.config.ts
import {ChannelId, EndpointId} from '@layerzerolabs/lz-definitions';
import {OAppReadOmniGraphHardhat} from '@layerzerolabs/oapp-evm';
import {ethers} from 'ethers';

const arbitrumContract: OmniPointHardhat = {
eid: EndpointId.ARBITRUM_V2_MAINNET,
contractName: 'UniswapV3QuoteDemo',
};

const config: OAppReadOmniGraphHardhat = {
contracts: [
{
contract: arbitrumContract, // Dummy contract address
config: {
readLibrary: '0xbcd4CADCac3F767C57c4F402932C4705DF62BEFf',
readChannels: [
{
channelId: ChannelId.READ_CHANNEL_1,
active: true,
},
],
readConfig: {
ulnConfig: {
requiredDVNs: ['0x1308151a7ebac14f435d3ad5ff95c34160d539a5'],
executor: '0x31CAe3B7fB82d847621859fb1585353c5720660D',
},
},
},
},
],
connections: [], // No connections needed for read-only setup
};

export default config;

You can generate this config file based on the networks specified in your hardhat.config.ts by running:

npx hardaht lz:oapp-read:config:init --contract-name <READ_CONTRACT_NAME> --oapp-config <NEW_CONFIG_FILE_NAME>

This will produce a new layerzero.config.ts file based on the READ_CONTRACT_NAME and available networks in your hardhat project.

Key configuration details include:

  • contracts: Define the contracts you intend to interact with. In this example, the origin chain Arbitrum has the child OAppRead contract address.

  • readLibrary: The address of the Read Library (ReadLib1002) contract deployed on your network.

  • readChannels: Specify the read channels you want to activate.

  • readConfig: Configure the Read Library settings, including required Decentralized Verifier Networks (DVNs) and the executor address.

Wire Your Read OApp

After configuring layerzero.config.ts, execute the following command to wire your Read OApp:

npx hardhat lz:oapp-read:wire --oapp-config layerzero.config.ts

This command sets up the necessary connections and configurations based on your layerzero.config.ts file, enabling your OApp to perform read operations.

Debugging Malformed or Unresolvable Commands

LayerZero provides a Hardhat task to assist in debugging and resolving read commands. This task helps identify and troubleshoot issues with your read commands.

To resolve a read command, run the following command in your terminal:

npx hardhat lz:read:resolve-command --command <READ_COMMAND>

If the command is correctly formed and resolvable, the task will provide the expected target data.

If the command is Malformed or Unresolvable, the task will output relevant error messages to help you pinpoint the issue.

Based on the feedback from the resolver task, make necessary adjustments to your command construction or target contract configurations.

Testing Contracts

Ensuring the reliability of your lzRead setup involves thorough testing. LayerZero provides a TestHelper tailored for Foundry unit tests, enabling you to simulate cross-chain reads in your tests.

For lzRead, this helper has been extended to support read-specific functionalities. Some limitations of this testing method should be understood:

  • Command Validation: Does not simulate whether a command is malformed or unresolvable.

To fully ensure contract functionality, it's recommended to conduct tests on mainnet even after unit testing, to ensure that the mocked state in your unit tests matches the behaviour found on-chain.