Your First Cross-Chain dApp with XTalk: A Step-by-Step Guide

Welcome, developer! This guide will walk you through integrating your Solidity smart contracts with the L1X XTalk Protocol to send and receive messages across different blockchains. We'll use a simplified example, similar to SimpleMessageTest.sol, to illustrate the core concepts.

Prerequisites

Before you start, you should have a basic understanding of:

  • Solidity and smart contract development.

  • The concept of cross-chain communication.

  • An XTalk environment set up (or access to a testnet where XTalk contracts like XTalkBeacon are deployed).

Known XTalkBeacon Testnet Addresses

For your convenience, here are some known deployed XTalkBeacon contract addresses on common testnets:

  • Sepolia Testnet:

    • Chain ID: 11155111

    • XTalkBeacon Address: 0x1a99f64254D998d9F6a2912Ca5b19c1DFE326eF8

  • BSC (Binance Smart Chain) Testnet:

    • Chain ID: 97

    • XTalkBeacon Address: 0x1a99f64254D998d9F6a2912Ca5b19c1DFE326eF8

Note: Always verify contract addresses from official project documentation or trusted sources before interacting with them on mainnet or for critical operations.

Goal

Our goal is to create a smart contract that can:

  1. Send a simple text message to a contract on another EVM-compatible chain using XTalk.

  2. Receive a simple text message from another chain via XTalk.

Step 1: Define the IXTalkBeacon Interface

To interact with the XTalk system on any EVM chain, your contract needs to know how to call the XTalkBeacon contract. This is done by defining an interface in your Solidity file.

  • registerMessage: This is the function you'll call on the XTalkBeacon to send your message.

  • getSenderRegistrationNextNonce: You'll use this to get a unique nonce for each message your contract sends, which is important for security.

Step 2: Setting Up Your Contract to Send Messages

Let's create a contract MyXTalkDApp and add a function to send a message. For a production or testnet dApp, the XTalkBeacon address on a specific chain is fixed. You can store this as a constant or an immutable variable in your contract for clarity and safety.

Explanation:

  1. XTALK_BEACON_ADDRESS: This is now an immutable state variable, set in the constructor. When deploying MyXTalkDApp, you would pass the known XTalkBeacon address for the chain you are deploying to (e.g., 0x1a99f64254D998d9F6a2912Ca5b19c1DFE326eF8 for Sepolia or BSC Testnet as per our known addresses list). This makes it clear which beacon your contract is configured to use.

  2. sendMessageToOtherChain Parameters: The function now only takes parameters specific to the message itself, as the beaconAddress is already configured for the contract instance.

  3. Using the Stored Address: Inside sendMessageToOtherChain, IXTalkBeacon(XTALK_BEACON_ADDRESS) is used, referencing the immutable address.

  4. Important Security Note: In a production system, you might want to add a check to ensure msg.sender is the legitimate XTalkBeacon contract on this chain. For example: require(msg.sender == XTALK_BEACON_ADDRESS, "Unauthorized XTalk caller");

Step 3: Setting Up Your Contract to Receive Messages

To receive a message from another chain via XTalk, your contract (or a specific contract you deploy on the destination chain) must implement a special callback function: _xtalkMessageReceived.

Explanation:

  1. _xtalkMessageReceived Signature: The function name and parameters (bytes32, address, uint32, uint32, bytes) must exactly match this signature. The XTalkBeacon on your contract's chain is programmed to call this specific function when it has a message for your contract.

  2. Security (Caller Verification - Optional but Recommended): Although not shown in the most basic SimpleMessageTest.sol, in a real-world scenario, you should verify that msg.sender of the _xtalkMessageReceived call is indeed the trusted XTalkBeacon contract address on the current chain. This prevents unauthorized contracts from spoofing XTalk messages directly to your callback.

  3. Decoding Payload: The _messageData arrives as bytes. Since our sendMessageToOtherChain function sent an ABI-encoded string, we use abi.decode(_messageData, (string)) to get the original text back.

  4. Storing Data: The example stores the message details in a mapping. You can adapt this to your dApp's needs.

  5. Custom Logic: After decoding and storing, you can add any logic your dApp needs to perform based on the received message content or type.

Step 4: Deployment and Interaction Flow

  1. Deploy MyXTalkDApp (or similar contracts) on both the source and destination chains.

    • The instance on the source chain will use sendMessageToOtherChain.

    • The instance on the destination chain will receive the message via _xtalkMessageReceived.

  2. Identify XTalkBeacon Addresses: You'll need the deployed addresses of the XTalkBeacon contracts on both chains. (See the "Known XTalkBeacon Testnet Addresses" section above for examples).

  3. Sending a Message:

    • Call sendMessageToOtherChain on the source chain with the appropriate parameters.

    • The message will be sent to the destination chain via XTalk.

    • The destination chain's _xtalkMessageReceived function will handle the message reception.

By following these steps, you'll be able to send and receive messages across different blockchains using the XTalk Protocol.

Last updated