# Cancel or replace a transaction

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 resources for the transaction are not yet fully allocated within the governance engine, you can cancel it with an intent type of `v0_AttemptTransactionOrderCancellation`.
For more information, see [Cancel transactions](#cancel-transactions).
- Replace the transaction order: If the resources for the transaction are fully allocated within the governance engine, 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](#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](/products/custody/v1.34/concepts/transactions-processing#ripple-custody-statuses)

### Prerequisites

To attempt transaction order cancellation, you need the following:

| Prerequisite | Additional information |
|  --- | --- |
| The ID of the transaction order to cancel | [View transactions](/products/custody/v1.34/api/accounting/transactions/view) |
| 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, follow the [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent) tutorial.

To attempt transaction order cancellation, follow the steps in [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent), with a payload similar to the following example.

#### Payload example


```json
"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`.

[Learn more about transaction statuses](/products/custody/v1.34/concepts/transactions-processing#ripple-custody-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](#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-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](#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:

| Ledger | Details |
|  --- | --- |
| 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, follow the [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent) tutorial.

To replace the transaction order, follow the steps in [Request a change with an intent](/products/custody/v1.34/resources/tutorials/intent), with a payload similar to one of the following examples.

#### Payload example - Ethereum


```json
{
    "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 example - Bitcoin


```json
{
    "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. |


#### 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`.