fix signal and get position during closing

This commit is contained in:
2025-05-14 14:48:01 +07:00
parent 15190a0516
commit 456867c352
3 changed files with 420 additions and 419 deletions

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Managing.Core;
using Managing.Domain.Candles;
using Managing.Domain.Users;
@@ -34,7 +35,7 @@ namespace Managing.Domain.Strategies
StrategyType = strategyType;
User = user;
Identifier = $"{StrategyType}-{direction}-{ticker}-{candle?.Close}-{date:yyyyMMdd-HHmmss}";
Identifier = $"{StrategyType}-{direction}-{ticker}-{candle?.Close.ToString(CultureInfo.InvariantCulture)}-{date:yyyyMMdd-HHmmss}";
SignalType = signalType;
}

View File

@@ -660,7 +660,9 @@ public class EvmManager : IEvmManager
{
account = account.Key,
ticker = ticker.ToString(),
direction = direction.ToString(),
direction = direction == TradeDirection.Long
? TradeDirection.Short.ToString()
: TradeDirection.Long.ToString(),
});
trade = new Trade(
DateTime.UtcNow,

View File

@@ -15,483 +15,481 @@ import {EntryField, SidecarSlTpOrderEntryValid} from "../../types/sidecarOrders.
/** Base Optional params for helpers, allows to avoid calling markets, tokens and uiFeeFactor methods if they are already passed */
interface BaseOptionalParams {
marketsInfoData?: MarketsInfoData;
tokensData?: TokensData;
uiFeeFactor?: bigint;
marketsInfoData?: MarketsInfoData;
tokensData?: TokensData;
uiFeeFactor?: bigint;
}
export type PositionIncreaseParams = (
| {
/** Increase amounts will be calculated based on collateral amount */
payAmount: bigint;
}
| {
/** Increase amounts will be calculated based on position size amount */
sizeAmount: bigint;
}
) & {
marketAddress: string;
payTokenAddress: string;
collateralTokenAddress: string;
| {
/** Increase amounts will be calculated based on collateral amount */
payAmount: bigint;
}
| {
/** Increase amounts will be calculated based on position size amount */
sizeAmount: bigint;
}
) & {
marketAddress: string;
payTokenAddress: string;
collateralTokenAddress: string;
/** @default 100 */
allowedSlippageBps?: number;
referralCodeForTxn?: string;
/** @default 100 */
allowedSlippageBps?: number;
referralCodeForTxn?: string;
leverage?: bigint;
/** If presented, then it's limit order */
limitPrice?: bigint;
acceptablePriceImpactBuffer?: number;
fixedAcceptablePriceImpactBps?: bigint;
leverage?: bigint;
/** If presented, then it's limit order */
limitPrice?: bigint;
acceptablePriceImpactBuffer?: number;
fixedAcceptablePriceImpactBps?: bigint;
skipSimulation?: boolean;
stopLossPrice?: bigint;
takeProfitPrice?: bigint;
skipSimulation?: boolean;
stopLossPrice?: bigint;
takeProfitPrice?: bigint;
} & BaseOptionalParams;
async function getAndValidateBaseParams(sdk: GmxSdk, params: BaseOptionalParams) {
let tokensData: TokensData | undefined = params.tokensData;
let marketsInfoData: MarketsInfoData | undefined = params.marketsInfoData;
let tokensData: TokensData | undefined = params.tokensData;
let marketsInfoData: MarketsInfoData | undefined = params.marketsInfoData;
if (!params.marketsInfoData && !params.tokensData) {
const result = await sdk.markets.getMarketsInfo();
marketsInfoData = result.marketsInfoData;
tokensData = result.tokensData;
}
if (!params.marketsInfoData && !params.tokensData) {
const result = await sdk.markets.getMarketsInfo();
marketsInfoData = result.marketsInfoData;
tokensData = result.tokensData;
}
if (!tokensData) {
throw new Error("Tokens data is not available");
}
if (!tokensData) {
throw new Error("Tokens data is not available");
}
if (!marketsInfoData) {
throw new Error("Markets info data is not available");
}
if (!marketsInfoData) {
throw new Error("Markets info data is not available");
}
let uiFeeFactor = params.uiFeeFactor;
if (!uiFeeFactor) {
uiFeeFactor = await sdk.utils.getUiFeeFactor();
}
let uiFeeFactor = params.uiFeeFactor;
if (!uiFeeFactor) {
uiFeeFactor = await sdk.utils.getUiFeeFactor();
}
return {
tokensData,
marketsInfoData,
uiFeeFactor,
};
return {
tokensData,
marketsInfoData,
uiFeeFactor,
};
}
export async function increaseOrderHelper(
sdk: GmxSdk,
params: PositionIncreaseParams & {
isLong: boolean;
}
sdk: GmxSdk,
params: PositionIncreaseParams & {
isLong: boolean;
}
) {
const { tokensData, marketsInfoData, uiFeeFactor } = await getAndValidateBaseParams(sdk, params);
const {tokensData, marketsInfoData, uiFeeFactor} = await getAndValidateBaseParams(sdk, params);
const isLimit = Boolean(params.limitPrice);
const isLimit = Boolean(params.limitPrice);
const fromToken = tokensData[params.payTokenAddress];
const collateralToken = tokensData[params.collateralTokenAddress];
const fromToken = tokensData[params.payTokenAddress];
const collateralToken = tokensData[params.collateralTokenAddress];
if (!fromToken) {
throw new Error("From token is not available");
}
if (!fromToken) {
throw new Error("From token is not available");
}
if (!collateralToken) {
throw new Error("Collateral token is not available");
}
if (!collateralToken) {
throw new Error("Collateral token is not available");
}
const marketInfo = getByKey(marketsInfoData, params.marketAddress);
const marketInfo = getByKey(marketsInfoData, params.marketAddress);
if (!marketInfo) {
throw new Error("Market info is not available");
}
if (!marketInfo) {
throw new Error("Market info is not available");
}
const collateralTokenAddress = collateralToken.address;
const allowedSlippage = params.allowedSlippageBps ?? 100;
const collateralTokenAddress = collateralToken.address;
const allowedSlippage = params.allowedSlippageBps ?? 100;
const graph = getMarketsGraph(Object.values(marketsInfoData));
const wrappedFromAddress = getWrappedAddress(sdk.chainId, params.payTokenAddress);
const wrappedToAddress = getWrappedAddress(sdk.chainId, collateralTokenAddress);
const graph = getMarketsGraph(Object.values(marketsInfoData));
const wrappedFromAddress = getWrappedAddress(sdk.chainId, params.payTokenAddress);
const wrappedToAddress = getWrappedAddress(sdk.chainId, collateralTokenAddress);
const allPaths = findAllSwapPaths({
chainId: sdk.chainId,
fromTokenAddress: params.payTokenAddress,
toTokenAddress: collateralTokenAddress,
marketsInfoData,
graph,
wrappedFromAddress,
wrappedToAddress,
});
const estimator = createSwapEstimator(marketsInfoData);
const findSwapPath = createFindSwapPath({
chainId: sdk.chainId,
fromTokenAddress: params.payTokenAddress,
toTokenAddress: collateralTokenAddress,
marketsInfoData,
estimator,
allPaths,
});
const payOrSizeAmount = "payAmount" in params ? params.payAmount : params.sizeAmount;
const increaseAmounts = getIncreasePositionAmounts({
marketInfo,
indexToken: marketInfo.indexToken,
initialCollateralToken: fromToken,
collateralToken,
isLong: params.isLong,
initialCollateralAmount: payOrSizeAmount,
position: undefined,
indexTokenAmount: payOrSizeAmount,
leverage: params.leverage,
triggerPrice: params.limitPrice,
limitOrderType: params.limitPrice ? OrderType.LimitIncrease : undefined,
userReferralInfo: undefined,
strategy: "payAmount" in params ? "leverageByCollateral" : "leverageBySize",
findSwapPath: findSwapPath,
uiFeeFactor,
acceptablePriceImpactBuffer: params.acceptablePriceImpactBuffer,
fixedAcceptablePriceImpactBps: params.fixedAcceptablePriceImpactBps,
externalSwapQuote: undefined,
});
const createSltpEntries: SidecarSlTpOrderEntryValid[] = [
]
let stopLossDecreaseAmounts: DecreasePositionAmounts | undefined;
if (params.stopLossPrice) {
const stopLossCollateralDeltaUsd = convertToUsd(increaseAmounts.collateralDeltaAmount, collateralToken.decimals, params.stopLossPrice);
const acceptablePriceInfo = getAcceptablePriceInfo({
marketInfo,
isIncrease: false,
isLong: params.isLong,
indexPrice: params.stopLossPrice,
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
maxNegativePriceImpactBps: marketInfo.maxPositionImpactFactorForLiquidations,
const allPaths = findAllSwapPaths({
chainId: sdk.chainId,
fromTokenAddress: params.payTokenAddress,
toTokenAddress: collateralTokenAddress,
marketsInfoData,
graph,
wrappedFromAddress,
wrappedToAddress,
});
stopLossDecreaseAmounts = {
isFullClose: true,
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
sizeDeltaInTokens: increaseAmounts.sizeDeltaInTokens,
collateralDeltaUsd: stopLossCollateralDeltaUsd,
collateralDeltaAmount: increaseAmounts.collateralDeltaAmount,
indexPrice: params.stopLossPrice,
collateralPrice: 0n,
acceptablePrice: params.isLong ? 2n ** 256n - 1n : 0n,
acceptablePriceDeltaBps: acceptablePriceInfo.acceptablePriceDeltaBps,
recommendedAcceptablePriceDeltaBps: 0n,
estimatedPnl: 0n,
estimatedPnlPercentage: 0n,
realizedPnl: 0n,
realizedPnlPercentage: 0n,
positionFeeUsd: 0n,
uiFeeUsd: 0n,
swapUiFeeUsd: 0n,
feeDiscountUsd: 0n,
borrowingFeeUsd: 0n,
fundingFeeUsd: 0n,
swapProfitFeeUsd: 0n,
positionPriceImpactDeltaUsd: 0n,
priceImpactDiffUsd: 0n,
payedRemainingCollateralAmount: 0n,
payedOutputUsd: 0n,
payedRemainingCollateralUsd: 0n,
receiveTokenAmount: 0n,
receiveUsd: 0n,
decreaseSwapType: DecreasePositionSwapType.SwapPnlTokenToCollateralToken,
triggerOrderType: OrderType.StopLossDecrease,
triggerPrice: params.stopLossPrice,
}
const estimator = createSwapEstimator(marketsInfoData);
const stopLossEntry: SidecarSlTpOrderEntryValid = {
decreaseAmounts: stopLossDecreaseAmounts,
id: "sl-order",
price: {
input: params.stopLossPrice?.toString() ?? "",
value: params.stopLossPrice,
error: null,
} as EntryField,
sizeUsd: {
input: increaseAmounts.sizeDeltaUsd.toString(),
value: increaseAmounts.sizeDeltaUsd,
error: null,
} as EntryField,
percentage: {
input: "100",
value: 100n,
error: null,
} as EntryField,
txnType: "create",
mode: "keepSize",
order: null,
increaseAmounts: undefined
}
createSltpEntries.push(stopLossEntry)
}
let takeProfitDecreaseAmounts: DecreasePositionAmounts | undefined;
if (params.takeProfitPrice) {
const takeProfitCollateralDeltaUsd = convertToUsd(increaseAmounts.collateralDeltaAmount, collateralToken.decimals, params.takeProfitPrice);
const acceptablePriceInfo = getAcceptablePriceInfo({
marketInfo,
isIncrease: false,
isLong: params.isLong,
indexPrice: params.takeProfitPrice,
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
maxNegativePriceImpactBps: marketInfo.maxPositionImpactFactorForLiquidations,
const findSwapPath = createFindSwapPath({
chainId: sdk.chainId,
fromTokenAddress: params.payTokenAddress,
toTokenAddress: collateralTokenAddress,
marketsInfoData,
estimator,
allPaths,
});
takeProfitDecreaseAmounts = {
isFullClose: true,
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
sizeDeltaInTokens: increaseAmounts.sizeDeltaInTokens,
collateralDeltaUsd: takeProfitCollateralDeltaUsd,
collateralDeltaAmount: increaseAmounts.collateralDeltaAmount,
indexPrice: params.takeProfitPrice, // Keep original trigger price for indexPrice
collateralPrice: 0n, // Consider if this needs calculation
acceptablePrice: acceptablePriceInfo.acceptablePrice,
acceptablePriceDeltaBps: acceptablePriceInfo.acceptablePriceDeltaBps,
recommendedAcceptablePriceDeltaBps: 0n,
estimatedPnl: 0n,
estimatedPnlPercentage: 0n,
realizedPnl: 0n,
realizedPnlPercentage: 0n,
positionFeeUsd: 0n,
uiFeeUsd: 0n,
swapUiFeeUsd: 0n,
feeDiscountUsd: 0n,
borrowingFeeUsd: 0n,
fundingFeeUsd: 0n,
swapProfitFeeUsd: 0n,
positionPriceImpactDeltaUsd: 0n,
priceImpactDiffUsd: 0n,
payedRemainingCollateralAmount: 0n,
payedOutputUsd: 0n,
payedRemainingCollateralUsd: 0n,
receiveTokenAmount: 0n,
receiveUsd: 0n,
decreaseSwapType: DecreasePositionSwapType.SwapPnlTokenToCollateralToken,
triggerOrderType: OrderType.LimitDecrease,
triggerPrice: params.takeProfitPrice,
const payOrSizeAmount = "payAmount" in params ? params.payAmount : params.sizeAmount;
const increaseAmounts = getIncreasePositionAmounts({
marketInfo,
indexToken: marketInfo.indexToken,
initialCollateralToken: fromToken,
collateralToken,
isLong: params.isLong,
initialCollateralAmount: payOrSizeAmount,
position: undefined,
indexTokenAmount: payOrSizeAmount,
leverage: params.leverage,
triggerPrice: params.limitPrice,
limitOrderType: params.limitPrice ? OrderType.LimitIncrease : undefined,
userReferralInfo: undefined,
strategy: "payAmount" in params ? "leverageByCollateral" : "leverageBySize",
findSwapPath: findSwapPath,
uiFeeFactor,
acceptablePriceImpactBuffer: params.acceptablePriceImpactBuffer,
fixedAcceptablePriceImpactBps: params.fixedAcceptablePriceImpactBps,
externalSwapQuote: undefined,
});
const createSltpEntries: SidecarSlTpOrderEntryValid[] = []
let stopLossDecreaseAmounts: DecreasePositionAmounts | undefined;
if (params.stopLossPrice) {
const stopLossCollateralDeltaUsd = convertToUsd(increaseAmounts.collateralDeltaAmount, collateralToken.decimals, params.stopLossPrice);
const acceptablePriceInfo = getAcceptablePriceInfo({
marketInfo,
isIncrease: false,
isLong: params.isLong,
indexPrice: params.stopLossPrice,
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
maxNegativePriceImpactBps: marketInfo.maxPositionImpactFactorForLiquidations,
});
stopLossDecreaseAmounts = {
isFullClose: true,
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
sizeDeltaInTokens: increaseAmounts.sizeDeltaInTokens,
collateralDeltaUsd: stopLossCollateralDeltaUsd,
collateralDeltaAmount: increaseAmounts.collateralDeltaAmount,
indexPrice: params.stopLossPrice,
collateralPrice: 0n,
acceptablePrice: params.isLong ? 2n ** 256n - 1n : 0n,
acceptablePriceDeltaBps: acceptablePriceInfo.acceptablePriceDeltaBps + 50n,
recommendedAcceptablePriceDeltaBps: 50n,
estimatedPnl: 0n,
estimatedPnlPercentage: 0n,
realizedPnl: 0n,
realizedPnlPercentage: 0n,
positionFeeUsd: 0n,
uiFeeUsd: 0n,
swapUiFeeUsd: 0n,
feeDiscountUsd: 0n,
borrowingFeeUsd: 0n,
fundingFeeUsd: 0n,
swapProfitFeeUsd: 0n,
positionPriceImpactDeltaUsd: 0n,
priceImpactDiffUsd: 0n,
payedRemainingCollateralAmount: 0n,
payedOutputUsd: 0n,
payedRemainingCollateralUsd: 0n,
receiveTokenAmount: 0n,
receiveUsd: 0n,
decreaseSwapType: DecreasePositionSwapType.SwapPnlTokenToCollateralToken,
triggerOrderType: OrderType.StopLossDecrease,
triggerPrice: params.stopLossPrice,
}
const stopLossEntry: SidecarSlTpOrderEntryValid = {
decreaseAmounts: stopLossDecreaseAmounts,
id: "sl-order",
price: {
input: params.stopLossPrice?.toString() ?? "",
value: params.stopLossPrice,
error: null,
} as EntryField,
sizeUsd: {
input: increaseAmounts.sizeDeltaUsd.toString(),
value: increaseAmounts.sizeDeltaUsd,
error: null,
} as EntryField,
percentage: {
input: "100",
value: 100n,
error: null,
} as EntryField,
txnType: "create",
mode: "keepSize",
order: null,
increaseAmounts: undefined
}
createSltpEntries.push(stopLossEntry)
}
const takeProfitEntry: SidecarSlTpOrderEntryValid = {
decreaseAmounts: takeProfitDecreaseAmounts,
id: "tp-order",
price: {
input: params.takeProfitPrice?.toString() ?? "",
value: params.takeProfitPrice,
error: null,
} as EntryField,
sizeUsd: {
input: increaseAmounts.sizeDeltaUsd.toString(),
value: increaseAmounts.sizeDeltaUsd,
error: null,
} as EntryField,
percentage: {
input: "100",
value: 100n,
error: null,
} as EntryField,
txnType: "create",
mode: "keepSize",
order: null,
increaseAmounts: undefined
let takeProfitDecreaseAmounts: DecreasePositionAmounts | undefined;
if (params.takeProfitPrice) {
const takeProfitCollateralDeltaUsd = convertToUsd(increaseAmounts.collateralDeltaAmount, collateralToken.decimals, params.takeProfitPrice);
const acceptablePriceInfo = getAcceptablePriceInfo({
marketInfo,
isIncrease: false,
isLong: params.isLong,
indexPrice: params.takeProfitPrice,
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
maxNegativePriceImpactBps: marketInfo.maxPositionImpactFactorForLiquidations,
});
takeProfitDecreaseAmounts = {
isFullClose: true,
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
sizeDeltaInTokens: increaseAmounts.sizeDeltaInTokens,
collateralDeltaUsd: takeProfitCollateralDeltaUsd,
collateralDeltaAmount: increaseAmounts.collateralDeltaAmount,
indexPrice: params.takeProfitPrice, // Keep original trigger price for indexPrice
collateralPrice: 0n, // Consider if this needs calculation
acceptablePrice: acceptablePriceInfo.acceptablePrice,
acceptablePriceDeltaBps: acceptablePriceInfo.acceptablePriceDeltaBps + 50n, // Add 0.5% buffer to acceptable price impact
recommendedAcceptablePriceDeltaBps: 50n, // Set recommended buffer to 0.5%
estimatedPnl: 0n,
estimatedPnlPercentage: 0n,
realizedPnl: 0n,
realizedPnlPercentage: 0n,
positionFeeUsd: 0n,
uiFeeUsd: 0n,
swapUiFeeUsd: 0n,
feeDiscountUsd: 0n,
borrowingFeeUsd: 0n,
fundingFeeUsd: 0n,
swapProfitFeeUsd: 0n,
positionPriceImpactDeltaUsd: 0n,
priceImpactDiffUsd: 0n,
payedRemainingCollateralAmount: 0n,
payedOutputUsd: 0n,
payedRemainingCollateralUsd: 0n,
receiveTokenAmount: 0n,
receiveUsd: 0n,
decreaseSwapType: DecreasePositionSwapType.SwapPnlTokenToCollateralToken,
triggerOrderType: OrderType.LimitDecrease,
triggerPrice: params.takeProfitPrice,
}
const takeProfitEntry: SidecarSlTpOrderEntryValid = {
decreaseAmounts: takeProfitDecreaseAmounts,
id: "tp-order",
price: {
input: params.takeProfitPrice?.toString() ?? "",
value: params.takeProfitPrice,
error: null,
} as EntryField,
sizeUsd: {
input: increaseAmounts.sizeDeltaUsd.toString(),
value: increaseAmounts.sizeDeltaUsd,
error: null,
} as EntryField,
percentage: {
input: "100",
value: 100n,
error: null,
} as EntryField,
txnType: "create",
mode: "keepSize",
order: null,
increaseAmounts: undefined
}
createSltpEntries.push(takeProfitEntry)
}
createSltpEntries.push(takeProfitEntry)
}
const createIncreaseOrderParams: Parameters<typeof sdk.orders.createIncreaseOrder>[0] = {
marketsInfoData,
tokensData,
isLimit,
marketAddress: params.marketAddress,
fromToken: tokensData[params.payTokenAddress],
allowedSlippage,
collateralToken,
referralCodeForTxn: params.referralCodeForTxn,
triggerPrice: params.limitPrice,
collateralTokenAddress: collateralToken.address,
isLong: params.isLong,
receiveTokenAddress: collateralTokenAddress,
indexToken: marketInfo.indexToken,
marketInfo,
skipSimulation: params.skipSimulation,
increaseAmounts,
createSltpEntries: createSltpEntries.length > 0 ? createSltpEntries : undefined,
};
const createIncreaseOrderParams: Parameters<typeof sdk.orders.createIncreaseOrder>[0] = {
marketsInfoData,
tokensData,
isLimit,
marketAddress: params.marketAddress,
fromToken: tokensData[params.payTokenAddress],
allowedSlippage,
collateralToken,
referralCodeForTxn: params.referralCodeForTxn,
triggerPrice: params.limitPrice,
collateralTokenAddress: collateralToken.address,
isLong: params.isLong,
receiveTokenAddress: collateralTokenAddress,
indexToken: marketInfo.indexToken,
marketInfo,
skipSimulation: params.skipSimulation,
increaseAmounts,
createSltpEntries: createSltpEntries.length > 0 ? createSltpEntries : undefined,
};
return sdk.orders.createIncreaseOrder(createIncreaseOrderParams);
return sdk.orders.createIncreaseOrder(createIncreaseOrderParams);
}
function getTriggerRatio({
toToken,
fromToken,
triggerPrice,
}: {
toToken: TokenData;
fromToken: TokenData;
triggerPrice: bigint;
toToken,
fromToken,
triggerPrice,
}: {
toToken: TokenData;
fromToken: TokenData;
triggerPrice: bigint;
}) {
const fromTokenPrice = fromToken?.prices.minPrice;
const markPrice = toToken.prices.minPrice;
const fromTokenPrice = fromToken?.prices.minPrice;
const markPrice = toToken.prices.minPrice;
const markRatio = getTokensRatioByPrice({
fromToken,
toToken,
fromPrice: fromTokenPrice,
toPrice: markPrice,
});
const markRatio = getTokensRatioByPrice({
fromToken,
toToken,
fromPrice: fromTokenPrice,
toPrice: markPrice,
});
const triggerRatio: TokensRatio = {
ratio: triggerPrice > 0 ? triggerPrice : markRatio.ratio,
largestToken: markRatio.largestToken,
smallestToken: markRatio.smallestToken,
};
const triggerRatio: TokensRatio = {
ratio: triggerPrice > 0 ? triggerPrice : markRatio.ratio,
largestToken: markRatio.largestToken,
smallestToken: markRatio.smallestToken,
};
return triggerRatio;
return triggerRatio;
}
export type SwapParams = (
| {
fromAmount: bigint;
}
| {
toAmount: bigint;
}
) & {
fromTokenAddress: string;
toTokenAddress: string;
allowedSlippageBps?: number;
referralCodeForTxn?: string;
| {
fromAmount: bigint;
}
| {
toAmount: bigint;
}
) & {
fromTokenAddress: string;
toTokenAddress: string;
allowedSlippageBps?: number;
referralCodeForTxn?: string;
/** If presented, then it's limit swap order */
triggerPrice?: bigint;
/** If presented, then it's limit swap order */
triggerPrice?: bigint;
} & BaseOptionalParams;
export async function swap(sdk: GmxSdk, params: SwapParams) {
const { tokensData, marketsInfoData, uiFeeFactor } = await getAndValidateBaseParams(sdk, params);
const {tokensData, marketsInfoData, uiFeeFactor} = await getAndValidateBaseParams(sdk, params);
const fromToken = tokensData[params.fromTokenAddress];
const toToken = tokensData[params.toTokenAddress];
const fromToken = tokensData[params.fromTokenAddress];
const toToken = tokensData[params.toTokenAddress];
if (!fromToken || !toToken) {
throw new Error("From or to token is not available");
}
if (!fromToken || !toToken) {
throw new Error("From or to token is not available");
}
const isLimit = Boolean(params.triggerPrice);
const isLimit = Boolean(params.triggerPrice);
if (!fromToken || !toToken) {
return undefined;
}
if (!fromToken || !toToken) {
return undefined;
}
const graph = getMarketsGraph(Object.values(marketsInfoData));
const wrappedFromAddress = getWrappedAddress(sdk.chainId, params.fromTokenAddress);
const wrappedToAddress = getWrappedAddress(sdk.chainId, params.toTokenAddress);
const graph = getMarketsGraph(Object.values(marketsInfoData));
const wrappedFromAddress = getWrappedAddress(sdk.chainId, params.fromTokenAddress);
const wrappedToAddress = getWrappedAddress(sdk.chainId, params.toTokenAddress);
const allPaths = findAllSwapPaths({
chainId: sdk.chainId,
fromTokenAddress: params.fromTokenAddress,
toTokenAddress: params.toTokenAddress,
marketsInfoData,
graph,
wrappedFromAddress,
wrappedToAddress,
});
const allPaths = findAllSwapPaths({
chainId: sdk.chainId,
fromTokenAddress: params.fromTokenAddress,
toTokenAddress: params.toTokenAddress,
marketsInfoData,
graph,
wrappedFromAddress,
wrappedToAddress,
});
const estimator = createSwapEstimator(marketsInfoData);
const estimator = createSwapEstimator(marketsInfoData);
const findSwapPath = createFindSwapPath({
chainId: sdk.chainId,
fromTokenAddress: params.fromTokenAddress,
toTokenAddress: params.toTokenAddress,
marketsInfoData,
estimator,
allPaths,
});
const findSwapPath = createFindSwapPath({
chainId: sdk.chainId,
fromTokenAddress: params.fromTokenAddress,
toTokenAddress: params.toTokenAddress,
marketsInfoData,
estimator,
allPaths,
});
const isWrapOrUnwrap = Boolean(
fromToken && toToken && (getIsWrap(fromToken, toToken) || getIsUnwrap(fromToken, toToken))
);
const isWrapOrUnwrap = Boolean(
fromToken && toToken && (getIsWrap(fromToken, toToken) || getIsUnwrap(fromToken, toToken))
);
const swapOptimizationOrder: Parameters<FindSwapPath>[1]["order"] = isLimit ? ["length", "liquidity"] : undefined;
const swapOptimizationOrder: Parameters<FindSwapPath>[1]["order"] = isLimit ? ["length", "liquidity"] : undefined;
let swapAmounts: SwapAmounts | undefined;
let swapAmounts: SwapAmounts | undefined;
const fromTokenPrice = fromToken.prices.minPrice;
const triggerRatio = params.triggerPrice
? getTriggerRatio({
fromToken,
toToken,
const fromTokenPrice = fromToken.prices.minPrice;
const triggerRatio = params.triggerPrice
? getTriggerRatio({
fromToken,
toToken,
triggerPrice: params.triggerPrice,
})
: undefined;
if (isWrapOrUnwrap) {
const tokenAmount = "fromAmount" in params ? params.fromAmount : params.toAmount;
const usdAmount = convertToUsd(tokenAmount, fromToken.decimals, fromTokenPrice)!;
const price = fromTokenPrice;
swapAmounts = {
amountIn: tokenAmount,
usdIn: usdAmount!,
amountOut: tokenAmount,
usdOut: usdAmount!,
swapPathStats: undefined,
priceIn: price,
priceOut: price,
minOutputAmount: tokenAmount,
};
return swapAmounts;
} else if ("fromAmount" in params) {
swapAmounts = getSwapAmountsByFromValue({
tokenIn: fromToken,
tokenOut: toToken,
amountIn: params.fromAmount,
triggerRatio,
isLimit,
findSwapPath: findSwapPath,
uiFeeFactor,
swapOptimizationOrder,
allowedSwapSlippageBps: isLimit ? BigInt(params.allowedSlippageBps ?? 100) : undefined,
});
} else {
swapAmounts = getSwapAmountsByToValue({
tokenIn: fromToken,
tokenOut: toToken,
amountOut: params.toAmount,
triggerRatio,
isLimit: isLimit,
findSwapPath: findSwapPath,
uiFeeFactor,
swapOptimizationOrder,
allowedSwapSlippageBps: isLimit ? BigInt(params.allowedSlippageBps ?? 100) : undefined,
});
}
if (!swapAmounts) {
return undefined;
}
const createSwapOrderParams: Parameters<typeof sdk.orders.createSwapOrder>[0] = {
tokensData,
fromToken: tokensData[params.fromTokenAddress],
toToken: tokensData[params.toTokenAddress],
swapAmounts,
isLimit,
allowedSlippage: params.allowedSlippageBps ?? 100,
referralCodeForTxn: params.referralCodeForTxn,
triggerPrice: params.triggerPrice,
})
: undefined;
if (isWrapOrUnwrap) {
const tokenAmount = "fromAmount" in params ? params.fromAmount : params.toAmount;
const usdAmount = convertToUsd(tokenAmount, fromToken.decimals, fromTokenPrice)!;
const price = fromTokenPrice;
swapAmounts = {
amountIn: tokenAmount,
usdIn: usdAmount!,
amountOut: tokenAmount,
usdOut: usdAmount!,
swapPathStats: undefined,
priceIn: price,
priceOut: price,
minOutputAmount: tokenAmount,
};
return swapAmounts;
} else if ("fromAmount" in params) {
swapAmounts = getSwapAmountsByFromValue({
tokenIn: fromToken,
tokenOut: toToken,
amountIn: params.fromAmount,
triggerRatio,
isLimit,
findSwapPath: findSwapPath,
uiFeeFactor,
swapOptimizationOrder,
allowedSwapSlippageBps: isLimit ? BigInt(params.allowedSlippageBps ?? 100) : undefined,
});
} else {
swapAmounts = getSwapAmountsByToValue({
tokenIn: fromToken,
tokenOut: toToken,
amountOut: params.toAmount,
triggerRatio,
isLimit: isLimit,
findSwapPath: findSwapPath,
uiFeeFactor,
swapOptimizationOrder,
allowedSwapSlippageBps: isLimit ? BigInt(params.allowedSlippageBps ?? 100) : undefined,
});
}
if (!swapAmounts) {
return undefined;
}
const createSwapOrderParams: Parameters<typeof sdk.orders.createSwapOrder>[0] = {
tokensData,
fromToken: tokensData[params.fromTokenAddress],
toToken: tokensData[params.toTokenAddress],
swapAmounts,
isLimit,
allowedSlippage: params.allowedSlippageBps ?? 100,
referralCodeForTxn: params.referralCodeForTxn,
triggerPrice: params.triggerPrice,
};
return sdk.orders.createSwapOrder(createSwapOrderParams);
return sdk.orders.createSwapOrder(createSwapOrderParams);
}