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.
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
To attempt transaction order cancellation, you need the following:
| Prerequisite | Additional information |
|---|---|
| The ID of the transaction order to cancel | View transactions |
| A replacement transaction order ID, in a standard UUID format |
You can attempt transaction order cancellation through creation of an intent with a type of v0_AttemptTransactionOrderCancellation.
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": {
"targetTransactionOrderId": "a945fe8a-dcb0-43d7-8440-60fe42aaefbf",
"replacementTransactionOrderId": "18c6ff37-f896-4a69-8f75-c877fb4283c3",
"reason": "fee too small",
"maximumFee": "12500",
"type": "v0_AttemptTransactionOrderCancellation"
}| Field | Description |
|---|---|
targetTransactionOrderId | The transaction order to cancel. |
replacementTransactionOrderId | A new ID to use for a replacement transaction. |
reason | Reason for cancellation of this operation. |
maximumFee | An 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.
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:
- 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 toHigh. The only value you can set is the maximum fee. For more information, see Replace through transaction order cancellation. - Create a new transaction order with a
resourceStrategy.typeofOrderReplacement: 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.
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.
Ripple Custody creates a new transaction order with the following details:
| Ledger | Details |
|---|---|
| Bitcoin |
|
| Ethereum |
|
Ripple Custody updates the replaced transaction order as follows:
processing.status:InterruptedledgerStatus: first becomesReplacedand laterExpired.
You can replace a transaction order through creation of a new one that explicitly replaces the previous transaction order.
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": {
"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:
| Field | Description |
|---|---|
id | A new transaction order ID. |
resourceStrategy | Used 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": {
"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"
}
}
| Field | Description |
|---|---|
id | A new transaction order ID. |
resourceStrategy | Used 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.amount | The 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. |
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
AandBwhich are both unconfirmed. - The user submits a transaction replacement
Cfor transactionA. - Transaction
Ais successfully replaced byCand chained transactionBbecomes invalid.
Transactions A and B show processing.status as Interrupted, and ledgerStatus appears first as Replaced and later as Expired.