Skip to content

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.

Behavioral changes

Review these changes and update your integrations before you migrate:

  • Use the availableAmount balance 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 the Detected state. Use the availableAmount field from Get account balances instead.
  • Negative balances. Starting in version 1.38, the totalAmount and availableAmount balance fields can hold values below zero, encoded as strings with a leading -. The reservedAmount and quarantinedAmount fields 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 Interrupted only 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 Detected state. 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.

Example: balance changes during a Bitcoin replacement

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.

SteptotalAmountreservedAmountavailableAmount
Initial state1000100
T1 reserved, over-reserving1001000
T1 detected: change of 40 released, 60 spent406040
T2 reserved: no additional reservation required406040
T2 detected: T1 reversed, then T2 reserved and detected307030
T2 confirmed30030

Prerequisites

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.

Pre-migration sanity check

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-check

If 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.

Migration procedure

Migrating to the new accounting flow is a one-time process:

  1. Deploy the release with HMZ_TEMPORAL_MIGRATION_ENABLED and HMZ_ACCOUNTING_SERVER_ENABLED set to false, 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.

  2. 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.

  3. Set HMZ_TEMPORAL_MIGRATION_ENABLED and HMZ_ACCOUNTING_SERVER_ENABLED to true and restart all services.

  4. 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 txnprocessor pod logs for:

    Balance migration converged. Saving COMPLETED.
  5. 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.

Known issues and limitations

  • 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 Transfer events. If a buggy or non-compliant contract emits Transfer events 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.

Support

For additional assistance with the migration, contact your Customer Partner Engineer (CPE) or Ripple Support.