UNPKG

blockchain-api

Version:

API utilities for interacting with the Exatechl2 blockchain

147 lines (146 loc) 6.09 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getTokenPrice = getTokenPrice; exports.getFormattedTokenPrice = getFormattedTokenPrice; const ethers_1 = require("ethers"); const abis_1 = require("./abis"); const logger_1 = require("../../utils/logger"); let lastPrice = { usd: 0, bnb: 0, lastUpdated: 0, changePercent: 0 }; let priceHistory = []; const EXATECH_DECIMALS = 9; /** * * @returns */ async function getTokenPrice() { try { const now = Date.now(); if (lastPrice.lastUpdated > 0 && (now - lastPrice.lastUpdated < 1 * 60 * 1000)) { return { usd: lastPrice.usd, bnb: lastPrice.bnb, changePercent: lastPrice.changePercent }; } const provider = new ethers_1.ethers.providers.JsonRpcProvider("https://bsc-dataseed1.binance.org"); const bnbPriceInUsd = await getBnbPriceInUsd(provider); logger_1.logger.debug(`BNB price in USD: ${bnbPriceInUsd}`); const bnbPerExatech = await getExatechPriceInBnbViaRouter(provider); logger_1.logger.debug(`EXATECH price in BNB via Router: ${bnbPerExatech}`); const usdPrice = bnbPerExatech * bnbPriceInUsd; logger_1.logger.debug(`EXATECH final price: ${usdPrice} USD`); priceHistory.push({ timestamp: now, usd: usdPrice, bnb: bnbPerExatech }); if (priceHistory.length > 24) { priceHistory.shift(); } let changePercent = 0; if (priceHistory.length > 1) { const oldestPrice = priceHistory[0].usd; changePercent = ((usdPrice - oldestPrice) / oldestPrice) * 100; } lastPrice = { usd: usdPrice, bnb: bnbPerExatech, lastUpdated: now, changePercent }; return { usd: usdPrice, bnb: bnbPerExatech, changePercent }; } catch (error) { logger_1.logger.error("Error fetching token price:", error); throw error; } } async function getBnbPriceInUsd(provider) { const router = new ethers_1.ethers.Contract(abis_1.CONTRACT_ADDRESSES.PANCAKESWAP_ROUTER, abis_1.PANCAKESWAP_ROUTER_ABI, provider); const oneBNB = ethers_1.ethers.utils.parseEther("1"); const bnbToUsdt = await router.getAmountsOut(oneBNB, [abis_1.CONTRACT_ADDRESSES.WBNB, abis_1.CONTRACT_ADDRESSES.USDT]); return parseFloat(ethers_1.ethers.utils.formatUnits(bnbToUsdt[1], 18)); } async function getExatechPriceInBnbViaRouter(provider) { try { const router = new ethers_1.ethers.Contract(abis_1.CONTRACT_ADDRESSES.PANCAKESWAP_ROUTER, abis_1.PANCAKESWAP_ROUTER_ABI, provider); const exatechAmount = ethers_1.ethers.utils.parseUnits("1", EXATECH_DECIMALS); logger_1.logger.debug(`Getting price for: ${exatechAmount.toString()} EXATECH baseunits (1 EXATECH)`); const amountsOut = await router.getAmountsOut(exatechAmount, [abis_1.CONTRACT_ADDRESSES.EXATECH, abis_1.CONTRACT_ADDRESSES.WBNB]); const bnbAmount = parseFloat(ethers_1.ethers.utils.formatEther(amountsOut[1])); logger_1.logger.debug(`Router estimates 1 EXATECH = ${bnbAmount} BNB`); return bnbAmount; } catch (error) { logger_1.logger.error("Error getting price via router:", error); return getExatechPriceInBnbViaReserves(provider); } } async function getExatechPriceInBnbViaReserves(provider) { try { logger_1.logger.debug("Trying reserve method as fallback..."); const pairContract = new ethers_1.ethers.Contract(abis_1.CONTRACT_ADDRESSES.EXATECH_BNB_PAIR, abis_1.PAIR_ABI, provider); const token0 = await pairContract.token0(); const token1 = await pairContract.token1(); logger_1.logger.debug(`Pair tokens: token0=${token0}, token1=${token1}`); logger_1.logger.debug(`EXATECH address: ${abis_1.CONTRACT_ADDRESSES.EXATECH}`); const isExatechToken0 = token0.toLowerCase() === abis_1.CONTRACT_ADDRESSES.EXATECH.toLowerCase(); logger_1.logger.debug(`Is EXATECH token0? ${isExatechToken0}`); const reserves = await pairContract.getReserves(); let exatechReserve, bnbReserve; if (isExatechToken0) { exatechReserve = parseFloat(ethers_1.ethers.utils.formatUnits(reserves.reserve0, EXATECH_DECIMALS)); bnbReserve = parseFloat(ethers_1.ethers.utils.formatEther(reserves.reserve1)); logger_1.logger.debug(`Reserves: EXATECH=${exatechReserve}, BNB=${bnbReserve}`); } else { exatechReserve = parseFloat(ethers_1.ethers.utils.formatUnits(reserves.reserve1, EXATECH_DECIMALS)); bnbReserve = parseFloat(ethers_1.ethers.utils.formatEther(reserves.reserve0)); logger_1.logger.debug(`Reserves: BNB=${bnbReserve}, EXATECH=${exatechReserve}`); } logger_1.logger.debug(`Exatech reserve: ${exatechReserve}, BNB reserve: ${bnbReserve}`); if (exatechReserve < 0.0001 || bnbReserve < 0.0001) { logger_1.logger.error("Reserves too small for accurate calculation"); throw new Error("Reserves too small"); } return bnbReserve / exatechReserve; } catch (error) { logger_1.logger.error("Error in reserve method:", error); throw error; } } /** * @returns */ async function getFormattedTokenPrice() { try { const price = await getTokenPrice(); const priceStr = price.usd.toFixed(8); const changeStr = price.changePercent >= 0 ? `+${price.changePercent.toFixed(1)}%` : `${price.changePercent.toFixed(1)}%`; return { price: `$${priceStr}`, change: changeStr, isPositive: price.changePercent >= 0 }; } catch (error) { logger_1.logger.error("Error formatting token price:", error); return { price: "N/A", change: "-", isPositive: false }; } }