v1.2 (Beta - Developer Guide)

Using SimpleMessageTest to Understand the XTalk Protocol

1. Overview

Purpose

This document provides a comprehensive guide for developers on how to use the SimpleMessageTest.sol contract. It serves as a practical, hands-on example for sending and receiving cross-chain messages using the L1X XTalk protocol.

SimpleMessageTest.sol is a minimal, developer-friendly smart contract that demonstrates the core functionality of the XTalk protocol. It is designed to be a clear and lucid starting point for building more complex cross-chain applications.

Target Audience & Limitations

This guide is intended for developers building applications on EVM-compatible blockchains.

  • Current Scope: This version of the XTalk protocol and this example support EVM-compatible networks only.

  • Supported Test Networks:

    • BSC Testnet

    • Ethereum Sepolia

Core Concepts

The heart of the XTalk protocol is the XTalkBeacon contract. It acts as a cross-chain "post office," where your contract drops off messages for other chains (registerMessage) and receives incoming messages via a standardized callback (_xtalkMessageReceived).


2. Contract Anatomy

The SimpleMessageTest.sol contract is structured to clearly separate the mandatory XTalk protocol code from the customizable user logic. This is highlighted by the in-code comments.

A. XTalk Infrastructure

These are the parts you must include and configure correctly for your contract to be XTalk-compatible.

  • IXTalkBeacon Interface: A standard Solidity interface that defines how your contract will communicate with the deployed XTalkBeacon.

  • xtalkBeaconAddress State Variable & constructor:

    This is a critical setup step. When you deploy your contract, you must provide the correct address of the XTalkBeacon for the specific blockchain you are deploying on. The contract then casts this address to the IXTalkBeacon interface when it needs to call a beacon function.

  • _xtalkMessageReceived Function:

    This is the mandatory callback function that the beacon executes to deliver a message to your contract.

    • Function Signature: The name and parameters must be exactly _xtalkMessageReceived(bytes32,address,uint32,uint32,bytes).

    • Security: It is crucial to include the require(msg.sender == address(xtalkBeacon), ...) check to ensure that only the legitimate beacon can call this function.

B. User-Defined Logic

This is the part of the contract that you customize to build your application's specific features.

  • Message Struct & receivedMessages Mapping:

    In this example, we use these to store the data from a received message. For your application, you might process a token swap, mint an NFT, or update some other state.

  • MessageReceived Event: This event provides off-chain tracking and visibility for when your contract receives a message. Note that the event for sending a message is emitted by the XTalkBeacon contract itself.

  • invokeMessage Function: This function demonstrates how the user-defined logic prepares data and then hands it off to the XTalk Infrastructure to be sent.


3. How It Works: The Cross-Chain Flow

The following diagram illustrates the end-to-end journey of a message. The L1X Validator Network and the XTalk Consensus Contract on the L1X chain are the core components that make this possible.

The process unfolds in these steps:

  1. Invocation (Source Chain): A user calls invokeMessage on the SimpleMessageTest contract.

  2. Registration (Source Chain): The contract calls registerMessage on the source chain's XTalkBeacon, which emits the XTalkMessageBroadcasted event containing a unique messageId.

  3. Consensus (L1X Network): The L1X network validators observe this event. They process the message, and a sufficient number of them sign it, reaching consensus. This status is recorded in the XTalk Consensus Contract on the L1X chain.

  4. Execution (Destination Chain): Once consensus is reached, the validators relay the message and the collected signatures to the XTalkBeacon on the destination chain. The beacon verifies the signatures and calls _xtalkMessageReceived on the target contract, completing the cross-chain transaction.


4. Practical Guide: Deployment and Interaction

Supported Networks & Chain IDs

List the currently supported test networks and their corresponding Chain IDs, which you will need for the _destinationChainId parameter when sending a message.

  • BSC Testnet:

    • Chain ID: 97

  • Ethereum Sepolia:

    • Chain ID: 11155111

Deployment

  1. Compile: Use a Solidity compiler (version ^0.8.0 or compatible) to compile SimpleMessageTest.sol.

  2. Deploy: Deploy the compiled contract to a supported network (e.g., BSC Testnet or ETH Sepolia).

  3. Provide Beacon Address: During deployment, you must provide the correct XTalkBeacon address for that network in the constructor.

    • BSC Testnet XTalkBeacon Address: 0x283217CFb842A235994397a36714eF90F7744B51

    • ETH Sepolia XTalkBeacon Address: 0x8cA818D30c01AD6ebD2273CC419553F38fE7c92f

Sending a Message

To send a message, call the invokeMessage function on your deployed contract.

  • _destinationChainId: The unique identifier for the destination chain. Use 97 for BSC Testnet or 11155111 for Ethereum Sepolia.

  • _destinationAddress: The address of the recipient contract on the destination chain, formatted as bytes32.

  • _message: The string message you want to send.

Confirming a Message on the Destination Chain

  1. When you call invokeMessage, listen for the XTalkMessageBroadcasted event on the XTalkBeacon contract. It contains the messageId.

  2. After a short delay for the L1X Network to relay the message, you can check for its arrival on the destination chain.

  3. Call the receivedMessages public mapping on the destination contract with the messageId to retrieve the stored message data and confirm its receipt.

