Ripple Custody version 1.34 migrates core balance tracking and transaction processing to a new event-driven accounting service. This guide describes the behavioral changes the new service introduces for API integrations and the one-time migration procedure for on-premises deployments.
The behavioral changes apply to all deployments. The migration procedure applies to on-premises deployments only; Ripple manages the migration for SaaS deployments.
Review these changes and update your integrations before you migrate:
- Use the
availableAmountbalance field. The accounting service computes the available balance directly. The old formula,totalAmount - reservedAmount - quarantinedAmount, can produce incorrect results in some situations, such as an incoming transaction in theDetectedstate. Use theavailableAmountfield from Get account balances instead. - Negative balances. Starting in version 1.38, the
totalAmountandavailableAmountbalance fields can hold values below zero, encoded as strings with a leading-. ThereservedAmountandquarantinedAmountfields still accept only non-negative values. A negative balance represents an on-chain state of outstanding debt or liability, such as an XRPL Multi-Purpose Token (MPT) issuer's balance for its own asset. If your integration parses these fields as unsigned values, or validates that balances are non-negative, update it to accept negative values. For details, see Ledger accounting refactor in the version 1.38 release notes. - Inbound processing status. The processing status of inbound transactions is now tracked and populated, in addition to outbound transactions.
- Concurrent processing. Transactions are processed concurrently. There is no guarantee that transactions are processed in the order you submit them. If your integration depends on submission order, enforce the ordering on your side.
- One sender per transfer. The new accounting service supports one sender per transfer.
- Outbound transaction processing pauses after 168 hours. If an outbound transaction can't be funded, the accounting service stops attempting to reserve funds for it after 168 hours (7 days). The transaction then no longer progresses on its own — even if it reaches the chain — and no balance updates or transfers are created for it. To resume processing, contact Ripple Support; processing can be resumed for up to two months.
- Replacement transactions are interrupted at finality. When a transaction is replaced, its status changes to
Interruptedonly after the replacement transaction reaches finality. Previously, the status changed as soon as the replacement was detected, before finality. - Reserved balance tracking on UTXO chains. On UTXO-based chains such as Bitcoin, the accounting service reserves the full value of the UTXOs the transaction will spend, which can exceed the transaction amount and fees. When the transaction is detected, the change amount — the reserved amount minus the transaction amount and fees — is released from the reservation. Previously, the entire reserved amount was released when the transaction reached the mempool.
- Replaced outbound transactions deactivate their transfers. When an outbound transaction is successfully replaced on-chain, its associated transfers are deactivated automatically. Previously, you had to handle those transfers manually by releasing quarantines.
- Don't release quarantines for replaced inbound transactions. When an inbound transaction is replaced, don't release the quarantines on the replaced transaction's transfers. Previous guidance was to release them so that they no longer counted toward the quarantined balance. The new accounting service might not allow those releases; contact Ripple Support to fail the replaced transaction instead.
- Orders that spend quarantined funds can get stuck. Previously, you could spend quarantined funds by submitting an order that doesn't clearly specify which funds it spends, such as a contract call order. After the migration, such a transaction still reaches the chain, but it can get stuck in the
Detectedstate. Make sure your compliance checks skip or release quarantines before you submit such transactions. - Replacement transaction accounting. When an outbound replacement transaction is detected — in the mempool for Bitcoin, or on-chain for other ledgers — the accounting service reverses all balance updates made by the replaced transaction before it registers the balance updates for the replacement transaction.
In this example scenario, Bitcoin transaction T2 replaces T1 with a higher fee, and both transactions over-reserve. The principal is 50, the fee on T1 is 10, the fee on T2 is 20, and each transaction reserves 100.
While a transaction is detected but not yet confirmed, the spent amount is deducted from totalAmount and is still counted in reservedAmount. As a result, reservedAmount can exceed totalAmount, and availableAmount is not totalAmount - reservedAmount. This is another reason to read availableAmount directly.
| Step | totalAmount | reservedAmount | availableAmount |
|---|---|---|---|
| Initial state | 100 | 0 | 100 |
T1 reserved, over-reserving | 100 | 100 | 0 |
T1 detected: change of 40 released, 60 spent | 40 | 60 | 40 |
T2 reserved: no additional reservation required | 40 | 60 | 40 |
T2 detected: T1 reversed, then T2 reserved and detected | 30 | 70 | 30 |
T2 confirmed | 30 | 0 | 30 |
Before starting the migration, confirm that:
- Your release package includes the new accounting services and their Helm charts.
- You have a maintenance window: the migration requires you to stop accepting new requests until it completes.
- You have a current backup of your database.
Run this check before you open your maintenance window. An account whose quarantined balance is greater than its total balance blocks the balance migration, and finding one after you've stopped accepting requests costs you the window.
To list the accounts in this state, call:
GET /internal/v1/migrations/lar-phase1-migration-sanity-checkIf quarantineExceedsTotalBalance is empty, nothing blocks the migration. Otherwise, the response identifies each affected account, the amount by which its quarantined balance exceeds its total balance, and the quarantined transfers that account for the excess:
{
"quarantineExceedsTotalBalance": [
{
"accountId": "a9333504-7f25-451f-9a57-ba74f5908753",
"domainId": "5cd224fe-193e-8bce-c94c-c6c05245e2d1",
"tickerId": "46a19341-5c3a-4aa2-bf15-aca3e4ffbee2",
"totalAmount": "0",
"quarantinedAmount": "5000000",
"excessAmount": "5000000",
"quarantinedTransfers": [
{
"transferId": "32442da4-9c09-4f0f-b48e-ba9cbf7a7661",
"transactionId": "3ea66660-1538-454d-9607-ec5fff98452b",
"value": "2000000",
"registeredAt": "2026-09-25T15:10:49.164Z"
}
]
}
]
}Amounts are strings, because these values can exceed the precision of a JSON number.
If the check reports any accounts, contact Ripple Support before you migrate.
Migrating to the new accounting flow is a one-time process:
Deploy the release with
HMZ_TEMPORAL_MIGRATION_ENABLEDandHMZ_ACCOUNTING_SERVER_ENABLEDset tofalse, and deploy all the new services with Helm. Confirm the system operates normally before continuing — this isolates the accounting migration from the release's unrelated changes.Make sure there are no in-flight outgoing transactions, and stop accepting new requests (such as new outgoing transactions or quarantine releases) until the migration completes.
Set
HMZ_TEMPORAL_MIGRATION_ENABLEDandHMZ_ACCOUNTING_SERVER_ENABLEDtotrueand restart all services.Wait for the balance migration to complete. It starts automatically the first time Ripple Custody runs with the new accounting flow enabled, and validates account balances as part of the same run — you don't need to trigger or validate it yourself. To follow its progress, monitor the
txnprocessorpod logs for:Balance migration converged. Saving COMPLETED.Resume normal operations. If account balances are found out of sync after migration, run a force balance refresh to sync on-chain balances with the accounting service.
- IBM s390x: Ledger Accounting does not support IBM s390x architecture. This affects non-secure components only; the notary and vault continue to be supported on s390x architecture.
- Staking balance sync: During Substrate staking operations, balances can go out of sync; run a force balance refresh after the operations complete. A fix follows the LTS release. Balances also go out of sync when staking rewards are paid out on Cardano and Ethereum — as in previous releases — so run force balance refresh after rewards payouts.
- ERC20 transfer event accuracy: The platform tracks token movements through ERC20
Transferevents. If a buggy or non-compliant contract emitsTransferevents without moving balances, transaction history shows transfers that didn't move funds. This is an inherent blockchain limitation, unchanged from previous releases, and compliant contracts are not affected. After interacting with such a contract, run a force balance refresh to sync balances.
For additional assistance with the migration, contact your Customer Partner Engineer (CPE) or Ripple Support.