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

# Cancelling Offers and Recovering Escrowed Collateral

Sellers can cancel the unfilled portion of any open offer at any time. Already-filled portions are final and unaffected.

## Authorization

Only the original seller (`msg.sender` at `createOffer` time) may cancel an offer. Any other address calling `cancel` with your `offerId` will revert with `NotSeller()`. There is no admin override — collateral recovery is strictly permissioned to the seller.

## Function Signature

```solidity theme={null}
function cancel(uint256 offerId) external;
```

## Parameters

<ParamField path="offerId" type="uint256" required>
  The sequential identifier of the offer to cancel. This is the `uint256` value returned by `createOffer` and emitted in the `OfferCreated` event. Calling `cancel` with an `offerId` that belongs to a different seller, is already inactive, or has no remaining assets will revert.
</ParamField>

## Effects

When `cancel` succeeds, the following state changes occur atomically:

1. The offer's `assetRemaining` is set to `0` and `active` is set to `false` — no further calls to `fill` on this `offerId` will succeed.
2. The remaining unfilled escrowed asset balance is transferred back to the seller's wallet.
3. An `OfferCancelled` event is emitted.

## Revert Conditions

| Condition                    | Error               |
| ---------------------------- | ------------------- |
| `offerId >= nextOfferId`     | `OfferNotFound()`   |
| `msg.sender != offer.seller` | `NotSeller()`       |
| `offer.active == false`      | `OfferInactive()`   |
| `offer.assetRemaining == 0`  | `NothingToCancel()` |

## Events

```solidity theme={null}
event OfferCancelled(
    uint256 indexed offerId,
    uint256 assetDebited,
    uint256 assetReceived
);
```

`assetDebited` is the amount removed from escrow (the full `assetRemaining`). `assetReceived` is the net amount the seller actually receives — for fee-on-transfer asset tokens this may be slightly less than `assetDebited` due to transfer fees applied on the return transfer.

## Partial Fill, Then Cancel

Cancellation returns whatever collateral remains after all fills. For example, if you created an offer with 500,000 tokens and 200,000 tokens were filled across one or more `fill` calls, cancellation returns the remaining 300,000 tokens to your wallet.

```
assetDebited = offer.assetRemaining (before cancel)
```

You do not need to track this arithmetic yourself — the contract maintains the fill state and applies it automatically.

## Example: Cancelling an Offer

<CodeGroup>
  ```typescript ethers.js v6 theme={null}
  import { ethers } from "ethers";

  const VENUE_ADDRESS = "0xYourVenueAddress";
  const venue = new ethers.Contract(VENUE_ADDRESS, VENUE_ABI, signer);

  // Cancel the offer — remaining escrowed assets are returned in the same tx
  const tx = await venue.cancel(offerId);
  await tx.wait();

  console.log("Offer cancelled. Remaining escrowed assets are back in your wallet.");
  ```

  ```typescript With Pre-flight Check theme={null}
  import { ethers } from "ethers";

  const venue = new ethers.Contract(VENUE_ADDRESS, VENUE_ABI, signer);

  // Fetch offer state before cancelling
  const offer = await venue.offers(offerId);

  if (!offer.active) {
    throw new Error("Offer is already inactive.");
  }
  if (offer.assetRemaining === 0n) {
    throw new Error("Offer has no remaining assets — nothing to cancel.");
  }

  const tx = await venue.cancel(offerId);
  const receipt = await tx.wait();
  console.log("Cancelled in block:", receipt.blockNumber);
  ```
</CodeGroup>

<Warning>
  You cannot reverse individual fills. Once assets are exchanged in a `fill` call they are permanently settled. Cancellation only reclaims the unfilled escrow balance and has no effect on prior fills.
</Warning>

<Info>
  For deferred forward offers, cancelling the offer does **not** invalidate already-issued claim tokens. Any buyers who received claim tokens before the cancellation retain valid, redeemable positions. They will still be able to call `redeem` after the unlock time to receive their share of the collateral that was committed to their fills.
</Info>
