@kamino-finance/kliquidity-sdk
Version:
Typescript SDK for interacting with the Kamino Liquidity (kliquidity) protocol
123 lines • 5.16 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTokensPrices = void 0;
const decimal_js_1 = __importDefault(require("decimal.js"));
const BATCH_TOKEN_PRICES_LIMIT = 100;
const BATCH_TOKEN_PRICES_MAX_URL_LENGTH = 2000;
const BATCH_TOKEN_PRICES_PATH = 'batch-token-prices';
const BATCH_TOKEN_PRICES_QUERY_KEY = 'tokens';
const getBatchTokenPricesBaseUrl = (apiBaseUrl) => `${apiBaseUrl.replace(/\/+$/, '')}/${BATCH_TOKEN_PRICES_PATH}`;
const getBatchTokenPricesUrl = (apiBaseUrl, tokens) => {
const tokensParams = new URLSearchParams();
for (const token of tokens) {
tokensParams.append(BATCH_TOKEN_PRICES_QUERY_KEY, token);
}
return `${getBatchTokenPricesBaseUrl(apiBaseUrl)}?${tokensParams.toString()}`;
};
const getTokenQueryParamLength = (token) => {
const tokenParam = new URLSearchParams();
tokenParam.append(BATCH_TOKEN_PRICES_QUERY_KEY, token);
return tokenParam.toString().length;
};
const getTokensPriceBatches = (apiBaseUrl, tokens) => {
const baseUrlLength = `${getBatchTokenPricesBaseUrl(apiBaseUrl)}?`.length;
const batches = [];
let batch = [];
let batchUrlLength = baseUrlLength;
for (const token of tokens) {
const tokenParamLength = getTokenQueryParamLength(token);
const separatorLength = batch.length === 0 ? 0 : 1;
const nextBatchUrlLength = batchUrlLength + separatorLength + tokenParamLength;
if (batch.length < BATCH_TOKEN_PRICES_LIMIT && nextBatchUrlLength <= BATCH_TOKEN_PRICES_MAX_URL_LENGTH) {
batch.push(token);
batchUrlLength = nextBatchUrlLength;
continue;
}
if (batch.length > 0) {
batches.push(batch);
}
const singleTokenUrl = getBatchTokenPricesUrl(apiBaseUrl, [token]);
if (singleTokenUrl.length > BATCH_TOKEN_PRICES_MAX_URL_LENGTH) {
throw new Error(`KSwap token price URL length ${singleTokenUrl.length} exceeds limit ${BATCH_TOKEN_PRICES_MAX_URL_LENGTH} for a single token: ${singleTokenUrl}`);
}
batch = [token];
batchUrlLength = baseUrlLength + tokenParamLength;
}
if (batch.length > 0) {
batches.push(batch);
}
return batches;
};
const getResponseBodyForLog = async (response) => {
try {
return await response.text();
}
catch (error) {
return `Failed to read response body: ${error instanceof Error ? error.message : String(error)}`;
}
};
const getTokensPrices = async (apiBaseUrl, tokens, logger = console) => {
if (tokens.length === 0) {
return new Map();
}
const batches = getTokensPriceBatches(apiBaseUrl, tokens);
const results = await Promise.all(batches.map(async (batch) => {
const url = getBatchTokenPricesUrl(apiBaseUrl, batch);
let response;
try {
response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
}
catch (error) {
logger.error(`Failed to fetch tokens batch price. URL: ${url}.`, error);
return { batch, data: null };
}
const responseBody = await getResponseBodyForLog(response);
if (!response.ok) {
logger.error(`Failed to fetch tokens batch price: ${response.status} ${response.statusText}. URL: ${url}. Response body: ${responseBody}`);
return { batch, data: null };
}
try {
const data = JSON.parse(responseBody);
if (data.success === false || !data.data) {
logger.error(`Unexpected tokens batch price response. URL: ${url}. Response body: ${responseBody}`);
return { batch, data: null };
}
return { batch, data };
}
catch (error) {
logger.error(`Failed to parse tokens batch price response. URL: ${url}. Response body: ${responseBody}`, error);
return { batch, data: null };
}
}));
const prices = new Map();
for (const { batch, data } of results) {
for (const token of batch) {
const tokenData = data?.data[token];
if (tokenData && tokenData.value !== null && tokenData.value !== undefined) {
try {
const price = new decimal_js_1.default(tokenData.value);
prices.set(token, price);
}
catch (error) {
logger.error(`Failed to parse price for token, setting to 0: ${token}:`, error);
prices.set(token, new decimal_js_1.default(0));
}
}
else {
logger.warn(`No price data available for token ${token}, setting to 0`);
prices.set(token, new decimal_js_1.default(0));
}
}
}
return prices;
};
exports.getTokensPrices = getTokensPrices;
//# sourceMappingURL=kSwap.js.map