Skip to content

If a transaction cannot be fully posted on chain, for example, if the transaction order has insufficient fees, you can attempt to fix the issue in one of the following ways:

  • Cancel the transaction order: If the transaction processing workflow has not fully allocated the transaction resources, you can cancel it with an intent type of v0_AttemptTransactionOrderCancellation.

    For more information, see Cancel transactions.

  • Replace the transaction order: If the transaction processing workflow has fully allocated the transaction resources, a straight cancellation is no longer possible and you need to replace the transaction order instead. You can replace the transaction order in one of the following ways:

    • Replace the order through cancellation: If successful, Ripple Custody automatically creates a new transaction order to replace the previous one.
    • Create a new transaction order manually to replace the previous transaction order.

    For more information, see Replace transactions.

Cancel transactions

These steps describe how to attempt transaction order cancellation. You can cancel transactions that are currently in any status up to and including Preparing on all ledgers.

Learn more about transaction statuses

Prerequisites

To attempt transaction order cancellation, you need the following:

PrerequisiteAdditional information
The ID of the transaction order to cancelView transactions
A replacement transaction order ID, in a standard UUID format

Attempt transaction order cancellation

You can attempt transaction order cancellation through creation of an intent with a type of v0_AttemptTransactionOrderCancellation.

System change process

All new requests to change the system state follow the same process. To familiarize yourself with this process first, see Manage intents and approvals.

To attempt transaction order cancellation, follow the steps in Manage intents and approvals, with a payload similar to the following example.

Payload example

"payload": {
    "targetTransactionOrderId": "a945fe8a-dcb0-43d7-8440-60fe42aaefbf",
    "replacementTransactionOrderId": "18c6ff37-f896-4a69-8f75-c877fb4283c3",
    "reason": "fee too small",
    "maximumFee": "12500",
    "type": "v0_AttemptTransactionOrderCancellation"
}
FieldDescription
targetTransactionOrderIdThe transaction order to cancel.
replacementTransactionOrderIdA new ID to use for a replacement transaction.
reasonReason for cancellation of this operation.
maximumFeeAn optional fee to cap the cost of the transaction.

When the intent is successfully approved and executed, the transaction order is cancelled and the status of the transaction changes to Interrupted.

Learn more about transaction statuses

Replace transactions

You can only replace transactions on Bitcoin and Ethereum ledgers.

If the transaction is in any status between Reserved and Broadcasting, you can no longer cancel the transaction order, you can only replace it. You can create a replacement transaction order using one of the following methods:

  1. Create an intent of type v0_AttemptTransactionOrderCancellation: With this method, Ripple Custody automatically creates the replacement transaction order for you and sets the fee strategy to High. The only value you can set is the maximum fee. For more information, see Replace through transaction order cancellation.
  2. Create a new transaction order with a resourceStrategy.type of OrderReplacement: With this method, you manually create the replacement transaction order, so you can change other fields of the transaction order as needed. For more information, see Replace through transaction order creation.

Replace through transaction order cancellation

You can replace a transaction order through cancellation of the previous one.

To replace the transaction order in this way, follow the instructions in Attempt transaction order cancellation.

When the intent is successfully approved, if the transaction is still not mined, Ripple Custody automatically creates a replacement transaction order and updates the replaced transaction order as described below.

Replacement transaction order

Ripple Custody creates a new transaction order with the following details:

LedgerDetails
Bitcoin
  • destination: The replaced transaction's sender account.
  • amount: The sum of all the outputs amounts of the replaced transaction.
  • paysFee: Set to true.
  • feeStrategy: Set to Priority with value High
  • resourceStrategy: Set to OrderReplacement, where the property transactionOrderId is the replaced transaction
Ethereum
  • destination: The replaced transaction's sender account.
  • amount: 0.
  • feeStrategy: Set to Priority with value High.
  • resourceStrategy: Set to OrderReplacement, where the property transactionOrderId is the replaced transaction order ID.

Replaced transaction order

Ripple Custody updates the replaced transaction order as follows:

  • processing.status: Interrupted
  • ledgerStatus: first becomes Replaced and later Expired.

Replace through transaction order creation

You can replace a transaction order through creation of a new one that explicitly replaces the previous transaction order.

System change process

All new requests to change the system state follow the same process. To familiarize yourself with this process first, see Manage intents and approvals.

To replace the transaction order, follow the steps in Manage intents and approvals, with a payload similar to one of the following examples.

Payload example - Ethereum

{
    "payload": {
        "id": "953d75b2-e384-46e9-8a72-a1ce753a50e2",
        "accountId": "7bb5622f-3c66-4244-8608-a6e92104d0f1",
        "parameters": {
            "destination": {
                "accountId": "f0048a50-3988-4e31-9cbf-c4b6582d338d",
                "type": "Account"
            },
            "amount": "1",
            "feeStrategy": {
                "priority": "High",
                "type": "Priority"
            },
            "maximumFee": "63000000000000",
            "data": null,
            "resourceStrategy":{
                "transactionOrderId":"a945fe8a-dcb0-43d7-8440-60fe42aaefbb",
                "type":"OrderReplacement"
                },
            "type": "Ethereum"
        },
        "description": "a eth transaction to an hmz account",
        "customProperties": {},
        "type": "v0_CreateTransactionOrder"
    }
}

Fields to note are as follows:

FieldDescription
idA new transaction order ID.
resourceStrategyUsed to replace the transaction in the mempool. The only available type is OrderReplacement and transactionOrderId is the ID of the previous transaction order to replace.

Payload example - Bitcoin

{
    "payload": {
        "id": "06cb5ed2-6a75-4759-96a1-bc1e2ac9e90a",
        "accountId": "b82a94ea-78f3-4fd4-8790-d8e4d6958986",
        "parameters": {
            "outputs": [
                {
                    "destination": {
                        "address": "2N2SzRSyeq8nu732jMa6CWs1ejVn7Z6WkX3",
                        "type": "Address"
                    },
                    "amount": "300000",
                    "paysfee": true
                },
                {
                    "destination": {
                        "accountId": "ccbe557e-48af-4514-b835-9675a8a6ea92",
                        "type": "Account"
                    },
                    "amount": "200000"
                }
            ],
            "feeStrategy": {
                "priority": "High",
                "type": "Priority"
            },
            "maximumFee": "10000",
            "resourceStrategy": {
                "transactionOrderId": "1d5b4330-d07a-4623-96aa-b6485acf3121",
                "reason":"Order to replace previous order",
                "type": "OrderReplacement"
            },
            "type": "Bitcoin"
        },
        "description": "double tx to check new policy",
        "customProperties": {},
        "type": "v0_CreateTransactionOrder"
    }
}
FieldDescription
idA new transaction order ID.
resourceStrategyUsed to replace the transaction in the mempool. The only available type is OrderReplacement and transactionOrderId is the ID of the previous transaction order to replace.
outputs.amountThe replacement transaction consumes at least all the UTXOs of the replaced transaction, so the replacement transaction total must equal at least the total of the replaced transaction, and have higher fees, to ensure the validator picks this transaction up instead of the replaced transaction.

Bitcoin chained transactions replacement

In a scenario where a user submits two chained transactions to a Bitcoin ledger, the replacement takes place as follows:

  • The user has two chained transactions A and B which are both unconfirmed.
  • The user submits a transaction replacement C for transaction A.
  • Transaction A is successfully replaced by C and chained transaction B becomes invalid.

Transactions A and B show processing.status as Interrupted, and ledgerStatus appears first as Replaced and later as Expired.