mirror of
				https://github.com/XRPLF/xrpl-dev-portal.git
				synced 2025-11-04 03:45:49 +00:00 
			
		
		
		
	Add Batch transactions tutorials
This commit is contained in:
		@@ -5,76 +5,75 @@
 | 
			
		||||
 * to create a single-account batch transaction.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import xrpl from "xrpl";
 | 
			
		||||
import { BatchFlags } from "xrpl/dist/npm/models/transactions/batch.js";
 | 
			
		||||
import xrpl from "xrpl"
 | 
			
		||||
import { BatchFlags } from "xrpl/dist/npm/models/transactions/batch.js"
 | 
			
		||||
 | 
			
		||||
const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233");
 | 
			
		||||
await client.connect();
 | 
			
		||||
const client = new xrpl.Client("wss://s.devnet.rippletest.net:51233/")
 | 
			
		||||
await client.connect()
 | 
			
		||||
 | 
			
		||||
// Create and fund the sender wallet
 | 
			
		||||
console.log("Funding new sender wallet from faucet...");
 | 
			
		||||
const { wallet } = await client.fundWallet();
 | 
			
		||||
console.log(`Wallet created: ${wallet.classicAddress}`);
 | 
			
		||||
 | 
			
		||||
// Create and fund recipient wallet
 | 
			
		||||
console.log("\nFunding new recipient wallet from faucet...");
 | 
			
		||||
const feeRecipient = (await client.fundWallet()).wallet;
 | 
			
		||||
console.log(`Fee Recipient: ${feeRecipient.classicAddress}`);
 | 
			
		||||
console.log("Funding new sender wallet from faucet...")
 | 
			
		||||
const { wallet: sender } = await client.fundWallet()
 | 
			
		||||
console.log(`Sender account: ${sender.address}`)
 | 
			
		||||
 | 
			
		||||
// Create and fund the receiver wallet
 | 
			
		||||
console.log("\nFunding new receiver wallet from faucet...")
 | 
			
		||||
const { wallet: receiver } = await client.fundWallet()
 | 
			
		||||
console.log(`Receiver account: ${receiver.address}`)
 | 
			
		||||
 | 
			
		||||
// Create inner transactions  --------------------------------------------
 | 
			
		||||
// REQUIRED: Inner transactions MUST have the tfInnerBatchTxn flag (0x40000000)
 | 
			
		||||
// autofill() will automatically add Fee: "0" and SigningPubKey: ""
 | 
			
		||||
// REQUIRED: Inner transactions MUST have the tfInnerBatchTxn flag (0x40000000).
 | 
			
		||||
// "autofill" will automatically add Fee: "0" and SigningPubKey: "".
 | 
			
		||||
 | 
			
		||||
// Transaction 1: Create DEX offer (sell 100 XRP for 100 USD)
 | 
			
		||||
// Transaction 1: Create DEX offer
 | 
			
		||||
const offerCreate = {
 | 
			
		||||
  TransactionType: "OfferCreate",
 | 
			
		||||
  Account: wallet.address,
 | 
			
		||||
  Account: sender.address,
 | 
			
		||||
  TakerPays: {
 | 
			
		||||
    currency: "USD",
 | 
			
		||||
    issuer: "rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc",
 | 
			
		||||
    value: "100"
 | 
			
		||||
    currency: "TST",
 | 
			
		||||
    issuer: "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd",
 | 
			
		||||
    value: "25"
 | 
			
		||||
  },
 | 
			
		||||
  TakerGets: xrpl.xrpToDrops(25 * 10 * 1.16),
 | 
			
		||||
  // 25 TST * 10 XRP per TST * 15% financial exchange (FX) cost
 | 
			
		||||
  TakerGets: xrpl.xrpToDrops(25 * 10 * 1.15),
 | 
			
		||||
  Flags: 0x40000000, // tfInnerBatchTxn - THIS IS REQUIRED
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Transaction 2: Pay platform fee (10 XRP)
 | 
			
		||||
// Transaction 2: Pay platform fee
 | 
			
		||||
const payment = {
 | 
			
		||||
  TransactionType: "Payment",
 | 
			
		||||
  Account: wallet.classicAddress,
 | 
			
		||||
  Destination: feeRecipient.classicAddress,
 | 
			
		||||
  Amount: xrpl.xrpToDrops(5), // 5 XRP
 | 
			
		||||
  Flags: 0x40000000,
 | 
			
		||||
};
 | 
			
		||||
  Account: sender.address,
 | 
			
		||||
  Destination: receiver.address,
 | 
			
		||||
  Amount: xrpl.xrpToDrops(2), // 2 XRP
 | 
			
		||||
  Flags: 0x40000000, // tfInnerBatchTxn - THIS IS REQUIRED
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send Batch transaction --------------------------------------------
 | 
			
		||||
const batchTx = {
 | 
			
		||||
  TransactionType: "Batch",
 | 
			
		||||
  Account: wallet.classicAddress,
 | 
			
		||||
  Account: sender.address,
 | 
			
		||||
  Flags: BatchFlags.tfAllOrNothing, // tfAllOrNothing: All inner transactions succeed or all fail
 | 
			
		||||
  RawTransactions: [{ RawTransaction: offerCreate }, { RawTransaction: payment }],
 | 
			
		||||
};
 | 
			
		||||
xrpl.validate(batchTx);
 | 
			
		||||
}
 | 
			
		||||
