From 31e0479275f98288c22d20aa37b03d52a5a8bfd1 Mon Sep 17 00:00:00 2001 From: Maria Shodunke Date: Tue, 14 Oct 2025 11:09:07 +0100 Subject: [PATCH] Add Batch transactions tutorials --- _code-samples/batch/README.md | 5 +- _code-samples/batch/js/README.md | 281 ++++++++++++++++++ _code-samples/batch/js/multiAccountBatch.js | 110 +++++++ _code-samples/batch/js/package.json | 6 + _code-samples/batch/js/singleAccountBatch.js | 90 ++++++ .../how-tos/use-batch-transactions/index.md | 14 + .../send-a-multi-account-batch-transaction.md | 158 ++++++++++ ...send-a-single-account-batch-transaction.md | 148 +++++++++ sidebars.yaml | 5 + 9 files changed, 815 insertions(+), 2 deletions(-) create mode 100644 _code-samples/batch/js/README.md create mode 100644 _code-samples/batch/js/multiAccountBatch.js create mode 100644 _code-samples/batch/js/package.json create mode 100644 _code-samples/batch/js/singleAccountBatch.js create mode 100644 docs/tutorials/how-tos/use-batch-transactions/index.md create mode 100644 docs/tutorials/how-tos/use-batch-transactions/send-a-multi-account-batch-transaction.md create mode 100644 docs/tutorials/how-tos/use-batch-transactions/send-a-single-account-batch-transaction.md diff --git a/_code-samples/batch/README.md b/_code-samples/batch/README.md index c0852466c2..87edb5a79a 100644 --- a/_code-samples/batch/README.md +++ b/_code-samples/batch/README.md @@ -1,4 +1,5 @@ # Batch -Code samples showing how to create and submit a [Batch transaction](../../docs/concepts/transactions/batch-transactions.md). -Both for simple and multi account batch transactions. +Code samples showing how to create and submit a [Batch transaction](https://xrpl.org/docs/concepts/transactions/batch-transactions). + +Both for single and multi account batch transactions. diff --git a/_code-samples/batch/js/README.md b/_code-samples/batch/js/README.md new file mode 100644 index 0000000000..70b0d6d2b1 --- /dev/null +++ b/_code-samples/batch/js/README.md @@ -0,0 +1,281 @@ +# Send a Batch Transaction + +Code samples showing how to create and submit a [Batch transaction](https://xrpl.org/docs/concepts/transactions/batch-transactions) with Javascript. + +Both for single and multi account batch transactions. + +## Single Account Batch Transaction + +Quick setup and usage: + +```sh +npm install xrpl +node singleAccountBatch.js +``` + +The script should output the following: + +```sh +Funding new wallets from faucet... +Sender: raNwujquxJ7QTLhfbkKN6sZa7RBPHV671e, Balance: 100 XRP +Wallet1: r4JMmKToZRMVT3mGWPnKHFEHsSMQEWigLC, Balance: 100 XRP +Wallet2: rKfPgHASYuttoF1HfU56V31WbJvZn3w8xn, Balance: 100 XRP + +Creating batch transaction: +{ + "TransactionType": "Batch", + "Account": "raNwujquxJ7QTLhfbkKN6sZa7RBPHV671e", + "Flags": 65536, + "RawTransactions": [ + { + "RawTransaction": { + "TransactionType": "Payment", + "Account": "raNwujquxJ7QTLhfbkKN6sZa7RBPHV671e", + "Destination": "r4JMmKToZRMVT3mGWPnKHFEHsSMQEWigLC", + "Amount": "2000000", + "Flags": 1073741824 + } + }, + { + "RawTransaction": { + "TransactionType": "Payment", + "Account": "raNwujquxJ7QTLhfbkKN6sZa7RBPHV671e", + "Destination": "rKfPgHASYuttoF1HfU56V31WbJvZn3w8xn", + "Amount": "5000000", + "Flags": 1073741824 + } + } + ] +} + +Submitting batch transaction... + +Batch transaction submitted successfully! +Result: + { + "close_time_iso": "2025-11-03T14:16:21Z", + "ctid": "C00D458B00020002", + "hash": "A93D3C2BDB5D600E592B64B84E66D789237D029267129EBC659EE483E532DD95", + "ledger_hash": "BE6B7C12E551305F09E942D6FA3FC8546F024AE5C53FC495DA6ABF78461E7019", + "ledger_index": 869771, + "meta": { + "AffectedNodes": [ + { + "ModifiedNode": { + "FinalFields": { + "Account": "raNwujquxJ7QTLhfbkKN6sZa7RBPHV671e", + "Balance": "99999996", + "Flags": 0, + "OwnerCount": 0, + "Sequence": 869767 + }, + "LedgerEntryType": "AccountRoot", + "LedgerIndex": "6238B6901FEBD1492C03546C7965A01F184C4E37B696304B86F78F4ADB7831B1", + "PreviousFields": { + "Balance": "100000000", + "Sequence": 869766 + }, + "PreviousTxnID": "559F102041D84FF9DA17483355C3C96A0F8923D9C9C7971BBB15C972DD1F37D6", + "PreviousTxnLgrSeq": 869766 + } + } + ], + "TransactionIndex": 2, + "TransactionResult": "tesSUCCESS" + }, + "tx_json": { + "Account": "raNwujquxJ7QTLhfbkKN6sZa7RBPHV671e", + "Fee": "4", + "Flags": 65536, + "LastLedgerSequence": 869789, + "RawTransactions": [ + { + "RawTransaction": { + "Account": "raNwujquxJ7QTLhfbkKN6sZa7RBPHV671e", + "Amount": "2000000", + "Destination": "r4JMmKToZRMVT3mGWPnKHFEHsSMQEWigLC", + "Fee": "0", + "Flags": 1073741824, + "Sequence": 869767, + "SigningPubKey": "", + "TransactionType": "Payment" + } + }, + { + "RawTransaction": { + "Account": "raNwujquxJ7QTLhfbkKN6sZa7RBPHV671e", + "Amount": "5000000", + "Destination": "rKfPgHASYuttoF1HfU56V31WbJvZn3w8xn", + "Fee": "0", + "Flags": 1073741824, + "Sequence": 869768, + "SigningPubKey": "", + "TransactionType": "Payment" + } + } + ], + "Sequence": 869766, + "SigningPubKey": "EDFECFB87A29F93E52BBA0BA5A14A59B520BB0E39F33943A2FDC1101D34349270D", + "TransactionType": "Batch", + "TxnSignature": "E08E300BDE1700C7CC27F3DA9B784907F637518E1C7E0978E57BFE5D1511A3B6A4269235FC2D9EAA550182A5F2B59415A442CE59555B9B9A0A79AB4030C9F701", + "ctid": "C00D458B00020002", + "date": 815494581, + "ledger_index": 869771 + }, + "validated": true +} + +Final balances after batch transaction: +Sender: raNwujquxJ7QTLhfbkKN6sZa7RBPHV671e, Balance: 92.999996 XRP +Wallet1: r4JMmKToZRMVT3mGWPnKHFEHsSMQEWigLC, Balance: 102 XRP +Wallet2: rKfPgHASYuttoF1HfU56V31WbJvZn3w8xn, Balance: 105 XRP + +Transaction URL: +https://devnet.xrpl.org/transactions/A93D3C2BDB5D600E592B64B84E66D789237D029267129EBC659EE483E532DD95 +``` + +## Multi-Account Batch Transaction + +```sh +npm install xrpl +node multiAccountBatch.js +``` + +The script should output the following: + +```sh +Funding new wallets from faucet... +Alice: rfCBfRGpcGJLwdbfz1M6HYoAL8nZyHRHHa, Balance: 100 XRP +Bob: rKPUDuS2jQNpAMhkNncqC9rKJDpL2gXDN7, Balance: 100 XRP +Charlie: rnz3Da7phfR6tgTZoPYF5psYTiHTshTB8K, Balance: 100 XRP +Third-party wallet: rU8LsCmVjSdf7hSmiGBtBDtt2WhHxp7Zpc, Balance: 100 XRP + +Creating batch transaction: +{ + "TransactionType": "Batch", + "Account": "rU8LsCmVjSdf7hSmiGBtBDtt2WhHxp7Zpc", + "Flags": 65536, + "RawTransactions": [ + { + "RawTransaction": { + "TransactionType": "Payment", + "Account": "rnz3Da7phfR6tgTZoPYF5psYTiHTshTB8K", + "Destination": "rfCBfRGpcGJLwdbfz1M6HYoAL8nZyHRHHa", + "Amount": "50000000", + "Flags": 1073741824 + } + }, + { + "RawTransaction": { + "TransactionType": "Payment", + "Account": "rKPUDuS2jQNpAMhkNncqC9rKJDpL2gXDN7", + "Destination": "rfCBfRGpcGJLwdbfz1M6HYoAL8nZyHRHHa", + "Amount": "50000000", + "Flags": 1073741824 + } + } + ] +} + +Submitting batch transaction... + +Batch transaction submitted successfully! +Result: + { + "close_time_iso": "2025-11-03T14:15:00Z", + "ctid": "C00D457000000002", + "hash": "8CBCCD88B8ABC248797B84ABB92066961C1CB5FE75ACE2115ADCA6B74C85993A", + "ledger_hash": "2217A0DBB38B870187B412533B939724095359A050B21E071A2A114BF57CFB60", + "ledger_index": 869744, + "meta": { + "AffectedNodes": [ + { + "ModifiedNode": { + "FinalFields": { + "Account": "rU8LsCmVjSdf7hSmiGBtBDtt2WhHxp7Zpc", + "Balance": "99999994", + "Flags": 0, + "OwnerCount": 0, + "Sequence": 869743 + }, + "LedgerEntryType": "AccountRoot", + "LedgerIndex": "1E9BA043B9C6518582D0FF73A08DCD8B6958195735086CF7295E5EB6433FB453", + "PreviousFields": { + "Balance": "100000000", + "Sequence": 869742 + }, + "PreviousTxnID": "F7019BC55D80438FDDB01C2549CCC3F7DAF9791F8645E0269D63979EAEC5BBA6", + "PreviousTxnLgrSeq": 869742 + } + } + ], + "TransactionIndex": 0, + "TransactionResult": "tesSUCCESS" + }, + "tx_json": { + "Account": "rU8LsCmVjSdf7hSmiGBtBDtt2WhHxp7Zpc", + "BatchSigners": [ + { + "BatchSigner": { + "Account": "rnz3Da7phfR6tgTZoPYF5psYTiHTshTB8K", + "SigningPubKey": "EDC566D7DA8186BBD30DDAE1FB770FCE7F248949194E1A2E70B18CFA060B140B59", + "TxnSignature": "31639BFA1359DD24345776EAEEACCF61C1CDC792988679263D113E80A22D837E20ACD2B25E482FCA769990C004D747836370C6BAD14524559639BBEBA5813002" + } + }, + { + "BatchSigner": { + "Account": "rKPUDuS2jQNpAMhkNncqC9rKJDpL2gXDN7", + "SigningPubKey": "EDEF1966B325000407940E4C0792E3CCC3E27F51D132BDC53DCC2B1998E7C32A34", + "TxnSignature": "6BF9860B0E2E134FB302329D711BAA7B6314395D39523982DBBC037E84FB17AB5E8E736DB3DB0019B4477686AF2D91E5D2B49409698A95219376B2E318D3E501" + } + } + ], + "Fee": "6", + "Flags": 65536, + "LastLedgerSequence": 869762, + "RawTransactions": [ + { + "RawTransaction": { + "Account": "rnz3Da7phfR6tgTZoPYF5psYTiHTshTB8K", + "Amount": "50000000", + "Destination": "rfCBfRGpcGJLwdbfz1M6HYoAL8nZyHRHHa", + "Fee": "0", + "Flags": 1073741824, + "Sequence": 869740, + "SigningPubKey": "", + "TransactionType": "Payment" + } + }, + { + "RawTransaction": { + "Account": "rKPUDuS2jQNpAMhkNncqC9rKJDpL2gXDN7", + "Amount": "50000000", + "Destination": "rfCBfRGpcGJLwdbfz1M6HYoAL8nZyHRHHa", + "Fee": "0", + "Flags": 1073741824, + "Sequence": 869738, + "SigningPubKey": "", + "TransactionType": "Payment" + } + } + ], + "Sequence": 869742, + "SigningPubKey": "ED2B56D6FB4E8C236A6B07E8D8AD9A4938606144E31779918F99525CA6B3C56664", + "TransactionType": "Batch", + "TxnSignature": "9C51C1F2CB0E8BCEA1FADD3992249DE72AC46FC86AB2FB023A597FBD5C4CCB3337967E9AAFFB5F1C0CBC91128F3FD194F78F207E461BE1FF906C496B94EC410E", + "ctid": "C00D457000000002", + "date": 815494500, + "ledger_index": 869744 + }, + "validated": true +} + +Final balances after batch transaction: +Alice: rfCBfRGpcGJLwdbfz1M6HYoAL8nZyHRHHa, Balance: 200 XRP +Bob: rKPUDuS2jQNpAMhkNncqC9rKJDpL2gXDN7, Balance: 50 XRP +Charlie: rnz3Da7phfR6tgTZoPYF5psYTiHTshTB8K, Balance: 50 XRP +Third-party wallet: rU8LsCmVjSdf7hSmiGBtBDtt2WhHxp7Zpc, Balance: 99.999994 XRP + +Transaction URL: +https://devnet.xrpl.org/transactions/8CBCCD88B8ABC248797B84ABB92066961C1CB5FE75ACE2115ADCA6B74C85993A +``` diff --git a/_code-samples/batch/js/multiAccountBatch.js b/_code-samples/batch/js/multiAccountBatch.js new file mode 100644 index 0000000000..575967a4e0 --- /dev/null +++ b/_code-samples/batch/js/multiAccountBatch.js @@ -0,0 +1,110 @@ +/** + * XRP Ledger Batch Transactions Tutorial + * + * This tutorial demonstrates how to use the Batch transaction feature (XLS-56) + * to perform a multi-account batch transaction. +*/ + +import xrpl from "xrpl" +import { BatchFlags } from 'xrpl/dist/npm/models/transactions/batch.js' +import { GlobalFlags } from 'xrpl/dist/npm/models/transactions/common.js' +import { signMultiBatch, combineBatchSigners } from 'xrpl/dist/npm/Wallet/batchSigner.js' + +const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233/") +await client.connect() + +// Create and fund wallets +console.log("Funding new wallets from faucet...") +const { wallet: alice } = await client.fundWallet() +const { wallet: bob } = await client.fundWallet() +const { wallet: charlie } = await client.fundWallet() +const { wallet: thirdPartyWallet } = await client.fundWallet() + +console.log(`Alice: ${alice.address}, Balance: ${await client.getXrpBalance(alice.address)} XRP`) +console.log(`Bob: ${bob.address}, Balance: ${await client.getXrpBalance(bob.address)} XRP`) +console.log(`Charlie: ${charlie.address}, Balance: ${await client.getXrpBalance(charlie.address)} XRP`) +console.log(`Third-party wallet: ${thirdPartyWallet.address}, Balance: ${await client.getXrpBalance(thirdPartyWallet.address)} XRP`) + +// Create inner transactions -------------------------------------------- +// REQUIRED: Inner transactions MUST have the tfInnerBatchTxn flag (0x40000000). +// This marks them as part of a batch (allows Fee: 0 and empty SigningPubKey). + +// Transaction 1: Charlie pays Alice +const charliePayment = { + TransactionType: "Payment", + Account: charlie.address, + Destination: alice.address, + Amount: xrpl.xrpToDrops(50), + Flags: GlobalFlags.tfInnerBatchTxn // THIS IS REQUIRED +} + +// Transaction 2: Bob pays Alice +const bobPayment = { + TransactionType: "Payment", + Account: bob.address, + Destination: alice.address, + Amount: xrpl.xrpToDrops(50), + Flags: GlobalFlags.tfInnerBatchTxn // THIS IS REQUIRED +} + +// Send Batch transaction -------------------------------------------- +console.log("\nCreating batch transaction:") +const batchTx = { + TransactionType: "Batch", + Account: thirdPartyWallet.address, + Flags: BatchFlags.tfAllOrNothing, // tfAllOrNothing: All inner transactions must succeed + RawTransactions: [ + { RawTransaction: charliePayment }, + { RawTransaction: bobPayment }, + ] +} +console.log(JSON.stringify(batchTx, null, 2)) + +// Validate the transaction structure +xrpl.validate(batchTx) + +// Set the expected number of signers for this transaction. +// "autofill" will automatically add Fee: "0" and SigningPubKey: "". +const autofilledBatchTx = await client.autofill(batchTx, 2) + +// Gather batch signatures -------------------------------- +// Each signer needs their own tx copy because signMultiBatch modifies the object. +// Charlie signs the Batch transaction +const charlieBatch = { ...autofilledBatchTx } +signMultiBatch(charlie, charlieBatch) + +// Bob signs the Batch transaction +const bobBatch = { ...autofilledBatchTx } +signMultiBatch(bob, bobBatch) + +// Combine inner transaction signatures. +// This returns a signed transaction blob (hex string) ready for submission. +const combinedSignedTx = combineBatchSigners([charlieBatch, bobBatch]) + +// Submit the signed blob with the third-party's wallet +console.log("\nSubmitting batch transaction...") +const submitResponse = await client.submitAndWait(combinedSignedTx, + { wallet: thirdPartyWallet } +) + +// Check Batch transaction result -------------------------------- +if (submitResponse.result.meta.TransactionResult !== "tesSUCCESS") { + const resultCode = submitResponse.result.meta.TransactionResult + console.warn(`\nTransaction failed with result code ${resultCode}`) + process.exit(1) +} + +console.log("\nBatch transaction submitted successfully!") +console.log("Result:\n", JSON.stringify(submitResponse.result, null, 2)) + +// Verify balances after transaction +console.log("\nFinal balances after batch transaction:") +console.log(`Alice: ${alice.address}, Balance: ${await client.getXrpBalance(alice.address)} XRP`) +console.log(`Bob: ${bob.address}, Balance: ${await client.getXrpBalance(bob.address)} XRP`) +console.log(`Charlie: ${charlie.address}, Balance: ${await client.getXrpBalance(charlie.address)} XRP`) +console.log(`Third-party wallet: ${thirdPartyWallet.address}, Balance: ${await client.getXrpBalance(thirdPartyWallet.address)} XRP`) + +// View the transaction on the XRPL Explorer +console.log(`\nTransaction URL:\nhttps://devnet.xrpl.org/transactions/${submitResponse.result.hash}`) + +await client.disconnect() diff --git a/_code-samples/batch/js/package.json b/_code-samples/batch/js/package.json new file mode 100644 index 0000000000..139f3bae72 --- /dev/null +++ b/_code-samples/batch/js/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "xrpl": "^4.4.2" + }, + "type": "module" +} diff --git a/_code-samples/batch/js/singleAccountBatch.js b/_code-samples/batch/js/singleAccountBatch.js new file mode 100644 index 0000000000..a7a069d7b1 --- /dev/null +++ b/_code-samples/batch/js/singleAccountBatch.js @@ -0,0 +1,90 @@ +/** + * Single Account Batch Transaction Example + * + * This example demonstrates how to use the Batch transactions feature (XLS-56) + * to create a single-account batch transaction that sends payments + * to multiple destinations in one atomic operation. +*/ + +import xrpl from "xrpl" +import { BatchFlags } from 'xrpl/dist/npm/models/transactions/batch.js' +import { GlobalFlags } from 'xrpl/dist/npm/models/transactions/common.js' + +const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233/") +await client.connect() + +// Create and fund wallets +console.log("Funding new wallets from faucet...") +const { wallet: sender } = await client.fundWallet() +const { wallet: wallet1 } = await client.fundWallet() +const { wallet: wallet2 } = await client.fundWallet() + +console.log(`Sender: ${sender.address}, Balance: ${await client.getXrpBalance(sender.address)} XRP`) +console.log(`Wallet1: ${wallet1.address}, Balance: ${await client.getXrpBalance(wallet1.address)} XRP`) +console.log(`Wallet2: ${wallet2.address}, Balance: ${await client.getXrpBalance(wallet2.address)} XRP`) + +// Create inner transactions -------------------------------------------- +// REQUIRED: Inner transactions MUST have the tfInnerBatchTxn flag (0x40000000). +// This marks them as part of a batch (allows Fee: 0 and empty SigningPubKey). + +// Transaction 1 +const payment1 = { + TransactionType: "Payment", + Account: sender.address, + Destination: wallet1.address, + Amount: xrpl.xrpToDrops(2), + Flags: GlobalFlags.tfInnerBatchTxn // THIS IS REQUIRED +} + +// Transaction 2 +const payment2 = { + TransactionType: "Payment", + Account: sender.address, + Destination: wallet2.address, + Amount: xrpl.xrpToDrops(5), + Flags: GlobalFlags.tfInnerBatchTxn // THIS IS REQUIRED +} + +// Send Batch transaction -------------------------------------------- +console.log("\nCreating batch transaction:") +const batchTx = { + TransactionType: "Batch", + Account: sender.address, + Flags: BatchFlags.tfAllOrNothing, // tfAllOrNothing: All inner transactions must succeed + RawTransactions: [ + { RawTransaction: payment1 }, + { RawTransaction: payment2 } + ] +} +console.log(JSON.stringify(batchTx, null, 2)) + +// Validate the transaction structure before submitting +xrpl.validate(batchTx) + +// Submit and wait for validation +console.log("\nSubmitting batch transaction...") +const submitResponse = await client.submitAndWait(batchTx, { + wallet: sender, + // "autofill" will automatically add Fee: "0" and SigningPubKey: "". + autofill: true +}) + +// Check Batch transaction result -------------------------------- +if (submitResponse.result.meta.TransactionResult !== "tesSUCCESS") { + const resultCode = submitResponse.result.meta.TransactionResult + console.warn(`\nTransaction failed with result code ${resultCode}`) + process.exit(1) +} +console.log("\nBatch transaction submitted successfully!") +console.log("Result:\n", JSON.stringify(submitResponse.result, null, 2)) + +// Verify balances after transaction +console.log("\nFinal balances after batch transaction:") +console.log(`Sender: ${sender.address}, Balance: ${await client.getXrpBalance(sender.address)} XRP`) +console.log(`Wallet1: ${wallet1.address}, Balance: ${await client.getXrpBalance(wallet1.address)} XRP`) +console.log(`Wallet2: ${wallet2.address}, Balance: ${await client.getXrpBalance(wallet2.address)} XRP`) + +// View the transaction on the XRPL Explorer +console.log(`\nTransaction URL:\nhttps://devnet.xrpl.org/transactions/${submitResponse.result.hash}`) + +await client.disconnect() diff --git a/docs/tutorials/how-tos/use-batch-transactions/index.md b/docs/tutorials/how-tos/use-batch-transactions/index.md new file mode 100644 index 0000000000..d64f91fc48 --- /dev/null +++ b/docs/tutorials/how-tos/use-batch-transactions/index.md @@ -0,0 +1,14 @@ +--- +seo: + description: Batch multiple transactions together and execute them as a single unit. +metadata: + indexPage: true +labels: + - Batch + - Transactions +--- +# Use Batch Transactions + +Batch multiple transactions together and execute them as a single unit. + +{% child-pages /%} diff --git a/docs/tutorials/how-tos/use-batch-transactions/send-a-multi-account-batch-transaction.md b/docs/tutorials/how-tos/use-batch-transactions/send-a-multi-account-batch-transaction.md new file mode 100644 index 0000000000..60ebc74a95 --- /dev/null +++ b/docs/tutorials/how-tos/use-batch-transactions/send-a-multi-account-batch-transaction.md @@ -0,0 +1,158 @@ +--- +seo: + description: Send a Batch transaction containing transactions from multiple accounts. +metadata: + indexPage: true +labels: + - Batch + - Transactions +--- +# Send a Multi-Account Batch Transaction + +This tutorial shows you how to create a [Batch transaction][] containing transactions from multiple accounts, where each account must sign the Batch transaction. Any account, even one not involved in the inner transactions, can submit the batch. + +## Goals + +By the end of this tutorial, you will be able to: + +- Create a Batch transaction with multiple inner transactions, signed by multiple accounts, and submitted by a third party account. +- Configure the Batch transaction to ensure atomicity, so that either all inner transactions succeed or they all fail. + +## Prerequisites + +To complete this tutorial, you should: + +- Have a basic understanding of the XRP Ledger. +- Have an XRP Ledger client library set up in your development environment. This page provides examples for the following: + - **JavaScript** with the [xrpl.js library](https://github.com/XRPLF/xrpl.js). See [Get Started Using JavaScript](../../javascript/build-apps/get-started.md) for setup steps. + +## Source Code + +You can find the complete source code for this tutorial's examples in the [code samples section of this website's repository](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/batch/). + +## Steps + +The example in this tutorial demonstrates a scenario where Bob and Charlie both owe Alice 50 XRP each, and a third-party (such as a payment processor) submits the Batch transaction atomically to ensure Alice is paid by both parties. + +### 1. Install dependencies + +{% tabs %} +{% tab label="Javascript" %} +From the code sample folder, use npm to install dependencies: + +```bash +npm install xrpl +``` + +{% /tab %} +{% /tabs %} + +### 2. Set up client and accounts + +To get started, import the client library and instantiate a client to connect to the XRPL. Then, create the accounts for Alice, Bob, Charlie, and the third-party. + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/multiAccountBatch.js" language="js" from="import xrpl" before="// Create inner transactions" /%} +{% /tab %} +{% /tabs %} + +### 3. Prepare inner transactions + +Next, prepare the inner transactions that will be included in the batch. + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/multiAccountBatch.js" language="js" from="// Create inner transactions" to="// Send Batch transaction" /%} +{% /tab %} +{% /tabs %} + +The first transaction sends a payment of 50 XRP from Charlie to Alice, and the second sends a payment of 50 XRP from Bob to Alice. Both transactions must include the `tfInnerBatchTxn` (0x40000000) flag to indicate that they are inner transactions of a batch. + +Inner transactions must have a Fee of **0** and an empty string for the `SigningPubKey`. The outer Batch transaction handles the overall fee and signing for all inner transactions. + +{% admonition type="info" name="Note" %} +The `Fee` and `SigningPubKey` fields are omitted as the client library's _autofill_ functionality automatically populates these when submitting the Batch transaction. + +You typically don't need to set these manually, but if you do, ensure `Fee` is set to 0 and `SigningPubKey` is an empty string. +{% /admonition %} + +### 4. Prepare Batch transaction + +Create the Batch transaction and provide the inner transactions. The key fields to note are: + +| Field | Value | +|:---------------- |:---------- | +| TransactionType | The type of transaction, in this case `Batch`.| +| Account | The wallet address of the account that is sending the Batch transaction. | +| Flags | The flags for the Batch transaction. For this example the transaction is configured with the `tfAllOrNothing` (0x00010000) flag to ensure that either all inner transactions succeed or they all fail atomically. See [Batch Flags](../../../references/protocol/transactions/types/batch.md#batch-flags) for other options. | +| RawTransactions | Contains the list of inner transactions to be applied. There can be up to **8** transactions included. These transactions can come from one account or multiple accounts. | +| BatchSigners | The list of signatures required for the Batch transaction. This is required because there are multiple accounts' transactions included in the batch. | + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/multiAccountBatch.js" language="js" from="// Send Batch transaction" before="// Gather batch signatures" /%} +{% /tab %} +{% /tabs %} + +Because we used `autofill`, the client library automatically fills in any missing fields, like `Fee` and `SigningPubKey`. Additionally, we specify the expected number of signers (2 in this case). + +### 5. Gather batch signatures + +To add the `BatchSigners` field, you need to collect signatures from each account that's sending a transaction within the batch. In this case we need two signatures, one from Charlie and one from Bob. Each sender must sign the Batch transaction to authorize their payment. + +{% tabs %} +{% tab label="Javascript" %} +The **xrpl.js** library provides a helper function, `signMultiBatch()`, to sign the Batch transaction for each account. + +Then, to combine the signatures into a single signed Batch transaction, use the `combineBatchSigners()` utility function. +{% code-snippet file="/_code-samples/batch/js/multiAccountBatch.js" language="js" from="// Gather batch signatures" to="// Submit" /%} +{% /tab %} +{% /tabs %} + +### 6. Submit Batch transaction + +With all the required signatures gathered, the third-party wallet can now submit the Batch transaction. + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/multiAccountBatch.js" language="js" from="// Submit" before="// Check Batch transaction" /%} +{% /tab %} +{% /tabs %} + +### 6. Check Batch transaction result + +To check the result of the Batch transaction submission: + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/multiAccountBatch.js" language="js" from="// Check Batch transaction" before="// Verify balances after transaction" /%} +{% /tab %} +{% /tabs %} + +The code checks for a `tesSUCCESS` result and displays the response details. + +{% admonition type="warning" name="Warning" %} +A `tesSUCCESS` result indicates that the Batch transaction was processed successfully, but does not guarantee the inner transactions succeeded. For example, see the [following transaction on the XRPL Explorer](https://devnet.xrpl.org/transactions/20CFCE5CF75E93E6D1E9C1E42F8E8C8C4CB1786A65BE23D2EA77EAAB65A455C5/simple). +{% /admonition %} + +To verify that the inner transactions have been successful, check the account balances to confirm the expected changes. + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/multiAccountBatch.js" language="js" from="// Verify balances after transaction" /%} +{% /tab %} +{% /tabs %} + +Because the Batch transaction is configured with a `tfAllOrNothing` flag, if any inner transaction fails, **all** inner transactions wil fail, and only the Batch transaction fee is deducted from the **third-party wallet**. + +## See Also + +- **Concepts**: + - [Batch Transactions](../../../concepts/transactions/batch-transactions.md) +- **Tutorials**: + - [Send a Single Account Batch Transaction](send-a-single-account-batch-transaction.md) +- **References**: + - [Batch Transaction][] + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/docs/tutorials/how-tos/use-batch-transactions/send-a-single-account-batch-transaction.md b/docs/tutorials/how-tos/use-batch-transactions/send-a-single-account-batch-transaction.md new file mode 100644 index 0000000000..5689e63d07 --- /dev/null +++ b/docs/tutorials/how-tos/use-batch-transactions/send-a-single-account-batch-transaction.md @@ -0,0 +1,148 @@ +--- +seo: + description: Send a Batch transaction from a single account. +metadata: + indexPage: true +labels: + - Batch + - Transactions +--- +# Send a Single Account Batch Transaction + +A [Batch transaction][] allows you to group multiple transactions together and execute them as a single atomic operation. + +This tutorial shows you how to create a Batch transaction where a single account submits multiple transactions that either all succeed together or all fail together. + +## Goals + +By the end of this tutorial, you will be able to: + +- Create a Batch transaction with multiple inner transactions, signed and submitted by a single account. +- Configure the Batch transaction to ensure atomicity, so that either all inner transactions succeed or they all fail. + +## Prerequisites + +To complete this tutorial, you should: + +- Have a basic understanding of the XRP Ledger. +- Have an XRP Ledger client library set up in your development environment. This page provides examples for the following: + - **JavaScript** with the [xrpl.js library](https://github.com/XRPLF/xrpl.js). See [Get Started Using JavaScript](../../javascript/build-apps/get-started.md) for setup steps. + +## Source Code + +You can find the complete source code for this tutorial's examples in the [code samples section of this website's repository](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/batch/). + +## Steps + +The example in this tutorial demonstrates a scenario where an account sends multiple payments that must be processed atomically in one Batch transaction. + +### 1. Install dependencies + +{% tabs %} +{% tab label="Javascript" %} +From the code sample folder, use npm to install dependencies: + +```bash +npm install xrpl +``` + +{% /tab %} +{% /tabs %} + +### 2. Set up client and accounts + +To get started, import the client library and instantiate a client to connect to the XRPL. For this tutorial you need a funded account for the Batch transaction **sender**, and two other accounts to **receive** the payments. + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/singleAccountBatch.js" language="js" from="import xrpl" before="// Create inner transactions" /%} +{% /tab %} +{% /tabs %} + +### 3. Prepare inner transactions + +Next, prepare the inner transactions that will be included in the batch. + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/singleAccountBatch.js" language="js" from="// Create inner transactions" to="// Send Batch transaction" /%} +{% /tab %} +{% /tabs %} + +The first transaction sends a payment of 2 XRP from the sender to `wallet1`, and the second transaction sends 5 XRP from the sender to `wallet2`. Both transactions must include the `tfInnerBatchTxn` (0x40000000) flag to indicate that they are inner transactions of a batch. + +Inner transactions must have a Fee of **0** and an empty string for the `SigningPubKey`. The outer Batch transaction handles the overall fee and signing for all inner transactions. + +{% admonition type="info" name="Note" %} +The `Fee` and `SigningPubKey` fields are omitted as the client library's _autofill_ functionality automatically populates these when submitting the Batch transaction. + +You typically don't need to set these manually, but if you do, ensure `Fee` is set to 0 and `SigningPubKey` is an empty string. +{% /admonition %} + +### 4. Prepare Batch transaction + +Create the Batch transaction and provide the inner transactions. The key fields to note are: + +| Field | Value | +|:---------------- |:---------- | +| TransactionType | The type of transaction, in this case `Batch`.| +| Account | The wallet address of the account that is sending the Batch transaction. | +| Flags | The flags for the Batch transaction. For this example the transaction is configured with the `tfAllOrNothing` (0x00010000) flag to ensure that either all inner transactions succeed or they all fail atomically. See [Batch Flags](../../../references/protocol/transactions/types/batch.md#batch-flags) for other options. | +| RawTransactions | Contains the list of inner transactions to be applied. There can be up to **8** transactions included. These transactions can come from one account or multiple accounts. | + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/singleAccountBatch.js" language="js" from="// Send Batch transaction" before="// Submit" /%} +{% /tab %} +{% /tabs %} + +### 5. Submit Batch transaction + +Now the sender can submit the Batch transaction: + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/singleAccountBatch.js" language="js" from="// Submit" before="// Check Batch transaction" /%} +{% /tab %} +{% /tabs %} + +Because `autofill` is set to `true`, the client library automatically fills in any missing fields, like the `Fee` and `SigningPubKey`, before submitting the batch. + +### 6. Check Batch transaction result + +To check the result of the Batch transaction submission: + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/singleAccountBatch.js" language="js" from="// Check Batch transaction" before="// Verify balances after transaction" /%} +{% /tab %} +{% /tabs %} + +The code checks for a `tesSUCCESS` result and displays the response details. + +{% admonition type="warning" name="Warning" %} +A `tesSUCCESS` result indicates that the Batch transaction was processed successfully, but does not guarantee the inner transactions succeeded. + +For example, see the [following transaction on the XRPL Explorer](https://devnet.xrpl.org/transactions/20CFCE5CF75E93E6D1E9C1E42F8E8C8C4CB1786A65BE23D2EA77EAAB65A455C5/simple). +{% /admonition %} + +To verify that the inner transactions have been successful, check the account balances to confirm the expected changes. + +{% tabs %} +{% tab label="Javascript" %} +{% code-snippet file="/_code-samples/batch/js/singleAccountBatch.js" language="js" from="// Verify balances after transaction" /%} +{% /tab %} +{% /tabs %} + +Because the Batch transaction is configured with a `tfAllOrNothing` flag, if any inner transaction fails, **all** inner transactions wil fail, and only the Batch transaction fee is deducted from the **sender**. + +## See Also + +- **Concepts**: + - [Batch Transactions](../../../concepts/transactions/batch-transactions.md) +- **Tutorials**: + - [Send a Multi-Account Batch Transaction](send-a-multi-account-batch-transaction.md) +- **References**: + - [Batch Transaction][] + +{% raw-partial file="/docs/_snippets/common-links.md" /%} diff --git a/sidebars.yaml b/sidebars.yaml index ee47bcbc2d..18fc89bf59 100644 --- a/sidebars.yaml +++ b/sidebars.yaml @@ -295,6 +295,11 @@ - page: docs/tutorials/how-tos/manage-account-settings/require-destination-tags.md - page: docs/tutorials/how-tos/manage-account-settings/offline-account-setup.md - page: docs/tutorials/how-tos/manage-account-settings/use-tickets.md + - page: docs/tutorials/how-tos/use-batch-transactions/index.md + expanded: false + items: + - page: docs/tutorials/how-tos/use-batch-transactions/send-a-single-account-batch-transaction.md + - page: docs/tutorials/how-tos/use-batch-transactions/send-a-multi-account-batch-transaction.md - page: docs/tutorials/how-tos/use-specialized-payment-types/index.md expanded: false items: