diff --git a/_code-samples/batch/js/singleAccountBatch.js b/_code-samples/batch/js/singleAccountBatch.js index aae1925712..d6e8cccbcb 100644 --- a/_code-samples/batch/js/singleAccountBatch.js +++ b/_code-samples/batch/js/singleAccountBatch.js @@ -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() diff --git a/docs/tutorials/how-tos/use-specialized-payment-types/batch-transactions/send-a-multi-account-batch-transaction.md b/docs/tutorials/how-tos/use-specialized-payment-types/batch-transactions/send-a-multi-account-batch-transaction.md index 02f0ca7378..19a30b7228 100644 --- a/docs/tutorials/how-tos/use-specialized-payment-types/batch-transactions/send-a-multi-account-batch-transaction.md +++ b/docs/tutorials/how-tos/use-specialized-payment-types/batch-transactions/send-a-multi-account-batch-transaction.md @@ -7,3 +7,4 @@ labels: - Batch - Transactions --- +# Send a Multi-Account Batch Transaction diff --git a/docs/tutorials/how-tos/use-specialized-payment-types/batch-transactions/send-a-single-account-batch-transaction.md b/docs/tutorials/how-tos/use-specialized-payment-types/batch-transactions/send-a-single-account-batch-transaction.md index fdee0befbb..7c9021637a 100644 --- a/docs/tutorials/how-tos/use-specialized-payment-types/batch-transactions/send-a-single-account-batch-transaction.md +++ b/docs/tutorials/how-tos/use-specialized-payment-types/batch-transactions/send-a-single-account-batch-transaction.md @@ -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" /%}