Skip to main content

Overview

The CTF Exchange provides two functions for cancelling orders. Orders can only be cancelled by their maker (the address that holds funds for the order). Once cancelled, an order cannot be filled.

cancelOrder

Cancels a single order.
function cancelOrder(Order memory order) external

Parameters

order
Order
required
The order to be cancelled. See Order Structure for details.Must be an order where msg.sender is the maker.

Requirements

  • Caller must be the order maker (msg.sender == order.maker)
  • Order must not already be filled or cancelled

Behavior

  1. Verifies the caller is the order maker
  2. Computes the order hash
  3. Checks if order is already filled or cancelled
  4. Marks the order as isFilledOrCancelled = true in storage
  5. Emits OrderCancelled event

Events

OrderCancelled
event
Emitted when an order is successfully cancelled.
event OrderCancelled(bytes32 indexed orderHash)
  • orderHash: Hash of the cancelled order

Errors

NotOwner
error
Caller is not the order maker and cannot cancel this order
OrderFilledOrCancelled
error
Order has already been fully filled or previously cancelled

Example Usage

// Create an order
Order memory order = Order({
    salt: 1,
    maker: msg.sender,
    signer: msg.sender,
    taker: address(0),
    tokenId: yesTokenId,
    makerAmount: 50_000_000,
    takerAmount: 100_000_000,
    expiration: 0,
    nonce: 0,
    feeRateBps: 100,
    side: Side.BUY,
    signatureType: SignatureType.EOA,
    signature: signature
});

// Cancel the order (must be called by maker)
exchange.cancelOrder(order);

// Order is now unfillable
// Attempting to fill will revert with OrderFilledOrCancelled

cancelOrders

Cancels multiple orders in a single transaction.
function cancelOrders(Order[] memory orders) external

Parameters

orders
Order[]
required
Array of orders to be cancelled. See Order Structure for details.Requirements:
  • All orders must have msg.sender as the maker
  • Each order must not already be filled or cancelled

Requirements

  • Caller must be the maker for all orders in the array
  • Each order must not already be filled or cancelled
  • Transaction will revert if any order fails validation

Behavior

Iterates through the orders array and calls the internal _cancelOrder function for each order. All cancellations are executed atomically - if any order fails, the entire transaction reverts. For each order:
  1. Verifies the caller is the order maker
  2. Computes the order hash
  3. Checks if order is already filled or cancelled
  4. Marks the order as isFilledOrCancelled = true
  5. Emits OrderCancelled event

Events

OrderCancelled
event
Emitted for each order that is successfully cancelled.
event OrderCancelled(bytes32 indexed orderHash)

Errors

All errors from cancelOrder can be thrown for any order in the array:
NotOwner
error
Caller is not the maker for one or more orders
OrderFilledOrCancelled
error
One or more orders have already been fully filled or previously cancelled

Example Usage

// Create multiple orders
Order[] memory orders = new Order[](3);

orders[0] = Order({
    salt: 1,
    maker: msg.sender,
    signer: msg.sender,
    taker: address(0),
    tokenId: yesTokenId,
    makerAmount: 50_000_000,
    takerAmount: 100_000_000,
    expiration: 0,
    nonce: 0,
    feeRateBps: 100,
    side: Side.BUY,
    signatureType: SignatureType.EOA,
    signature: signature1
});

orders[1] = Order({
    salt: 2,
    maker: msg.sender,
    signer: msg.sender,
    taker: address(0),
    tokenId: yesTokenId,
    makerAmount: 25_000_000,
    takerAmount: 50_000_000,
    expiration: 0,
    nonce: 0,
    feeRateBps: 100,
    side: Side.BUY,
    signatureType: SignatureType.EOA,
    signature: signature2
});

orders[2] = Order({
    salt: 3,
    maker: msg.sender,
    signer: msg.sender,
    taker: address(0),
    tokenId: noTokenId,
    makerAmount: 30_000_000,
    takerAmount: 60_000_000,
    expiration: 0,
    nonce: 0,
    feeRateBps: 50,
    side: Side.SELL,
    signatureType: SignatureType.EOA,
    signature: signature3
});

// Cancel all orders in one transaction
exchange.cancelOrders(orders);

// All three orders are now unfillable

Important Notes

On-Chain State

Cancelling an order updates its on-chain state by setting isFilledOrCancelled = true. This is permanent and irreversible.

Signature Still Valid

Even after cancellation, the order’s cryptographic signature remains valid. However, any attempt to fill a cancelled order will fail the validation check and revert.

Gas Efficiency

Use cancelOrders instead of multiple cancelOrder calls to save gas when cancelling multiple orders.

Alternative: Nonce Increment

Instead of cancelling orders individually, makers can invalidate all their orders with a specific nonce by calling incrementNonce(). This is more gas-efficient when cancelling many orders. See Nonce Manager for details.

Pre-Cancellation

Orders can be cancelled before they are filled, even if they haven’t been submitted to the order book yet. This is useful for pre-emptively cancelling orders that may have been signed but not yet broadcast.

Use Cases

Single Order Cancellation

Use cancelOrder when you need to cancel a specific order:
  • Market conditions changed
  • Order was created with wrong parameters
  • Strategic repositioning of liquidity

Batch Cancellation

Use cancelOrders when you need to:
  • Cancel multiple orders from the same market
  • Clear all pending orders atomically
  • Reduce gas costs compared to individual cancellations

Emergency Cancellation

Quickly cancel all orders if:
  • Market experiences extreme volatility
  • Security concerns arise
  • Need to withdraw liquidity immediately

See Also