Tracking Message Status on the L1X Network

The ultimate source of truth for a message's journey is the XTalk Consensus Contract deployed on the L1X Network. You can query this contract directly using the messageId to see its current consensus status, including how many validators have signed it.

The address for this contract on L1X Testnet v2 is:

  • XTalk Consensus Contract: ce527bdc3eeaa201a2706ab2e447fc7f0db5cb68

The following script shows how to do this using the @l1x/l1x-wallet-sdk.

Understanding the Consensus Status Response

The JSON object returned by get_consensus_status represents the complete state of a cross-chain message as it moves through the L1X consensus process. Here is a breakdown of each field:

Validator and Confirmation Counts

These fields provide an overview of the validator set and the progress of votes for this specific message.

  • total_listener_validators: The total number of registered "Listener" validators at the time the message was processed. Listeners are responsible for observing and confirming the initial event on the source chain.

  • total_signer_validators: The total number of registered "Signer" validators. Signers are responsible for cryptographically signing the message payload that will be executed on the destination chain.

  • total_relayer_validators: The total number of registered "Relayer" validators. Relayers are responsible for broadcasting the transaction to the destination chain and confirming its final state.

  • agreed_listener_validators: The current count of Listener validators who have successfully voted and agreed on the validity of the source chain event.

  • agreed_signer_validators: The current count of Signer validators who have successfully voted on and signed the destination payload.

  • agreed_relayer_confirmations: The current count of Relayer validators who have confirmed that the transaction was successfully executed on the destination chain.

  • disagreed_relayer_confirmations: The current count of Relayer validators who have reported that the transaction failed on the destination chain.

Lifecycle and Timestamps

These fields track the message's current stage and when key milestones were reached.

  • consensus_stage: The current stage of the message. Possible values are:

    • 'Pending': The message has not yet reached consensus in any phase.

    • 'ListenerFinalized': The Listeners have reached consensus on the source chain event.

    • 'SignerFinalized': The Signers have reached consensus on the destination payload.

    • 'RelayerBroadcasted': The Relayers have successfully broadcasted the transaction to the destination chain.

    • 'RelayerFinalized': The Relayers have confirmed the final status (success or failure) of the destination transaction.

  • listener_finalized_timestamp: A Unix timestamp (in milliseconds) of when the Listener consensus was reached.

  • signer_finalized_timestamp: A Unix timestamp (in milliseconds) of when the Signer consensus was reached.

  • relayer_finalized_timestamp: A Unix timestamp (in milliseconds) of when the Relayer consensus was reached.

    • Note on relayer_finalized_timestamp: This field is reserved for future protocol enhancements where relayers explicitly confirm the final on-chain status (e.g., after a certain number of block confirmations). In the current implementation, the most reliable indicator that a message has been successfully passed to the destination chain is the presence of a non-empty destination_tx_hash.

Message Payload and Routing

These fields contain the core data of the cross-chain message and the necessary information to route it correctly.

  • signer_payload: The raw byte payload that the Signer validators have agreed upon. This is the exact data passed to the XTalkBeacon on the destination chain.

  • signer_signatures: A list of the raw, recoverable signatures from the Signer validators. These are submitted to the destination XTalkBeacon to prove the payload's authenticity.

Transaction and Address Details

These fields provide the specific identifiers and addresses involved in the cross-chain transaction.

  • source_network_id: The chain ID of the network where the message originated.

  • source_tx_hash: The transaction hash of the initial call on the source chain.

  • flow_contract_address: The address of an intermediary "flow" contract on the L1X network that may have processed the event data.

  • source_contract_address: The address that emitted the event on the source chain (i.e., the XTalkBeacon).

  • destination_tx_hash: The transaction hash of the execution call on the destination chain, as reported by the first relayer.

  • destination_network_id: The chain ID of the target network.

  • destination_contract_address: The address of the target contract on the destination chain.

  • destination_relayer_address: The address of the relayer validator that broadcast the transaction.


5. Next Steps

This SimpleMessageTest contract and its usage guide are designed to be your launchpad. You can use this contract as a boilerplate for your own projects. By replacing the user-defined logic, you can build powerful cross-chain applications such as:

  • Cross-chain token swaps

  • Multi-chain NFT marketplaces

  • Decentralized governance across multiple networks


6. Example: Standalone Ethers.js Script

This example shows how to interact with the contract in a standalone Node.js script using the ethers library (v6), without relying on a framework like Hardhat.

Important Note: Listening for the Correct Event

When you call invokeMessage, your contract does not emit an event. The event is emitted by the XTalkBeacon contract that invokeMessage calls. You must listen to the XTalkBeacon contract for the XTalkMessageBroadcasted event to get the messageId and confirm the message was sent.

Important Note: Address to bytes32 Conversion

The _destinationAddress parameter in the invokeMessage function expects a bytes32 value. However, standard Ethereum addresses are 20-byte values. You must pad the 20-byte address with leading zeros to convert it to a 32-byte value. With ethers.js, you can do this easily:

Sample Interaction Script

This script shows a complete flow: setting up a connection, sending a message, and retrieving the messageId by listening to the XTalkBeacon contract's events.

Last updated