> ## Documentation Index
> Fetch the complete documentation index at: https://developers.paxoslabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Direct Withdrawal Cancellations

> Cancel pending withdrawal orders by calling the WithdrawQueue contract directly

This guide walks you through cancelling a pending [withdrawal order](/v0.5.2/intro/products/earn/developers/guides/direct-contract/withdrawals) by calling `cancelOrder()` on the **WithdrawQueue** contract directly. It covers both direct cancellation (you submit the transaction) and meta-transaction cancellation (a relayer submits on your behalf).

## How Cancellations Work

When you submitted a withdrawal order, the WithdrawQueue locked your account shares and minted an **ERC-721 NFT** to your address representing ownership of the order. To cancel:

<Steps>
  <Step title="Find your pending orders">
    Enumerate your order NFTs using the ERC-721 enumerable interface, then
    filter by `PENDING` status.
  </Step>

  <Step title="Cancel the order">
    Call `cancelOrder(orderIndex)`. The contract verifies you own the order NFT,
    then returns your account shares to the `refundReceiver` address.
  </Step>
</Steps>

There is no approval step — the only requirement is that `msg.sender` holds the NFT for the given order.

<Info>
  Only orders with `PENDING` status (value `1`) can be cancelled. Once an order
  has been fulfilled or is being processed, it cannot be cancelled.
</Info>

***

## What You'll Need

| Requirement           | Description                                                                                                                                   |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| Contract address      | `withdrawQueueAddress` — see [Account Discovery](/v0.5.2/intro/products/earn/developers/guides/direct-contract/vault-queries/vault-discovery) |
| ABI                   | Provided below                                                                                                                                |
| RPC endpoint          | An Ethereum node URL                                                                                                                          |
| Private key or wallet | The same wallet that submitted the withdrawal order                                                                                           |
| Order index           | From the `OrderSubmitted` event or NFT enumeration (shown below)                                                                              |

***

## ABI Reference

```json theme={null}
[
  {
    "inputs": [{ "name": "orderIndex", "type": "uint256" }],
    "name": "cancelOrder",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      { "name": "orderIndex", "type": "uint256" },
      { "name": "deadline", "type": "uint256" },
      { "name": "cancelSignature", "type": "bytes" }
    ],
    "name": "cancelOrderWithSignature",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [{ "name": "orderIndex", "type": "uint256" }],
    "name": "getOrderStatus",
    "outputs": [{ "name": "", "type": "uint8" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [{ "name": "tokenId", "type": "uint256" }],
    "name": "ownerOf",
    "outputs": [{ "name": "", "type": "address" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [{ "name": "owner", "type": "address" }],
    "name": "balanceOf",
    "outputs": [{ "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      { "name": "owner", "type": "address" },
      { "name": "index", "type": "uint256" }
    ],
    "name": "tokenOfOwnerByIndex",
    "outputs": [{ "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  }
]
```

***

## Contract Method Reference

### `cancelOrder(orderIndex)`

| Parameter    | Type      | Description                                                                                          |
| ------------ | --------- | ---------------------------------------------------------------------------------------------------- |
| `orderIndex` | `uint256` | Index of the order to cancel. Get this from the `OrderSubmitted` event or by enumerating order NFTs. |

### `cancelOrderWithSignature(orderIndex, deadline, cancelSignature)`

For meta-transaction support — a relayer can cancel on behalf of the order owner.

