Skip to main content
Version: Endpoint V1

Configuring Custom Oracle

Learn how to seamlessly set up and integrate a new Oracle for your User Application (UA).

This tutorial provides a step-by-step guide on setting a new Oracle for your User Application (UA).

Understanding Oracle Configuration

In LayerZero, Oracle configurations help enable smooth messaging across chain pathways. A chain pathway represents a connected route that utilizes both the Oracle and Relayer to facilitate message routing between blockchains.

  1. Consistent Oracle Configuration: It's essential to ensure that the same Oracle provider is present on both the source and destination chains. This uniformity guarantees that messages can be reliably sent and received in both directions on the pathway.
  2. Payment and Delivery Logic: If you're paying Oracle A on the source chain, you'd expect Oracle A to also handle the delivery on the destination chain. Hence, if Oracle A is available on both chains, it can be used in both directions. On the other hand, if Oracle A is only present on one chain, you'd need to opt for an alternative that's supported on both chain directions.

Remember, the objective is to ensure that the Oracle setup supports the chain pathways, as they are the conduits for message routing. This is vital for efficient, error-free cross-chain communication.

Prerequisites

You should have an LZApp to start with that's already working with default settings. While we use OmniCounter in this tutorial, any app that inherits LZApp.sol (including the OFT and ONFT standards) can be used.

In order to set a new Oracle, all a user will need to do is call the setConfig function on Chain A and Chain B.

Below is a simple example for how to set your Oracle, using the Ethereum Goerli and Optimism Goerli Testnets.

Example: Setting an Oracle using Ethereum Goerli and Optimism Goerli Testnets

Deploying OmniCounter

After deploying OmniCounter on both Goerli and OP-Goerli, ensure that:

  • You've correctly called setTrustedRemote.
  • The incrementCounter function works by default on both contracts.
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
pragma abicoder v2;

import "https://github.com/LayerZero-Labs/solidity-examples/blob/e43908440cefdcbc93cd8e0ea863326c4bd904eb/contracts/lzApp/NonblockingLzApp.sol";

/// @title A LayerZero example sending a cross chain message from a source chain to a destination chain to increment a counter
contract OmniCounter is NonblockingLzApp {
bytes public constant PAYLOAD = "\x01\x02\x03\x04";
uint public counter;

constructor(address _lzEndpoint) NonblockingLzApp(_lzEndpoint) {}

function _nonblockingLzReceive(uint16, bytes memory, uint64, bytes memory) internal override {
counter += 1;
}

function estimateFee(uint16 _dstChainId, bool _useZro, bytes calldata _adapterParams) public view returns (uint nativeFee, uint zroFee) {
return lzEndpoint.estimateFees(_dstChainId, address(this), PAYLOAD, _useZro, _adapterParams);
}

function incrementCounter(uint16 _dstChainId) public payable {
_lzSend(_dstChainId, PAYLOAD, payable(msg.sender), address(0x0), bytes(""), msg.value);
}
}

Setting a new Oracle

To modify your UA contracts, you'll need to invoke the setConfig function. This can be done directly from a verified block explorer or using scripting tools. In this tutorial, we'll demonstrate using Remix.

Here's how to set the Oracle for the Goerli OmniCounter using the Goerli TSS Oracle address, 0x36ebea3941907c438ca8ca2b1065deef21ccdaed:

let config = ethers.utils.defaultAbiCoder.encode(
['address'],
['0x36ebea3941907c438ca8ca2b1065deef21ccdaed'], // oracleAddress
);
await lzEndpoint.setConfig(
0, // default library version
10132, // dstChainId
6, // CONFIG_TYPE_ORACLE
0x00000000000000000000000036ebea3941907c438ca8ca2b1065deef21ccdaed, // config
);
info

This process should be repeated on both the source and destination contracts. Ensure you adjust the _dstChainId and oracleAddress based on the contract's location. For instance, on OP Goerli, use the OP Goerli TSS Oracle Address and set the destination chain to 10121 for Goerli ETH.

In Remix, passing these arguments will show the following: alt text

Checking Oracle configuration

To ensure your Oracle setup is correctly configured:

Navigate to the Block Explorer: Go to your chain's Endpoint Address on the designated block explorer.

Access the Contract Details: Click on "Read Contract". Here, you should see an option labeled defaultReceiveLibraryAddress. Select it to navigate to LayerZero's UltraLightNode.

alt text

Query the UltraLightNode Contract:

  • getConfig: This returns the current configuration of your UA Contract.
  • defaultAppConfig: This gives the default configuration based on the latest library version. To use this, you'll need to provide the _dstChainId parameter.

View the Oracle Parameter: For the defaultAppConfig, simply pass the _dstChainId and observe the returned oracle parameter. alt text

For the getConfig, pass the _dstChainId, your UA Contract Address, and set the constant CONFIG_TYPE_ORACLE to 6. alt text

Compare Oracle Addresses:

At the time of writing this tutorial, TSS is the default testnet Oracle. Therefore, if you haven't made any changes, both getConfig and defaultAppConfig should return identical Oracle addresses.

However, if you've opted for a different Oracle from the current default, the two queries should return different Oracle addresses.

info

Understanding Query Results: You might notice a difference in how the queries present the Oracle:

  • defaultAppConfig: This query returns the Oracle as an address.
  • getConfig: In contrast, this displays the Oracle as a bytes value.

However, don't be alarmed by this variation. If the only discrepancy between the two results is the presence of '0' padding, then both queries are referencing the same Oracle.

Testing message delivery

Validate your Oracle setup by calling incrementCounter. The protocol should now reflect your custom Oracle configuration and be capable to send messages in both directions.

Congratulations on your successful configuration! 🥳 alt text

A successful oracle configuration will not impact message delivery.

Troubleshooting

Encountering a FAILED message status on LayerZero Scan? This likely points to a misconfiguration of the oracle address on either one or both contracts.

alt text

  • Ensure you're using the local oracle address (i.e., the same chain as your UA) when invoking setConfig.
  • Double-check the dstChainId you're passing

For further customization, refer to the UA Custom Configuration documentation.