Last updated

Submit Cross-chain Transactions

(Requires the XChainBridge amendment )

This tutorial explains how to create a test account on a locking chain (Devent), and transfer XRP to an issuing chain (Sidechain-Devnet), using a supported client library to query and submit transactions. Witness servers are already set up to monitor the XRP-XRP bridge and submit attestations.


  • The locking and issuing chains are both up and running.
  • The witness servers are up and running.
  • Set up the XRP-XRP bridge.


1. Connect to the locking chain (Devnet) and issuing chain (Sidechain-Devnet).

const xrpl = require('xrpl')

const WS_URL_lockingchain = 'wss://' // Locking chain
const WS_URL_issuingchain = 'wss://' // Issuing chain

// Define the XChainBridge
const xchainbridge = {
  "LockingChainDoor": "rnQAXXWoFNN6PEqwqsdTngCtFPCrmfuqFJ", // Locking chain door account
  "LockingChainIssue": {
    "currency": "XRP"
  "IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", // Use the genesis address hardcoded in rippled
  "IssuingChainIssue": {
    "currency": "XRP"

async function main() {
  // Define the network clients.
  const client_lockingchain = new xrpl.Client(WS_URL_lockingchain)
  await client_lockingchain.connect()

  const client_issuingchain = new xrpl.Client(WS_URL_issuingchain)
  await client_issuingchain.connect()

  // ... custom code goes here

  // Disconnect when done (If you omit this, Node.js won't end the process)
  await client_lockingchain.disconnect()
  await client_issuingchain.disconnect()


2. Fund a wallet on Devnet and generate a wallet address for Sidechain-Devnet.

  // Create a wallet and fund it using the XRP faucet on Devnet.
  const wallet_lockingchain = (await client_lockingchain.fundWallet()).wallet

  // Generate a wallet to create and fund on the issuing chain.
  const wallet_issuingchain = await xrpl.Wallet.generate()

3. Submit an XChainAccountCreateCommit transaction from the Devnet wallet.

  const createwallet_issuingchain = await client_lockingchain.submitAndWait({
    "TransactionType": "XChainAccountCreateCommit",
    "Account": wallet_lockingchain.address,
    "Destination": wallet_issuingchain.address,
    "XChainBridge": xchainbridge,
    "SignatureReward": "100",
    "Amount": "5000000000"
  }, {autofill: true, wallet: wallet_lockingchain})

4. Create a claim ID with XChainCreateClaimID, using your account on the issuing chain.

  const createclaim = await client_issuingchain.submitAndWait({
    "TransactionType": "XChainCreateClaimID",
    "Account": wallet_issuingchain.address,
    "OtherChainSource": wallet_lockingchain.address,
    "SignatureReward": "100",
    "XChainBridge": xchainbridge
  }, {autofill: true, wallet: wallet_issuingchain})

5. Retrieve the claim ID from the transaction metadata.

  let metadata = createclaim.result.meta.AffectedNodes

  let claimnode = null;

  for (const item of metadata) {
    if (item.CreatedNode && item.CreatedNode.LedgerEntryType === 'XChainOwnedClaimID') {
      claimnode = item.CreatedNode

  const claimID = claimnode.NewFields.XChainClaimID

6. Submit an XChainCommit transaction with the claim ID, using your account on the locking chain.

If you don't specify an "OtherChainDestination", the account that submitted the XChainCreateClaimID transaction needs to submit an XChainClaim transaction to claim the funds.

  const xchaincommit = await client_lockingchain.submitAndWait({
    "TransactionType": "XChainCommit",
    "Account": wallet_lockingchain.address,
    "OtherChainDestination": wallet_issuingchain.address,
    "Amount": "10000",
    "XChainBridge": xchainbridge,
    "XChainClaimID": claimID
  }, {autofill: true, wallet: wallet_lockingchain})

Note: When enough XChainAddClaimAttestation signatures are submitted by the witness servers to reach quorum, the funds are released on the issuing chain to the OtherChainDestination.