The Flashnet SDK provides a comprehensive error system with typed error codes, automatic fund recovery, and clear guidance on how to handle each type of failure.
Error Codes
All Flashnet AMM Gateway errors follow the format FSAG-XXXX and are categorized by their numeric range:
| Range | Category | Description |
|---|
| 1000-1999 | Validation | Request validation failures |
| 2000-2999 | Security | Authentication and authorization errors |
| 3000-3999 | Infrastructure | External service and network issues |
| 4000-4999 | Business | AMM logic and pool state errors |
| 5000-5999 | System | Internal service errors |
Recovery Strategies
Each error has an associated recovery strategy that tells you how to handle fund recovery:
| Strategy | Description | Action Required |
|---|
clawback_required | Funds are at risk and must be recovered | Clawback will be attempted automatically |
clawback_recommended | Uncertain state, recovery recommended | Clawback will be attempted automatically |
auto_refund | Funds return automatically | No action needed |
none | No funds at risk | No action needed |
Automatic Clawback
The SDK automatically attempts to clawback your funds when an operation fails with a clawbackable error. You don’t need to manually handle fund recovery in most cases.
When you execute operations like executeSwap, executeRouteSwap, addLiquidity, or createSingleSidedPool, the SDK:
- Sends your funds to the pool
- Executes the operation
- If the operation fails with a clawbackable error, automatically attempts to recover your funds
- Returns a
FlashnetError with details about what happened and the recovery status
Example: Handling Auto-Clawback
import { isFlashnetError } from '@flashnet/sdk';
try {
const swap = await client.executeSwap({
poolId: "pool-id",
assetInAddress: "bitcoin-pubkey",
assetOutAddress: "usdb-pubkey",
amountIn: "100000000",
minAmountOut: "99000000",
maxSlippageBps: 100,
});
console.log('Swap successful:', swap.amountOut);
} catch (error) {
if (isFlashnetError(error)) {
console.log('Error code:', error.errorCode);
console.log('Category:', error.category);
console.log('User message:', error.userMessage);
// Check if auto-clawback was attempted
if (error.wasClawbackAttempted()) {
const summary = error.clawbackSummary!;
if (error.wereAllTransfersRecovered()) {
console.log('✅ All funds recovered automatically!');
} else if (error.werePartialTransfersRecovered()) {
console.log(`⚠️ Partial recovery: ${summary.successCount}/${summary.totalTransfers}`);
console.log('Unrecovered transfers:', summary.unrecoveredTransferIds);
} else {
console.log('❌ Fund recovery failed');
console.log('At-risk transfers:', error.transferIds);
}
}
// Check specific error types
if (error.isSlippageError()) {
console.log('Price moved too much - funds auto-refunded');
} else if (error.isInsufficientLiquidityError()) {
console.log('Pool lacks liquidity - funds auto-refunded');
}
}
}
Complete Error Code Reference
Validation Errors (1000-1999)
These errors indicate invalid request parameters. Recovery: Clawback Required
| Code | HTTP | Summary | Retryable |
|---|
| FSAG-1000 | 400 | Validation failed | No |
| FSAG-1001 | 400 | Required field missing | No |
| FSAG-1002 | 400 | Invalid field format | No |
| FSAG-1003 | 400 | Value out of range | No |
| FSAG-1004 | 409 | Duplicate value for unique entity | No |
Security Errors (2000-2999)
Authentication and authorization failures. Recovery: Clawback Required (except auth token errors)
| Code | HTTP | Summary | Retryable |
|---|
| FSAG-2001 | 403 | Signature verification failed | No |
| FSAG-2002 | 403 | Token identity mismatch | No |
| FSAG-2003 | 401 | Authorization token missing | Yes |
| FSAG-2004 | 401 | Authorization token invalid/expired | Yes |
| FSAG-2005 | 403 | Nonce verification failed | No |
| FSAG-2101 | 400 | Public key invalid | No |
Infrastructure Errors (3000-3999)
External service and network issues. Recovery: Clawback Recommended
| Code | HTTP | Summary | Retryable |
|---|
| FSAG-3001 | 503 | Internal server error | Yes |
| FSAG-3002 | 500 | Internal server error | Yes |
| FSAG-3101 | 500 | Internal server error | Yes |
| FSAG-3201 | 503 | Internal server error | Yes |
| FSAG-3201T1 | 503 | Internal server error | Yes |
| FSAG-3201T2 | 503 | Internal server error | Yes |
| FSAG-3202 | 503 | Internal server error | Yes |
| FSAG-3301 | 500 | Internal server error | Yes |
| FSAG-3302 | 503 | Internal server error | Yes |
| FSAG-3401 | 500 | Internal server error | Yes |
| FSAG-3402 | 500 | Internal server error | Yes |
Business Errors (4000-4999)
AMM logic and pool state errors. Recovery: Auto Refund (funds return automatically)
| Code | HTTP | Summary | Retryable |
|---|
| FSAG-4001 | 404 | Pool not found | No |
| FSAG-4002 | 404 | Host not found | No |
| FSAG-4101 | 404 | Auth session not found | Yes |
| FSAG-4102 | 400 | Incorrect authentication flow | Yes |
| FSAG-4201 | 400 | Insufficient liquidity/reserves | Yes |
| FSAG-4202 | 400 | Slippage exceeded limit | Yes |
| FSAG-4203 | 409 | Operation not allowed in current phase | Yes |
| FSAG-4204 | 400 | Insufficient LP token balance | No |
| FSAG-4301 | 400 | Invalid fee configuration | No |
| FSAG-4401 | 409 | Spark transfer ID already used | No |
System Errors (5000-5999)
Internal service errors. Recovery: Clawback Required
| Code | HTTP | Summary | Retryable |
|---|
| FSAG-5001 | 500 | Failed to generate unique ID | Yes |
| FSAG-5002 | 501 | Feature not implemented | No |
| FSAG-5003 | 500 | Internal state inconsistent | No |
| FSAG-5004 | 500 | Invalid configuration parameter | No |
| FSAG-5100 | 500 | Unexpected panic | No |
FlashnetError Properties
The FlashnetError class provides rich error information:
interface FlashnetError extends Error {
// Core properties
errorCode: string; // e.g., "FSAG-4202"
category: string; // "Validation" | "Security" | "Infrastructure" | "Business" | "System"
recovery: string; // "clawback_required" | "clawback_recommended" | "auto_refund" | "none"
httpStatus: number; // HTTP status code
requestId: string; // Unique request ID for debugging
// User-facing
userMessage: string; // Human-readable explanation
actionHint: string; // Suggested action
isRetryable: boolean; // Whether retry makes sense
// Clawback info
transferIds: string[]; // Unrecovered transfer IDs
lpIdentityPublicKey?: string; // Pool ID for clawback
clawbackSummary?: { // Auto-clawback results
attempted: boolean;
totalTransfers: number;
successCount: number;
failureCount: number;
recoveredTransferIds: string[];
unrecoveredTransferIds: string[];
results: ClawbackAttemptResult[];
};
}
FlashnetError Methods
// Recovery status
error.isClawbackRequired(); // True if clawback is mandatory
error.isClawbackRecommended(); // True if clawback is advised
error.shouldClawback(); // True if either required or recommended
error.willAutoRefund(); // True if funds return automatically
error.hasTransfersAtRisk(); // True if unrecovered transfers exist
// Clawback status
error.wasClawbackAttempted(); // True if auto-clawback ran
error.wereAllTransfersRecovered(); // True if all funds recovered
error.werePartialTransfersRecovered(); // True if some but not all recovered
error.getRecoveredTransferCount(); // Number of recovered transfers
error.getRecoveredTransferIds(); // IDs of recovered transfers
error.getUnrecoveredTransferIds(); // IDs still at risk
// Error type checks
error.isValidationError();
error.isSecurityError();
error.isInfrastructureError();
error.isBusinessError();
error.isSystemError();
// Specific error checks
error.isSlippageError(); // FSAG-4202
error.isInsufficientLiquidityError(); // FSAG-4201
error.isAuthError(); // FSAG-2003 or FSAG-2004
error.isPoolNotFoundError(); // FSAG-4001
error.isTransferAlreadyUsedError(); // FSAG-4401
// Formatting
error.getUserFriendlyMessage(); // Full user-facing message
error.toLogString(); // Formatted for logging
error.toJSON(); // Serializable object
Best Practices
1. Always Use Type Guards
import { isFlashnetError, FlashnetError } from '@flashnet/sdk';
try {
await client.executeSwap({ /* ... */ });
} catch (error) {
if (isFlashnetError(error)) {
// Full typed access to error properties
console.log(error.errorCode, error.userMessage);
} else {
// Generic error handling
console.error('Unknown error:', error);
}
}
2. Handle Business Errors Gracefully
Business errors (4000-4999) indicate conditions like slippage or insufficient liquidity. These are auto-refunded and often retryable:
if (error.isBusinessError()) {
if (error.isSlippageError()) {
// Suggest user increase slippage tolerance
showMessage('Price moved. Try increasing slippage tolerance.');
} else if (error.isInsufficientLiquidityError()) {
// Suggest smaller trade or different pool
showMessage('Not enough liquidity. Try a smaller amount.');
}
// Funds are automatically returned
if (error.willAutoRefund()) {
showMessage('Your funds will be returned automatically.');
}
}
3. Log Request IDs for Debugging
catch (error) {
if (isFlashnetError(error)) {
console.error(`[${error.requestId}] ${error.toLogString()}`);
// Report to your error tracking service
reportError({
requestId: error.requestId,
errorCode: error.errorCode,
...error.toJSON()
});
}
}
4. Implement Retry Logic for Retryable Errors
async function executeWithRetry(fn: () => Promise<any>, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (isFlashnetError(error) && error.isRetryable && attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
console.log(`Retrying in ${delay}ms... (attempt ${attempt}/${maxRetries})`);
await new Promise(r => setTimeout(r, delay));
continue;
}
throw error;
}
}
}
Next Steps