Fspot Flash APIs
Integrate the Flash API backend for cross-chain swap applications: authentication, quotes, swap execution, and status tracking.
Complete documentation for integrating with the Flash API backend for cross-chain swap applications.
Table of Contents
Overview
The Flash API provides a comprehensive backend service for cross-chain USDC swaps using the Gateway protocol. It handles:
- Chain configuration management
- Token listings and prices
- Quote generation for swaps
- Swap execution and tracking
- User authentication and referrals
- Transaction history
Base URL
Production: https://flash.rath.fiAuthentication
Flash API uses wallet signature-based authentication.
Flow:
- Request a message to sign
- Sign the message with user's wallet
- Verify signature to receive JWT token
- Include token in subsequent requests
Headers:
Authorization: Bearer <jwt_token>
Content-Type: application/jsonChain Configuration
Dynamic Chain Support
All chain configurations are fetched from the backend, making it easy to add/remove chains without frontend changes.
Key Features:
- Gateway wallet addresses
- Gateway minter addresses
- USDC contract addresses
- Chain metadata (logo, explorer, name)
- Domain numbers for Gateway protocol
API Endpoints
1. Supported Chains
Get all supported chains with their configuration.
Endpoint: GET /supported-chains
Response:
[
{
"id": 8453, // Chain ID
"name": "Base", // Chain name
"displayName": "Base", // Display name
"logoUrl": "https://...", // Chain logo URL
"explorerUrl": "https://...", // Block explorer URL
"domain": 6, // Gateway protocol domain
"routerAddress": "0x...", // Swap router address
"gatewayWallet": "0x...", // Gateway wallet contract
"gatewayMinter": "0x...", // Gateway minter contract
"nativeToken": {
"address": "0x0000000000000000000000000000000000000000",
"name": "Ethereum",
"symbol": "ETH",
"decimals": 18,
"logoUrl": "https://..."
},
"usdc": {
"address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"name": "USD Coin",
"symbol": "USDC",
"decimals": 6,
"logoUrl": "https://..."
}
}
]Example:
const chains = await fetch('https://flash.rath.fi/supported-chains')
.then(res => res.json());2. Authentication
2.1 Request Sign Message
Endpoint: POST /auth/message
Request:
{
"userAddress": "0x1234567890abcdef1234567890abcdef12345678"
}Response:
{
"message": "Sign this message to authenticate with Flash Computer...",
"expiry": 1705449600,
"messageId": "550e8400-e29b-41d4-a716-446655440000"
}2.2 Verify Signature
Endpoint: POST /auth/verify
Request:
{
"signature": "0xabcdef...",
"messageId": "550e8400-e29b-41d4-a716-446655440000",
"referredByCode": "REFERRAL123" // Optional
}Response:
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"user_address": "0x1234567890abcdef1234567890abcdef12345678",
"referralCode": "ABC123XYZ",
"is_new_user": true
}Complete Flow Example:
// 1. Request message
const { message, messageId } = await fetch('https://flash.rath.fi/auth/message', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userAddress: address })
}).then(res => res.json());
// 2. Sign message with wallet
const signature = await walletClient.signMessage({ message });
// 3. Verify and get token
const { token } = await fetch('https://flash.rath.fi/auth/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ signature, messageId })
}).then(res => res.json());
// 4. Use token for authenticated requests
const authenticatedHeaders = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};3. Token List
Get available tokens for swapping.
Endpoint: GET /token-list?chain_id={chainId}
Query Parameters:
chain_id(optional): Filter tokens by chain ID. Omit for all chains.
Response:
{
"tokens": [
{
"address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"symbol": "USDC",
"decimals": 6,
"logo_url": "https://...",
"name": "USD Coin",
"chain_id": 8453,
"in_rath_token_list": true
}
]
}Examples:
// Get all tokens
const { tokens } = await fetch('https://flash.rath.fi/token-list')
.then(res => res.json());
// Get tokens for Base (chain ID 8453)
const { tokens } = await fetch('https://flash.rath.fi/token-list?chain_id=8453')
.then(res => res.json());4. Quote
Get a quote for a swap.
Endpoint: GET /quote
Query Parameters:
inputAmount: Amount in USDC smallest units (1 USDC = 1000000)outputToken: Output token addresschainId: Destination chain IDfrom: User wallet addressslippage: Slippage tolerance (1.5 = 1.5%)recipient: Recipient address (optional if not passed, defaults tofrom)
Example Request:
GET /quote?inputAmount=1000000&outputToken=0x...&chainId=8453&from=0x...&slippage=1.5&recipient=0x...Response:
{
"token_in": {
"address": "0x...",
"amount": "1000000",
"decimals": 6,
"logo_url": "https://...",
"price_usd": "1.00",
"usd_amount": "1.00"
},
"token_out": {
"address": "0x...",
"amount": "998500",
"decimals": 6,
"logo_url": "https://...",
"price_usd": "1.00",
"usd_amount": "0.9985"
},
"fees": {
"total_fee": "1500",
"gateway_fee": "1000",
"execution_fee": "500"
},
"single_swap_router": "0x...",
"hook_data": "0x...",
"swap_router_address": "0x...",
"swap_calldata": "0x...",
"expires_at": 1705449600
}Example:
const params = new URLSearchParams({
inputAmount: '1000000', // 1 USDC
outputToken: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
chainId: '8453',
from: userAddress,
slippage: '1.5'
});
const quote = await fetch(`https://flash.rath.fi/quote?${params}`)
.then(res => res.json());5. Gateway Balance
Get user's balance across all chains in the Gateway protocol.
Endpoint: GET /balance/{address}
Response:
{
"balances": [
{
"domain": 6,
"depositor": "0x...",
"balance": "5000000", // Balance in USDC smallest units
"chainId": 8453,
"chainName": "Base"
}
],
"totalBalance": "5000000" // Total across all chains
}Example:
const { balances, totalBalance } = await fetch(
`https://flash.rath.fi/balance/${userAddress}`
).then(res => res.json());6. Swap Execution
Execute a swap transaction.
Endpoint: POST /swap
Authentication: Required (Bearer token)
Request:
{
"signedOrder": [...], // Array of signed burn intents
"userAddress": "0x...",
"chainId": 8453,
"swapRouterAddress": "0x...",
"swapCalldata": "0x...",
"slippageBps": 150 // 150 basis points = 1.5%
}Response:
{
"transactionHash": "0xabcdef...",
"status": "pending",
"message": "Swap initiated successfully"
}Example:
// After creating and signing burn intents
const result = await fetch('https://flash.rath.fi/swap', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
signedOrder: signedBurnIntents,
userAddress: address,
chainId: destinationChainId,
swapRouterAddress: quote.swap_router_address,
swapCalldata: quote.swap_calldata,
slippageBps: 150
})
}).then(res => res.json());7. Search Token
Search for a token by address.
Endpoint: POST /search-token
Request:
{
"chainId": 8453,
"address": "0x..."
}Response:
{
"address": "0x...",
"symbol": "UNI",
"decimals": 18,
"name": "Uniswap",
"chainId": 8453,
"logoUrl": "https://...",
"inRathTokenList": false
}Example:
const token = await fetch('https://flash.rath.fi/search-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chainId: 8453,
address: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984'
})
}).then(res => res.json());8. Swap History
Get user's swap transaction history.
Endpoint: GET /history?page={page}&page_size={size}&status={status}
Authentication: Required (Bearer token)
Query Parameters:
page(optional): Page number (default: 1)page_size(optional): Items per page (default: 20)status(optional): Filter by status (pending,completed,failed)
Response:
{
"swaps": [
{
"id": "uuid",
"sourceDomain": 6,
"destinationDomain": 3,
"sourceToken": "0x...",
"destinationToken": "0x...",
"tokenIn": {
"address": "0x...",
"symbol": "USDC",
"decimals": 6,
"logo_url": "https://...",
"name": "USD Coin",
"chain_id": 8453,
"in_rath_token_list": true
},
"tokenOut": {
"address": "0x...",
"symbol": "UNI",
"decimals": 18,
"logo_url": "https://...",
"name": "Uniswap",
"chain_id": 42161,
"in_rath_token_list": true
},
"amountUsdc": "1.00",
"amountUsdcRaw": "1000000",
"chainId": 42161,
"minAmountOut": "0.9985",
"rathFee": "0.0015",
"rathFeeRaw": "1500",
"transactionHash": "0x...",
"status": "completed",
"txId": "gateway-tx-id",
"createdAt": "2024-01-17T10:00:00Z",
"updatedAt": "2024-01-17T10:05:00Z"
}
],
"pagination": {
"current_page": 1,
"page_size": 20,
"total_entries": 45,
"total_pages": 3,
"has_next": true,
"has_previous": false
},
"summary": {
"totalSwaps": 45,
"totalVolume": "12500.50",
"totalVolumeRaw": "12500500000",
"totalFees": "18.75",
"totalFeesRaw": "18750000"
}
}Example:
const history = await fetch(
'https://flash.rath.fi/history?page=1&page_size=20',
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
).then(res => res.json());9. Leaderboard
Get trading leaderboard rankings.
Endpoint: GET /leaderboard?page={page}&page_size={size}&time_range={range}
Query Parameters:
page(optional): Page number (default: 1)page_size(optional): Items per page (default: 50)time_range(optional): Time filter (all,30d,7d,24h)
Response:
{
"entries": [
{
"rank": 1,
"walletAddress": "0x...",
"totalVolume": "50000.00",
"totalVolumeRaw": "50000000000",
"swapCount": 150,
"referralCount": 25,
"referralVolume": "5000.00",
"referralVolumeRaw": "5000000000",
"combined_volume": "55000.00",
"referralCode": "ABC123",
"lastSwapAt": "2024-01-17T10:00:00Z"
}
],
"pagination": {
"current_page": 1,
"page_size": 50,
"total_entries": 250,
"total_pages": 5,
"has_next": true,
"has_previous": false
}
}Example:
const leaderboard = await fetch(
'https://flash.rath.fi/leaderboard?time_range=7d'
).then(res => res.json());10. User Referrals
Get user's referral information.
Endpoint: GET /referrals
Authentication: Required (Bearer token)
Response:
{
"referrals": [
{
"user_address": "0x...",
"total_volume_usdc": 1500.25
}
],
"total_referral_volume": 5250.75,
"total_referrals_count": 3,
"remaining_referral_limit": 7
}Example:
const referrals = await fetch('https://flash.rath.fi/referrals', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}).then(res => res.json());TypeScript Integration
Gateway Protocol Integration
Creating Burn Intents (Signed Orders)
Burn intents are EIP-712 signed messages that authorize cross-chain USDC transfers via the Gateway protocol.
Step 1: Define EIP-712 Types
const EIP712Domain = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
];
const TransferSpec = [
{ name: "version", type: "uint32" },
{ name: "sourceDomain", type: "uint32" },
{ name: "destinationDomain", type: "uint32" },
{ name: "sourceContract", type: "bytes32" },
{ name: "destinationContract", type: "bytes32" },
{ name: "sourceToken", type: "bytes32" },
{ name: "destinationToken", type: "bytes32" },
{ name: "sourceDepositor", type: "bytes32" },
{ name: "destinationRecipient", type: "bytes32" },
{ name: "sourceSigner", type: "bytes32" },
{ name: "destinationCaller", type: "bytes32" },
{ name: "value", type: "uint256" },
{ name: "salt", type: "bytes32" },
{ name: "hookData", type: "bytes" },
];
const BurnIntent = [
{ name: "maxBlockHeight", type: "uint256" },
{ name: "maxFee", type: "uint256" },
{ name: "spec", type: "TransferSpec" },
];
const BurnIntentSet = [
{ name: "intents", type: "BurnIntent[]" }
];
const domain = { name: "GatewayWallet", version: "1" };Step 2: Create Burn Intent
import { pad, maxUint256 } from 'viem';
// Helper to convert address to bytes32
function addressToBytes32(address: string): string {
return pad(address.toLowerCase() as `0x${string}`, { size: 32 });
}
// Generate random salt
function generateRandomSalt(): string {
const bytes = new Uint8Array(32);
crypto.getRandomValues(bytes);
return '0x' + Array.from(bytes)
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}
// Create a burn intent
function createBurnIntent({
userAddress,
sourceChain,
destinationChain,
amount,
recipient,
hookData = '0x',
maxFee = '2010000' // Gateway fee in smallest units
}: {
userAddress: string;
sourceChain: ChainConfig;
destinationChain: ChainConfig;
amount: string; // Amount in smallest units (e.g., 1000000 for 1 USDC)
recipient: string;
hookData?: string;
maxFee?: string;
}) {
return {
maxBlockHeight: maxUint256, // Far future block
maxFee: BigInt(maxFee),
spec: {
version: 1,
sourceDomain: sourceChain.domain,
destinationDomain: destinationChain.domain,
sourceContract: sourceChain.gatewayWallet,
destinationContract: destinationChain.gatewayMinter,
sourceToken: sourceChain.usdc.address,
destinationToken: destinationChain.usdc.address,
sourceDepositor: userAddress,
destinationRecipient: recipient,
sourceSigner: userAddress,
destinationCaller: recipient,
value: BigInt(amount),
salt: generateRandomSalt(),
hookData: hookData,
},
};
}Step 3: Create Typed Data for Signing
function createBurnIntentTypedData(burnIntent: any) {
return {
types: { EIP712Domain, TransferSpec, BurnIntent },
domain,
primaryType: "BurnIntent",
message: {
maxBlockHeight: burnIntent.maxBlockHeight,
maxFee: burnIntent.maxFee,
spec: {
...burnIntent.spec,
sourceContract: addressToBytes32(burnIntent.spec.sourceContract),
destinationContract: addressToBytes32(burnIntent.spec.destinationContract),
sourceToken: addressToBytes32(burnIntent.spec.sourceToken),
destinationToken: addressToBytes32(burnIntent.spec.destinationToken),
sourceDepositor: addressToBytes32(burnIntent.spec.sourceDepositor),
destinationRecipient: addressToBytes32(burnIntent.spec.destinationRecipient),
sourceSigner: addressToBytes32(burnIntent.spec.sourceSigner),
destinationCaller: addressToBytes32(burnIntent.spec.destinationCaller),
},
},
};
}
// For multiple intents (burn intent set)
function createBurnIntentSetTypedData(burnIntents: any[]) {
return {
types: { EIP712Domain, TransferSpec, BurnIntent, BurnIntentSet },
domain,
primaryType: "BurnIntentSet",
message: {
intents: burnIntents.map(intent =>
createBurnIntentTypedData(intent).message
),
},
};
}Step 4: Sign Burn Intent(s)
// Using ethers.js
import { ethers } from 'ethers';
async function signBurnIntent(
wallet: ethers.Wallet,
burnIntent: any
): Promise<string> {
const typedData = createBurnIntentTypedData(burnIntent);
const signature = await wallet._signTypedData(
typedData.domain,
{ TransferSpec: typedData.types.TransferSpec, BurnIntent: typedData.types.BurnIntent },
typedData.message
);
return signature;
}
// Using viem
import { signTypedData } from 'viem/accounts';
async function signBurnIntentViem(
walletClient: any,
burnIntent: any
): Promise<string> {
const typedData = createBurnIntentTypedData(burnIntent);
const signature = await walletClient.signTypedData({
domain: typedData.domain,
types: {
TransferSpec: typedData.types.TransferSpec,
BurnIntent: typedData.types.BurnIntent
},
primaryType: 'BurnIntent',
message: typedData.message
});
return signature;
}Complete Example: Creating Signed Order for Swap
async function createSignedSwapOrder({
walletClient,
userAddress,
sourceChains, // Array of chains to pull USDC from
destinationChain, // Chain to swap on
allocations, // Amount to pull from each source chain
recipient, // Swap router address (from quote)
hookData, // Hook data from quote
gatewayFee // Gateway fee from quote
}: {
walletClient: any;
userAddress: string;
sourceChains: ChainConfig[];
destinationChain: ChainConfig;
allocations: { chainId: number; amount: string }[];
recipient: string;
hookData: string;
gatewayFee: string;
}) {
// Create burn intents for each source chain
const burnIntents = allocations.map((allocation, index) => {
const sourceChain = sourceChains[index];
return createBurnIntent({
userAddress,
sourceChain,
destinationChain,
amount: allocation.amount,
recipient,
hookData,
maxFee: gatewayFee
});
});
// Create typed data for signing
const typedData = createBurnIntentSetTypedData(burnIntents);
// Sign the burn intent set
const signature = await walletClient.signTypedData({
domain: typedData.domain,
types: {
TransferSpec: typedData.types.TransferSpec,
BurnIntent: typedData.types.BurnIntent,
BurnIntentSet: typedData.types.BurnIntentSet
},
primaryType: 'BurnIntentSet',
message: typedData.message
});
// Format for API
const signedOrder = burnIntents.map((intent, index) => ({
intent,
signature: index === 0 ? signature : undefined // Only first intent needs signature
}));
return signedOrder;
}Depositing USDC to Gateway Wallet
To deposit USDC into the Gateway wallet, you can use the depositWithPermit function which combines USDC approval and deposit in a single transaction using EIP-2612 permits.
Gateway Wallet ABI
const gatewayWalletAbi = [
{
inputs: [
{ internalType: "address", name: "token", type: "address" },
{ internalType: "address", name: "owner", type: "address" },
{ internalType: "uint256", name: "value", type: "uint256" },
{ internalType: "uint256", name: "deadline", type: "uint256" },
{ internalType: "uint8", name: "v", type: "uint8" },
{ internalType: "bytes32", name: "r", type: "bytes32" },
{ internalType: "bytes32", name: "s", type: "bytes32" }
],
name: "depositWithPermit",
outputs: [],
stateMutability: "nonpayable",
type: "function"
}
];Step 1: Generate USDC Permit Signature
import { parseUnits } from 'viem';
async function generateUSDCPermit({
walletClient,
publicClient,
chainId,
usdcAddress,
usdcName,
usdcVersion,
ownerAddress,
spenderAddress, // Gateway wallet address
amount
}: {
walletClient: any;
publicClient: any;
chainId: number;
usdcAddress: string;
usdcName: string;
usdcVersion: string;
ownerAddress: string;
spenderAddress: string;
amount: bigint;
}) {
// Get current nonce
const nonce = await publicClient.readContract({
address: usdcAddress,
abi: [{
inputs: [{ name: 'owner', type: 'address' }],
name: 'nonces',
outputs: [{ name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
}],
functionName: 'nonces',
args: [ownerAddress],
});
// Set deadline (e.g., 1 hour from now)
const deadline = BigInt(Math.floor(Date.now() / 1000) + 3600);
// EIP-2612 Permit types
const types = {
Permit: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" }
]
};
// Domain
const domain = {
name: usdcName,
version: usdcVersion,
chainId,
verifyingContract: usdcAddress
};
// Sign permit
const signature = await walletClient.signTypedData({
domain,
types,
primaryType: 'Permit',
message: {
owner: ownerAddress,
spender: spenderAddress,
value: amount,
nonce,
deadline
}
});
// Parse signature
const { r, s, v } = parseSignature(signature);
return { deadline, v, r, s };
}
function parseSignature(signature: string) {
const r = `0x${signature.slice(2, 66)}`;
const s = `0x${signature.slice(66, 130)}`;
const v = parseInt(signature.slice(130, 132), 16);
return { r, s, v };
}Step 2: Execute depositWithPermit
import { writeContract, waitForTransactionReceipt } from 'viem';
async function depositWithPermit({
walletClient,
publicClient,
chainConfig,
amount, // Amount in USDC (e.g., "1.5" for 1.5 USDC)
ownerAddress
}: {
walletClient: any;
publicClient: any;
chainConfig: ChainConfig;
amount: string;
ownerAddress: string;
}) {
// Convert amount to smallest units (USDC has 6 decimals)
const amountInWei = parseUnits(amount, 6);
// Generate permit signature
const { deadline, v, r, s } = await generateUSDCPermit({
walletClient,
publicClient,
chainId: chainConfig.id,
usdcAddress: chainConfig.usdc.address,
usdcName: chainConfig.usdc.name,
usdcVersion: chainConfig.usdc.version.toString(),
ownerAddress,
spenderAddress: chainConfig.gatewayWallet,
amount: amountInWei
});
// Execute depositWithPermit
const hash = await walletClient.writeContract({
address: chainConfig.gatewayWallet,
abi: gatewayWalletAbi,
functionName: 'depositWithPermit',
args: [
chainConfig.usdc.address,
ownerAddress,
amountInWei,
deadline,
v,
r,
s
]
});
console.log('Transaction hash:', hash);
// Wait for confirmation
const receipt = await waitForTransactionReceipt(publicClient, { hash });
console.log('Deposit confirmed:', receipt);
return receipt;
}Complete Deposit Example
// Example: Deposit 10 USDC on Base chain
async function depositExample() {
// Get chain config from API
const chains = await flashApi.getSupportedChains();
const baseChain = chains.find(c => c.id === 8453);
if (!baseChain) {
throw new Error('Base chain not found');
}
// Deposit 10 USDC
const receipt = await depositWithPermit({
walletClient,
publicClient,
chainConfig: baseChain,
amount: '10',
ownerAddress: userAddress
});
console.log('✅ Deposited 10 USDC to Gateway wallet');
console.log('Transaction:', receipt.transactionHash);
// Check new balance
const balance = await flashApi.getGatewayBalance(userAddress);
console.log('New Gateway balance:', balance.totalBalance);
}