Cancel orders
On this page, we explore the various methods available to traders for canceling live orders. Immutable's Global orderbook supports both soft (gas-free) and hard cancels, providing traders with versatile options to manage their risk and operational expenses effectively.
Immutable provides two distinct types of orders:
- Listings: These are orders initiated by an NFT owner who intends to sell their asset on a marketplace. Listings are considered sell orders.
- Bids: Representing a prospective buyer's intention to acquire an asset, bids allow users to express their interest in purchasing a specific asset. Users can place a bid on the order book, anticipating a match with a seller. Bids are considered buy orders.
How cancels are enforced at Immutable
Immutable offers a centralized global orderbook but does not act as an intermediary during the trading process. In most cases, trades are settled through a settlement contract, ensuring secure and trustless peer-to-peer trading.
In simpler terms, marketplaces and traders can easily find liquidity thanks to orders listed on Immutable's orderbook. However, the actual trading process is facilitated by a settlement contract.
Executing a trade involves several steps, as depicted in the accompanying diagram:
- The buyer selects a sell order they want to purchase and sends a buy order to Immutable's Global orderbook via a marketplace.
- Immutable prepares the trade instructions (payload) in preparation to be submitted to the settlement contract to settle the trade. This is sent to the buyer to sign the transaction.
- The buyer reviews and signs the transaction.
- The signed transaction is transmitted to the settlement contract.
- The settlement contract executes the trade, swapping assets between the buyer's and seller's wallets, provided all details are valid.
Once the buyer obtains the signature for the future trade, routing this signed transaction to the settlement contract will trigger the trade, assuming it remains a valid transaction.
This setup allows for two opportunities to cancel a potential trade if the order is no longer live:
Soft Cancel at Step 2: Prevent Immutable's orderbook from providing transaction details for signature. Since Immutable's orderbook is off-chain, this cancellation method does not require gas to implement.
Hard Cancel at Step 5: Prevent the settlement contract from executing the trade. As the settlement contract operates as an on-chain smart contract, implementing a hard cancel requires gas.
"Gas" refers to the computational unit or fee required to perform actions or transactions on a blockchain network. Gas exists on the blockchain for 2 primary reasons:
Transaction Fees: To incentivize miners or validators to include a transaction or smart contract execution in a block, users must attach a certain amount of gas to their transactions.
Preventing Spam and Misuse: Gas serves as a mechanism to prevent spam and abuse of the blockchain network. Users have to pay for the resources they consume, discouraging frivolous or malicious activities.
In trading transactions, the buyer is responsible for the gas fees, which vary depending on network congestion and are determined at the time of the transaction. Hard cancels require the seller to pay for gas. To minimize costs for the seller and enhance the user experience, Immutable advises the use of soft cancels, particularly when the seller can accommodate the potential race conditions described below.
Soft Cancels: Gasless Cancellation
Gasless cancellation provides traders with the ability to cancel their orders without incurring gas fees. Cancelling the order on the off-chain orderbook prevents the transaction details being prepared for the trader to sign without incurring gas fees. Immutable ensures the trader initiating the cancellation is the owner of the original orders by having them signing a message confirming their ownership of the asset (See EIP712 for more details). Once this signature is submitted to the orderbook, it ensures that transaction details (i.e. fulfillment data payload) can no longer be generated for these orders, rendering them unfillable by any other user (corresponding to Step 2 in the diagram above).
In simple terms, a gasless cancel means that Immutable refrains from preparing transaction details for the settlement contract to execute. This approach is particularly beneficial for traders aiming to minimize gas costs in their trading activities.
However, it's important to note that this method introduces additional asset risk due to potential race conditions. If a trader has already initiated a transaction through Immutable's orderbook before the cancel request is received, that trader can still execute this transaction with the settlement contract. While the settlement contract validates the information within the transaction, it does not verify if the order is still live.
Transactions issued by Immutable's orderbook remain valid for 90 seconds (by default) after being issued. This means that the asset involved in the canceled trade may still be exchanged at the previously agreed-upon price if the signature is routed to the settlement contract within this 90-second window.
It's important to understand that the window during which an order can be executed after a soft cancel is placed is 90 seconds from when Immutable's orderbook provides the transaction details to the trader for a signature (step 2 in the diagram above), not from when the cancel was initiated. This means that the race condition exists for less than 90 seconds from when the cancel was accepted. During this time, the asset involved in the canceled trade may still be exchanged for the previously agreed-upon price.
When a soft cancellation is requested, Immutable has the capability to notify the requester if the order has an active transaction in progress that is awaiting signature. This can be used by marketplaces to warn traders that their orders may still execute post cancellation. Traders may choose to place a hard cancel in this situation to remove the risk of execution post cancellation request.
How to perform a soft cancel
Copy the below code to simulate a gasless soft cancel:
import { orderbook } from '@imtbl/sdk';
import { Wallet } from 'ethers'; // ethers v5
const cancelListings = async (
client: orderbook.Orderbook,
signer: Wallet,
listingIds: string[]
) => {
const account = await signer.getAddress();
const { signableAction } = await client.prepareOrderCancellations(listingIds);
const cancellationSignature = await signer._signTypedData(
signableAction.message.domain,
signableAction.message.types,
signableAction.message.value,
)
return client.cancelOrders(listingIds, account, cancellationSignature)
};
The following will be returned:
{
"result": {
"successful_cancellations": [
"018a8c71-d7e4-e303-a2ef-318871ef7756",
"458a8c71-d7e4-e303-a2ef-318871ef7778"
],
"pending_cancellations": [
"238a8c71-d7e4-e303-a2ef-318871ef7778",
"898a8c71-d7e4-e303-a2ef-318871ef7735"
],
"failed_cancellations": [
{
"order": "458a8c71-d7e4-e303-a2ef-318871ef7790",
"reason_code": "FILLED"
},
{
"order": "338a8c71-d7e4-e303-a2ef-318871ef7342",
"reason_code": "FILLED"
}
]
}
}
If the response to a soft cancel request includes an order_id
marked as pending_cancellations
, it represents that this specific order has an active transaction payload with another user which may be executed. Importantly, these orders may still execute even though the soft cancel request has been processed by Immutable's orderbook.
The following is an example of the results of a soft cancel with successful and pending cancellation confirmations:
{
"result": {
"successful_cancellations": [
"018a8c71-d7e4-e303-a2ef-318871ef7756",
"458a8c71-d7e4-e303-a2ef-318871ef7778"
],
"pending_cancellations": [
"238a8c71-d7e4-e303-a2ef-318871ef7778",
"898a8c71-d7e4-e303-a2ef-318871ef7735"
],
"failed_cancellations": [
{
"order": "458a8c71-d7e4-e303-a2ef-318871ef7790",
"reason_code": "FILLED"
},
{
"order": "338a8c71-d7e4-e303-a2ef-318871ef7342",
"reason_code": "FILLED"
}
]
}
}
How to validate a soft cancel has been processed
To validate that your order has been cancelled, use the Get order function from the SDK to poll the off-chain representation of the order. It will asynchronously transition to CANCELLED
once the order has been updated by Immutable's Global orderbook.
import { orderbook } from '@imtbl/sdk';
const getListing = async (client: orderbook.Orderbook, listingId: string) => {
const listing = await client.getListing(listingId);
};
The following will be returned (truncated response for illustration purposes):
{
"result": {
"account_address": "0x784578949a4a50dea641fb15dd2b11c72e76919a",
....
"status": {
"cancellation_type": "OFF_CHAIN",
"name": "CANCELLED",
"pending": false
},
....
}
}
How to determine a trade has occurred after a soft cancel has been sent
import { orderbook } from '@imtbl/sdk';
const getListing = async (client: orderbook.Orderbook, listingId: string) => {
const listing = await client.getListing(listingId);
};
The following will be returned (truncated response for illustration purposes):
{
"result": {
"account_address": "0x784578949a4a50dea641fb15dd2b11c72e76919a",
....
"status": {
"name": "FILLED"
},
....
}
}
Hard Cancels: On-Chain Cancellation
Hard cancellation offers traders the definitive means to cancel their orders, eliminating the race condition issue that can arise with soft cancels (as described in soft cancels). This is achieved by directly notifying the settlement contract of the cancellation.
Since the settlement contract operates on-chain, updating it with the details of the canceled order does involve gas fees, unlike the gasless soft cancels. Once the settlement contract is informed that the order is no longer valid, it will reject any signed transactions containing the canceled order details, effectively preventing the execution of Step 5 in the previously mentioned diagram.
Even if a trader possesses a previously issued signed transaction, the settlement contract will refuse to execute it if the order is on the settlement contract's blacklist.
This solution is suited for algorithmic bots that require absolute certainty regarding the cancellation of their orders. However, it comes at an operational cost in the form of gas fees. It is expected that most regular gamers will not opt for this level of certainty due to the associated gas expenses.
If the hard cancel is rejected by platform it will not have been processed; the order may have already or may still execute.
How to perform a hard cancel
Copy the below code to simulate a hard cancel by notifying the settlement contract of the cancelled order:
import { orderbook } from '@imtbl/sdk';
import { Signer } from 'ethers'; // ethers v5
import { TransactionResponse } from "@ethersproject/providers"; // ethers v5
const cancelListingOnChain = async (
client: orderbook.Orderbook,
signer: Signer,
listingId: string
): Promise<TransactionResponse> => {
const offerer = await signer.getAddress();
const { cancellationAction } = await client.cancelOrdersOnChain(
[ listingId ],
offerer
);
const unsignedCancelOrderTransaction = await cancellationAction.buildTransaction();
const receipt = await signer.sendTransaction(unsignedCancelOrderTransaction);
return receipt;
};
The following will be returned:
{
"type": 2,
"chainId": 31337,
"nonce": 1,
"maxPriorityFeePerGas": {
"type": "BigNumber",
"hex": "0x59682f00"
},
"maxFeePerGas": {
"type": "BigNumber",
"hex": "0x7697ce30"
},
"gasPrice": null,
"gasLimit": {
"type": "BigNumber",
"hex": "0xd821"
},
"to": "0x0165878A594ca255338adfa4d48449f69242Eb8F",
"value": {
"type": "BigNumber",
"hex": "0x00"
},
"data": "0xfd9f1e14f7f8cb7730d62bf4b15ecff270857",
"accessList": [],
"hash": "0x3ad4833ff47ddef5982746935cdcf555631676e097e4e64218c593664f478e7a",
"v": 0,
"r": "0x72406f45b99d4aaf987c58d8eb08c471f7a09cfedbf24378bee68fce6a0a3552",
"s": "0x105971dbe074b9f08e905e7bb249a01312a89f515d45bca977e15de633b33e63",
"from": "0xFb1C44E8034f7F8cb7730d62Bf4b15ECFF270857",
"confirmations": 0
}
How to validate a hard cancel has been processed
To validate that your order has been cancelled, use the Get order function from the SDK to poll the off-chain representation of the order. It will asynchronously transition to CANCELLED
once on-chain events have been registered by Immutable services.