| Parameter         | Type      | Description                                                                                                        |
| ----------------- | --------- | ------------------------------------------------------------------------------------------------------------------ |
| `orderIndex`      | `uint256` | Index of the order to cancel                                                                                       |
| `deadline`        | `uint256` | Unix timestamp after which the signature expires                                                                   |
| `cancelSignature` | `bytes`   | EIP-712 signature from the order owner (see [Meta-Transaction Cancellation](#meta-transaction-cancellation) below) |

### ERC-721 Enumeration (finding your orders)

The WithdrawQueue is an ERC-721 contract. Each withdrawal order is represented by an NFT.

| Method                              | Returns   | Description                                         |
| ----------------------------------- | --------- | --------------------------------------------------- |
| `balanceOf(owner)`                  | `uint256` | Number of order NFTs held by the address            |
| `tokenOfOwnerByIndex(owner, index)` | `uint256` | The order index (token ID) at the given position    |
| `ownerOf(tokenId)`                  | `address` | The current owner of a specific order NFT           |
| `getOrderStatus(orderIndex)`        | `uint8`   | The order's current status (see status table below) |

### Order Statuses

| Value | Status                     | Cancellable? |
| ----- | -------------------------- | ------------ |
| `0`   | NOT\_FOUND                 | No           |
| `1`   | PENDING                    | **Yes**      |
| `2`   | COMPLETE                   | No           |
| `3`   | COMPLETE\_PRE\_FILLED      | No           |
| `4`   | PENDING\_REFUND            | No           |
| `5`   | COMPLETE\_REFUNDED         | No           |
| `6`   | FAILED\_TRANSFER\_REFUNDED | No           |

***

## Direct Cancellation Walkthrough

<Steps>
  <Step title="Find your order NFTs (read)">
    Get the number of order NFTs held by your address.

    ```
    WithdrawQueue.balanceOf(yourAddress) → uint256 orderCount
    ```

    If `orderCount` is 0, you have no orders to cancel.
  </Step>

  <Step title="Enumerate and filter pending orders (read)">
    Loop through your NFTs and check each order's status.

    For each `i` from `0` to `orderCount - 1`:

    ```
    WithdrawQueue.tokenOfOwnerByIndex(yourAddress, i) → uint256 orderIndex
    WithdrawQueue.getOrderStatus(orderIndex) → uint8 status
    ```

    Only orders with `status == 1` (PENDING) can be cancelled.
  </Step>

  <Step title="Cancel the order (transaction)">
    Call `cancelOrder()` for each pending order you want to cancel.

    ```
    WithdrawQueue.cancelOrder(orderIndex)
    ```

    The contract:

    1. Verifies that `msg.sender` owns the order NFT
    2. Returns the locked account shares to the `refundReceiver` address (set during order submission)
    3. Burns the order NFT

    Wait for the transaction to be mined. Your account shares are now unlocked and available.
  </Step>

  <Step title="Verify cancellation (read, optional)">
    Confirm the order status changed.

    ```
    WithdrawQueue.getOrderStatus(orderIndex) → uint8 status
    ```

    Expected: `5` (COMPLETE\_REFUNDED)
  </Step>
</Steps>

<Info>
  If you already know the `orderIndex` (e.g., you saved it from the
  `OrderSubmitted` event when you submitted the withdrawal), you can skip
  Steps 1–2 and go directly to cancellation. Just verify the order is still
  `PENDING` first.
</Info>

***

## Meta-Transaction Cancellation

For relayer or gasless cancellation, the order owner signs an EIP-712 message off-chain and anyone can submit the transaction.

### EIP-712 Type

```
Cancel(uint256 orderIndex, uint256 deadline, address queueAddress, uint256 chainId)
```

### Walkthrough

<Steps>
  <Step title="Build the EIP-712 typed data (off-chain)">
    **EIP-712 Domain**:

    | Field               | Value                 |
    | ------------------- | --------------------- |
    | `name`              | `"WithdrawQueue"`     |
    | `chainId`           | Chain ID (e.g., `1`)  |
    | `verifyingContract` | WithdrawQueue address |

    **Cancel message**:

    | Field          | Value                               |
    | -------------- | ----------------------------------- |
    | `orderIndex`   | The order to cancel                 |
    | `deadline`     | Unix timestamp (e.g., now + 1 hour) |
    | `queueAddress` | WithdrawQueue address               |
    | `chainId`      | Chain ID (e.g., `1`)                |
  </Step>

  <Step title="Sign the typed data (off-chain)">
    The order owner signs the EIP-712 typed data using their wallet's `signTypedData` method. This produces a 65-byte signature.
  </Step>

  <Step title="Submit via relayer (transaction)">
    Anyone can submit the cancellation using the owner's signature:

    ```
    WithdrawQueue.cancelOrderWithSignature(
      orderIndex,        // the order to cancel
      deadline,          // from the signed message
      cancelSignature    // 65-byte EIP-712 signature
    )
    ```

    The contract verifies the signature came from the order NFT owner and that the deadline hasn't passed.
  </Step>
</Steps>

<Warning>
  The `deadline` in the signed message and the `deadline` passed to
  `cancelOrderWithSignature()` **must match exactly**. If the current block
  timestamp exceeds the deadline, the transaction will revert with
  `SignatureExpired`.
</Warning>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="OnlyOrderOwnerCanCancel">
    Your wallet doesn't own this order's NFT. Only the original submitter (or
    whoever holds the NFT) can cancel.
  </Accordion>

  <Accordion title="InvalidOrderType">
    The order isn't in `PENDING` status. Check `getOrderStatus()` — only status
    `1` is cancellable.
  </Accordion>

  <Accordion title="InvalidOrderIndex">
    The order index doesn't exist. Verify it from the `OrderSubmitted` event or
    NFT enumeration.
  </Accordion>

  <Accordion title="SignatureExpired">
    The deadline in `cancelOrderWithSignature` has passed. Generate a fresh
    signature with a future deadline.
  </Accordion>
</AccordionGroup>

***

## Next Steps

* [Direct Deposits](/v0.5.2/intro/products/earn/developers/guides/direct-contract/deposits) — Deposit tokens into an account
* [Direct Withdrawals](/v0.5.2/intro/products/earn/developers/guides/direct-contract/withdrawals) — Submit a withdrawal order
* [Account Queries & Monitoring](/v0.5.2/intro/products/earn/developers/guides/direct-contract/vault-queries/index) — Read APY, TVL, check balances, and monitor withdrawal status
* [SDK Withdrawals Guide](/v0.5.2/intro/products/earn/developers/guides/withdrawals) — Cancel via the Amplify SDK instead
