Documentation Index
Fetch the complete documentation index at: https://mintlify.com/1inch/cross-chain-sdk/llms.txt
Use this file to discover all available pages before exploring further.
The SDK provides methods to cancel on-chain orders and recover funds before they are filled by resolvers.
Overview
Orders can be cancelled in two scenarios:
- User Cancellation: Cancel your own order before it’s filled
- Resolver Cancellation: Resolvers can cancel premium orders for a fee
Cancellation is available on both EVM and Solana chains, with slightly different workflows.
Building Cancel Order Call Data (EVM)
For EVM chains, you need to build the cancel order transaction call data.
Basic Usage
import { SDK } from '@1inch/cross-chain-sdk'
const sdk = new SDK({
url: 'https://api.1inch.com/fusion-plus',
authKey: 'your-auth-key'
})
const orderHash = '0x1234...'
// Build cancel order call data
const callData = await sdk.buildCancelOrderCallData(orderHash)
// Send transaction
const tx = await wallet.sendTransaction({
to: limitOrderProtocolAddress,
data: callData,
gasLimit: 200000
})
await tx.wait()
console.log('Order cancelled:', tx.hash)
How It Works
- Fetches order details from the API using the order hash
- Extracts the maker traits from the order
- Encodes the cancel order function call
- Returns ready-to-send transaction data
Requirements:
- Order must exist and be in a cancellable state
- Source chain must be EVM (Ethereum, Polygon, BSC, etc.)
- Transaction must be sent by the order maker or authorized canceller
Error Handling
try {
const callData = await sdk.buildCancelOrderCallData(orderHash)
// Send transaction
} catch (error) {
if (error.message.includes('Can not get order')) {
console.error('Order not found:', orderHash)
} else if (error.message.includes('expected evm src chain')) {
console.error('Source chain must be EVM')
} else {
console.error('Failed to build cancel data:', error)
}
}
Getting Cancellable Orders
Query orders that can be cancelled by resolvers (premium service).
EVM Chains
import { ChainType, ApiVersion } from '@1inch/cross-chain-sdk'
// Get cancellable EVM orders
const evmOrders = await sdk.getCancellableOrders(
ChainType.EVM,
1, // page
100 // limit
)
console.log('Total cancellable EVM orders:', evmOrders.total)
for (const order of evmOrders.items) {
console.log('Order:', {
orderHash: order.orderHash,
srcChain: order.srcChainId,
dstChain: order.dstChainId,
makerAddress: order.order.maker,
makerAsset: order.order.makerAsset,
takerAsset: order.order.takerAsset,
makingAmount: order.order.makingAmount,
takingAmount: order.order.takingAmount,
cancellationFee: order.cancellationReward // Fee for cancelling
})
}
Solana Orders
// Get cancellable Solana orders
const svmOrders = await sdk.getCancellableOrders(
ChainType.SVM,
1, // page
100 // limit
)
console.log('Total cancellable Solana orders:', svmOrders.total)
for (const order of svmOrders.items) {
console.log('Solana Order:', {
orderHash: order.orderHash,
srcChain: order.srcChainId,
dstChain: order.dstChainId,
escrowAddress: order.escrowAddress,
cancellationReward: order.cancellationReward
})
}
Filtering by API Version
import { ApiVersion } from '@1inch/cross-chain-sdk'
// Get only v1.2 cancellable orders
const orders = await sdk.getCancellableOrders(
ChainType.EVM,
1,
100,
[ApiVersion.V1_2]
)
// Get only v1.1 cancellable orders
const legacyOrders = await sdk.getCancellableOrders(
ChainType.EVM,
1,
100,
[ApiVersion.V1_1]
)
// Get both versions
const allOrders = await sdk.getCancellableOrders(
ChainType.EVM,
1,
100,
[ApiVersion.V1_1, ApiVersion.V1_2]
)
// Fetch all cancellable orders
const allOrders = []
let page = 1
const limit = 100
while (true) {
const result = await sdk.getCancellableOrders(
ChainType.EVM,
page,
limit
)
allOrders.push(...result.items)
if (allOrders.length >= result.total) {
break
}
page++
}
console.log(`Fetched ${allOrders.length} cancellable orders`)
Order Cancellation Types
EvmOrderCancellationData
type EvmOrderCancellationData = {
orderHash: string
srcChainId: number
dstChainId: number
order: LimitOrderV4Struct
extension: string
signature: string
quoteId: string
cancellationReward?: string // Fee for cancelling this order
}
SvmOrderCancellationData
type SvmOrderCancellationData = {
orderHash: string
srcChainId: number
dstChainId: number
escrowAddress: string // Solana escrow program address
cancellationReward?: string // Fee for cancelling this order
}
Cancellation Workflow
User-Initiated Cancellation
import { SDK } from '@1inch/cross-chain-sdk'
import { ethers } from 'ethers'
const sdk = new SDK({
url: 'https://api.1inch.com/fusion-plus',
authKey: 'your-auth-key'
})
const wallet = new ethers.Wallet(privateKey, provider)
// 1. Get order hash from order creation or tracking
const orderHash = '0x1234...'
// 2. Build cancel call data
const callData = await sdk.buildCancelOrderCallData(orderHash)
// 3. Send cancellation transaction
const tx = await wallet.sendTransaction({
to: limitOrderProtocolAddress,
data: callData,
gasLimit: 200000
})
// 4. Wait for confirmation
const receipt = await tx.wait()
console.log('Order cancelled in block:', receipt.blockNumber)
// 5. Verify cancellation via WebSocket
ws.order.onOrderCancelled((event) => {
if (event.data.orderHash === orderHash) {
console.log('Cancellation confirmed:', event.data)
}
})
Resolver-Initiated Cancellation
import { ChainType } from '@1inch/cross-chain-sdk'
// 1. Query cancellable orders
const orders = await sdk.getCancellableOrders(
ChainType.EVM,
1,
100
)
// 2. Filter profitable orders
const profitableOrders = orders.items.filter(order => {
const reward = BigInt(order.cancellationReward || '0')
const gasCost = BigInt('50000000000000000') // 0.05 ETH estimated gas
return reward > gasCost
})
// 3. Cancel orders
for (const order of profitableOrders) {
try {
const callData = await sdk.buildCancelOrderCallData(order.orderHash)
const tx = await wallet.sendTransaction({
to: limitOrderProtocolAddress,
data: callData,
gasLimit: 200000
})
console.log(`Cancelled order ${order.orderHash}:`, tx.hash)
console.log(`Expected reward: ${order.cancellationReward}`)
} catch (error) {
console.error(`Failed to cancel ${order.orderHash}:`, error)
}
}
Refund Process
When an order is cancelled, funds are refunded based on the escrow state:
Source Chain (EVM)
- Before Escrow Deployment: Order is cancelled in the limit order protocol, no escrow exists
- After Escrow Deployment: Escrow contract must be cancelled, funds returned to maker
// Check if escrow was deployed
const escrowAddress = computeEscrowAddress(orderHash)
const code = await provider.getCode(escrowAddress)
if (code === '0x') {
console.log('No escrow deployed, order cancelled in protocol')
} else {
console.log('Escrow deployed, cancelling escrow contract')
// Escrow will refund maker + safety deposit
}
Destination Chain
If destination escrow was deployed, it must be cancelled separately:
// Cancel destination escrow (if deployed)
const dstEscrowAddress = computeEscrowAddress(orderHash)
const dstCode = await dstProvider.getCode(dstEscrowAddress)
if (dstCode !== '0x') {
// Wait for timelock expiry
// Then call cancel() on destination escrow
console.log('Destination escrow exists, will refund after timelock')
}
Timelock Considerations
Orders have different timelocks for cancellation:
const timeLocks = quote.timeLocks
console.log('Source Chain Timelocks:', {
cancellation: timeLocks.srcCancellation, // Maker can cancel after this
publicCancellation: timeLocks.srcPublicCancellation // Anyone can cancel after this
})
console.log('Destination Chain Timelocks:', {
cancellation: timeLocks.dstCancellation // Cancellation timeout
})
Cancellation Windows
- Private Cancellation: Only maker can cancel after
srcCancellation seconds
- Public Cancellation: Anyone can cancel after
srcPublicCancellation seconds
- Premium Cancellation: Resolvers can cancel before timelocks for a fee
WebSocket Event Monitoring
Track cancellation events in real-time:
import { WebSocketApi } from '@1inch/cross-chain-sdk'
const ws = new WebSocketApi({
url: 'wss://api.1inch.com/fusion-plus/ws',
authKey: 'your-auth-key'
})
// Monitor cancellation events
ws.order.onOrderCancelled((event) => {
console.log('Order cancelled:', {
orderHash: event.data.orderHash,
remainingAmount: event.data.remainingMakerAmount
})
})
// Monitor all order events
ws.order.onOrder((event) => {
if (event.event === 'order_cancelled') {
console.log('Cancellation detected:', event.data)
}
})
Best Practices
Check Order Status First
const orderStatus = await sdk.getOrderStatus({ orderHash })
if (orderStatus.status === 'filled') {
console.log('Order already filled, cannot cancel')
return
}
if (orderStatus.status === 'cancelled') {
console.log('Order already cancelled')
return
}
if (orderStatus.status === 'pending') {
// Proceed with cancellation
const callData = await sdk.buildCancelOrderCallData(orderHash)
}
Estimate Gas Before Cancelling
const callData = await sdk.buildCancelOrderCallData(orderHash)
const gasEstimate = await provider.estimateGas({
to: limitOrderProtocolAddress,
from: wallet.address,
data: callData
})
const gasPrice = await provider.getFeeData()
const estimatedCost = gasEstimate * gasPrice.gasPrice
console.log(`Estimated cancellation cost: ${ethers.formatEther(estimatedCost)} ETH`)
// Compare with cancellation reward for resolver cancellations
if (cancellationReward > estimatedCost) {
console.log('Cancellation is profitable')
}
Handle Partial Fills
ws.order.onOrderFilledPartially((event) => {
console.log('Order partially filled:', {
orderHash: event.data.orderHash,
remainingAmount: event.data.remainingMakerAmount
})
// Can still cancel the remaining amount
if (BigInt(event.data.remainingMakerAmount) > 0n) {
console.log('Remaining amount can be cancelled')
}
})
Multi-Chain Considerations
// For cross-chain orders, track both chains
const srcProvider = new ethers.JsonRpcProvider(srcChainRpc)
const dstProvider = new ethers.JsonRpcProvider(dstChainRpc)
// Cancel on source chain
const srcCallData = await sdk.buildCancelOrderCallData(orderHash)
const srcTx = await srcWallet.sendTransaction({
to: srcLimitOrderProtocol,
data: srcCallData
})
await srcTx.wait()
console.log('Source chain cancellation:', srcTx.hash)
// Check destination chain escrow
const dstEscrowAddress = computeEscrowAddress(orderHash)
const dstCode = await dstProvider.getCode(dstEscrowAddress)
if (dstCode !== '0x') {
console.log('Destination escrow deployed, funds will be refunded after timelock')
}
Error Scenarios
Order Not Found
try {
const callData = await sdk.buildCancelOrderCallData(orderHash)
} catch (error) {
if (error.message.includes('Can not get order')) {
console.error('Order does not exist or was already processed')
}
}
Wrong Chain Type
try {
const callData = await sdk.buildCancelOrderCallData(orderHash)
} catch (error) {
if (error.message.includes('expected evm src chain')) {
console.error('This method only works for EVM source chains')
console.log('For Solana, use the Solana-specific cancellation method')
}
}
Already Filled
try {
const tx = await wallet.sendTransaction({
to: limitOrderProtocolAddress,
data: callData
})
await tx.wait()
} catch (error) {
if (error.message.includes('execution reverted')) {
console.error('Transaction reverted - order may be already filled or cancelled')
}
}
Insufficient Permissions
try {
const tx = await wallet.sendTransaction({
to: limitOrderProtocolAddress,
data: callData,
from: wallet.address
})
await tx.wait()
} catch (error) {
if (error.message.includes('unauthorized')) {
console.error('Only the order maker or authorized canceller can cancel this order')
}
}
Advanced: Batch Cancellation
// Cancel multiple orders in a single transaction (using multicall)
import { ethers } from 'ethers'
const orderHashes = ['0x1234...', '0x5678...', '0x9abc...']
// Build call data for each order
const callDatas = await Promise.all(
orderHashes.map(hash => sdk.buildCancelOrderCallData(hash))
)
// Use multicall contract to batch
const multicallData = callDatas.map(data => ({
target: limitOrderProtocolAddress,
callData: data
}))
const tx = await multicallContract.aggregate(multicallData)
await tx.wait()
console.log('Batch cancellation complete:', tx.hash)