Skip to content

Wormhole Relayer

Introduction

The Wormhole-deployed relayers provide a mechanism for contracts on one blockchain to send messages to contracts on another without requiring off-chain infrastructure. Through the Wormhole relayer module, developers can use an untrusted delivery provider to transport VAAs, saving the need to build and maintain custom relaying solutions. The option to run a custom relayer is available for more complex needs.

This section covers the components and interfaces involved in using the Wormhole relayer module, such as message sending and receiving, delivery guarantees, and considerations for building reliable and efficient cross-chain applications. Additionally, you'll find details on how to handle specific implementation scenarios and track message delivery progress using the Wormhole CLI tool.

Get Started with the Wormhole Relayer

Before getting started, it's important to note that the Wormhole-deployed relayer configuration is currently limited to EVM environments. The complete list of EVM environment blockchains is on the Supported Networks page.

To interact with the Wormhole relayer, you'll need to create contracts on the source and target chains to handle the sending and receiving of messages. No off-chain logic needs to be implemented to take advantage of Wormhole-powered relaying.

Wormhole Relayer
The components outlined in blue must be implemented.

Wormhole Relayer Interfaces

There are three relevant interfaces to discuss when utilizing the Wormhole relayer module:

  • IWormholeRelayer - the primary interface by which you send and receive messages. It allows you to request the sending of messages and VAAs
  • IWormholeReceiver - this is the interface you are responsible for implementing. It allows the selected delivery provider to deliver messages/VAAs to your contract
  • IDeliveryProvider - this interface represents the delivery pricing information for a given relayer network. Each delivery provider implements this on every blockchain they support delivering from

Interact with the Wormhole Relayer

To start interacting with the Wormhole relayer in your contracts, you'll need to import the IWormholeRelayer interface and set up a reference using the contract address to the Wormhole-deployed relayer on the supported network of your choice.

To easily integrate with the Wormhole relayer interface, you can use the Wormhole Solidity SDK.

To retrieve the contract address of the Wormhole relayer, refer to the Wormhole relayer section on the Contract Addresses reference page.

Your initial set up should resemble the following:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import "wormhole-solidity-sdk/interfaces/IWormholeRelayer.sol";

contract Example {
    IWormholeRelayer public wormholeRelayer;

    constructor(address _wormholeRelayer) {
        wormholeRelayer = IWormholeRelayer(_wormholeRelayer);
    }
}

The code provided sets up the basic structure for your contract to interact with the Wormhole relayer using the address supplied to the constructor. By leveraging methods from the IWormholeRelayer interface, you can implement message sending and receiving functionalities. The following sections will detail the specific methods you need to use for these tasks.

Send a Message

To send a message to a contract on another EVM chain, you can call the sendPayloadToEvm method provided by the IWormholeRelayer interface.

function sendPayloadToEvm(
    // Chain ID in Wormhole format
    uint16 targetChain,     
    // Contract Address on target chain we're sending a message to
    address targetAddress,  
    // The payload, encoded as bytes
    bytes memory payload,   
    // How much value to attach to the delivery transaction 
    uint256 receiverValue,  
    // The gas limit to set on the delivery transaction
    uint256 gasLimit        
) external payable returns (
    // Unique, incrementing ID, used to identify a message
    uint64 sequence
);

The sendPayloadToEvm method is marked payable to receive fee payment for the transaction. The value to attach to the invocation is determined by calling the quoteEVMDeliveryPrice, which provides an estimate of the cost of gas on the target chain.

function quoteEVMDeliveryPrice(
    // Chain ID in Wormhole format
    uint16 targetChain,
    // How much value to attach to delivery transaction 
    uint256 receiverValue,
    // The gas limit to attach to the delivery transaction
    uint256 gasLimit
) external view returns (
    // How much value to attach to the send call
    uint256 nativePriceQuote, 
    uint256 targetChainRefundPerGasUnused
);

