---
description: Step by Step guide and Repository link provided in Templates Section.
---

# Build your first X-Talk Swap Contract

### Building Blocks for X-Talk Swap

1. Smart Contracts on Source Chain and Destination Chain (example ethereum, binance chain and solana) that will be the endpoints for swapping tokens. This is runtime agnostic.&#x20;
2. L1X X-Talk Swap Contract that includes Source Chain Contract Registration Initialisation and X-Talk Swap Contract Deployment and Initialisation to facilitate token swapping.&#x20;



### Implementing EVM Smart Contract on Source/Destination Chain

Implement below evm-compatible smart contarct on source and destination chain. Once the contract is deployed, _**use the source chain contract address during registration on X-Talk node.**_



**Step 1: Initialize a New Project**

1.  **Create a New Directory** (if you're starting fresh):

    ```bash
    mkdir evm_swap
    cd evm_swap
    ```
2.  **Initialize a new NPM project**:

    ```bash
    npm init -y
    ```

**Step 2: Install Hardhat and Set Up the Project**

1.  **Install Hardhat**:

    ```bash
    npm install --save-dev hardhat
    ```
2.  **Set up the Hardhat project**: Run the setup command and choose to create a TypeScript project:

    ```bash
    npx hardhat init
    ```

    When prompted, select to create a TypeScript project. Follow the prompts to add a `.gitignore` and install the project's dependencies.

**Step 3: Install Necessary Plugins and Dependencies**

1.  **Install TypeScript-related dependencies**:

    ```bash
    npm install --save-dev ts-node typescript @types/node @types/mocha
    ```
2.  **Install OpenZeppelin Contracts**:

    ```bash
    npm install @openzeppelin/contracts
    ```
3.  **Install Ethers and Hardhat Ethers** (ensure compatibility):

    ```bash
    npm install --save-dev @nomiclabs/hardhat-ethers ethers
    ```



**Step 4: Configure TypeScript**

Update **`tsconfig.json` file** in your project root with the following content:

```json
{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "resolveJsonModule": true
  },
  "include": [
    "./scripts/**/*",
    "./test/**/*",
    "./hardhat.config.ts"
  ],
  "exclude": ["node_modules"]
}
```



**Step 5: Write your smart contract**

Create **Swap.sol** inside the **contracts** directory and paste your contract code there.

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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

interface IERC20Extended is IERC20 {
    function decimals() external view returns (uint8);
}

contract Swap {
    using SafeERC20 for IERC20;

    event XTalkMessageBroadcasted(
        bytes message,
        string destinationNetwork,
        string destinationSmartContractAddress
    );

    function _l1xSend(
        address senderAddress,
        address recipientAddress, 
        address sourceTokenAddress, 
        address destinationTokenAddress, 
        uint256 sourceAmount, 
        uint256 destinationAmount, 
        string memory destinationSmartContractAddress, 
        string memory destinationNetwork
    ) external {
        // Convert the struct to bytes
        bytes memory messageBytes = abi.encode(
            senderAddress,
            recipientAddress,
            sourceAmount,
            destinationAmount,
            sourceTokenAddress,
            destinationTokenAddress
        );

        IERC20(sourceTokenAddress).safeTransferFrom(senderAddress,address(this), sourceAmount);
        emit XTalkMessageBroadcasted(messageBytes, destinationNetwork, destinationSmartContractAddress);
    }

    function _l1xReceive(bytes32 globalTxId, bytes memory message) external {
        (
            address recipientAddress, 
            uint256 destinationAmount,
            address destinationTokenAddress
        ) = abi.decode(message, (address, uint256, address));
        IERC20(destinationTokenAddress).safeTransfer(recipientAddress, destinationAmount);  
    }
}
```



**Step 6: Compile and Deploy Your Contracts**

1.  **Compile your project**:

    ```bash
    npx hardhat compile
    ```



2. **Write deployment scripts or tests** as needed, using the setup you've created. Example Provided below.

```javascript
//scripts/deploy.js
 const hre = require("hardhat");

 async function main() {
     const [deployer] = await hre.ethers.getSigners();
 
     console.log(
         "Deploying contracts with the account:",
         deployer.address
     );
 
     // getBalance is a method on the provider, not the signer
     console.log("Account balance:", (await deployer.provider.getBalance(deployer.address)).toString());
 
     const SimpleSwap = await hre.ethers.getContractFactory("Swap");
     const SimpleSwapContract = await SimpleSwap.deploy([deployer.address]);
 
     await SimpleSwapContract.waitForDeployment();
 
     console.log("SimpleSwap contract deployed to:", await SimpleSwapContract.getAddress());
 }
 
 main()
     .then(() => process.exit(0))
     .catch((error) => {
         console.error(error);
         process.exit(1);
 });
```



3. **Sample Hardhat Config JS File:** Configure your Hardhat project by editing hardhat.config.js. Add your network in this file with relevant details. Ensure it looks like this.&#x20;

```javascript
//hardhat.config.js
require("@nomicfoundation/hardhat-toolbox");

// Example Only. Please use MPC or env
const PRIVATE_KEY = "YOUR_PRIVATE_KEY"; 


module.exports = {
  solidity: "0.8.24",
  networks: {
    bscTestnet: {
      url: "https://data-seed-prebsc-1-s1.binance.org:8545/", // BSC Testnet RPC URL
      chainId: 97,
      accounts: [PRIVATE_KEY] 
    },
    sepolia: {
      url: "https://rpc.sepolia.org", // Sepolia Testnet RPC URL
      accounts: [PRIVATE_KEY],
    },
  }
};
```



4. **Deployment Bash - Source**

Deploy the Smart Contract on Source Chain

```bash
npx hardhat run scripts/deploy.js --network SOURCE_NETWORK
```

Save this SOURCE\_CONTRACT\_ADDRESS to be used while initiating swap.

Also, Use this SOURCE\_CONTRACT\_ADDRESS  (without 0x) to register on X-Talk Node.

[\
](https://l1x-sdk.gitbook.io/l1x-developer-interface/v/multi-chain-with-x-talk/start-building-with-x-talk/x-talk-swap/build-your-first-x-talk-swap-contract)

5. **Deployment Bash - Destination**

Similarly, deploy the same smart contract on the Destination Chain.

```bash
npx hardhat run scripts/deploy.js --network DESTINATION_NETWORK
```

Save this DESTINATION\_CONTRACT\_ADDRESS  to be used while initiating swap.



### Implementing L1X X-Talk Swap Contract&#x20;

X-Talk Swap Contract is at the core of token swapping and liquidity management across different chains.&#x20;



Create a new L1X project that provides the necessary files to get started

```bash
cargo l1x create xtalk_swap
```



Use the provided code below to implement the cross-chain swap logic. The X-Talk Swap Contract consists of fundamental building blocks which are re-usable across all development standards with X-Talk for token swapping.&#x20;

1. Payload Definition that is being received. This could be deterministic or a generic vector of bytes. You can be deterministic or make this logic programmable.&#x20;
2. Saving the event data that will store the event that is received.&#x20;
3. Payload Logic that will allow you to implement logic based on what the destination payload required.&#x20;
4. Payload Transformation that will be based on the destination runtime.&#x20;
5. Emitting the Event to be sent to the Destination.&#x20;

```rust
//lib.rs
use borsh::{BorshDeserialize, BorshSerialize};
use ethers::{
    abi::{decode, ParamType, Token},
    prelude::{parse_log, EthEvent},
};
use l1x_sdk::{contract, store::LookupMap};
use serde::{Deserialize, Serialize};

const STORAGE_CONTRACT_KEY: &[u8; 4] = b"swap";
const STORAGE_EVENTS_KEY: &[u8; 6] = b"events";

#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
pub struct SwapInitiated {
    sender_address: l1x_sdk::types::Address,
    recipient_address: l1x_sdk::types::Address,
    source_amount: l1x_sdk::types::U256,
    destination_amount: l1x_sdk::types::U256,
    source_token_address: l1x_sdk::types::Address,
    destination_token_address: l1x_sdk::types::Address,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SwapInitiatedSolidity {
    sender_address: ethers::types::Address,
    recipient_address: ethers::types::Address,
    source_amount: ethers::types::U256,
    destination_amount: ethers::types::U256,
    source_token_address: ethers::types::Address,
    destination_token_address: ethers::types::Address,
}

impl From<SwapInitiatedSolidity> for SwapInitiated {
    fn from(event: SwapInitiatedSolidity) -> Self {
        Self {
            sender_address: l1x_sdk::types::Address::from(event.sender_address.0),
            recipient_address: l1x_sdk::types::Address::from(event.recipient_address.0),
            source_amount: Swap::from_ethers_u256_to_l1x_u256(event.source_amount),
            destination_amount: Swap::from_ethers_u256_to_l1x_u256(event.destination_amount),
            source_token_address: l1x_sdk::types::Address::from(event.source_token_address.0),
            destination_token_address: l1x_sdk::types::Address::from(
                event.destination_token_address.0,
            ),
        }
    }
}

#[derive(Clone, Debug, EthEvent, Serialize, Deserialize)]
#[ethevent(name = "XTalkMessageBroadcasted")]
pub struct XTalkMessageBroadcasted {
    message: ethers::abi::Bytes,
    destination_network: String,
    destination_smart_contract_address: String,
}

#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
pub struct Payload {
    data: Vec<u8>,
    destination_network: String,
    destination_contract_address: String,
}

#[derive(BorshSerialize, BorshDeserialize)]
pub struct Swap {
    events: LookupMap<String, SwapInitiated>,
    total_events: u64,
}

impl Default for Swap {
    fn default() -> Self {
        Self {
            events: LookupMap::new(STORAGE_EVENTS_KEY.to_vec()),
            total_events: u64::default(),
        }
    }
}

#[contract]
impl Swap {
    /// Generate contract based on bytes in storage
    fn load() -> Self {
        match l1x_sdk::storage_read(STORAGE_CONTRACT_KEY) {
            Some(bytes) => match Self::try_from_slice(&bytes) {
                Ok(contract) => contract,
                Err(_) => {
                    panic!("Unable to parse contract bytes")
                }
            },
            None => {
                panic!("The contract isn't initialized")
            }
        }
    }

    /// Save contract to storage
    fn save(&mut self) {
        match borsh::BorshSerialize::try_to_vec(self) {
            Ok(encoded_contract) => {
                l1x_sdk::storage_write(STORAGE_CONTRACT_KEY, &encoded_contract);
                log::info!("Saved event data successfully");
            }
            Err(_) => panic!("Unable to save contract"),
        };
    }

    /// Instantiate and save contract to storage with default values
    pub fn new() {
        let mut contract = Self::default();
        contract.save();
    }

    /// Save event to contract storage
    ///
    /// - `global_tx_id`: Global transaction identifier
    /// - `source_id`: Source Identifier
    /// - `event_data`: Data to store in contract's storage
    pub fn save_event_data(event_data: Vec<u8>, global_tx_id: String) {
        l1x_sdk::msg(&format!(
            "********************global tx id {} **************",
            global_tx_id
        ));

        let mut contract = Self::load();

        log::info!("Received event data!!!");
        assert!(!global_tx_id.is_empty(), "global_tx_id cannot be empty");
        assert!(!event_data.is_empty(), "event_data cannot be empty");
        assert!(
            !contract.events.contains_key(&global_tx_id),
            "event is saved already"
        );

        let event_data = match base64::decode(event_data) {
            Ok(data) => data,
            Err(_) => panic!("Can't decode base64 event_data"),
        };

        let log: ethers::types::Log =
            serde_json::from_slice(&event_data).expect("Can't deserialize Log object");

        l1x_sdk::msg(&format!("{:#?}", log));
        let event_id = log.topics[0].to_string();
        if let Ok(swap_initiated_event) = parse_log::<XTalkMessageBroadcasted>(log.clone()) {
            let event = decode(
                &[
                    ParamType::Address,
                    ParamType::Address,
                    ParamType::Uint(256),
                    ParamType::Uint(256),
                    ParamType::Address,
                    ParamType::Address,
                ],
                &swap_initiated_event.message,
            )
            .unwrap();

            let event = SwapInitiatedSolidity {
                sender_address: event[0].clone().into_address().unwrap(),
                recipient_address: event[1].clone().into_address().unwrap(),
                source_amount: event[2].clone().into_uint().unwrap(),
                destination_amount: event[3].clone().into_uint().unwrap(),
                source_token_address: event[4].clone().into_address().unwrap(),
                destination_token_address: event[5].clone().into_address().unwrap(),
            };

            contract.save_swap_initiated_event(
                global_tx_id,
                event_id,
                event,
                swap_initiated_event.destination_network,
                swap_initiated_event.destination_smart_contract_address,
            );
        } else {
            panic!("invalid event!")
        }

        contract.save()
    }

    fn save_swap_initiated_event(
        &mut self,
        global_tx_id: String,
        event_id: String,
        event: SwapInitiatedSolidity,
        destination_network: String,
        destination_contract_address: String,
    ) {
        let event_data: SwapInitiated = event.clone().into();
        l1x_sdk::msg(&format!("{:#?}", event_data));
        let key = Swap::to_key(global_tx_id.clone(), event_id);
        self.events.insert(key, event_data);

        let payload = Swap::get_execute_swap_payload(
            global_tx_id,
            event,
            destination_network,
            destination_contract_address,
        );
        l1x_sdk::emit_event_experimental(payload);
    }

    fn from_ethers_u256_to_l1x_u256(number: ethers::types::U256) -> l1x_sdk::types::U256 {
        let mut tmp = vec![0u8; 32];
        number.to_little_endian(&mut tmp);
        let destination_amount = l1x_sdk::types::U256::from_little_endian(&tmp);
        destination_amount
    }

    pub fn to_key(global_tx_id: String, event_type: String) -> String {
        global_tx_id.to_owned() + "-" + &event_type
    }

    fn get_execute_swap_payload(
        global_tx_id: String,
        event: SwapInitiatedSolidity,
        destination_network: String,
        destination_contract_address: String,
    ) -> Payload {
        let message_encoded = ethers::abi::encode(&[
            Token::Address(event.recipient_address),
            Token::Uint(event.destination_amount),
            Token::Address(event.destination_token_address),
        ]);

        let signature = "_l1xReceive(bytes32,bytes)";
        let payload_encoded = ethers::abi::encode(&[
            Token::FixedBytes(hex::decode(global_tx_id).unwrap()),
            Token::Bytes(message_encoded),
        ]);

        let hash = ethers::utils::keccak256(signature.as_bytes());
        let selector = &hash[..4];
        let payload = [&selector[..], &payload_encoded[..]].concat();
        l1x_sdk::msg(&format!("payload --> {}", hex::encode(payload.clone())));
        return Payload {
            data: payload,
            destination_network,
            destination_contract_address: destination_contract_address,
        };
    }
}
```



**X-Talk Swap Contract Components**&#x20;

**Swap Level Functions**: manage the core processes of initiating and executing swap contracts between different blockchain networks. They ensure transparent and secure asset exchange by defining swap terms, obtaining mutual consent, facilitating asset transfer, and providing status updates throughout the transaction.

**Registration Level Functions**: deal with registration and management of participants in the X-Talk swap platform. By enabling registration, a trusted environment is established while allowing participants to maintain control over their engagement.

**Oracle Service Level Functions**: allow integrating external data sources into the swap contracts to ensure accuracy and reliability. They facilitate the retrieval, validation, and utilization of real-time data, such as exchange rates or asset prices, enhancing the integrity and efficiency of swap transactions.



The Fundamental Building Blocks of X-Talk Swap require the below building blocks in X-Talk Swap Contract.&#x20;

* **Data Structures**: Define messages and events used within the contract.
* **Event Handling**: Parse, log, and handle blockchain events.
* **State Management**: Load and save the contract's state to maintain event records.
* **Message Parsing**: Convert blockchain event logs into usable data formats.
* **Event Emission and Logging**: Emit structured logs for cross-chain messaging.
* **Security**: Ensure that only valid and expected data is processed.



Ensure you have all the necessary packages, libraries and dependencies in your **cargo.toml** file as below.&#x20;

```toml
[package]
name = "swap-example"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
borsh = { version = "0.9", features = ["const-generics"] }
l1x-sdk = "0.3.1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
base64 = "*"
ethers = "2.0.11"
getrandom = { version = "0.2.10", features = ["js"] }
hex = "0.4"
log = "0.4.20"
```



To deploy the X-Talk Swap contract, you can use this command on your project level. After successfully building, you will find the "project\_name.o" file in target/l1x/release folder. This is the object file which will be deployed.&#x20;

```bash
cargo l1x build 
```



To deploy your contract, use an existing L1X Account with L1X for Mainnet and L1X TestNet for TestNet.&#x20;

**Create Wallet**

Create your own wallet to generate a new keypair.

```bash
l1x-cli-beta wallet create
```

**Import Wallet**

Import your existing wallet using the l1x-cli-beta tool, by providing a private key. If you don't have one, Create Wallet.

```bash
l1x-cli-beta wallet import YOUR_PRIV_KEY
```

Response will be as below

```sh
Wallet Imported Successfully
{
  "address": "YOUR_ADDRESS",
  "privateKey": "YOUR_PRIV_KEY"
}
```

**Default Wallet**

After Importing your wallet, set it to be the default interaction account.

```bash
l1x-cli-beta wallet default YOUR_ADDRESS
```



**-- Check Endpoints in Interface Essentials for TestNet Faucet**



Deploy your X-Talk Swap Contract with l1x-cli-beta&#x20;

```bash
l1x-cli-beta contract deploy ./target/l1x/release/swap_example.o --endpoint https://v2-testnet-rpc.l1x.foundation
```

Response expected:&#x20;

```bash
Contract Deployed Successfully:
-----------------------------------------------------------------------
{
  "contract_address": "YOUR_CONTRACT_ADDRESS",
  "hash": "HASH"
}
```



To initiate your smart contract, use this command:

```bash
l1x-cli-beta contract init YOUR_CONTRACT_ADDRESS --endpoint https://v2-testnet-rpc.l1x.foundation --fee_limit 100000 
```

Response expected:&#x20;

```bash
Contract Initialized Successfully:
-----------------------------------------------------------------------
{
  "contract_address": "YOUR_INSTANCE_ADDRESS",
  "hash": "HASH"
}
```



The instance address is your contract address which you can use to call your functions and interact.



### **Register Source Chain Contract and X-Talk Swap Contract with X-Talk Node**&#x20;

X-Talk Nodes allow for data listening and send to the X-Talk Swap contract.&#x20;

To register your addresses to the source registry, you need to call this:

```bash
l1x-cli-beta contract call SOURCE_REGISTRY_INSTANCE_ADDRESS register_new_source --args "{\"destination_contract_address\": \"YOUR_FLOW_CONTRACT_ADDRESS\", \
\"source_contract_address\": \"EVM_ADDRESS_ON_SOURCE_CHAIN\", \
\"source_chain\": \"SOURCE_NETWORK\", \
\"event_filters\": [\"TOPIC_OF_YOUR_EVENT\"]}" --endpoint https://v2-testnet-rpc.l1x.foundation --fee_limit 100000
```

```
SOURCE_REGISTRY_INSTANCE_ADDRESS => This is provided
source_contract_address => Without 0x, This is the contract address you want to listen to
TOPIC_OF_YOUR_EVENT => Topic of the event
YOUR_FLOW_CONTRACT_ADDRESS => The initiated X-TalK Swap Contract Address
```

Request Example:&#x20;

```bash
l1x-cli-beta contract call b97f1a3708ae6d7df6ada0c695ce29e8acef954e register_new_source --args "{\"destination_contract_address\": \"512645313ec01dce17f023f5f710a07f010649cc\", \"source_contract_address\": \"011Fd5aE974A75e702388Cb798c57403610d93d1\", \"source_chain\": \"sepolia\", \"event_filters\": [\"5c6877990d83003ae27cf7c8f1a9d622868080df757847943133b78663358e42\"]}" --endpoint https://v2-testnet-rpc.l1x.foundation --fee_limit 100000
```



To validate that your data has been registered to the registry:

```bash
l1x-cli-beta contract view SOURCE_REGISTRY_INSTANCE_ADDRESS get_sources_from --args "{ \"from_index\": \"0\" }" --endpoint https://v2-testnet-rpc.l1x.foundation
```

Response Example:&#x20;

```bash
"{\\"index\\":1,\\"sources\\":[[{\\"destination_contract_address\\":\\"512645313ec01dce17f023f5f710a07f010649cc\\",\\"source_contract_address\\":\\"011Fd5aE974A75e702388Cb798c57403610d93d1\\",\\"source_chain\\":\\"sepolia\\",\\"event_filters\\":[\\"5c6877990d83003ae27cf7c8f1a9d622868080df757847943133b78663358e42\\"]},\\"Create\\"]]}"
```



You have successfully deployed your first Bridgeless Cross-Chain Token Swapping Application.&#x20;



### Initiate Swap

1. **Add Script:** Add below listed initiateSwap.js at scripts folder of Souce Chain. Update all relevant details related to Source and Destination network.
   1. **Ensure that your SOURCE\_WALLET has SOURCE\_TOKEN in it.**
   2. **Ensure that your DESTINATION\_CONTRACT\_ADDRESS has DESTINATION\_TOKEN.**

```javascript
//scripts/initiateSwap.js

const hre = require("hardhat");
const { ethers } = hre;


async function main() {
  const [deployer, user] = await ethers.getSigners();


  console.log("Deployer address:", deployer.address);


  const simpleSwap = await ethers.getContractFactory("Swap");
  const simpleSwapAddress = "SOURCE_CONTRACT_ADDRESS";
  const simpleSwapContract = simpleSwap.attach(simpleSwapAddress);


  const tokenAddress = "SOURCE_TOKEN_CONTRACT_ADDRESS";
  const token = await ethers.getContractAt("IERC20", tokenAddress);


  const amount = 100000; // SOURCE_AMOUNT- Adjust the amount and decimals accordingly


  // Approve the Swap contract to spend tokens on your behalf
  let approvalTx = await token.connect(deployer).approve(simpleSwapAddress, amount);
  await approvalTx.wait();
  console.log("Approved token transfer:", approvalTx.hash);


  // Call the _l1xSend function
  let tx = await simpleSwapContract.connect(deployer)._l1xSend(
    "SOURCE_WALLET_ADDRESS",
    "DESTINATION_WALLET_ADDRESS",
    "SOURCE_TOKEN_CONTRACT_ADDRESS",
    "DESTINATION_TOKEN_CONTRACT_ADDRESS",
    amount,
    DESTINATION_AMOUNT,
    "DESTINATION_CONTRACT_ADDRESS",
    "bsc" //DESTINATION_NETWORK
  );


  await tx.wait();
  console.log("Initiate swap tx:", tx.hash);
}


main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });
```



2. **Run Script on Source Network**

```bash
npx hardhat run scripts/initiateSwap.js --network SOURCE_NETWORK
```

Output looks like this

```bash
// Some code
Deployer address: 0xBD4842bcb98164dC3bBcd5eB2fDf6BF5Fa114032
Approved token transfer: 0x652f734d89c692a853e41696cd582049b467d904b79178ead9ef23d4aa5a3510
Initiate swap tx: 0x57ec8792cc98985e1e378002a730dfb996dc05b2d87f877831d1e1d97290c0e4
```

3. Check the **Source Network Transaction log**

Use the TransactionHash received in above command as **Initiate swap tx** to check transaction log in the source network.

<figure><img src="https://3579180892-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FJT8OOYC9bpptIKZlB2tt%2Fuploads%2Fruc5Dhf8ZDrjiOEqnrhN%2FScreenshot%202024-08-02%20180847.png?alt=media&#x26;token=3cef2528-7897-4569-8682-33cf1b3c1dbe" alt=""><figcaption></figcaption></figure>

4. Check the **Destination Network Transaction log**

Use the **Destination X-Talk Gateway Contract Address** from the [table](#x-talk-gateway-contract-address) to check the transaction on Destination Network and then check the Transaction log.

<figure><img src="https://3579180892-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FJT8OOYC9bpptIKZlB2tt%2Fuploads%2FfIhoX6s9klUfckRDdJb0%2FScreenshot%202024-08-02%20181118.png?alt=media&#x26;token=8362715d-213a-4fa0-b021-6d25c5ffbc5f" alt=""><figcaption></figcaption></figure>

### X-TALK GATEWAY CONTRACT ADDRESS

Below table contains a list of contract address that serve as an authenticated entry to interact with X-Talk from respective client chain network.



<table><thead><tr><th width="219">Network</th><th>Contract Address</th></tr></thead><tbody><tr><td>sepolia</td><td>0xf650162aF059734523E4Be23Ec5bAB9a5b878f57</td></tr><tr><td>bscTestnet</td><td>0x77d046D7d733672D44eA2Df53a1663b6CF453432</td></tr></tbody></table>



