@robertprp/intents-sdk
Version:
Shogun Network Intent-based cross-chain swaps SDK
104 lines • 4.29 kB
JavaScript
import { ChainID } from '../chains.js';
import { NATIVE_EVM_ETH_ADDRESSES, NATIVE_SOLANA_TOKEN_ADDRESS, WRAPPED_SOL_MINT_ADDRESS } from '../constants.js';
import { Parsers } from './parsers.js';
import { QuoteProvider } from './quote/aggregator.js';
const TOKEN_PRICE_BASE_URL = 'https://coins.llama.fi/prices/current/';
const STABLECOIN_DECIMALS = 6; // USDC/USDT typically use 6 decimals
/**
* Maps chain IDs to their corresponding chain types
* Used to determine which SDK implementation to use for a given chain
*/
export const chainIdToDefiLlamaChainMap = {
[ChainID.Arbitrum]: 'arbitrum',
[ChainID.Base]: 'base',
[ChainID.Optimism]: 'optimism',
[ChainID.Hyperliquid]: 'hyperliquid',
[ChainID.Solana]: 'solana',
[ChainID.Sui]: 'sui',
};
/**
* Creates DefiLlama coin key from chain ID and token address
* Format: "chainName:tokenAddress"
*/
export const createDefiLlamaCoinKey = (chainId, tokenAddress) => {
const chainName = chainIdToDefiLlamaChainMap[chainId];
return `${chainName}:${toDefiLlamaToken(tokenAddress)}`;
};
/**
* Retrieves token data from DefiLlama response by chain and address
*/
export const getCoinFromResponse = (response, chainId, tokenAddress) => {
const key = createDefiLlamaCoinKey(chainId, tokenAddress);
const coin = response.coins[key];
if (!coin) {
throw new Error(`DefiLlama coin not found for ${key}`);
}
return coin;
};
/**
* Converts Solana native token address to wrapped SOL mint address
* DefiLlama uses wrapped SOL mint address for native SOL
*
* @param tokenAddress The token address to convert
* @returns The DefiLlama-compatible token address
*/
function toDefiLlamaToken(tokenAddress) {
if (isNativeTokenEvmAddress(tokenAddress)) {
return '0x0000000000000000000000000000000000000000';
}
if (tokenAddress === NATIVE_SOLANA_TOKEN_ADDRESS) {
return WRAPPED_SOL_MINT_ADDRESS;
}
return tokenAddress;
}
function isNativeTokenEvmAddress(tokenAddress) {
const normalizedAddress = tokenAddress.toLowerCase();
return NATIVE_EVM_ETH_ADDRESSES.some((addr) => addr.toLowerCase() === normalizedAddress);
}
/**
* Builds a comma-separated query string for DefiLlama API token requests
*
* Converts an array of chain/token pairs into the format expected by DefiLlama's
* bulk price endpoint: "chain1:token1,chain2:token2,..."
*
* @param tokens - Array of [ChainID, token address] tuples to query
* @returns Comma-separated string of DefiLlama coin keys
*/
function buildTokensQueryString(tokens) {
return tokens.map(([chainId, tokenAddress]) => createDefiLlamaCoinKey(chainId, tokenAddress)).join(',');
}
/**
* Fetch tokens data for array of coins
*
* @param tokens Array of [ChainID, Token Address] tuples
* @returns Promise resolving to DefiLlama tokens response
*/
export async function getTokensData(tokens) {
const tokensStr = buildTokensQueryString(tokens);
const url = `${TOKEN_PRICE_BASE_URL}${tokensStr}`;
const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
return response.json();
}
export async function calculateAmounts({ srcChainId, tokenIn, amountIn, destChainId, tokenOut, }) {
// Fetch token data from DefiLlama
const tokensResponse = await getTokensData([
[srcChainId, tokenIn],
[destChainId, tokenOut],
]);
const tokenInData = getCoinFromResponse(tokensResponse, srcChainId, tokenIn);
const tokenOutData = getCoinFromResponse(tokensResponse, destChainId, tokenOut);
// Calculate 80% of the amount_in value as amount_out_min and min_stablecoins_amount
const tokenInUsdAmount = Parsers.bigintToFloat(amountIn, tokenInData.decimals) * tokenInData.price;
const reductionFactor = QuoteProvider.calculateWeightedReductionFactorForUsd(tokenInUsdAmount);
const amountInUsdReduced = tokenInUsdAmount * reductionFactor;
const amountOutReduced = amountInUsdReduced / tokenOutData.price;
const amountOut = Parsers.floatToBigint(amountOutReduced, tokenOutData.decimals);
const minStablecoinsAmount = Parsers.floatToBigint(amountInUsdReduced, STABLECOIN_DECIMALS);
return { amountOut, minStablecoinsAmount };
}
//# sourceMappingURL=defillama.js.map