Overview
You can cancel deBridge orders that are still pending fulfillment. This is useful when you need to reclaim your funds from an order that hasn’t been picked up by solvers or when market conditions have changed.
You can only cancel orders that haven’t been fulfilled yet. Once an order is fulfilled, cancellation is not possible.
Prerequisites
Node.js and npm installed
Environment variables configured (.env file)
An unfulfilled order ID
Private key for the wallet that created the order
How Cancellation Works
To cancel an order, you need to:
Get the cancellation transaction data from the DLN API
Verify the transaction is for the correct chain and wallet
Sign and submit the cancellation transaction on the destination chain
Cancellation must be done by the destination chain authority address (the wallet that has authority on the destination chain).
Finding an Order ID
Before cancelling, you need the order ID. Here are several ways to find it:
Use the getOrderIdByTransactionHash utility: const { orderIds } = await getOrderIdByTransactionHash ( txHash );
const orderId = orderIds [ 0 ]. stringValue ;
Visit deBridge Explorer
Search by your transaction hash or wallet address
Find the order ID in the URL:
https://app.debridge.finance/order?orderId=0x...
For testing, create an intentionally stuck order: npx tsx src/scripts/orders/cancellation/stuck-order-sol-to-poly.ts
This creates an order with unrealistic parameters that won’t be fulfilled, making it perfect for testing cancellation.
Implementation
Get Cancellation Transaction
The getCancelOrderTx utility function retrieves the cancellation transaction details from the API:
import { getCancelOrderTx } from "./utils/deBridge" ;
const orderId = "0xc0b6853690f085eb232c47b57fe8aebb38e2426f391b0805094910f1863cec46" ;
const cancelTx = await getCancelOrderTx ( orderId );
This function should be implemented in your utils/deBridge/index.ts file to call the appropriate DLN API endpoint.
Complete Cancellation Script
Here’s the complete example for cancelling an order:
import { getAddress , TransactionReceipt , TransactionRequest , TransactionResponse , Wallet } from "ethers" ;
import { getEnvConfig , getJsonRpcProviders } from "./utils" ;
import { getCancelOrderTx } from "./utils/deBridge" ;
async function main () {
const orderId = "0xc0b6853690f085eb232c47b57fe8aebb38e2426f391b0805094910f1863cec46" ;
// Get the cancellation transaction from the API
const cancelTx = await getCancelOrderTx ( orderId );
const { privateKey } = getEnvConfig ();
const { polygonProvider } = await getJsonRpcProviders ();
// Set up wallet and signer
const wallet = new Wallet ( privateKey );
const signer = wallet . connect ( polygonProvider );
const senderAddress = await signer . getAddress ();
const network = await signer . provider . getNetwork ();
// Verify the chain ID matches
if ( BigInt ( cancelTx . chainId ) !== network . chainId ) {
throw new Error ( `Expected wallet on chain ${ cancelTx . chainId } but got ${ network . chainId } ` );
}
// Verify the sender address matches
if ( getAddress ( senderAddress ) !== getAddress ( cancelTx . from )) {
throw new Error ( "Sender not matching the order destination chain authority address" );
}
// Prepare the transaction
const tx : TransactionRequest = {
to: cancelTx . to ,
value: cancelTx . value ,
data: cancelTx . data
};
console . log ( " \n Transaction Request Object:" , tx );
// Estimate gas
try {
const estimateGasResponse = await signer . estimateGas ( tx );
// Add 30% buffer
tx . gasLimit = ( estimateGasResponse * 130 n ) / 100 n ;
} catch ( error ) {
console . error ( " \n 🚨 Error estimating gas for the transaction:" );
if ( error instanceof Error ) { console . error ( ` Message: ${ error . message } ` ); }
else { console . error ( " An unexpected error occurred:" , error ); }
process . exitCode = 1 ;
}
// Send the transaction
try {
console . log ( " \n --- Sending Cancel Order Transaction ---" );
const txResponse : TransactionResponse = await signer . sendTransaction ( tx );
console . log ( `Transaction sent successfully!` );
console . log ( ` --> Transaction Hash: ${ txResponse . hash } ` );
console . log ( ` --> View on Polygonscan: https://polygonscan.com/tx/ ${ txResponse . hash } ` );
console . log ( " \n Waiting for transaction to be mined (awaiting 1 confirmation)..." );
const txReceipt : TransactionReceipt | null = await txResponse . wait ();
if ( txReceipt ) {
console . log ( " \n Transaction mined successfully!" );
console . log ( ` Status: ${ txReceipt . status === 1 ? '✅ Success' : '❌ Failed' } ` );
console . log ( ` Block number: ${ txReceipt . blockNumber } ` );
console . log ( ` Gas used: ${ txReceipt . gasUsed . toString () } ` );
} else {
console . error ( "Transaction receipt was null. Transaction might have been dropped or replaced." );
console . error ( "Check the explorer link above for the final status of the hash:" , txResponse . hash );
}
} catch ( error ) {
console . error ( " \n 🚨 Error sending or waiting for the transaction:" );
if ( error instanceof Error ) { console . error ( ` Message: ${ error . message } ` ); }
else { console . error ( " An unexpected error occurred:" , error ); }
process . exitCode = 1 ;
}
console . log ( " \n --- Script finished ---" );
process . exitCode = 0 ;
}
main (). catch (( error ) => {
if ( ! ( error instanceof Error && error . message . includes ( "Token approval failed" ))) {
console . error ( " \n 🚨 FATAL ERROR in script execution:" , error );
}
process . exitCode = 1 ;
});
Source : src/scripts/orders/cancellation/cancel-order.ts
Running the Example
Set up environment
Ensure your .env file contains the required variables: PRIVATE_KEY = your_private_key_here
POLYGON_RPC_URL = your_polygon_rpc_url
Update the order ID
Open src/scripts/orders/cancellation/cancel-order.ts and replace the orderId value: const orderId = "0xYOUR_ORDER_ID_HERE" ;
Run the cancellation script
npx tsx src/scripts/orders/cancellation/cancel-order.ts
Verify cancellation
Check the transaction on the block explorer using the provided link, or query the order status: npx tsx src/scripts/orders/queries/get-order-status.ts
The order state should be OrderCancelled.
Creating a Test Order for Cancellation
To practice cancellation, create an intentionally stuck order:
// This creates an order requesting 20,000 POL for 0.01 SOL
// This unrealistic exchange rate ensures no solver will fulfill it
const orderInput : deBridgeOrderInput = {
srcChainId: CHAIN_IDS . Solana . toString (),
srcChainTokenIn: SOL . nativeSol ,
srcChainTokenInAmount: ethers . parseUnits ( "0.01" , 9 ). toString (),
dstChainId: CHAIN_IDS . Polygon . toString (),
dstChainTokenOut: EVM_NATIVE_TOKEN . address ,
dstChainTokenOutRecipient: evmUserAddress ,
dstChainTokenOutAmount: ethers . parseEther ( "20000" ). toString (),
account: solWallet . publicKey . toBase58 (),
srcChainOrderAuthorityAddress: solWallet . publicKey . toBase58 (),
dstChainOrderAuthorityAddress: evmUserAddress ,
};
Source : src/scripts/orders/cancellation/stuck-order-sol-to-poly.ts
Run this script to create a test order:
npx tsx src/scripts/orders/cancellation/stuck-order-sol-to-poly.ts
The script outputs a transaction hash. Find the order ID using the deBridge Explorer:
Visit https://app.debridge.finance/orders?s={transactionHash}
The order ID appears in the URL when viewing the order details
Security Considerations
Important Security Checks :
The script verifies the chain ID matches your wallet’s network
The sender address must match the destination chain authority address
Only the wallet that created the order can cancel it
Gas estimation includes a 30% buffer for safety
Chain Verification
if ( BigInt ( cancelTx . chainId ) !== network . chainId ) {
throw new Error ( `Expected wallet on chain ${ cancelTx . chainId } but got ${ network . chainId } ` );
}
This prevents accidentally sending the transaction to the wrong chain.
Address Verification
if ( getAddress ( senderAddress ) !== getAddress ( cancelTx . from )) {
throw new Error ( "Sender not matching the order destination chain authority address" );
}
This ensures only the authorized wallet can cancel the order.
Error Handling
The script includes comprehensive error handling:
If gas estimation fails, the transaction won’t be sent: try {
const estimateGasResponse = await signer . estimateGas ( tx );
tx . gasLimit = ( estimateGasResponse * 130 n ) / 100 n ;
} catch ( error ) {
console . error ( "Error estimating gas:" , error . message );
process . exitCode = 1 ;
}
If the transaction is sent but fails: if ( txReceipt . status !== 1 ) {
console . log ( "Transaction failed!" );
}
If you attempt to cancel a fulfilled order, the transaction will revert. Check the order status first: const status = await getOrderStatusByOrderId ( orderId );
if ( status . orderState === "Fulfilled" ) {
throw new Error ( "Cannot cancel a fulfilled order" );
}
Best Practices
Check Status First Always verify the order status before attempting cancellation: const status = await getOrderStatusByOrderId ( orderId );
console . log ( "Current state:" , status . orderState );
Gas Buffer The script adds a 30% gas buffer to prevent out-of-gas errors: tx . gasLimit = ( estimateGasResponse * 130 n ) / 100 n ;
Monitor Confirmation Wait for transaction confirmation before considering it complete: const txReceipt = await txResponse . wait ();
Verify Result After cancellation, verify the order state changed to OrderCancelled.
Next Steps
Query Status Learn how to verify the cancellation was successful.
Order Management Overview Return to the order management overview.