This method should be called before sending a message, and the value returned for nativePriceQuote should be attached to the call to send the payload to cover the transaction's cost on the target chain.

In total, sending a message across EVM chains can be as simple as getting a fee quote and sending the message as follows:

// Get a quote for the cost of gas for delivery
(cost, ) = wormholeRelayer.quoteEVMDeliveryPrice(
    targetChain,
    valueToSend,
    GAS_LIMIT
);

// Send the message
wormholeRelayer.sendPayloadToEvm{value: cost}(
    targetChain,
    targetAddress,
    abi.encode(payload),
    valueToSend, 
    GAS_LIMIT
);

Receive a Message

To receive a message using a Wormhole relayer, the target contract must implement the IWormholeReceiver interface, as shown in the previous section.

function receiveWormholeMessages(
    bytes memory payload,           // Message passed by source contract 
    bytes[] memory additionalVaas,  // Any additional VAAs that are needed (Note: these are unverified) 
    bytes32 sourceAddress,          // The address of the source contract
    uint16 sourceChain,             // The Wormhole chain ID
    bytes32 deliveryHash            // A hash of contents, useful for replay protection
) external payable;

The logic inside the function body may be whatever business logic is required to take action on the specific payload.

Delivery Guarantees

The Wormhole relayer protocol is intended to create a service interface whereby mutually distrustful integrators and delivery providers can work together to provide a seamless dApp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement between integrators and delivery providers is that when a delivery is requested, the provider will attempt to deliver the VAA within the provider's stated delivery timeframe.

This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages even if they do so at a loss.

Delivery providers should set their prices such that they turn a profit on average but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees or lower rates for less stringent guarantees.

Delivery Statuses

All deliveries result in one of the following four outcomes before the delivery provider's delivery timeframe. When they occur, these outcomes are emitted as EVM events from the Wormhole relayer contract. The four possible outcomes are:

  • (0) Delivery Success
  • (1) Receiver Failure
  • (2) Forward Request Success
  • (3) Forward Request Failure

A receiver failure is a scenario in which the selected provider attempted the delivery but it could not be completely successfully. The three possible causes for a delivery failure are:

  • The target contract does not implement the IWormholeReceiver interface
  • The target contract threw an exception or reverted during the execution of receiveWormholeMessages
  • The target contract exceeded the specified gasLimit while executing receiveWormholeMessages

All three of these scenarios can be avoided with correct design by the integrator, and thus, it is up to the integrator to resolve them. Any other scenario that causes a delivery to not be performed should be considered an outage by some component of the system, including potentially the blockchains themselves.

Forward Request Success and Forward Failure represent when the delivery succeeded and the user requested a forward during the delivery. If the user has enough funds left over as a refund to complete the forward, the forward will be executed, and the status will be Forward Request Success. Otherwise, it will be Forward Request Failure.

Other Considerations

Some implementation details should be considered during development to ensure safety and a pleasant UX. Ensure that your engineering efforts have appropriately considered each of the following areas:

  • Receiving a message from a relayer
  • Checking for expected emitter
  • Calling parseAndVerify on any additional VAAs
  • Replay protection
  • Message ordering (no guarantees on order of messages delivered)
  • Forwarding and call chaining
  • Refunding overpayment of gasLimit
  • Refunding overpayment of value sent

Track the Progress of Messages with the Wormhole CLI

While no off-chain programs are required, a developer may want to track the progress of messages in flight. To track the progress of messages in flight, use the Wormhole CLI tool's status subcommand. As an example, you can use the following commands to track the status of a transfer by providing the environment, origin network, and transaction hash to the worm status command:

worm status mainnet ethereum INSERT_TRANSACTION_HASH
worm status testnet ethereum INSERT_TRANSACTION_HASH

See the Wormhole CLI tool docs for installation and usage.

Step-by-Step Tutorial

For detailed, step-by-step guidance on creating cross-chain contracts that interact with the Wormhole relayer, refer to the Create Cross-Chain Contracts tutorial.