REFUNDED and includes a failReason field that explains why the refund occurred. Understanding these reasons helps you build better error handling and improve user experience.
For a complete reference of all fail reason codes with detailed explanations, see Error Codes.
How Refund Reasons Work
When you check the status of a quote using the Get Execution Status endpoint, refunded quotes include additional context:Copy
Ask AI
{
"quoteId": "0xfa6094cd...",
"status": "REFUNDED",
"user": "0x9b747cC14...",
"failReason": "SLIPPAGE",
"originChainOperations": [],
"destinationChainOperations": []
}
Implementation Patterns by Category
Balance and Allowance Issues
Handle insufficient funds and token approval problems:Copy
Ask AI
function handleBalanceAndAllowanceErrors(failReason: string) {
switch (failReason) {
case 'TRANSFER_AMOUNT_EXCEEDS_BALANCE':
// Check current balance before retrying
return handleInsufficientBalance();
case 'TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE':
// Request token approval
return handleInsufficientAllowance();
case 'INSUFFICIENT_NATIVE_TOKENS_SUPPLIED':
// Add gas tokens
return handleInsufficientGas();
case 'TRANSFER_FROM_FAILED':
case 'TRANSFER_FAILED':
// Transfer operation failed
return handleTransferFailure();
}
}
async function handleInsufficientBalance() {
const balance = await getBalance(userAddress, tokenAddress);
if (balance.gte(requiredAmount)) {
// Balance recovered, safe to retry
return { action: 'retry', message: 'Balance sufficient, retrying...' };
} else {
// Show balance error to user
return { action: 'error', message: 'Insufficient balance for this transaction' };
}
}
async function handleInsufficientAllowance() {
// Request token approval
return {
action: 'approval_needed',
message: 'Token approval required',
nextStep: 'approve_token'
};
}
Price and Market Issues
Handle slippage, expired orders, and market conditions:Copy
Ask AI
function handleMarketErrors(failReason: string, originalQuote: any) {
switch (failReason) {
case 'SLIPPAGE':
// Retry with higher slippage tolerance
return retryWithHigherSlippage(originalQuote);
case 'ORDER_EXPIRED':
// Generate fresh quote
return generateFreshQuote(originalQuote);
case 'ORDER_IS_CANCELLED':
// Order was cancelled
return { action: 'new_quote', message: 'Order cancelled, please create a new order' };
case 'ORDER_ALREADY_FILLED':
// Order already completed
return { action: 'error', message: 'Order already filled' };
case 'NO_QUOTES':
// No liquidity available
return handleNoLiquidity(originalQuote);
case 'TOO_LITTLE_RECEIVED':
// Output below minimum
return handleLowOutput(originalQuote);
case 'NO_INTERNAL_SWAP_ROUTES_FOUND':
// No routing path available
return { action: 'error', message: 'No swap route available for this pair' };
case 'SWAP_USES_TOO_MUCH_GAS':
// Gas cost too high
return { action: 'retry', message: 'Gas cost too high, try smaller amount' };
}
}
async function retryWithHigherSlippage(originalQuote: any) {
const currentSlippage = originalQuote.slippageTolerance || 100;
const newSlippage = Math.min(currentSlippage * 1.5, 500); // Cap at 5%
return {
action: 'retry',
message: `Retrying with ${newSlippage / 100}% slippage tolerance`,
newParams: {
...originalQuote,
slippageTolerance: newSlippage
}
};
}
async function generateFreshQuote(originalQuote: any) {
return {
action: 'new_quote',
message: 'Order expired, generating new quote with current prices',
newParams: originalQuote
};
}
Signature and Authentication Issues
Handle wallet and signing problems:Copy
Ask AI
function handleSignatureErrors(failReason: string) {
switch (failReason) {
case 'INVALID_SIGNATURE':
return {
action: 'resign',
message: 'Invalid signature, please sign again'
};
case 'SIGNATURE_EXPIRED':
return {
action: 'resign',
message: 'Signature expired, please sign the new transaction'
};
case 'INVALID_SENDER':
return {
action: 'reconnect',
message: 'Please reconnect your wallet'
};
case 'ACCOUNT_ABSTRACTION_INVALID_NONCE':
case 'ACCOUNT_ABSTRACTION_SIGNATURE_ERROR':
return {
action: 'sync_wallet',
message: 'Smart wallet sync required, please retry'
};
}
}
System and Protocol Issues
Handle system capacity and protocol-specific errors:Copy
Ask AI
function handleSystemErrors(failReason: string) {
switch (failReason) {
case 'SOLVER_CAPACITY_EXCEEDED':
return {
action: 'retry',
message: 'System at capacity, retrying in a moment',
delay: 2000
};
case 'EXECUTION_REVERTED':
case 'TRANSACTION_REVERTED':
return {
action: 'error',
message: 'Transaction reverted, please check parameters'
};
case 'GENERATE_SWAP_FAILED':
case 'REVERSE_SWAP_FAILED':
return {
action: 'retry',
message: 'Swap generation failed, retrying'
};
case 'MISSING_REVERT_DATA':
return {
action: 'contact_support',
message: 'Transaction failed without details, contact support'
};
}
}
Deposit and Validation Issues
Handle deposit-related errors:Copy
Ask AI
function handleDepositErrors(failReason: string) {
switch (failReason) {
case 'DEPOSIT_ADDRESS_MISMATCH':
case 'DEPOSIT_CHAIN_MISMATCH':
case 'INCORRECT_DEPOSIT_CURRENCY':
return {
action: 'error',
message: 'Deposit details incorrect, verify and retry'
};
case 'AMOUNT_TOO_LOW_TO_REFUND':
case 'DEPOSITED_AMOUNT_TOO_LOW_TO_FILL':
return {
action: 'error',
message: 'Amount too low, increase amount'
};
case 'NEGATIVE_NEW_AMOUNT_AFTER_FEES':
return {
action: 'error',
message: 'Fees exceed amount, increase amount'
};
case 'ORIGIN_CURRENCY_MISMATCH':
return {
action: 'error',
message: 'Source currency mismatch, check token'
};
}
}
Token and Protocol Specific Issues
Handle token-specific and protocol errors:Copy
Ask AI
function handleTokenErrors(failReason: string) {
switch (failReason) {
case 'TOKEN_NOT_TRANSFERABLE':
return {
action: 'error',
message: 'Token has transfer restrictions'
};
case 'ZERO_SELL_AMOUNT':
return {
action: 'error',
message: 'Invalid amount, must be greater than zero'
};
case 'SEAPORT_INEXACT_FRACTION':
case 'SEAPORT_INVALID_FULFILLER':
return {
action: 'error',
message: 'NFT order validation failed'
};
case 'MINT_NOT_ACTIVE':
return {
action: 'wait',
message: 'Minting not active, try later'
};
case 'ERC_1155_TOO_MANY_REQUESTED':
return {
action: 'error',
message: 'Reduce number of tokens requested'
};
case 'INCORRECT_PAYMENT':
return {
action: 'error',
message: 'Payment amount incorrect'
};
case 'INVALID_GAS_PRICE':
return {
action: 'retry',
message: 'Invalid gas price, retrying with updated price'
};
case 'FLUID_DEX_ERROR':
return {
action: 'retry',
message: 'DEX protocol error, retrying'
};
case 'NEW_CALLDATA_INCLUDES_HIGHER_RENT_FEE':
return {
action: 'confirm',
message: 'Higher fees required, confirm to proceed'
};
}
}
Solana-Specific Issues
Handle Solana blockchain specific problems:Copy
Ask AI
function handleSolanaErrors(failReason: string) {
switch (failReason) {
case 'INSUFFICIENT_FUNDS_FOR_RENT':
return {
action: 'add_sol',
message: 'Insufficient SOL for rent. Add SOL to your wallet.',
minAmount: '0.002 SOL'
};
case 'JUPITER_INVALID_TOKEN_ACCOUNT':
return {
action: 'init_account',
message: 'Token account needs initialization. This will be handled automatically.',
autoRetry: true
};
}
}
Automatic Retry Logic
Implement smart retry mechanisms for recoverable errors:Copy
Ask AI
const RETRYABLE_REASONS = [
'SLIPPAGE',
'ORDER_EXPIRED',
'SOLVER_CAPACITY_EXCEEDED',
'SWAP_USES_TOO_MUCH_GAS',
'EXECUTION_REVERTED',
'TRANSACTION_REVERTED',
'GENERATE_SWAP_FAILED',
'REVERSE_SWAP_FAILED',
'TOO_LITTLE_RECEIVED',
'INVALID_GAS_PRICE',
'FLUID_DEX_ERROR'
];
const USER_ACTION_REQUIRED = [
'TRANSFER_AMOUNT_EXCEEDS_BALANCE',
'TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE',
'INSUFFICIENT_NATIVE_TOKENS_SUPPLIED',
'INVALID_SIGNATURE',
'SIGNATURE_EXPIRED',
'INVALID_SENDER',
'ACCOUNT_ABSTRACTION_INVALID_NONCE',
'ACCOUNT_ABSTRACTION_SIGNATURE_ERROR',
'TRANSFER_FROM_FAILED',
'TRANSFER_FAILED',
'INSUFFICIENT_FUNDS_FOR_RENT',
'JUPITER_INVALID_TOKEN_ACCOUNT'
];
const NON_RETRYABLE_ERRORS = [
'UNKNOWN',
'DOUBLE_SPEND',
'AMOUNT_TOO_LOW_TO_REFUND',
'DEPOSIT_ADDRESS_MISMATCH',
'DEPOSIT_CHAIN_MISMATCH',
'INCORRECT_DEPOSIT_CURRENCY',
'DEPOSITED_AMOUNT_TOO_LOW_TO_FILL',
'NEGATIVE_NEW_AMOUNT_AFTER_FEES',
'NO_QUOTES',
'NO_INTERNAL_SWAP_ROUTES_FOUND',
'ORDER_IS_CANCELLED',
'ORDER_ALREADY_FILLED',
'TOKEN_NOT_TRANSFERABLE',
'ZERO_SELL_AMOUNT',
'SEAPORT_INEXACT_FRACTION',
'SEAPORT_INVALID_FULFILLER',
'MINT_NOT_ACTIVE',
'ERC_1155_TOO_MANY_REQUESTED',
'INCORRECT_PAYMENT',
'ORIGIN_CURRENCY_MISMATCH',
'MISSING_REVERT_DATA'
];
async function executeWithSmartRetry(quoteParams: QuoteParams, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const quote = await getQuote(quoteParams);
const result = await executeQuote(quote);
if (result.status === 'COMPLETED') {
return { success: true, result };
}
// Handle refunded quotes
if (result.status === 'REFUNDED' && result.failReason) {
const errorHandler = getErrorHandler(result.failReason);
const handlerResult = errorHandler(result.failReason, quoteParams);
if (handlerResult.action === 'retry' && attempt < maxRetries) {
// Automatic retry with adjusted parameters
quoteParams = { ...quoteParams, ...handlerResult.newParams };
await delay(1000 * attempt); // Exponential backoff
continue;
}
// Return error for user action or final attempt
return {
success: false,
error: result.failReason,
action: handlerResult.action,
message: handlerResult.message,
retryable: RETRYABLE_REASONS.includes(result.failReason)
};
}
} catch (error) {
if (attempt === maxRetries) throw error;
await delay(1000 * attempt);
}
}
}
function getErrorHandler(failReason: string) {
// Balance and Allowance Issues
if ([
'TRANSFER_AMOUNT_EXCEEDS_BALANCE',
'TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE',
'INSUFFICIENT_NATIVE_TOKENS_SUPPLIED',
'TRANSFER_FROM_FAILED',
'TRANSFER_FAILED'
].includes(failReason)) {
return handleBalanceAndAllowanceErrors;
}
// Price and Market Issues
if ([
'SLIPPAGE',
'ORDER_EXPIRED',
'ORDER_IS_CANCELLED',
'ORDER_ALREADY_FILLED',
'NO_QUOTES',
'TOO_LITTLE_RECEIVED',
'NO_INTERNAL_SWAP_ROUTES_FOUND',
'SWAP_USES_TOO_MUCH_GAS'
].includes(failReason)) {
return handleMarketErrors;
}
// Signature and Authentication Issues
if ([
'INVALID_SIGNATURE',
'SIGNATURE_EXPIRED',
'INVALID_SENDER',
'ACCOUNT_ABSTRACTION_INVALID_NONCE',
'ACCOUNT_ABSTRACTION_SIGNATURE_ERROR'
].includes(failReason)) {
return handleSignatureErrors;
}
// System and Protocol Issues
if ([
'SOLVER_CAPACITY_EXCEEDED',
'EXECUTION_REVERTED',
'TRANSACTION_REVERTED',
'GENERATE_SWAP_FAILED',
'REVERSE_SWAP_FAILED',
'MISSING_REVERT_DATA'
].includes(failReason)) {
return handleSystemErrors;
}
// Deposit and Validation Issues
if ([
'DEPOSIT_ADDRESS_MISMATCH',
'DEPOSIT_CHAIN_MISMATCH',
'INCORRECT_DEPOSIT_CURRENCY',
'AMOUNT_TOO_LOW_TO_REFUND',
'DEPOSITED_AMOUNT_TOO_LOW_TO_FILL',
'NEGATIVE_NEW_AMOUNT_AFTER_FEES',
'ORIGIN_CURRENCY_MISMATCH'
].includes(failReason)) {
return handleDepositErrors;
}
// Token and Protocol Specific Issues
if ([
'TOKEN_NOT_TRANSFERABLE',
'ZERO_SELL_AMOUNT',
'SEAPORT_INEXACT_FRACTION',
'SEAPORT_INVALID_FULFILLER',
'MINT_NOT_ACTIVE',
'ERC_1155_TOO_MANY_REQUESTED',
'INCORRECT_PAYMENT',
'INVALID_GAS_PRICE',
'FLUID_DEX_ERROR',
'NEW_CALLDATA_INCLUDES_HIGHER_RENT_FEE'
].includes(failReason)) {
return handleTokenErrors;
}
// Solana-Specific Issues
if ([
'INSUFFICIENT_FUNDS_FOR_RENT',
'JUPITER_INVALID_TOKEN_ACCOUNT'
].includes(failReason)) {
return handleSolanaErrors;
}
// Default handler for unknown or unhandled errors
return () => ({
action: 'manual',
message: 'Unexpected error, please try again or contact support'
});
}
User Experience Patterns
Progress Indicators
Show users what’s happening during retry flows:Copy
Ask AI
interface RetryState {
attempt: number;
maxAttempts: number;
currentAction: string;
failReason?: string;
}
function ProgressIndicator({ retryState }: { retryState: RetryState }) {
const progress = (retryState.attempt / retryState.maxAttempts) * 100;
return (
<div className="retry-progress">
<div className="progress-bar" style={{ width: `${progress}%` }} />
<p>
Attempt {retryState.attempt} of {retryState.maxAttempts}: {retryState.currentAction}
</p>
{retryState.failReason && (
<p className="error-reason">
Previous attempt failed: {getUserFriendlyMessage(retryState.failReason)}
</p>
)}
</div>
);
}
function getUserFriendlyMessage(failReason: string): string {
const messages = {
// Balance and Allowance
TRANSFER_AMOUNT_EXCEEDS_BALANCE: 'Insufficient token balance',
TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE: 'Token approval needed',
INSUFFICIENT_NATIVE_TOKENS_SUPPLIED: 'Insufficient gas tokens',
TRANSFER_FROM_FAILED: 'Token transfer failed',
TRANSFER_FAILED: 'Token transfer failed',
// Price and Market
SLIPPAGE: 'Price changed during execution',
ORDER_EXPIRED: 'Quote expired',
ORDER_IS_CANCELLED: 'Order was cancelled',
ORDER_ALREADY_FILLED: 'Order already completed',
NO_QUOTES: 'No liquidity available',
TOO_LITTLE_RECEIVED: 'Output amount too low',
NO_INTERNAL_SWAP_ROUTES_FOUND: 'No swap route found',
SWAP_USES_TOO_MUCH_GAS: 'Gas cost too high',
// Signature and Authentication
INVALID_SIGNATURE: 'Invalid signature',
SIGNATURE_EXPIRED: 'Signature expired',
INVALID_SENDER: 'Invalid sender',
ACCOUNT_ABSTRACTION_INVALID_NONCE: 'Wallet sync needed',
ACCOUNT_ABSTRACTION_SIGNATURE_ERROR: 'Wallet signature error',
// System and Protocol
SOLVER_CAPACITY_EXCEEDED: 'System at capacity',
EXECUTION_REVERTED: 'Transaction reverted',
TRANSACTION_REVERTED: 'Transaction reverted',
GENERATE_SWAP_FAILED: 'Swap generation failed',
REVERSE_SWAP_FAILED: 'Reverse swap failed',
MISSING_REVERT_DATA: 'Transaction failed',
// Deposit and Validation
DEPOSIT_ADDRESS_MISMATCH: 'Wrong deposit address',
DEPOSIT_CHAIN_MISMATCH: 'Wrong blockchain',
INCORRECT_DEPOSIT_CURRENCY: 'Wrong token deposited',
AMOUNT_TOO_LOW_TO_REFUND: 'Amount too low',
DEPOSITED_AMOUNT_TOO_LOW_TO_FILL: 'Amount too low',
NEGATIVE_NEW_AMOUNT_AFTER_FEES: 'Fees exceed amount',
ORIGIN_CURRENCY_MISMATCH: 'Source token mismatch',
DOUBLE_SPEND: 'Duplicate transaction',
// Token and Protocol Specific
TOKEN_NOT_TRANSFERABLE: 'Token transfer restricted',
ZERO_SELL_AMOUNT: 'Invalid amount',
SEAPORT_INEXACT_FRACTION: 'NFT order error',
SEAPORT_INVALID_FULFILLER: 'NFT fulfiller error',
MINT_NOT_ACTIVE: 'Minting not active',
ERC_1155_TOO_MANY_REQUESTED: 'Too many tokens requested',
INCORRECT_PAYMENT: 'Payment amount incorrect',
INVALID_GAS_PRICE: 'Invalid gas price',
FLUID_DEX_ERROR: 'DEX protocol error',
NEW_CALLDATA_INCLUDES_HIGHER_RENT_FEE: 'Higher fees required',
// Solana-Specific
INSUFFICIENT_FUNDS_FOR_RENT: 'Insufficient SOL for rent',
JUPITER_INVALID_TOKEN_ACCOUNT: 'Solana account issue',
// Unknown
UNKNOWN: 'Unknown error'
};
return messages[failReason] || 'Transaction failed';
}
Error Recovery UI
Provide clear next steps for users:Copy
Ask AI
function ErrorRecoveryUI({ error, onRetry, onCancel }) {
const getActionButton = (action: string) => {
switch (action) {
case 'retry':
return <button onClick={onRetry}>Try Again</button>;
case 'approval_needed':
return <button onClick={handleApproval}>Approve Token</button>;
case 'add_sol':
return <button onClick={handleAddSol}>Add SOL</button>;
case 'reconnect':
return <button onClick={handleReconnect}>Reconnect Wallet</button>;
default:
return <button onClick={onCancel}>Cancel</button>;
}
};
return (
<div className="error-recovery">
<h3>Transaction Failed</h3>
<p>{error.message}</p>
<div className="actions">
{getActionButton(error.action)}
<button onClick={onCancel} className="secondary">Cancel</button>
</div>
{error.retryable && (
<p className="retry-hint">
This error can be automatically retried. Click "Try Again" to retry with adjusted parameters.
</p>
)}
</div>
);
}
Analytics and Monitoring
Track fail reason patterns to optimize your integration:Copy
Ask AI
interface FailReasonAnalytics {
failReason: string;
tokenPair: string;
amount: string;
attempt: number;
userAgent: string;
timestamp: string;
}
function trackFailReason(data: FailReasonAnalytics) {
// Send to your analytics service
analytics.track('quote_refunded', {
fail_reason: data.failReason,
token_pair: data.tokenPair,
amount_usd: data.amount,
retry_attempt: data.attempt,
user_agent: data.userAgent,
timestamp: data.timestamp
});
}
function analyzeFailReasonTrends(timeRange: string) {
// Query your analytics to identify patterns
return {
mostCommonReasons: ['SLIPPAGE', 'TRANSFER_AMOUNT_EXCEEDS_BALANCE'],
successRateByReason: {
SLIPPAGE: 0.85, // 85% success after retry
ORDER_EXPIRED: 0.92,
NO_QUOTES: 0.45
},
recommendations: [
'Increase default slippage tolerance to 1.5%',
'Implement balance checking before quote generation',
'Add liquidity warnings for low-liquidity pairs'
]
};
}
Best Practices Summary
- Categorize Error Handling: Group similar fail reasons and handle them with consistent patterns
- Implement Smart Retries: Automatically retry recoverable errors with adjusted parameters
- Provide Clear UI: Show users exactly what went wrong and what they need to do
- Monitor Patterns: Track fail reasons to identify optimization opportunities
- Progressive Enhancement: Start with basic error handling and add sophistication over time
Related Resources
Error Codes Reference
Complete reference of all fail reason codes with detailed explanations
Transaction Lifecycle
Understand the complete journey of a quote from creation to completion
Quote Examples
Working examples of quote generation and execution with proper error handling
Slippage Guide
Deep dive into slippage tolerance and price impact management