Nomad Docs
  • Nomad 101
    • Funds Recovery
    • Introduction
    • Our Mission
    • Getting Started
  • The Nomad Protocol
    • Overview
    • Cross-chain Messaging
      • Lifecycle of a Message
    • Verification Mechanisms
      • Background on Verification
      • Native Verification
      • External Verification
      • Optimistic Verification
      • Comparing Mechanisms
    • Security
      • Root of Trust
        • Fraud
          • Optimistic Timeout Period
          • Fraud Recovery
        • App-Governed Root of Trust
        • Liveness Assumptions
      • Attack Vectors
        • Key Compromise
        • Economic Attacks
        • Smart Contract Bugs
      • Long-Term Security
        • Permissionless Watchers
        • Financial Controls
        • Cross-Domain MEV
    • Smart Contracts
      • Home
      • Replica
      • XAppConnectionManager
    • Off-chain Agents
      • Updater
      • Watchers
      • Relayer
      • Processor
  • Token Bridge
    • Overview
    • How to Bridge
      • Using Etherscan
      • Nomad Bridge App
      • Testnet Bridge App
    • Asset Issuers
      • Custom Representations
    • Deployed Tokens
      • Mainnet
      • Testnet
    • Smart Contracts
      • BridgeRouter
      • TokenRegistry
      • BridgeToken
      • BridgeMessage
    • Architecture
    • FAQ
  • Governance Bridge
    • Overview
    • Zodiac: Nomad Module
    • Smart Contracts
      • NomadModule
    • Architecture
  • Developers
    • Quickstart
      • Send Messages
      • Receive Messages
    • Environments
      • Domain (Chain) IDs
    • Application Developers
      • Building xApps
      • SDK
        • Contracts SDK
        • Typescript SDK
      • Examples
        • Ping Pong
        • Example Bridge GUI
        • xApp Example
      • Advanced
        • Router Pattern
    • Node Operators
      • Running Agents Guide
        • Troubleshooting
      • Running a Watcher
      • Agent Operations
      • Agent Gas Values
      • The Keymaster
    • Core Developers
      • Upgrade Setup
      • Deploying Contracts
        • Development
        • Production
  • Operational Security
    • Audits
    • Bug Bounty
    • Governance
    • Contracts
    • Agent Operations
  • Resources
    • Awesome Interoperability
    • Brand Kit
    • FAQ
    • Glossary
    • GitHub
    • Discord
    • Twitter
    • Website
Powered by GitBook
On this page
  • Interface
  • Hello World
  • Example Usage
  • Advanced Examples
  • FAQs
  1. Developers
  2. Quickstart

Send Messages

The on-chain API for sending cross-chain messages

Send messages to other chains by calling the dispatch() method on the Home contract.

Interface

The dispatch method is simple. Just specify the destination chain, the message recipient, and the message you want to send!

  • _destination is a Nomad domain. List of domains here

  • _recipient is the address that will receive the message on the destination chain. The _recipient must be set up to receive Nomad messages by implementing handle.

  • _message contains the contents of your cross-chain message

/*
 * @notice Dispatch the message to the destination domain & recipient
 * @param _destination Domain of destination chain
 * @param _recipient Address of recipient on destination chain as bytes32
 * @param _message Raw bytes content of message
 */
 function dispatch(
     uint32 _destination,
     bytes32 _recipient,
     bytes memory _message
 ) external {
   // message is sent to recipient address on destination chain
 }

Hello World

 import {TypeCasts} from "@nomad-xyz/contracts-core/libs/TypeCasts.sol";
 
 contract HelloWorld {
    // address of the Nomad Home contract
    immutable address public home;

    /*
     * @notice Send a Hello message to another chain :)
     * @param _destination Domain of destination chain
     * @param _recipient Address of recipient on destination chain
     */
    function hello(uint32 _destination, address _recipient) {
        // craft your hello message
        bytes memory _message = "hello world >:~)";
        // cast recipient to bytes32
        bytes32 _recip = TypeCasts.addressToBytes32(_recipient);
        // dispatch your message across chains!
        home.dispatch(_destination, _recipient, _message);
    }
}

Example Usage

contract PingPong {
    // registry of opponents on each chain
    mapping(uint32 => bytes32) public opponents;

    /**
     * @notice Start a PingPong match with the destination chain
     * by serving the ball.
     * @param _destination The domain to initiate the match with
     */
    function serve(uint32 _destination) external {
        // serve to your opponent on the destination domain
        bytes32 _recipient = opponents[_destination];
        // Create a message for the first volley.
        // the PingPong match always begins with a Ping
        bool _ping = true;
        // the volley count always starts at 0
        uint256 _volley = 0;
        // encode the PingPong message using abi.encode
        bytes memory _message = abi.encode(_ping, _volley);
        // dispatch your message across chains!
        home.dispatch(_destination, _recipient, _message);
    }

}

Advanced Examples

FAQs

Why domains instead of chain IDs?

Chain IDs change during intentional consensus splits such as the merge to Eth2.0; additionally, not all chains even have a Chain ID! We created Nomad domains to have a clean standard for chains supported by Nomad which didn't suffer from these challenges.

Why are recipients bytes32 instead of address?

We use bytes32 instead of address so that, in the future, messages will be compatible with other chain VMs like Cosmos and Polkadot. In the EVM, addresses are 20 bytes long, but most other chains have 32 byte addresses. Worry not - we have a TypeCasts.sol library to help convert between these types easily.

PreviousQuickstartNextReceive Messages

Last updated 2 years ago

The example app we know and love - but make it cross-chain

Ready to get a little more advanced? Let's play PingPong across chains

BridgeRouter.sol

GovernanceRouter.sol

🤝
🏓
send
executeGovernanceActions