> For the complete documentation index, see [llms.txt](https://l1x-sdk.gitbook.io/l1x-developer-interface/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://l1x-sdk.gitbook.io/l1x-developer-interface/multi-chain-with-x-talk/start-building-with-x-talk/cross-chain-data-and-message-passing-xcdp/v1.1-latest/your-first-cross-chain-dapp-with-xtalk-a-step-by-step-guide.md).

# 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.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IXTalkBeacon {
    // Function to initiate a cross-chain message
    function registerMessage(
        uint32 _destinationChainId,
        bytes32 _destinationAddress,
        bytes memory _messageData,
        uint32 _messageType,
        uint256 _messageNonce
    ) external;

    // Function to get the next valid nonce for your contract
    function getSenderRegistrationNextNonce(address _sender) external view returns (uint256);
}

// Your contract will go here
// contract MyXTalkDApp is ...
```

* `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.

```solidity
contract MyXTalkDApp {
    // Address of the XTalkBeacon on the current chain.
    // For Sepolia Testnet, for example:
    address public immutable XTALK_BEACON_ADDRESS;

    // Event to log message sending attempts (optional)
    event MessageSentToXTalk(
        uint32 indexed destinationChainId,
        bytes32 indexed destinationContractAddress,
        string messageContent,
        uint256 nonceUsed
    );

    constructor(address beaconContractAddress) {
        XTALK_BEACON_ADDRESS = beaconContractAddress;
    }

    // Function to send a cross-chain message
    function sendMessageToOtherChain(
        uint32 destinationChainId,  // The ID of the chain you want to send to
        bytes32 destinationContractAddress, // The address of your target contract on the other chain (as bytes32)
        string memory myTextMessage    // The actual text you want to send
    ) public {
        // 1. Define a message type (application-specific)
        uint32 messageType = 1; // You can define different types for different actions

        // 2. Encode your payload (the string message)
        // The XTalk system transmits data as `bytes`. So, we ABI-encode our string.
        bytes memory encodedMessagePayload = abi.encode(myTextMessage);

        // 3. Get the next valid nonce for your contract
        // This makes each message unique from your contract's perspective on the source chain.
        IXTalkBeacon beacon = IXTalkBeacon(XTALK_BEACON_ADDRESS); // Use the stored beacon address
        uint256 nonce = beacon.getSenderRegistrationNextNonce(address(this));

        // 4. Call `registerMessage` on the XTalkBeacon
        beacon.registerMessage(
            destinationChainId,
            destinationContractAddress,
            encodedMessagePayload,
            messageType,
            nonce
        );

        // Optional: Emit an event in your contract to log that a message was sent
        emit MessageSentToXTalk(destinationChainId, destinationContractAddress, myTextMessage, nonce);
    }
}
```

**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`.

```solidity
// Continuing our MyXTalkDApp contract...
contract MyXTalkDApp {
    // ... (sendMessageToOtherChain function from above) ...

    // Data structure to store received message details
    struct ReceivedMessage {
        bytes32 messageId;          // Unique ID from XTalk system
        address sourceInvokerAddress; // Address of the contract that sent the message (on source chain)
        uint32 sourceChainId;       // ID of the chain the message came from
        uint32 messageType;         // Application-specific type from sender
        string actualMessage;       // The decoded text message
        bytes rawMessageData;       // The raw payload received
    }

    mapping(bytes32 => ReceivedMessage) public receivedXTalkMessages;
    event MessageReceived(bytes32 indexed messageId, address sourceInvoker, string message);

    // This is the REQUIRED callback function for XTalk
    function _xtalkMessageReceived(
        bytes32 _messageId,             // The unique XTalk message ID
        address _sourceInvokerAddress,  // Who sent it on the source chain
        uint32 _sourceChainId,          // Which chain it came from
        uint32 _messageType,            // The type defined by the sender
        bytes memory _messageData       // The raw payload (our ABI-encoded string)
    ) public {
        // 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");

        // 1. Decode the message payload if you know its type
        // Assuming the sender used `abi.encode(string)` like our `sendMessageToOtherChain` function
        string memory decodedTextMessage = abi.decode(_messageData, (string));

        // 2. Store the received message details
        receivedXTalkMessages[_messageId] = ReceivedMessage({
            messageId: _messageId,
            sourceInvokerAddress: _sourceInvokerAddress,
            sourceChainId: _sourceChainId,
            messageType: _messageType,
            actualMessage: decodedTextMessage,
            rawMessageData: _messageData
        });

        // 3. Emit an event to signal the message was received and processed
        emit MessageReceived(_messageId, _sourceInvokerAddress, decodedTextMessage);

        // 4. (Optional) Add any custom logic here to act upon the received message
        // For example, update state, call another function, etc.
    }
}
```

**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.
