UNPKG

baluni-api

Version:
190 lines (189 loc) 10.5 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.route = exports.getBestQuote = exports.getBestQuoteForSwapPath = exports.getAdjAmount = void 0; const ethers_1 = require("ethers"); const constants_1 = require("../../constants"); // Assuming these constants are defined correctly const utils_1 = require("ethers/lib/utils"); const ERC20_json_1 = __importDefault(require("../../abis/common/ERC20.json")); const Quoter_json_1 = __importDefault(require("../../abis/uniswap/Quoter.json")); const Factory_json_1 = __importDefault(require("../../abis/uniswap/Factory.json")); const Pool_json_1 = __importDefault(require("../../abis/uniswap/Pool.json")); const smart_order_router_1 = require("@uniswap/smart-order-router"); const sdk_core_1 = require("@uniswap/sdk-core"); const parseToken_1 = require("./parseToken"); const router_sdk_1 = require("@uniswap/router-sdk"); const POOL_FEES = [100, 500, 3000, 10000]; const ZERO_ADDRESS = ethers_1.ethers.constants.AddressZero; function logError(context, error) { console.error(`Error in ${context}:`, error); } function getAdjAmount(_amount, _decimals) { return (0, utils_1.parseUnits)(_amount, _decimals); } exports.getAdjAmount = getAdjAmount; function findPoolAndFee(factoryContract, tokenIn, tokenOut) { return __awaiter(this, void 0, void 0, function* () { for (const poolFee of POOL_FEES) { const poolAddress = yield getPoolAddress(factoryContract, tokenIn, tokenOut, poolFee); if (poolAddress !== ZERO_ADDRESS) return poolFee; } return 0; }); } function getPoolAddress(factoryContract, tokenIn, tokenOut, poolFee) { return __awaiter(this, void 0, void 0, function* () { const poolAddress = yield factoryContract.getPool(tokenIn, tokenOut, poolFee); return poolAddress; }); } function getAmountOut(quoterContract, tokenIn, tokenOut, poolFee, amountIn, slippage) { return __awaiter(this, void 0, void 0, function* () { try { const expectedAmountOut = yield quoterContract.callStatic.quoteExactInputSingle(tokenIn, tokenOut, poolFee, amountIn.toString(), 0); return expectedAmountOut.mul(10000 - slippage).div(10000); } catch (error) { logError('::API:: getAmountOut', error); return ethers_1.BigNumber.from(0); } }); } // Utilizza questa funzione per verificare la validità delle condizioni prima della chiamata function isSwapPossible(factoryContract, tokenIn, tokenOut, poolFee) { return __awaiter(this, void 0, void 0, function* () { const poolAddress = yield factoryContract.getPool(tokenIn, tokenOut, poolFee); return poolAddress !== ZERO_ADDRESS; }); } function getPoolData(poolContract, minRequiredLiquidity) { return __awaiter(this, void 0, void 0, function* () { const slot0 = yield poolContract.slot0(); const currentSqrtPriceX96 = slot0.sqrtPriceX96; const currentTick = slot0.tick; const tickSpacing = yield poolContract.tickSpacing(); const desiredTickLower = currentTick - (currentTick % tickSpacing); const desiredTickUpper = desiredTickLower + tickSpacing; const tickLowerData = yield poolContract.ticks(desiredTickLower); const tickUpperData = yield poolContract.ticks(desiredTickUpper); const liquidityInLowerTick = tickLowerData.liquidityGross; const liquidityInUpperTick = tickUpperData.liquidityGross; const isLiquiditySufficient = liquidityInLowerTick.gt(minRequiredLiquidity) && liquidityInUpperTick.gt(minRequiredLiquidity); return isLiquiditySufficient; }); } function quoteSwapAmountOut(factoryContract, quoterContract, tokenIn, tokenOut, amountIn, slippageTolerance) { return __awaiter(this, void 0, void 0, function* () { const poolFee = yield findPoolAndFee(factoryContract, tokenIn, tokenOut); if (poolFee === 0) { console.log('Nessuna pool adatta trovata, evitando la chiamata che fallirebbe.'); return { amountOut: ethers_1.BigNumber.from(0), poolFee: 0 }; } // Verifica se la swap è possibile prima di procedere const swapPossible = yield isSwapPossible(factoryContract, tokenIn, tokenOut, poolFee); if (!swapPossible) { console.log('La swap non è possibile, evitando la chiamata che fallirebbe.'); return { amountOut: ethers_1.BigNumber.from(0), poolFee }; } const amountOut = yield getAmountOut(quoterContract, tokenIn, tokenOut, poolFee, amountIn, slippageTolerance); if (amountOut == ethers_1.BigNumber.from(0)) { return { amountOut: ethers_1.BigNumber.from(0), poolFee }; } const poolAddress = yield getPoolAddress(factoryContract, tokenIn, tokenOut, poolFee); const poolContract = new ethers_1.Contract(poolAddress, Pool_json_1.default, quoterContract.provider); const minimalLiquidity = getPoolData(poolContract, amountOut); if (!minimalLiquidity) { return { amountOut: ethers_1.BigNumber.from(0), poolFee }; } return { amountOut, poolFee }; }); } function getBestQuoteForSwapPath(factoryContract, quoterContract, tokenIn, tokenOut, amountIn, slippageTolerance, chainId) { var _a; return __awaiter(this, void 0, void 0, function* () { let bestQuote = yield quoteSwapAmountOut(factoryContract, quoterContract, tokenIn, tokenOut, amountIn, slippageTolerance); let bestPath = [tokenIn, tokenOut]; // Check through intermediate tokens if direct path isn't the best const intermediateTokens = [ (_a = constants_1.NATIVETOKENS[chainId]) === null || _a === void 0 ? void 0 : _a.WRAPPED, constants_1.WETH[chainId], constants_1.DAI[chainId], constants_1.USDT[chainId], constants_1.USDC[chainId], ].filter(token => token !== tokenIn && token !== tokenOut); for (const intermediateToken of intermediateTokens) { const toIntermediateQuote = yield quoteSwapAmountOut(factoryContract, quoterContract, tokenIn, intermediateToken, amountIn, slippageTolerance); if (toIntermediateQuote.amountOut.isZero()) continue; const fromIntermediateQuote = yield quoteSwapAmountOut(factoryContract, quoterContract, intermediateToken, tokenOut, toIntermediateQuote.amountOut, slippageTolerance); if (fromIntermediateQuote.amountOut.gt(bestQuote.amountOut)) { bestQuote = fromIntermediateQuote; bestPath = [tokenIn, intermediateToken, tokenOut]; } } console.log('::DEBUG:: final bestQuote:', bestQuote); console.log('::DEBUG:: final bestPath:', bestPath); return { amountOut: bestQuote.amountOut, path: bestPath, poolFees: [bestQuote.poolFee], }; }); } exports.getBestQuoteForSwapPath = getBestQuoteForSwapPath; function getBestQuote(wallet, token0, token1, reverse, protocol, chainId, amount, slippage) { return __awaiter(this, void 0, void 0, function* () { const _protocol = constants_1.PROTOCOLS[chainId][protocol]; const quoter = String(_protocol.QUOTER); const quoterContract = new ethers_1.Contract(quoter, Quoter_json_1.default, wallet); const factory = String(_protocol.FACTORY); const factoryContract = new ethers_1.Contract(factory, Factory_json_1.default, wallet); const tokenAAddress = reverse ? token1 : token0; const tokenAContract = new ethers_1.Contract(tokenAAddress, ERC20_json_1.default, wallet); const tokenADecimals = yield tokenAContract.decimals(); const tokenBAddress = reverse ? token0 : token1; const adjAmount = getAdjAmount(amount, tokenADecimals); const bestQuote = yield getBestQuoteForSwapPath(factoryContract, quoterContract, tokenAAddress, tokenBAddress, adjAmount, slippage, chainId); console.log('::DEBUG:: final bestQuote:', bestQuote); return bestQuote; }); } exports.getBestQuote = getBestQuote; function route(tradeRequest) { return __awaiter(this, void 0, void 0, function* () { const router = new smart_order_router_1.AlphaRouter({ chainId: tradeRequest.chainId, provider: new ethers_1.ethers.providers.JsonRpcProvider(constants_1.NETWORKS[tradeRequest.chainId]), }); const currencyAmount = (0, parseToken_1.parseToken)(tradeRequest.currencyAmount, tradeRequest.chainId); const currency = (0, parseToken_1.parseToken)(tradeRequest.currency, tradeRequest.chainId); const formatedSlippage = tradeRequest.slippage / 100; // 5000/100 = 50 const SLIPPAGE = new sdk_core_1.Percent(formatedSlippage, 10000); // Correct 15% const routing = router.route(smart_order_router_1.CurrencyAmount.fromRawAmount(currencyAmount, Number(tradeRequest.amount)), currency, sdk_core_1.TradeType.EXACT_INPUT, { slippageTolerance: SLIPPAGE, type: smart_order_router_1.SwapType.SWAP_ROUTER_02, // SwapType.UNIVERSAL_ROUTER recipient: tradeRequest.recipient, deadline: Math.floor(Date.now() / 1000) + 360, //deadlineOrPreviousBlockhash: Math.floor(Date.now() / 1000) + 360, }, { distributionPercent: 5, maxSplits: 4, protocols: [router_sdk_1.Protocol.V3, router_sdk_1.Protocol.V2, router_sdk_1.Protocol.MIXED], }); return routing; }); } exports.route = route;