# Blockchain Interoperability: Connecting Multiple Blockchain Networks for Payments

**URL:** <https://community.rapyd.net/t/blockchain-interoperability-connecting-multiple-blockchain-networks-for-payments/59930>\
**Category:** 👓 Blog\
**Tags:** get-started, tech-blog, tutorials\
**Created:** [September 9, 2025, 7:00am UTC](https://community.rapyd.net/t/blockchain-interoperability-connecting-multiple-blockchain-networks-for-payments/59930 "2025-09-09T07:00:40Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Community\_Team](https://avatars.discourse-cdn.com/v4/letter/c/46a35a/32.png) [@Community\_Team](https://community.rapyd.net/u/Community_Team)\
**Post date:** [September 9, 2025, 7:00am UTC](https://community.rapyd.net/t/blockchain-interoperability-connecting-multiple-blockchain-networks-for-payments/59930/1 "2025-09-09T07:00:40Z")

</div>

![Banner: Blockchain Interoperability Connecting Multiple Blockchain Networks for Payments](https://us1.discourse-cdn.com/flex016/uploads/rapyd/original/3X/b/e/bed268db4d56f3954e18dca9eac2c63cc6c0367a.jpeg)  
By: **Vivek Kumar Maskara**

Blockchain is a decentralized and immutable digital database or ledger that’s distributed across a network of computers in a transparent and tamperproof manner.

Blockchain interoperability refers to the ability of blockchains to communicate and share data with other blockchains. This enables developers to build cross-chain solutions that combine the strengths of each blockchain. For example, financial applications need blockchain interoperability to enable smooth cross-chain transactions and to improve liquidity, accessibility, and expand financial inclusion.

In this article, you’ll learn how to implement blockchain interoperability using [Solidity](https://soliditylang.org/) smart contracts for payment verification.

## Why Fintech Applications Need Blockchain Interoperability

If you’re building a [decentralized application](https://www.coinbase.com/en-ca/learn/crypto-basics/what-are-decentralized-applications-dapps) (dApps), you need blockchain interoperability. This allows your app to interact with different blockchain networks, expanding the app’s access to assets, usability, and scalability.

Here are a few benefits of blockchain interoperability:

- **Seamless cross-chain transactions:** Blockchain interoperability enables users to transfer assets across different blockchain networks without relying on centralized exchanges or manually converting them to [fiat currency](https://www.trmlabs.com/glossary/fiat-currency).
- **Lower transaction costs and faster settlement:** It reduces the need for intermediaries to carry out a transaction, optimizes payment processing costs, and enables [faster settlement across blockchain networks](https://www.rapidinnovation.io/post/blockchain-for-cross-border-payments-ultimate-guide-to-fast-cheap-transfers#42-faster-settlement-times).
- **Improved liquidity and accessibility:** It connects fragmented payment ecosystems, allowing users to access a wider liquidity pool to exchange their tokens. For example, a user can transfer USDT from Ethereum ([ERC-20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/)) to the [Tron network](https://tron.network/) to take advantage of lower fees and faster transaction speeds. This enhances financial accessibility for global users as they can transfer their assets to a different chain based on their needs.
- **Expanded financial inclusion:** Supporting multichain compatibility enables fintech applications to reach more users and businesses, even in regions where traditional financial services are limited.

## Simplifying Payment Verification with Rapyd

Blockchain interoperability sounds great in theory: move assets and data across networks seamlessly. But building a complete payment verification system requires significant developer effort. Smart contracts struggle to handle real-world requirements, like fiat conversions, regulatory compliance, fraud prevention, and off-chain settlement on their own, especially when these systems must remain reliable and responsive at scale.

Thankfully, [Rapyd](https://www.rapyd.net/) offers a robust financial infrastructure with easy-to-integrate [REST APIs](https://docs.rapyd.net/en/get-started.html) that offload the hard parts for you. It acts as an off-chain settlement layer and cross-chain data exchange, enabling use cases like automated compliance checks, [escrow](https://docs.rapyd.net/en/managing-escrow.html), and transaction verification, without requiring developers to build and maintain that infrastructure themselves.

From [real-time fraud prevention](https://www.rapyd.net/blog/ai-fraud-prevention/) and automated [global KYC/AML](https://www.rapyd.net/blog/how-rapyd-verify-can-help-global-businesses-with-robust-kyc/) to fiat on/off-ramps in over 100 countries, Rapyd removes the traditional finance complexity from blockchain payments. The [Rapyd API platform](https://docs.rapyd.net/en/api-reference.html) simplifies the end-to-end financial workflow:

- The **[Collect Payments API](https://docs.rapyd.net/en/rapyd-collect-363484.html)** receives funds from various payment methods and deposits them into [Rapyd Wallets](https://docs.rapyd.net/en/rapyd-wallet.html).
- The **[Rapyd Verify APIs](https://docs.rapyd.net/en/rapyd-verify-386565.html)** perform hosted Know Your Business (KYB) and Know Your Customer (KYC) verifications to meet compliance requirements.
- The **[Rapyd Protect APIs](https://docs.rapyd.net/en/rapyd-protect.html)** detect fraud and suspicious activity through built-in risk scoring, enhancing compliance and eliminating the need to build custom fraud logic.
- **[Webhooks](https://docs.rapyd.net/en/webhook-format.html)** receive real-time notifications for key events, such as payment status changes or verification updates.

As an off-chain infrastructure layer, Rapyd also aligns with one of the core principles of blockchain systems: availability. Even during peak congestion or transaction delays on the blockchain, Rapyd continues to operate reliably, ensuring high availability for compliance, verification, and settlement workflows.

## Implementing Blockchain Interoperability

In this tutorial, you’ll build, deploy, and test smart contracts on Ethereum testnets like [Sepolia](https://sepolia.etherscan.io/) and [Holesky](https://holesky.etherscan.io/). The tutorial uses the [Hardhat](https://hardhat.org/hardhat-runner/docs/getting-started#overview) developer environment to easily deploy your [Solidity smart contracts](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html) and test them using the Hardhat network, which is a local Ethereum network designed for development.

Here are the primary components of the project:

 ![Project architecture, courtesy of Vivek Kumar Maskara](https://us1.discourse-cdn.com/flex016/uploads/rapyd/original/3X/2/2/2287bfcfcbdf40ac3885961272ea7349c719e056.png)

- **`CrossChainPayment`** is a simple smart contract that initiates a cross-chain transaction and emits the `PaymentSent` event.
- **`PaymentVerifier`** is another smart contract that simulates a cross-chain transaction verification and emits the `PaymentVerified` event. For simplicity, it doesn’t perform any complex checks, but it can be extended based on the use case.
- **`relay.js` script** watches for events on the source chain (_ie_ Sepolia) with the destination chain as Holesky and invokes the `verifyPayment` method of the destination chain.

### Prerequisites

Before you get started, you need to do the following:

- [Install a Node.js development environment](https://nodejs.org/en/learn/getting-started/introduction-to-nodejs).
- Sign up for an [Alchemy account](https://auth.alchemy.com/signup/) and [create an API key](https://docs.alchemy.com/docs/alchemy-quickstart-guide#1key-create-an-alchemy-api-key).
- [Set up Metamask and create a wallet](https://support.metamask.io/start/getting-started-with-metamask/).
- [Obtain a Metamask account private key](https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/).
- Fund your Metamask wallet using Google Cloud’s Ethereum [Holešky](https://cloud.google.com/application/web3/faucet/ethereum/holesky) and [Sepolia Faucet](https://cloud.google.com/application/web3/faucet/ethereum/sepolia). You can use any faucet of your choice, but some faucets may require a minimum wallet balance to receive funds.

### Cloning the Starter Project

This tutorial uses [this GitHub starter code](https://github.com/Rapyd-Samples/rapyd-starter-blockhain) that has a barebones Hardhat app set up. To follow along, clone the GitHub repo and switch to the `starter` branch:

```sh
git clone https://github.com/Rapyd-Samples/rapyd-starter-blockhain.git
cd rapyd-starter-blockhain
git checkout starter

```

Let’s go over the structure of the codebase:

- The `package.json` file defines the Hardhat project dependencies. It uses the [Hardhat](https://www.npmjs.com/package/hardhat) dependency to get an Ethereum development environment and uses [@nomicfoundation/hardhat-toolbox](https://www.npmjs.com/package/@nomicfoundation/hardhat-toolbox) to get all the common Hardhat plugins.
- The `contracts` directory contains a sample `Lock.sol` solidity smart contract. You won’t need it in the tutorial, but you can use it to understand the basic structure of a Solidity smart contract.

### Defining Smart Contracts for Cross-Chain Transaction Verification

In this section, you’ll define two smart contracts to enable cross-chain transaction verification.

#### CrossChainPayment contract

Initially, you’ll define the `CrossChainPayment` that initiates a cross-chain payment and emits the `PaymentSent` event. Here, you’ll define a simple smart contract that checks for amount mismatch issues before emitting the `PaymentSent` event.

Create a `contracts/CrossChainPayment.sol` file and add the following code snippet to it:

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

contract CrossChainPayment {
    event PaymentSent(address indexed from, address indexed to, uint256 amount, uint256 chainId);

    function sendPayment(address to, uint256 amount, uint256 destChainId) external payable {
        require(msg.value == amount, "Amount mismatch");
        emit PaymentSent(msg.sender, to, amount, destChainId);
    }
}

```

The smart contract defines a `sendPayment` function that does the following:

- It takes the `to` address and `amount` for sending the payment, and it asserts that the `amount` matches the value set by the sender in the `msg` payload.
- It emits a `PaymentSent` event with the sender’s address (`msg.sender`), receiver’s address (`to`), amount, and destination chain ID (`destChainId`).

#### PaymentVerified contract

Now it’s time to define the `PaymentVerifier` that will be invoked by the [relayer](https://antiersolutions.medium.com/the-role-of-blockchain-relayer-in-transforming-financial-systems-ca2776dd761f) (more on this later). The `PaymentVerifier` smart contract contains the `verifyPayment` method, where on-chain verification can be performed before emitting the `PaymentVerified` event.

Create a `contracts/PaymentVerifier.sol` file and add the following code snippet to it:

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

contract PaymentVerifier {
    event PaymentVerified(address indexed to, uint256 amount, uint256 srcChainId, bytes32 txHash);

    function verifyPayment(address to, uint256 amount, uint256 srcChainId, bytes32 txHash) external {
        // perform verification steps
        emit PaymentVerified(to, amount, srcChainId, txHash);
    }
}

```

This contract doesn’t perform a full cross-chain verification on its own. It acts as a receiver for cross-chain data, and usually, a relayer or a middleware service invokes the `verifyPayment` method of the contract. This method expects the transaction receiver’s address (`to`), amount, source chain ID (`srcChainId`), and the transaction hash (`txHash`). These fields will be supplied by the relayer while invoking the contract.

The `txHash` refers to the on-chain transaction hash and can be used to perform additional transaction checks before emitting the `PaymentVerified` event. For this tutorial, the smart contract emits the event without any checks.

Note that in a real-world system, the `PaymentVerifier` contract can be extended to include more extensive verification checks, such as validating signatures and cryptographic proofs.

### Defining Scripts to Deploy the Smart Contracts

Now that you’ve defined the smart contracts, you need to deploy them to [test blockchain networks (testnets)](https://www.alchemy.com/overviews/what-are-testnets) before you can use them.

To deploy the smart contracts, you can use a `node` script that uses the `hardhat` SDK to deploy the smart contract and print its address. To deploy the `CrossChainPayment` contract, create a `scripts/deploy_crosschain.js` script and add the following contents to it:

```javascript
const hre = require("hardhat");

async function main() {
  const Contract = await hre.ethers.getContractFactory("CrossChainPayment");
  const contract = await Contract.deploy();
  
  await contract.waitForDeployment();
  console.log("Contract deployed to:", await contract.getAddress());
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

```

The Hardhat SDK creates an instance of the Ethers [ContractFactory](https://docs.ethers.org/v5/api/contract/contract-factory/) to convert the `CrossChainPayment` solidity contract into [bytecode](https://blog.chain.link/what-are-abi-and-bytecode-in-solidity/) and deploys it on the blockchain network.

Before using the script, you need to make sure that the network is configured under `hardhat.config.js`. You also need to specify the network name as a CLI parameter while using the script. More on this in a later section.

Similarly, to deploy the `PaymentVerifier` contract, create a `scripts/deploy_paymentverifier.js` file and add the following contents to it:

```javascript
const hre = require("hardhat");

async function main() {
  const Contract = await hre.ethers.getContractFactory("PaymentVerifier");
  const contract = await Contract.deploy();
  
  await contract.waitForDeployment();
  
  console.log("Contract deployed to:", await contract.getAddress());
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

```

This script converts the `PaymentVerifier` contract into bytecode and deploys it. Notice that both the contract deployment scripts are quite similar, and you could also parameterize the script and pass the contract name as a CLI argument.

### Deploying the Smart Contracts to testnets

This tutorial uses the [Sepolia](https://sepolia.etherscan.io/) and [Holesky](https://holesky.etherscan.io/) testnets. Because deploying a smart contract to a [network requires gas](https://www.web3.university/tracks/create-a-smart-contract/what-is-gas-and-how-is-it-used), make sure to fund your wallet with tokens using a faucet like Google Cloud’s Ethereum [Holešky](https://cloud.google.com/application/web3/faucet/ethereum/holesky) or [Sepolia Faucet](https://cloud.google.com/application/web3/faucet/ethereum/sepolia).

Before deploying the smart contracts, you need to configure the desired testnets in the `hardhat.config.js` file. Update the contents of the `hardhat.config.js` file with the following code snippet:

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

module.exports = {
  solidity: "0.8.20",
  networks: {
    sepolia: {
      url: process.env.SEPOLIA_RPC,
      accounts: [process.env.PRIVATE_KEY],
      chainId: 11155111,
    },
    holesky: {
      url: process.env.HOLESKY_RPC,
      accounts: [process.env.PRIVATE_KEY],
      chainId: 17000,
    },
  },
};

```

This snippet updates the `network` configuration to add `sepolia` and `holesky` testnets. Notice that the config file uses `SEPOLIA_RPC`, `HOLESKY_RPC`, and `PRIVATE_KEY` environment variables. To configure environment variables, create a `.env` file in the project’s root and add the following contents to it:

```auto
PRIVATE_KEY=<YOUR_META_MASK_PRIVATE_KEY>
SEPOLIA_RPC=<YOUR_ALCHEMY_SEPOLOIA_TEST_NET_HTTPS_RPC_URL>
SEPOLIA_WSS=<YOUR_ALCHEMY_SEPOLOIA_TEST_NET_WSS_RPC_URL>
HOLESKY_RPC=<YOUR_ALCHEMY_HOLESKY_TEST_NET_HTTPS_RPC_URL>

```

Replace `<YOUR_META_MASK_PRIVATE_KEY>` with the [Metamask wallet’s private key](https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/) obtained earlier. Replace `<YOUR_ALCHEMY_SEPOLOIA_TEST_NET_HTTPS_RPC_URL>` and `<YOUR_ALCHEMY_HOLESKY_TEST_NET_HTTPS_RPC_URL>` with your HTTPS RPC URL from the Alchemy dashboard:

 ![Obtain RPC URLs from Alchemy](https://us1.discourse-cdn.com/flex016/uploads/rapyd/original/3X/2/9/29796deac6c847ca4a61f0fb233357fd3d44679b.png)

Additionally, make sure you replace `<YOUR_ALCHEMY_SEPOLOIA_TEST_NET_WSS_RPC_URL>` with the WebSocket (WSS) RPC URL obtained from the Alchemy dashboard.

Now that your environment variables and Hardhat configuration are set up, you can deploy the contracts. Either of these chains can be used as a source or destination for a transaction, so you need to deploy `PaymentVerifier` and `CrossChainPayment` contracts to both Sepolia and Holesky chains.

Execute the following command to deploy the `CrossChainPayment` to the Holesky chain:

```sh
npx hardhat run scripts/deploy_crosschain.js --network holesky

```

It might take a few seconds for the contract to deploy, and it outputs the contract address like this:

```auto
Contract deployed to: 0x09292e7C53697DFcdBA3c51425bb7e36d7F6Ef2a

```

Note the contract address and deploy the `PaymentVerifier` contract to the Holesky chain by executing the following:

```sh
npx hardhat run scripts/deploy_paymentverifier.js --network holesky

```

Then, deploy the `CrossChainPayment` to the Sepolia chain:

```sh
npx hardhat run scripts/deploy_crosschain.js --network sepolia

```

Finally, deploy the `PaymentVerifier` to the Sepolia chain:

```sh
npx hardhat run scripts/deploy_paymentverifier.js --network sepolia

```

Make sure to save all the contract addresses as you will need them while defining the relay script.

### Defining the Relay Script

Now that the smart contracts are defined, you need to define a relay script that will listen for `PaymentSent` events on the source chain. When it finds a `PaymentSent` event, it matches the destination chain ID and triggers the `verifyPayment` smart contract method on the destination chain.

Create a `scripts/relay.js` file and add the following code snippet to it:

```javascript
const { WebSocketProvider, JsonRpcProvider, Contract, Wallet } = require("ethers");
require("dotenv").config();

// Use WebSocket for Sepolia (where we're listening for events)
const SEPOLIA_WSS = process.env.SEPOLIA_WSS;
const HOLESKY_RPC = process.env.HOLESKY_RPC;
const PRIVATE_KEY = process.env.PRIVATE_KEY;

const SEPOLIA_CONTRACT = "<YOUR_CROSS_PAYMENT_SEPOLIA_ADDRESS>";
const HOLESKY_VERIFIER = "<YOUR_PAYMENT_VERIFIER_HOLESKY_ADDRESS>";

const eventAbi = [
    "event PaymentSent(address indexed from, address indexed to, uint256 amount, uint256 chainId)"
];

const verifierAbi = [
    "function verifyPayment(address to, uint256 amount, uint256 srcChainId, bytes32 txHash)"
];

async function startRelayer() {
    // Use WebSocketProvider for event monitoring
    const sepoliaProvider = new WebSocketProvider(SEPOLIA_WSS);
    const holeskyProvider = new JsonRpcProvider(HOLESKY_RPC);
    const wallet = new Wallet(PRIVATE_KEY, holeskyProvider);

    const sourceContract = new Contract(SEPOLIA_CONTRACT, eventAbi, sepoliaProvider);
    const verifier = new Contract(HOLESKY_VERIFIER, verifierAbi, wallet);

    console.log("Relayer is watching for events on Sepolia via WebSocket...");

    // Set up reconnection logic
    sepoliaProvider.websocket.on('close', (code) => {
        console.log(`WebSocket connection closed with code ${code}. Reconnecting...`);
        setTimeout(startRelayer, 3000);
    });

    // Listen for events using WebSocket
    sourceContract.on("PaymentSent", async (from, to, amount, chainId, event) => {
        console.log("PaymentSent Detected:");
        console.log({ from, to, amount: amount.toString(), chainId });

        if (chainId.toString() !== "17000") {
            console.log("Skipping non-Holesky destination.");
            return;
        }

        try {
            // Get transaction hash from event and ensure it's in bytes32 format
            const txHash = event.log.transactionHash;

            const tx = await verifier.verifyPayment(
                to,
                BigInt(amount.toString()),
                11155111,
                txHash
            );
            console.log("Verification TX sent:", tx.hash);
        } catch (err) {
            console.error("Error verifying payment:", err.message);
            console.log("Error details:", err);
        }
    });
    
    // Handle process termination
    process.on('SIGINT', async () => {
        console.log('Closing WebSocket connection...');
        await sepoliaProvider.destroy();
        process.exit();
    });
}

// In case of connection errors, restart the relayer
try {
    startRelayer();
} catch (error) {
    console.error("Error starting relayer:", error);
    setTimeout(startRelayer, 3000);
}

```

To interact with the Sepolia and Holesky chains, this code creates an instance of the [JsonRpcProvider](https://docs.ethers.org/v5/api/providers/jsonrpc-provider/). The relay script assumes that the transaction will be initiated on the Sepolia chain and starts listening for the `PaymentSent` events on this chain. It sets the Holesky chain as the destination chain, creates an instance of the `PaymentVerifier` contract deployed on it, and invokes the `verifyPayment` method using the payload received in the `PaymentSent` event.

This setup enables blockchain interoperability by bridging event data between two separate chains. It captures transactions on the source chain (Sepolia) and triggers verification logic on the destination chain (Holesky), without requiring a built-in bridge or shared state between them.

### Testing Cross-chain Interactions

With smart contracts deployed to both Sepolia and Holesky chains and the relay scripts in place, you can test blockchain interoperability. The goal of testing is to verify the following:

- Initiate a cross-chain transaction on the Sepolia chain using the `sendPayment` method defined in the `CrossChainPayment`. Once the transaction is complete, you will receive a `ContractTransactionResponse` confirming the successful completion of the transaction.
- Within a few seconds of completion, the relay script should receive a `PaymentSent` event from the `CrossChainPayment` contract deployed on the Sepolia chain. The script should invoke the `verifyPayment` method defined in the `PaymentVerifier` contract deployed on the Holesky chain.
- On invocation, the `PaymentVerifier` contract deployed on the Holesky chain should verify the transaction and return a successful response.

Before you begin testing, start the relay script in a new terminal window:

```sh
# Execute this command in the project's root directory
node scripts/relay.js

```

This code starts the relay script, which listens for events on the Sepolia chain.

To initiate a transaction on the Sepolia chain, start the `hardhat` console for the `sepolia` network by executing the following command in the project’s root in a separate terminal window:

```sh
# Execute this in the project's root
npx hardhat console --network sepolia

```

This command starts the `hardhat` console, where you can execute smart contracts and perform transactions. To initiate a cross-chain payment, paste the following script in the `hardhat` console:

```javascript
// Get ethers from Hardhat runtime
const { ethers } = hre;

// Load your deployed contract
const contract = await ethers.getContractAt("CrossChainPayment", "0x45d88f6DD0f0eDB69C563233Be73458c9980b519");

// Send payment
await contract.sendPayment(
  "0x11ddd4b07B095802B537267358fB8Eb954B29d99", // Recipient
  ethers.parseEther("0.001"), // Amount
  17000, // Destination Chain ID (Holešky)
  { value: ethers.parseEther("0.001") } // Payment value
);

```

Note that if the terminal prompts you to confirm pasting multiple lines of code, click **Paste** to confirm the action. Once you paste the code and press **Enter** , you will receive a `ContractTransactionResponse` confirming that the transaction was successful:

```auto
ContractTransactionResponse {
  provider: HardhatEthersProvider {
    _hardhatProvider: LazyInitializationProviderAdapter {
      _providerFactory: [AsyncFunction (anonymous)],
      _emitter: [EventEmitter],
      _initializingPromise: [Promise],
      provider: [BackwardsCompatibilityProviderAdapter]
    },
    _networkName: 'sepolia',
    _blockListeners: [],
    _transactionHashListeners: Map(0) {},
    _eventListeners: []
  },
  blockNumber: null,
  blockHash: null,
  index: undefined,
  hash: '0xa2bd160eb0bfde7b1eadbde6c3a1c3a19f876ed5e8731e0d32d582628ba5e361',
  type: 2,
  to: '0x45d88f6DD0f0eDB69C563233Be73458c9980b519',
  from: '0xcD0AAcf118B43C0878D90886f0e1D54D043CF726',
  nonce: 7,
  gasLimit: 25215n,
  gasPrice: 55068367n,
  maxPriorityFeePerGas: 50000000n,
  maxFeePerGas: 55068367n,
  maxFeePerBlobGas: null,
  data: '0x8d82e72f00000000000000000000000011ddd4b07b095802b537267358fb8eb954b29d9900000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000000000000000000000000000000000000000004268',
  value: 1000000000000000n,
  chainId: 11155111n,
  signature: Signature { r: "0x9c0bc7dd319671a3bf13c09e3d0b7398529fe0805055a86ecb41fc7a0a2c76f8", s: "0x047fcab2b6594f02d3fa8b3d0a00e92364b8c1a41713126cd2974bc15d00dd52", yParity: 0, networkV: null },
  accessList: [],
  blobVersionedHashes: null
}

```

The response contains details about the executed transaction, including the transaction hash (`hash`), the sender’s address (`from`), the receiver’s address (`to`), and the hashed transaction payload (`data`).

Head back to the relay script’s terminal window, and within a few seconds, you should see a `PaymentSent` event log printed in the console:

```auto
PaymentSent Detected:
{
  from: '0xcD0AAcf118B43C0878D90886f0e1D54D043CF726',
  to: '0x11ddd4b07B095802B537267358fB8Eb954B29d99',
  amount: '1000000000000000',
  chainId: 17000n
}

```

Notice that the `from` and `to` addresses in the event match the addresses received in the `ContractTransactionResponse`. The relay script will invoke the `verifyPayment` contract on the Holesky chain, and within a few seconds, a transaction verification log will be printed in the console:

```auto
Verification TX sent: 0xb034b9bcd67eb3b58615fcdcd3704df70f75608bda16c1f2a454dc0f200a14dd

```

## Conclusion

In this tutorial, you learned how to achieve blockchain interoperability by building smart contracts using Solidity and Hardhat. Smart contracts can be used to initiate cross-chain transactions and verify them based on preset rules. This lets developers connect and share data between isolated blockchains, helping them build innovative applications.

However, developing extensive verification checks to handle different scenarios relating to fraud, settlement, and compliance can be challenging for developers. With [Rapyd](https://www.rapyd.net/), developers can focus on their core application logic, whether on-chain or off-chain, while relying on Rapyd to handle the complexity of compliance, identity verification, and secure settlement. More than just a complementary tool, Rapyd serves as your fiat bridge and compliance co-pilot by simplifying off-chain infrastructure, allowing teams to focus on delivering innovative, seamless, and scalable payment experiences faster.

Experiment with the [Rapyd API](https://docs.rapyd.net/en/api-reference.html) and the [code used in this tutorial](https://github.com/Rapyd-Samples/rapyd-starter-blockhain) to discover how Rapyd can offer you the best in building an interoperable payment system.
