On October 9, 2026, BatchV1_1 became enabled on the XRP Ledger mainnet. For developers, this creates a practical way to group related ledger actions under one explicit execution policy. For software architects, it also creates a new responsibility: distinguish acceptance of the batch from completion of the business operation.
The XRPSCAN amendment record reports activation at 14:47:52 UTC / 16:47:52 CEST, in ledger 107540993. We independently queried the public mainnet Amendments ledger entry: validated ledger 107541231 contained both BatchV1_1 and fixBatchV1_2. This is an observed activation, rather than a forecast based on validator votes. The raw responses are preserved with this article's examples.
For Homann Software's work in software architecture, Java integration and blockchain engineering, the useful question is how this capability changes application boundaries. Consider a customer payment that must also pay a platform fee. Two separate submissions leave a period in which one obligation may be complete and the other unresolved. A batch can express the relationship on the ledger. Your application must still prove what happened before releasing an order or booking revenue.
What went live—and why the accompanying fix matters
The official amendment reference identifies BatchV1_1 as the XLS-56 batch feature that replaces the original Batch implementation and fixes its critical bug. XRPSCAN also records fixBatchV1_2 becoming enabled earlier today, at 14:15:21 UTC, in ledger 107540481. These are separate amendments with separate activation records. XRPSCAN activation data
The official xrpld 3.4.1 release announcement, dated September 25, describes an emergency security release introducing fixBatchV1_2. Its changelog identifies rejection of inner transactions with the wrong wrapper and additional integer-arithmetic hardening. Operators were instructed to upgrade; installing a compatible server release and activating a protocol amendment are different events.
There is earlier history, too. The original Batch amendment was disabled before mainnet activation after a signature-validation flaw was discovered in February. That flaw could have allowed unauthorized inner transactions; the disclosure says it never activated on mainnet and no funds were at risk. BatchV1_1 replaced that implementation. The February incident and September correction should not be collapsed into one bug or used to imply a theft occurred. Official February disclosure
Observed activation times come from XRPSCAN; both enabled IDs were independently found in a validated mainnet ledger entry. Protocol rules take effect for transactions in the ledger after the enabling ledger, rather than changing midway through it. Amendments ledger entry
The wider trend: richer ledger operations, explicit authority
Three developments make this a timely architecture topic. First, batch execution gives applications more control over how related actions complete. Second, permission delegation separates some operational powers from full account control. XRPSCAN records PermissionDelegationV1_1 activation on October 8 at 21:29:50 UTC. Third, the security releases show why deployment readiness must include the interaction between features and corrective amendments.
Permission delegation is relevant to automated services, but it is not a substitute for application authorization. The documentation describes revocable permissions and warns against delegating PaymentBurn until fixCleanup3_4_0 is enabled. That fix was still absent from our validated activation snapshot. Teams considering delegation should check its current status separately. Permission delegation documentation
Our engineering interpretation is that these changes make the ledger a more expressive execution platform. They also make a simple “transaction succeeded” abstraction less useful. An integration needs to know the intended business outcome, the authority that approved it, the execution mode and the evidence that permits a state transition.
This article extends our recent work on XRPL settlement evidence in Java and AI payment authorization with Spring AI. Here the focus is the relationship between multiple ledger actions.
Choose the batch mode from the business invariant
A batch contains two to eight inner transactions. The mode defines what should happen when one of those actions cannot succeed. Batch transaction reference
| Mode | Completion rule | Useful design question |
|---|---|---|
| All or Nothing | Every inner action must succeed for any to succeed. | Would a partial outcome violate the agreement? |
| Only One | The first successful action wins; later actions are skipped. | Are these alternatives to satisfy one obligation? |
| Until Failure | Apply a successful prefix; stop at the first failure. | Can the business accept that prefix? |
| Independent | Attempt each action despite failures in others. | Are these separate obligations that merely share transport? |
The four rules are described in the Batch concepts documentation. The questions in the right-hand column are our design guidance.
This is a conceptual comparison, not a ledger execution trace. It illustrates the difference between a joint commitment, alternatives, a prefix and independent obligations.
For a merchant payment plus platform fee, we choose All or Nothing if the agreement requires both transfers. For unrelated payouts, Independent may be appropriate, but the application then needs a status for each obligation. Naming the group “batch” should never erase those distinctions.
A multi-account swap introduces another review requirement. Every participant must approve the collection, not just a private interpretation of their own leg. Inner transactions remain unsigned; authorization belongs to the batch arrangement. The XLS-56 specification explains how this prevents a participant from extracting a separately signed payment or changing the exchange after another party approves it.
That leads to a concrete interface rule: display the entire proposal and its mode before signing. In a service, persist the exact approved plan and the network it targets. In an AI-assisted workflow, the agent may propose the plan, but a trusted component should enforce authority over every action in it.
A small, tested example: prepare the plan without moving funds
The accompanying Python example uses only the standard library. It demonstrates a restricted single-account batch of direct XRP payments and a conservative completion check. Python keeps the boundary easy to inspect and run; the same checks can be implemented in a Java service around an XRPL client.
The builder accepts integer drops, an explicit fee cap, reserved sequences and an expiry ledger. It sets All or Nothing on the outer transaction and supplies zero fees, an empty signing public key and the inner-batch flag on each payment. These requirements follow the single-account tutorial.
import json
from batch_boundary import build_batch, complete_all_or_nothing, Observation
# Synthetic account labels: this demonstration never signs or submits anything.
template = build_batch("payer", 100, 500, 40, 100,
[("merchant", 1_000_000), ("platform", 1_000)])
print(json.dumps(template, indent=2))
outer_hash, first, second = "A" * 64, "B" * 64, "C" * 64
outer = Observation(outer_hash, 200, True, "tesSUCCESS")
inner = [Observation(h, 200, True, "tesSUCCESS", outer_hash) for h in (first, second)]
print("Complete evidence:", complete_all_or_nothing(outer_hash, [first, second], outer, inner).value)
print("Missing evidence:", complete_all_or_nothing(outer_hash, [first, second], outer, inner[:1]).value)
The demo deliberately uses synthetic account labels and hashes. Its output is a JSON template and two decisions: complete evidence returns confirmed; missing evidence returns reconcile. It is not a signable production transaction. A real adapter must validate addresses and destination tags, use an XRPL binary codec, reserve account sequences against concurrent writers, obtain a suitable fee, check balances and reserves, and bind the signed transaction to the approved network and plan. The illustrative 40-drop fee is a test input, not a live fee quote or estimate.
The builder rejects zero, negative, fractional and boolean amounts; too few or too many payments; fees above the cap; and sequence overflow. It intentionally omits issued tokens, partial payments, Tickets, delegation and multiple signers. Extending it to those cases requires additional rules and tests rather than simply adding fields.
Outer success is not proof that the obligation completed
The outer Batch transaction has its own fee and sequence processing. Its tesSUCCESS result does not establish that every inner action succeeded. The official tutorial explicitly requires computing the inner transaction hashes and retrieving their results. Result verification tutorial
Our example checks an approved set of expected hashes against normalized observations supplied by a trusted RPC adapter. It requires a validated outer result, the complete expected inner set, successful inner results, the same ledger and the correct ParentBatchID. It treats missing or contradictory evidence as a reconciliation task.
def complete_all_or_nothing(expected_outer, expected_inner, outer, inner):
"""Confirm inclusion and tesSUCCESS for every planned inner hash.
Expected hashes MUST come from the approved, persisted signed plan and an
XRPL binary-codec implementation. Missing evidence remains RECONCILE.
This does not verify delivered amounts, asset identity or business posting.
"""
expected = tuple(expected_inner)
if (not hash256(expected_outer) or not 2 <= len(expected) <= 8
or any(not hash256(h) for h in expected)
or len(set(expected)) != len(expected) or expected_outer in expected):
raise ValueError("invalid planned hashes")
if (outer.hash != expected_outer or outer.validated is not True
or type(outer.ledger_index) is not int or outer.ledger_index <= 0
or outer.result != "tesSUCCESS" or outer.parent_batch_id is not None):
return Outcome.RECONCILE
observed = tuple(inner)
if len(observed) != len(expected) or {tx.hash for tx in observed} != set(expected):
return Outcome.RECONCILE
for tx in observed:
if (tx.validated is not True or type(tx.ledger_index) is not int
or tx.ledger_index != outer.ledger_index
or tx.parent_batch_id != expected_outer or tx.result != "tesSUCCESS"):
return Outcome.RECONCILE
return Outcome.CONFIRMED
Two choices are deliberate. Expected hashes come from the persisted plan, not from whichever transactions an observer happens to return. And a missing inner result is not automatically classified as a failed business operation. An incomplete provider response or indexing delay is insufficient evidence to make that decision.
Here, CONFIRMED means only that all expected inner transactions have matching validated success observations. Before updating an invoice or delivering goods, production code must also check the relevant payment metadata, delivered value, asset identity and business reference. The sample neither parses raw RPC responses nor verifies signatures. Its observations are synthetic test fixtures, not records of successful live payments.
Proposed integration sequence. Only the preparation and evidence-checking components are implemented in the example. Signing, submission, durable workflow and database posting are production extensions. Editable PlantUML source is included in the package.
The ledger boundary also stops at the ledger. Sending an email, reserving inventory or writing to a SQL database does not become atomic with the batch. We would keep application state durable, record the verified ledger evidence, and commit the local business update with an outbox event. Consumers would handle replay using a business idempotency key. A timeout should move work into reconciliation, where the original transaction identity can be checked before creating another plan.
Verify activation from a validated ledger
The package includes a read-only activation checker. It queries ledger_entry for the Amendments object and requires both the feature and corrective amendment IDs in its enabled list. Majority support alone does not satisfy the check. ledger_entry API
def activation_ready(response):
result = response.get("result", {})
node = result.get("node", {})
return (result.get("status") == "success"
and result.get("validated") is True
and type(result.get("ledger_index")) is int
and result["ledger_index"] > 0
and node.get("LedgerEntryType") == "Amendments"
and {BATCH_ID, FIX_ID}.issubset(set(node.get("Amendments", []))))
For our research snapshot, the checker returned batch_and_fix_enabled: true at ledger 107541231. The response also records ledger hash 32CFE796E1252A90DEB8211A68C3284D6893E1BAD9434599C76947192B0ADDA3. This independently confirms the two amendments were enabled; the precise activation times reported above remain attributed to XRPSCAN. A production service should select and monitor its own trusted RPC infrastructure and bind that configuration to the intended network.
What we tested, and what remains to test
Download the tested examples, raw activation evidence and editable UML source.
We executed the example with Python 3.13.14. All 30 tests passed, covering plan construction, input boundaries, fee caps, sequence overflow, complete and incomplete evidence, duplicates, unexpected hashes, wrong parents, different ledgers, provisional results and activation checks. Three deliberately weakened variants—accepting outer success alone, ignoring the parent link and ignoring the ledger relationship—were rejected by the unchanged test suite.
Run the downloaded example from its examples directory:
python -m unittest -v test_batch_boundary.py
python demo.py
python verify_activation.py ../evidence/validated-amendments.json
The last command rechecks the saved evidence offline. Running python verify_activation.py performs a fresh, read-only public mainnet request. Neither path needs a wallet or moves funds.
These tests establish the behavior of our application boundary. They do not execute consensus rules, reproduce the server vulnerabilities, prove cryptographic authorization or measure throughput. We submitted no payment and ran no live settlement experiment. A release candidate should additionally exercise a compatible test network, failed inner actions, signing and binary encoding, process crashes, provider outages, sequence contention and idempotent business posting.
The architectural opportunity
BatchV1_1 gives teams a useful tool for representing related ledger actions. Its value depends on choosing a mode that matches the business agreement and preserving enough evidence to tell whether that agreement completed.
For a first integration, start with one bounded use case: one payer, a small set of direct payments, a clearly approved plan and an explicit reconciliation path. Expand to more assets, accounts and permissions when the model and tests support them. Today's activation is the start of that engineering work.