@robertprp/intents-sdk
Version:
Shogun Network Intent-based cross-chain swaps SDK
254 lines • 10.2 kB
JavaScript
import { ChainID, isEvmChain } from '../../chains.js';
import { JupiterQuoteProvider } from './jupiter.js';
import {} from '@jup-ag/api';
import { ParaswapQuoteProvider } from './paraswap.js';
import { CROSS_CHAIN_TOKENS } from './stablecoins-tokens.js';
import { AftermathQuoteProvider } from './aftermath.js';
import { calculateAmounts } from '../defillama.js';
import { LiquidSwapQuoteProvider } from './liquidswap.js';
export class QuoteProvider {
static async getQuoteFromDefillama(params) {
const defillamaQuote = await calculateAmounts({
amountIn: params.amount,
tokenIn: params.tokenIn,
tokenOut: params.tokenOut,
destChainId: params.destChainId,
srcChainId: params.sourceChainId,
});
return {
amountInUsd: 0,
estimatedAmountOutUsd: 0,
estimatedAmountOutUsdReduced: 0,
estimatedAmountInAsMinStablecoinAmount: defillamaQuote.minStablecoinsAmount,
estimatedAmountOut: defillamaQuote.amountOut,
estimatedAmountOutReduced: defillamaQuote.amountOut,
};
}
static async getQuoteWithDefillamaFallback(params) {
try {
const quote = await this.getQuoteFromRouters(params);
return quote;
}
catch (e) {
const quote = await this.getQuoteFromDefillama(params);
return quote;
}
}
static async getQuote(params) {
return this.getQuoteWithDefillamaFallback(params);
}
static async getQuoteFromRouters(params) {
const bridgeTokenSymbol = QuoteProvider.DEFAULT_BRIDGE_TOKEN;
const sourceBridgeToken = CROSS_CHAIN_TOKENS[bridgeTokenSymbol]?.[params.sourceChainId];
const destBridgeToken = CROSS_CHAIN_TOKENS[bridgeTokenSymbol]?.[params.destChainId];
const sourceSingleChainQuoteParams = {
chainId: params.sourceChainId,
amount: params.amount,
tokenIn: params.tokenIn,
tokenOut: sourceBridgeToken,
};
const sourceQuote = await this.getSingleChainQuote(sourceSingleChainQuoteParams);
const destSingleChainQuoteParams = {
chainId: params.destChainId,
amount: sourceQuote.amountOut,
tokenIn: destBridgeToken,
tokenOut: params.tokenOut,
};
const destQuote = await this.getSingleChainQuote(destSingleChainQuoteParams);
// Use weighted reduction instead of fixed percentage
const weightedReductionFactor = this.calculateWeightedReductionFactorForUsd(destQuote.amountOutUsd);
const estimatedAmountOutReduced = BigInt(Math.floor(Number(destQuote.amountOut) * weightedReductionFactor));
const estimatedAmountOutUsdReduced = destQuote.amountOutUsd * weightedReductionFactor;
const reducedAmountInUsd = this.calculateWeightedReductionFactorForUsd(sourceQuote.amountInUsd);
const estimatedAmountInAsMinStablecoinAmount = BigInt(Math.floor(reducedAmountInUsd * 10 ** this.DEFAULT_BRIDGE_TOKEN_DECIMALS));
return {
estimatedAmountOut: destQuote.amountOut,
estimatedAmountOutUsd: destQuote.amountOutUsd,
amountInUsd: sourceQuote.amountInUsd,
estimatedAmountInAsMinStablecoinAmount,
estimatedAmountOutReduced,
estimatedAmountOutUsdReduced,
};
}
static async getSingleChainQuote(params) {
if (params.tokenIn.toLowerCase() === params.tokenOut.toLowerCase()) {
let amountUsd = 0;
if (params.tokenIn.toLowerCase() === CROSS_CHAIN_TOKENS.USDC[params.chainId].toLowerCase()) {
amountUsd = Number(params.amount) / 10 ** this.DEFAULT_BRIDGE_TOKEN_DECIMALS;
}
return {
amountIn: params.amount,
amountOut: params.amount,
amountOutUsd: amountUsd,
amountInUsd: amountUsd,
slippage: 0,
priceImpact: 0,
provider: getProviderNameByChainId(params.chainId),
rawQuote: null,
};
}
if (params.chainId === ChainID.Hyperliquid) {
const liquidSwapQuote = await QuoteProvider.getLiquidSwapQuote(params);
return QuoteProvider.transformLiquidSwapQuote(liquidSwapQuote);
}
if (params.chainId === ChainID.Solana) {
const jupiterQuote = await QuoteProvider.getJupiterQuote(params);
return QuoteProvider.transformJupiterQuote(jupiterQuote);
}
if (params.chainId === ChainID.Sui) {
const quote = await QuoteProvider.getAftermathQuote(params);
return QuoteProvider.transformAftermathQuote({ quote, request: params });
}
if (isEvmChain(params.chainId)) {
const paraswapQuote = await QuoteProvider.getParaswapQuote(params);
return QuoteProvider.transformParaswapQuote(paraswapQuote);
}
throw new Error(`Unsupported chain for quote: ${params.chainId}`);
}
static transformLiquidSwapQuote(liquidSwapQuote) {
return {
amountIn: BigInt(liquidSwapQuote.amountIn),
amountOut: BigInt(liquidSwapQuote.amountOut),
amountOutUsd: 0,
amountInUsd: 0,
slippage: 0,
priceImpact: Number(liquidSwapQuote.averagePriceImpact),
provider: 'liquidswap',
rawQuote: liquidSwapQuote,
};
}
/**
* Calculates the weighted reduction factor for an amount in USD.
* For amounts <= $5, the reduction factor is 0.65.
*/
static calculateWeightedReductionFactorForUsd(amountUsd) {
if (amountUsd <= 5) {
return 0.50;
}
else if (amountUsd <= 10) {
return 0.65;
}
else if (amountUsd <= 20) {
return 0.77;
}
else if (amountUsd <= 30) {
return 0.90;
}
else {
return 0.95;
}
}
static async getLiquidSwapQuote(params) {
const liquidSwapQuoter = new LiquidSwapQuoteProvider();
return liquidSwapQuoter.getQuote({
tokenIn: params.tokenIn,
tokenOut: params.tokenOut,
amountIn: params.amount.toString(),
});
}
static async getJupiterQuote(params) {
const jupiterQuoter = new JupiterQuoteProvider();
return jupiterQuoter.getQuote({
amount: params.amount,
tokenIn: params.tokenIn,
tokenOut: params.tokenOut,
swapMode: 'ExactIn',
slippageBps: params.slippageBps,
});
}
static async getParaswapQuote(params) {
const paraswapQuoter = new ParaswapQuoteProvider(params.chainId);
return paraswapQuoter.getSwapEstimation({
amount: BigInt(params.amount),
srcToken: params.tokenIn,
destToken: params.tokenOut,
side: 'SELL',
});
}
static async getAftermathQuote(params) {
const aftermathQuoter = new AftermathQuoteProvider();
return aftermathQuoter.getQuote({
amountIn: params.amount,
tokenIn: params.tokenIn,
tokenOut: params.tokenOut,
});
}
static transformAftermathQuote({ quote, request, }) {
let amountUsd = 0;
if (request.tokenIn === CROSS_CHAIN_TOKENS.USDC[request.chainId]) {
amountUsd = Number(quote.coinIn.amount) / 10 ** this.DEFAULT_BRIDGE_TOKEN_DECIMALS;
}
if (request.tokenOut === CROSS_CHAIN_TOKENS.USDC[request.chainId]) {
amountUsd = Number(quote.coinOut.amount) / 10 ** this.DEFAULT_BRIDGE_TOKEN_DECIMALS;
}
return {
amountIn: quote.coinIn.amount,
amountOut: quote.coinOut.amount,
amountOutUsd: amountUsd,
amountInUsd: amountUsd,
slippage: quote.slippage ?? 0,
priceImpact: 0,
provider: 'aftermath',
rawQuote: quote,
};
}
static transformParaswapQuote(paraswapQuote) {
return {
amountIn: BigInt(paraswapQuote.amountIn),
amountOut: BigInt(paraswapQuote.amountOut),
amountOutUsd: paraswapQuote.amountOutUsd,
amountInUsd: paraswapQuote.amountInUsd,
slippage: 0, // Calculate from paraswap data if available
priceImpact: paraswapQuote.quote.maxImpact ? Number(paraswapQuote.quote.maxImpact) * 100 : 0,
provider: 'paraswap',
rawQuote: paraswapQuote,
};
}
static transformJupiterQuote({ quote }) {
const amountIn = Number(quote.inAmount);
const amountOut = Number(quote.outAmount);
let amountUsd = 0;
const priceImpact = quote.priceImpactPct ? Number(quote.priceImpactPct) * 100 : 0;
if (quote.outputMint === CROSS_CHAIN_TOKENS.USDC[ChainID.Solana]) {
amountUsd = amountOut / 10 ** this.DEFAULT_BRIDGE_TOKEN_DECIMALS;
}
if (quote.inputMint === CROSS_CHAIN_TOKENS.USDC[ChainID.Solana]) {
amountUsd = amountIn / 10 ** this.DEFAULT_BRIDGE_TOKEN_DECIMALS;
}
return {
amountIn: BigInt(amountIn),
amountOut: BigInt(amountOut),
amountOutUsd: amountUsd,
amountInUsd: amountUsd,
slippage: quote.slippageBps ? quote.slippageBps / 100 : 0,
priceImpact,
provider: 'jupiter',
rawQuote: quote,
};
}
}
Object.defineProperty(QuoteProvider, "DEFAULT_BRIDGE_TOKEN", {
enumerable: true,
configurable: true,
writable: true,
value: 'USDC'
});
Object.defineProperty(QuoteProvider, "DEFAULT_BRIDGE_TOKEN_DECIMALS", {
enumerable: true,
configurable: true,
writable: true,
value: 6
});
function getProviderNameByChainId(chainId) {
switch (chainId) {
case ChainID.Sui:
return 'aftermath';
case ChainID.Solana:
return 'jupiter';
case ChainID.Hyperliquid:
return 'liquidswap';
default:
return 'paraswap';
}
}
//# sourceMappingURL=aggregator.js.map