Quote System
Overview
Architecture
Core Components
class IXFIQuoteSystem {
constructor() {
this.quoteSources = new Map(); // dexName -> QuoteSource
this.priceCache = new PriceCache();
this.gasOracle = new GasOracle();
this.slippageCalculator = new SlippageCalculator();
this.routeOptimizer = new RouteOptimizer();
}
async getQuote(request) {
const {
fromToken,
toToken,
amountIn,
fromChain,
toChain,
slippageTolerance = 0.005, // 0.5% default
gasPrice,
includeGasCosts = true,
preferredDEXes = [],
maxHops = 3
} = request;
// Validate input parameters
this.validateQuoteRequest(request);
// Get quotes from all relevant sources
const quotes = await this.aggregateQuotes(request);
// Filter and rank quotes
const rankedQuotes = await this.rankQuotes(quotes, request);
// Return best quotes with detailed breakdown
return {
bestQuote: rankedQuotes[0],
alternativeQuotes: rankedQuotes.slice(1, 5),
marketAnalysis: await this.getMarketAnalysis(request),
timestamp: Date.now(),
validUntil: Date.now() + 30000 // 30 seconds
};
}
async aggregateQuotes(request) {
const { fromToken, toToken, fromChain, toChain } = request;
const quotePromises = [];
// Same chain quotes - direct DEX swaps
if (fromChain === toChain) {
const chainDEXes = this.getChainDEXes(fromChain);
for (const dex of chainDEXes) {
if (await this.supportsPair(dex, fromToken, toToken)) {
quotePromises.push(
this.getDirectQuote(dex, request)
);
}
}
// Multi-hop quotes on same chain
if (request.maxHops > 1) {
quotePromises.push(
this.getMultiHopQuotes(request)
);
}
} else {
// Cross-chain quotes
quotePromises.push(
this.getCrossChainQuotes(request)
);
}
// Execute all quote requests in parallel
const results = await Promise.allSettled(quotePromises);
return results
.filter(result => result.status === 'fulfilled')
.map(result => result.value)
.flat()
.filter(quote => quote && quote.outputAmount > 0);
}
async getDirectQuote(dex, request) {
try {
const source = this.quoteSources.get(dex.name);
if (!source) {
throw new Error(`No quote source for DEX: ${dex.name}`);
}
const rawQuote = await source.getQuote(
request.fromToken,
request.toToken,
request.amountIn,
request.fromChain
);
return this.enrichQuote(rawQuote, dex, request);
} catch (error) {
console.warn(`Failed to get quote from ${dex.name}:`, error.message);
return null;
}
}
async enrichQuote(rawQuote, dex, request) {
const enrichedQuote = {
...rawQuote,
dexName: dex.name,
dexType: dex.type,
chainId: request.fromChain,
route: 'DIRECT',
timestamp: Date.now()
};
// Add gas cost estimation
if (request.includeGasCosts) {
const gasEstimate = await this.estimateGasCost(dex, request);
enrichedQuote.gasCost = gasEstimate;
enrichedQuote.netOutputAmount = enrichedQuote.outputAmount - gasEstimate.usdValue;
}
// Add slippage analysis
enrichedQuote.slippageAnalysis = await this.analyzeSlippage(dex, request);
// Add execution probability
enrichedQuote.executionProbability = await this.calculateExecutionProbability(dex, request);
// Add route breakdown
enrichedQuote.routeBreakdown = [{
step: 1,
dex: dex.name,
fromToken: request.fromToken,
toToken: request.toToken,
inputAmount: request.amountIn,
outputAmount: enrichedQuote.outputAmount,
fee: enrichedQuote.fee,
priceImpact: enrichedQuote.priceImpact
}];
return enrichedQuote;
}
async getMultiHopQuotes(request) {
const intermediateTokens = await this.getIntermediateTokens(request.fromChain);
const multiHopQuotes = [];
for (const intermediateToken of intermediateTokens) {
try {
// First hop: fromToken -> intermediateToken
const firstHopQuotes = await this.getHopQuotes(
request.fromToken,
intermediateToken,
request.amountIn,
request.fromChain
);
for (const firstHop of firstHopQuotes) {
// Second hop: intermediateToken -> toToken
const secondHopQuotes = await this.getHopQuotes(
intermediateToken,
request.toToken,
firstHop.outputAmount,
request.fromChain
);
for (const secondHop of secondHopQuotes) {
// Skip if using same DEX twice (unless it's beneficial)
if (firstHop.dexName === secondHop.dexName &&
!this.isBeneficialSameDEX(firstHop, secondHop)) {
continue;
}
const multiHopQuote = this.combineHops([firstHop, secondHop], request);
if (multiHopQuote.outputAmount > 0) {
multiHopQuotes.push(multiHopQuote);
}
}
}
} catch (error) {
console.warn(`Multi-hop quote failed for ${intermediateToken}:`, error.message);
}
}
return multiHopQuotes;
}
async getCrossChainQuotes(request) {
const crossChainQuotes = [];
const bridges = await this.getAvailableBridges(request.fromChain, request.toChain);
for (const bridge of bridges) {
try {
// Option 1: Swap then bridge
const swapThenBridge = await this.getSwapThenBridgeQuote(bridge, request);
if (swapThenBridge) {
crossChainQuotes.push(swapThenBridge);
}
// Option 2: Bridge then swap
const bridgeThenSwap = await this.getBridgeThenSwapQuote(bridge, request);
if (bridgeThenSwap) {
crossChainQuotes.push(bridgeThenSwap);
}
// Option 3: Bridge native asset (if applicable)
if (this.isNativeAsset(request.fromToken) || this.isNativeAsset(request.toToken)) {
const nativeBridge = await this.getNativeBridgeQuote(bridge, request);
if (nativeBridge) {
crossChainQuotes.push(nativeBridge);
}
}
} catch (error) {
console.warn(`Cross-chain quote failed for bridge ${bridge.name}:`, error.message);
}
}
return crossChainQuotes;
}
async getSwapThenBridgeQuote(bridge, request) {
// Step 1: Swap fromToken to bridgeable token on source chain
const bridgeableTokens = bridge.getSupportedTokens(request.fromChain);
let bestQuote = null;
for (const bridgeToken of bridgeableTokens) {
if (bridgeToken === request.fromToken) continue;
try {
// Get swap quote on source chain
const swapQuote = await this.getBestDirectQuote(
request.fromToken,
bridgeToken,
request.amountIn,
request.fromChain
);
if (!swapQuote) continue;
// Get bridge quote
const bridgeQuote = await bridge.getQuote(
bridgeToken,
swapQuote.outputAmount,
request.fromChain,
request.toChain
);
if (!bridgeQuote) continue;
// Get final swap quote on destination chain (if needed)
let finalQuote = null;
if (bridgeToken !== request.toToken) {
finalQuote = await this.getBestDirectQuote(
bridgeToken,
request.toToken,
bridgeQuote.outputAmount,
request.toChain
);
}
const finalOutputAmount = finalQuote
? finalQuote.outputAmount
: bridgeQuote.outputAmount;
const combinedQuote = {
outputAmount: finalOutputAmount,
route: 'SWAP_BRIDGE_SWAP',
steps: [
{ type: 'SWAP', ...swapQuote },
{ type: 'BRIDGE', ...bridgeQuote },
...(finalQuote ? [{ type: 'SWAP', ...finalQuote }] : [])
],
totalGasCost: this.calculateTotalGasCost([swapQuote, bridgeQuote, finalQuote].filter(Boolean)),
estimatedTime: swapQuote.estimatedTime + bridgeQuote.estimatedTime + (finalQuote?.estimatedTime || 0),
bridgeUsed: bridge.name,
reliability: Math.min(
swapQuote.reliability || 0.99,
bridgeQuote.reliability || 0.99,
finalQuote?.reliability || 0.99
)
};
if (!bestQuote || combinedQuote.outputAmount > bestQuote.outputAmount) {
bestQuote = combinedQuote;
}
} catch (error) {
console.warn(`Swap-then-bridge quote failed for ${bridgeToken}:`, error.message);
}
}
return bestQuote;
}
async rankQuotes(quotes, request) {
const rankedQuotes = [];
for (const quote of quotes) {
const score = await this.scoreQuote(quote, request);
rankedQuotes.push({ ...quote, score });
}
// Sort by score (higher is better)
rankedQuotes.sort((a, b) => b.score - a.score);
return rankedQuotes;
}
async scoreQuote(quote, request) {
const weights = request.weights || {
outputAmount: 0.4, // 40% - amount received
gasCost: 0.25, // 25% - gas efficiency
reliability: 0.15, // 15% - execution probability
speed: 0.1, // 10% - execution time
priceImpact: 0.1 // 10% - slippage
};
// Normalize metrics to 0-1 scale
const normalizedMetrics = {
outputAmount: this.normalizeOutputAmount(quote.outputAmount, request.amountIn),
gasCost: this.normalizeGasCost(quote.gasCost, quote.outputAmount),
reliability: quote.reliability || 0.99,
speed: this.normalizeSpeed(quote.estimatedTime),
priceImpact: 1 - Math.min(quote.priceImpact || 0, 0.1) / 0.1
};
// Calculate weighted score
let score = 0;
for (const [metric, weight] of Object.entries(weights)) {
score += normalizedMetrics[metric] * weight;
}
return score;
}
normalizeOutputAmount(outputAmount, inputAmount) {
// Higher output ratio is better (capped at 1.0 for safety)
return Math.min(outputAmount / inputAmount, 1.0);
}
normalizeGasCost(gasCost, outputAmount) {
if (!gasCost || !gasCost.usdValue) return 1.0;
// Lower gas cost ratio is better
const gasCostRatio = gasCost.usdValue / outputAmount;
return Math.max(0, 1 - Math.min(gasCostRatio * 10, 1));
}
normalizeSpeed(estimatedTime) {
// Faster is better (normalize against 1 hour max)
const maxTime = 3600; // 1 hour in seconds
return Math.max(0, 1 - Math.min(estimatedTime / maxTime, 1));
}
}Quote Sources
DEX Integration
Gas Cost Estimation
Quote Validation and Guarantees
Market Analysis
Integration Examples
React Hook for Quotes
Node.js Integration
Performance Metrics
Best Practices
Resources
Last updated