@quantara/sdk
Version:
JavaScript/TypeScript SDK for interacting with Quantara Protocol on Neura Testnet
222 lines (221 loc) • 10.2 kB
JavaScript
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;
}