UNPKG

@quantara/sdk

Version:

JavaScript/TypeScript SDK for interacting with Quantara Protocol on Neura Testnet

222 lines (221 loc) 10.2 kB
import { BASIS_POINTS_DIVISOR_BIGINT, DEFAULT_ALLOWED_SWAP_SLIPPAGE_BPS } from "../configs/factors"; import { OrderType, } from "../types/orders"; import { getSwapPathOutputAddresses, getSwapPathStats } from "./swap/swapStats"; import { bigMath } from "./bigmath"; import { getByKey } from "./objects"; import { parsePositionKey } from "./positions"; import { getOrderThresholdType } from "./prices"; import { convertToTokenAmount, convertToUsd, getTokensRatioByAmounts, getTokensRatioByMinOutputAmountAndTriggerPrice, parseContractPrice, } from "./tokens"; export function isMarketOrderType(orderType) { return [OrderType.MarketDecrease, OrderType.MarketIncrease, OrderType.MarketSwap].includes(orderType); } export function isLimitOrderType(orderType) { return [OrderType.LimitIncrease, OrderType.LimitSwap, OrderType.StopIncrease].includes(orderType); } export function isTriggerDecreaseOrderType(orderType) { return [OrderType.LimitDecrease, OrderType.StopLossDecrease].includes(orderType); } export function isDecreaseOrderType(orderType) { return [OrderType.MarketDecrease, OrderType.LimitDecrease, OrderType.StopLossDecrease].includes(orderType); } export function isIncreaseOrderType(orderType) { return [OrderType.MarketIncrease, OrderType.LimitIncrease, OrderType.StopIncrease].includes(orderType); } export function isSwapOrderType(orderType) { return [OrderType.MarketSwap, OrderType.LimitSwap].includes(orderType); } export function isLimitSwapOrderType(orderType) { return orderType === OrderType.LimitSwap; } export function isLiquidationOrderType(orderType) { return orderType === OrderType.Liquidation; } export function isStopLossOrderType(orderType) { return orderType === OrderType.StopLossDecrease; } export function isLimitDecreaseOrderType(orderType) { return orderType === OrderType.LimitDecrease; } export function isLimitIncreaseOrderType(orderType) { return orderType === OrderType.LimitIncrease; } export function isStopIncreaseOrderType(orderType) { return orderType === OrderType.StopIncrease; } export function isTwapOrder(orderInfo) { return orderInfo.isTwap; } export function isTwapSwapOrder(orderInfo) { return orderInfo.isTwap && orderInfo.isSwap; } export function isTwapPositionOrder(orderInfo) { return orderInfo.isTwap && !orderInfo.isSwap; } export function isSwapOrder(orderInfo) { return orderInfo.isSwap; } export function isPositionOrder(orderInfo) { return !orderInfo.isSwap; } export function getOrderKeys(order) { return isTwapOrder(order) ? order.orders.map((o) => o.key) : [order.key]; } export function getOrderInfo(p) { const { marketsInfoData, tokensData, wrappedNativeToken, order } = p; if (isSwapOrderType(order.orderType)) { const initialCollateralToken = getByKey(tokensData, order.initialCollateralTokenAddress); const { outTokenAddress } = getSwapPathOutputAddresses({ marketsInfoData, swapPath: order.swapPath, initialCollateralAddress: order.initialCollateralTokenAddress, wrappedNativeTokenAddress: wrappedNativeToken.address, shouldUnwrapNativeToken: order.shouldUnwrapNativeToken, isIncrease: false, }); const targetCollateralToken = getByKey(tokensData, outTokenAddress); if (!initialCollateralToken || !targetCollateralToken) { return undefined; } const swapPathStats = getSwapPathStats({ marketsInfoData, swapPath: order.swapPath, initialCollateralAddress: order.initialCollateralTokenAddress, wrappedNativeTokenAddress: wrappedNativeToken.address, usdIn: convertToUsd(order.initialCollateralDeltaAmount, initialCollateralToken.decimals, initialCollateralToken.prices.minPrice), shouldUnwrapNativeToken: order.shouldUnwrapNativeToken, shouldApplyPriceImpact: true, isAtomicSwap: false, }); const priceImpactAmount = convertToTokenAmount(swapPathStats?.totalSwapPriceImpactDeltaUsd, targetCollateralToken.decimals, targetCollateralToken.prices.minPrice); const swapFeeAmount = convertToTokenAmount(swapPathStats?.totalSwapFeeUsd, targetCollateralToken.decimals, targetCollateralToken.prices.minPrice); let toAmount = order.minOutputAmount; let triggerRatio; const isLimitSwapOrder = isLimitSwapOrderType(order.orderType); if (isLimitSwapOrder) { if (order.contractTriggerPrice === 0n) { /** * If not stored trigger price in contract, we use the min output amount with default slippage * @see https://app.asana.com/0/1207525044994982/1209109731071143 */ toAmount = order.minOutputAmount - bigMath.mulDiv(order.minOutputAmount, DEFAULT_ALLOWED_SWAP_SLIPPAGE_BPS, BASIS_POINTS_DIVISOR_BIGINT); } triggerRatio = getTokensRatioByMinOutputAmountAndTriggerPrice({ fromToken: initialCollateralToken, toToken: targetCollateralToken, fromTokenAmount: order.initialCollateralDeltaAmount, toTokenAmount: toAmount, triggerPrice: order.contractTriggerPrice, minOutputAmount: order.minOutputAmount, }); } else { toAmount = order.minOutputAmount - (priceImpactAmount ?? 0n) + (swapFeeAmount ?? 0n); triggerRatio = getTokensRatioByAmounts({ fromToken: initialCollateralToken, toToken: targetCollateralToken, fromTokenAmount: order.initialCollateralDeltaAmount, toTokenAmount: toAmount, }); } const orderInfo = { ...order, swapPathStats, triggerRatio, initialCollateralToken, targetCollateralToken, isSwap: true, isTwap: false, }; return orderInfo; } else { const marketInfo = getByKey(marketsInfoData, order.marketAddress); const indexToken = marketInfo?.indexToken; const initialCollateralToken = getByKey(tokensData, order.initialCollateralTokenAddress); const { outTokenAddress } = getSwapPathOutputAddresses({ marketsInfoData, swapPath: order.swapPath, initialCollateralAddress: order.initialCollateralTokenAddress, wrappedNativeTokenAddress: wrappedNativeToken.address, shouldUnwrapNativeToken: order.shouldUnwrapNativeToken, isIncrease: isIncreaseOrderType(order.orderType), }); const targetCollateralToken = getByKey(tokensData, outTokenAddress); if (!marketInfo || !indexToken || !initialCollateralToken || !targetCollateralToken) { return undefined; } const acceptablePrice = parseContractPrice(order.contractAcceptablePrice, indexToken.decimals); const triggerPrice = parseContractPrice(order.contractTriggerPrice, indexToken.decimals); const swapPathStats = getSwapPathStats({ marketsInfoData, swapPath: order.swapPath, initialCollateralAddress: order.initialCollateralTokenAddress, wrappedNativeTokenAddress: wrappedNativeToken.address, usdIn: convertToUsd(order.initialCollateralDeltaAmount, initialCollateralToken.decimals, initialCollateralToken.prices.minPrice), shouldUnwrapNativeToken: order.shouldUnwrapNativeToken, shouldApplyPriceImpact: true, isAtomicSwap: false, }); let triggerThresholdType; if (!isMarketOrderType(order.orderType)) { triggerThresholdType = getOrderThresholdType(order.orderType, order.isLong); } const orderInfo = { ...order, swapPathStats, marketInfo, indexToken, initialCollateralToken, targetCollateralToken, acceptablePrice, triggerPrice, triggerThresholdType, isSwap: false, isTwap: false, }; return orderInfo; } } export function isVisibleOrder(orderType) { return (isLimitOrderType(orderType) || isTriggerDecreaseOrderType(orderType) || isLimitSwapOrderType(orderType) || isMarketOrderType(orderType)); } export function isOrderForPosition(order, positionKey) { const { account, marketAddress, collateralAddress, isLong } = parsePositionKey(positionKey); let isMatch = !isSwapOrderType(order.orderType) && order.account === account && order.marketAddress === marketAddress && order.isLong === isLong; // For limit orders, we need to check the target collateral token if (isLimitOrderType(order.orderType)) { const targetCollateralTokenAddress = order.targetCollateralToken.isNative ? order.targetCollateralToken.wrappedAddress : order.targetCollateralToken.address; isMatch = isMatch && targetCollateralTokenAddress === collateralAddress; } else if (isTriggerDecreaseOrderType(order.orderType)) { isMatch = isMatch && order.initialCollateralTokenAddress === collateralAddress; } return isMatch; } export function isOrderForPositionByData(order, { account, marketAddress, collateralAddress, isLong, }) { let isMatch = !isSwapOrderType(order.orderType) && order.account === account && order.marketAddress === marketAddress && order.isLong === isLong; // For limit orders, we need to check the target collateral token if (isLimitOrderType(order.orderType)) { const targetCollateralTokenAddress = order.targetCollateralToken.isNative ? order.targetCollateralToken.wrappedAddress : order.targetCollateralToken.address; isMatch = isMatch && targetCollateralTokenAddress === collateralAddress; } else if (isTriggerDecreaseOrderType(order.orderType)) { isMatch = isMatch && order.initialCollateralTokenAddress === collateralAddress; } return isMatch; }