Lucid
  • USING LUCID
    • Welcome to Lucid
    • Homepage
    • Explore Page
    • Organisation Summary Page
    • Sidebar Navigation
  • Organisation Creation Page
  • Creating an Organisation
    • 1. Setup Organisation Details
    • 2. Module Selection
    • 3. Module Configuration
    • 4. Safe and Protocol Upgrades Configuration
    • 5. Governor Configuration
    • 6. Veto and Multi-Bridge Configuration
    • 7. Token Configuration
    • 8. Asset Transfer Portals Configuration
    • 9. Review and Deploy Organisation
    • 10. Lucid Post-Deployment Integration
  • Editing an Organisation
  • Modules and integrations
    • Multi-Bridge
      • Multi-Bridge Asset Transfers
      • Multi-Bridge Message and Asset Transfers
      • Resend Transaction
    • Bridge Portals
    • Vested Emission Offerings (VEOs)
      • VEO Purchase Flow
      • VEO Creation Flow
      • VEO Removal Flow
      • Claiming Vested Tokens
    • Wizard | Protocol Upgrades
  • Developer Reference
    • VEOs
      • Vesting Options
      • Price Models
      • Debt Buffer
      • Deposit Interval
    • Message Bridging
      • Sending a Message
      • Message Execution
      • Admin Functions
    • Asset Bridging
      • Bridging Assets
      • Admin Functions
    • Adapters
      • Axelar Adapter
      • CCIP Adapter
      • Connext Adapter
      • Hyperlane Adapter
      • LayerZero Adapter
      • Polymer Adapter
      • Wormhole Adapter
    • Deployed Contracts
      • Multibridge Contracts
      • VEO Contracts
  • API Reference
  • RESOURCES
    • About
    • Fees
      • Lucid Pricing and Fee Structure
      • Fee Estimates for Bridges
    • Frequently Asked Questions
    • Key Terms and Explanations
    • Contact
Powered by GitBook
On this page
  • Introduction
  • Sending a Message
  • sendMessage
  • Resending a Message
  1. Developer Reference
  2. Message Bridging

Sending a Message

Introduction

To send messages across chains using any of the bridges that Lucid integrates with, a project must deploy and configure a Message Controller contract. The Lucid App deploys Message Controllers using a Create3 factory, ensuring that the contracts have the same address across all deployed chains.

To send a message from Chain A to Chain B, a Message Controller must be deployed on both chains.

To receive messages from a controller on another chain, the target Message Controller must have either:

  • A list of local Bridge Adapter contracts, or

  • A Registry contract set

If neither is configured, the controller will not be able to receive messages. Additionally, the address of the remote controller must be registered in each deployed Message Controller. Without this, messages cannot be sent or received.

✅ The Lucid App handles all of this configuration automatically.

The following sections explain how to manually send a message by interacting directly with the smart contracts. This is intended for advanced users. We recommend using the Lucid App to construct messages, which can then be exported for use with Safe, Snapshot’s oSnap module, or to create a Governor proposal.

Sending a Message

To send a message, call the following function on the source chain:

sendMessage

function sendMessage( RelayedMessage memory relayedMsg, uint256 destChainId, address[] memory adapters, uint256[] memory fees, bytes[] memory options ) public payable
Name
Type
Description

relayedMsg

RelayedMessage Struct

An instance of RelayedMessage struct to be relayed (see below)

destChainId

uint256

The destination chain ID.

adapters

address[]

The list of adapters addresses. Adapters provided must support the destination chain id

fees

uint256[]

The list of fees for each adapter. It must include any protocol fee. Must have the same length as adapters.

options

bytes[]

Additional abi-encoded options that are passed to the bridge adapter, specific for every bridge adapter.

This function sends a message from the current controller to a controller in another chain.

  • If a Registry is configured, the list of local adapters is ignored.

  • The function is payable — the caller must send the total amount specified in the fees[] array in the native token (e.g., ETH, MATIC).

  • The controller forwards the message to each specified Bridge Adapter, passing:

    • The corresponding fee

    • Any additional adapter-specific options

The RelayedMessage contains the following fields:

    struct RelayedMessage {
        address[] targets; ///< The list of target addresses.
        bytes[] calldatas; ///< The list of calldata to be executed.
        bytes32 messageId; ///< The unique identifier of the message, leave blank
        uint256 threshold; ///< The threshold required for the message to be executed.
    }
  • targets: Smart contract addresses to call on the destination chain

  • calldatas: The encoded function data for each target

  • threshold: The minimum number of bridge adapters that must deliver the message before execution

Multiple contract calls can be defined and will be executed sequentially.

Only accounts with the MESSAGE_ORIGINATOR_ROLE can call this function.

After sending a message, the following event is emitted:

event MessageCreated(bytes32 indexed messageId, uint256 chainId, uint256 threshold);

The messageId can be used to:

  • Track delivery status on the destination chain

  • Retry delivery with another bridge adapter if needed

Resending a Message

If a bridge fails to deliver a message — or if the threshold is not met — an account with the MESSAGE_RESENDER_ROLE can resend the message using a different adapter.

function resendMessage( bytes32 messageId, address[] memory adapters, uint256[] memory fees, bytes[] memory options ) public payable
Name
Type
Description

messageId

bytes32

The unique identifier of the message.

adapters

address[]

The list of adapters addresses. Adapters provided must support the destination chain id.

fees

uint256[]

The list of fees for each adapter. It must include any protocol fee. Must have the same length as adapters.

options

bytes[]

Additional abi-encoded options that are passed to the bridge adapter, specific for every bridge adapter.

  • Takes the original messageId as input

  • Is payable — the caller must send the total amount in the fees[] array

  • The controller resends the same message to the specified Bridge Adapters

The function behavior mirrors sendMessage, forwarding the message with the appropriate fees and options.

PreviousMessage BridgingNextMessage Execution

Last updated 1 month ago