// Validate the transaction structure before submitting
 | 
			
		||||
xrpl.validate(batchTx)
 | 
			
		||||
 | 
			
		||||
// Sign, submit, and wait for validation in one call
 | 
			
		||||
console.log(
 | 
			
		||||
  "\nSigning and submitting batch transaction:\n",
 | 
			
		||||
  JSON.stringify(batchTx, null, 2)
 | 
			
		||||
);
 | 
			
		||||
console.log("\nSigning and submitting batch transaction:\n", JSON.stringify(batchTx, null, 2))
 | 
			
		||||
const submitResponse = await client.submitAndWait(batchTx, {
 | 
			
		||||
  wallet: wallet,
 | 
			
		||||
  wallet: sender,
 | 
			
		||||
  autofill: true, // Autofill handles Fee, Sequence, LastLedgerSequence, etc.
 | 
			
		||||
});
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// Check transaction results and disconnect --------------------------------
 | 
			
		||||
if (submitResponse.result.meta.TransactionResult !== "tesSUCCESS") {
 | 
			
		||||
  const resultCode = response.result.meta.TransactionResult;
 | 
			
		||||
  console.warn(`Transaction failed with result code ${resultCode}.`);
 | 
			
		||||
  process.exit(1);
 | 
			
		||||
  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(JSON.stringify(submitResponse.result, null, 2));
 | 
			
		||||
console.log("\nBatch transaction submitted successfully!")
 | 
			
		||||
console.log("\nResult:\n", JSON.stringify(submitResponse.result, null, 2))
 | 
			
		||||
console.log(`\nTransaction URL:\nhttps://devnet.xrpl.org/transactions/${submitResponse.result.hash}`)
 | 
			
		||||
 | 
			
		||||
await client.disconnect();
 | 
			
		||||
await client.disconnect()
 | 
			
		||||
 
 | 
			
		||||
@@ -7,3 +7,4 @@ labels:
 | 
			
		||||
  - Batch
 | 
			
		||||
  - Transactions
 | 
			
		||||
---
 | 
			
		||||
# Send a Multi-Account Batch Transaction
 | 
			
		||||
 
 | 
			
		||||
@@ -11,23 +11,21 @@ labels:
 | 
			
		||||
# 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 and send a batch transaction from a single account, and how to configure the batch transaction so that either all inner transactions succeed or none are submitted.
 | 
			
		||||
 | 
			
		||||
The example in this tutorial demonstrates a scenario where an account creates a DEX offer and pays a platform fee all in one batch transaction, ensuring the platform gets paid if and only if the offer is created.
 | 
			
		||||
This tutorial shows you how to create and send a batch transaction from a single account, and how to configure the batch transaction so that either all inner transactions succeed or they all fail.
 | 
			
		||||
 | 
			
		||||
## Goals
 | 
			
		||||
 | 
			
		||||
By the end of this tutorial, you will be able to:
 | 
			
		||||
 | 
			
		||||
- Create a batch transaction with multiple inner transactions from a single account.
 | 
			
		||||
- Configure the batch transaction to ensure atomicity, so that either all inner transactions succeed or none are submitted.
 | 
			
		||||
- 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 XRPL Ledger.
 | 
			
		||||
- Have an XRP Ledger client library set up in your development environment:
 | 
			
		||||
- 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: [xrpl.js](https://github.com/XRPLF/xrpl.js)
 | 
			
		||||
  - Python: [xrpl-py](https://github.com/XRPLF/xrpl-py)
 | 
			
		||||
 | 
			
		||||
@@ -37,6 +35,8 @@ You can find the complete source code for this tutorial's examples in the [code
 | 
			
		||||
 | 
			
		||||
## Steps
 | 
			
		||||
 | 
			
		||||
The example in this tutorial demonstrates a scenario where an account creates a DEX offer and pays a platform fee all in one batch transaction, ensuring the platform gets paid if and only if the offer is created.
 | 
			
		||||
 | 
			
		||||
### 1. Install dependencies
 | 
			
		||||
 | 
			
		||||
{% tabs %}
 | 
			
		||||
@@ -58,7 +58,7 @@ pip install xrpl-py
 | 
			
		||||
{% /tab %}
 | 
			
		||||
{% /tabs %}
 | 
			
		||||
 | 
			
		||||
## Set up client and accounts
 | 
			
		||||
### 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 transaction **sender**, and a second account to **receive** the platform fee.
 | 
			
		||||
 | 
			
		||||
@@ -71,20 +71,82 @@ To get started, import the client library and instantiate a client to connect to
 | 
			
		||||
{% /tab %}
 | 
			
		||||
{% /tabs %}
 | 
			
		||||
 | 
			
		||||
## Prepare inner transactions
 | 
			
		||||
### 3. Prepare inner transactions
 | 
			
		||||
 | 
			
		||||
Next, prepare the inner transactions that will be included in the batch. The following code shows the two inner transactions we want to send: one for the DEX UI offer, and another for the platform fee.
 | 
			
		||||
Next, prepare the inner transactions that will be included in the batch. The following code shows the two inner transactions we want to send: one for the DEX offer, and another for the platform fee.
 | 
			
		||||
 | 
			
		||||
{% tabs %}
 | 
			
		||||
{% tab label="Javascript" %}
 | 
			
		||||
{% code-snippet file="/_code-samples/batch/js/singleAccountBatch.js" language="js" from="// Transaction 1:" to="// Send Batch transaction" /%}
 | 
			
		||||
{% code-snippet file="/_code-samples/batch/js/singleAccountBatch.js" language="js" from="// Create inner transactions" to="// Send Batch transaction" /%}
 | 
			
		||||
{% /tab %}
 | 
			
		||||
 | 
			
		||||
{% tab label="Python" %}
 | 
			
		||||
{% /tab %}
 | 
			
		||||
{% /tabs %}
 | 
			
		||||
 | 
			
		||||
In the code above we prepare the [OfferCreate transaction][] transaction which creates a DEX offer to sell 100 USD for XRP, and the [Payment transaction][] which sends 5 XRP to the platform fee recipient.
 | 
			
		||||
The [OfferCreate transaction][] creates a DEX offer to buy TST using XRP, and the [Payment transaction][] sends 2 XRP to the platform fee recipient. Both transactions must include the `tfInnerBatchTxn` (0x40000000) flag to indicate that they are inner transactions of a batch.
 | 
			
		||||
 | 
			
		||||
The `Fee` and `SigningPubKey` fields are omitted as the client library's _autofill_ functionality automatically populates these when submitting the batch transaction.
 | 
			
		||||
 | 
			
		||||
{% admonition type="info" name="Note" %}
 | 
			
		||||
The autofill functionality automatically adds `Fee: "0"` and `SigningPubKey: ""` when it detects the `tfInnerBatchTxn` flag. You typically don't need to set these manually, but if you do, ensure `Fee` is `"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` field, which is set to `tfAllOrNothing` (0x00010000) to ensure that either all inner transactions succeed or none are submitted. 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="// Sign, submit" /%}
 | 
			
		||||
{% /tab %}
 | 
			
		||||
 | 
			
		||||
{% tab label="Python" %}
 | 
			
		||||
{% /tab %}
 | 
			
		||||
{% /tabs %}
 | 
			
		||||
 | 
			
		||||
### 5. Sign and submit batch transaction
 | 
			
		||||
 | 
			
		||||
Now, sign and submit the batch transaction:
 | 
			
		||||
 | 
			
		||||
{% tabs %}
 | 
			
		||||
{% tab label="Javascript" %}
 | 
			
		||||
{% code-snippet file="/_code-samples/batch/js/singleAccountBatch.js" language="js" from="// Sign, submit" before="// Check transaction" /%}
 | 
			
		||||
{% /tab %}
 | 
			
		||||
 | 
			
		||||
{% tab label="Python" %}
 | 
			
		||||
{% /tab %}
 | 
			
		||||
{% /tabs %}
 | 
			
		||||
 | 
			
		||||
Because we set `autofill` to `true`, the client library automatically fills in any missing fields, like the `Fee` and `SigningPubKey`, before signing and submitting the transaction.
 | 
			
		||||
 | 
			
		||||
### 6. Check transaction result
 | 
			
		||||
 | 
			
		||||
Finally, 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 transaction" /%}
 | 
			
		||||
{% /tab %}
 | 
			
		||||
 | 
			
		||||
{% tab label="Python" %}
 | 
			
		||||
{% /tab %}
 | 
			
		||||
{% /tabs %}
 | 
			
		||||
 | 
			
		||||
## 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" /%}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user