diff --git a/sdk/src/driftClient.ts b/sdk/src/driftClient.ts index 597f2635b..9d5cdb91f 100644 --- a/sdk/src/driftClient.ts +++ b/sdk/src/driftClient.ts @@ -2448,6 +2448,7 @@ export class DriftClient { * @param makerInfo * @param txParams * @param bracketOrdersParams + * @param cancelExistingOrders - Builds and returns an extra transaciton to cancel the existing orders in the same market. Intended use is to auto-cancel TP/SL orders when closing a position * @returns */ public async sendMarketOrderAndGetSignedFillTx( @@ -2457,8 +2458,13 @@ export class DriftClient { makerInfo?: MakerInfo | MakerInfo[], txParams?: TxParams, bracketOrdersParams = new Array(), - referrerInfo?: ReferrerInfo - ): Promise<{ txSig: TransactionSignature; signedFillTx: Transaction }> { + referrerInfo?: ReferrerInfo, + cancelExistingOrders?: boolean + ): Promise<{ + txSig: TransactionSignature; + signedFillTx: Transaction; + signedCancelExistingOrdersTx?: Transaction; + }> { const marketIndex = orderParams.marketIndex; const orderId = userAccount.nextOrderId; const bracketOrderIxs = []; @@ -2483,6 +2489,23 @@ export class DriftClient { referrerInfo ); + let cancelOrdersIx: TransactionInstruction; + let cancelExistingOrdersTx: Transaction; + if (cancelExistingOrders) { + cancelOrdersIx = await this.getCancelOrdersIx( + orderParams.marketType, + orderParams.marketIndex, + null + ); + + //@ts-ignore + cancelExistingOrdersTx = await this.buildTransaction( + [cancelOrdersIx], + txParams, + this.txVersion + ); + } + // use versioned transactions if there is a lookup table account and wallet is compatible if (this.txVersion === 0) { const versionedMarketOrderTx = await this.buildTransaction( @@ -2495,21 +2518,31 @@ export class DriftClient { txParams, 0 ); - const [signedVersionedMarketOrderTx, signedVersionedFillTx] = - await this.provider.wallet.signAllTransactions([ - //@ts-ignore + + const [ + signedVersionedMarketOrderTx, + signedVersionedFillTx, + signedCancelExistingOrdersTx, + ] = await this.provider.wallet.signAllTransactions( + [ versionedMarketOrderTx, - //@ts-ignore versionedFillTx, - ]); + cancelExistingOrdersTx, + ].filter((tx) => tx !== undefined) + ); const { txSig, slot } = await this.txSender.sendRawTransaction( signedVersionedMarketOrderTx.serialize(), this.opts ); this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot); - // @ts-ignore - return { txSig, signedFillTx: signedVersionedFillTx }; + return { + txSig, + // @ts-ignore + signedFillTx: signedVersionedFillTx, + // @ts-ignore + signedCancelExistingOrdersTx, + }; } else { const marketOrderTx = wrapInTx( placePerpOrderIx, @@ -2537,8 +2570,12 @@ export class DriftClient { marketOrderTx.feePayer = userAccount.authority; fillTx.feePayer = userAccount.authority; - const [signedMarketOrderTx, signedFillTx] = - await this.provider.wallet.signAllTransactions([marketOrderTx, fillTx]); + const [signedMarketOrderTx, signedFillTx, signedCancelExistingOrdersTx] = + await this.provider.wallet.signAllTransactions( + [marketOrderTx, fillTx, cancelExistingOrdersTx].filter( + (tx) => tx !== undefined + ) + ); const { txSig, slot } = await this.sendTransaction( signedMarketOrderTx, [], @@ -2547,7 +2584,7 @@ export class DriftClient { ); this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot); - return { txSig, signedFillTx }; + return { txSig, signedFillTx, signedCancelExistingOrdersTx }; } } diff --git a/sdk/src/math/trade.ts b/sdk/src/math/trade.ts index bd15eb407..3ce7d4dc9 100644 --- a/sdk/src/math/trade.ts +++ b/sdk/src/math/trade.ts @@ -649,15 +649,15 @@ export function calculateEstimatedPerpEntryPrice( } } - const entryPrice = cumulativeQuoteFilled - .mul(BASE_PRECISION) - .div(cumulativeBaseFilled); + const entryPrice = + cumulativeBaseFilled && cumulativeBaseFilled.gt(ZERO) + ? cumulativeQuoteFilled.mul(BASE_PRECISION).div(cumulativeBaseFilled) + : ZERO; - const priceImpact = entryPrice - .sub(bestPrice) - .mul(PRICE_PRECISION) - .div(bestPrice) - .abs(); + const priceImpact = + bestPrice && bestPrice.gt(ZERO) + ? entryPrice.sub(bestPrice).mul(PRICE_PRECISION).div(bestPrice).abs() + : ZERO; return { entryPrice, @@ -858,15 +858,15 @@ export function calculateEstimatedSpotEntryPrice( } } - const entryPrice = cumulativeQuoteFilled - .mul(basePrecision) - .div(cumulativeBaseFilled); + const entryPrice = + cumulativeBaseFilled && cumulativeBaseFilled.gt(ZERO) + ? cumulativeQuoteFilled.mul(basePrecision).div(cumulativeBaseFilled) + : ZERO; - const priceImpact = entryPrice - .sub(bestPrice) - .mul(PRICE_PRECISION) - .div(bestPrice) - .abs(); + const priceImpact = + bestPrice && bestPrice.gt(ZERO) + ? entryPrice.sub(bestPrice).mul(PRICE_PRECISION).div(bestPrice).abs() + : ZERO; return { entryPrice, @@ -900,8 +900,8 @@ export function calculateEstimatedEntryPriceWithL2( const levels = [...(takerIsLong ? l2.asks : l2.bids)]; let nextLevel = levels.shift(); - let bestPrice; - let worstPrice; + let bestPrice: BN; + let worstPrice: BN; if (nextLevel) { bestPrice = nextLevel.price; worstPrice = nextLevel.price; @@ -945,15 +945,15 @@ export function calculateEstimatedEntryPriceWithL2( } } - const entryPrice = cumulativeQuoteFilled - .mul(basePrecision) - .div(cumulativeBaseFilled); + const entryPrice = + cumulativeBaseFilled && cumulativeBaseFilled.gt(ZERO) + ? cumulativeQuoteFilled.mul(basePrecision).div(cumulativeBaseFilled) + : ZERO; - const priceImpact = entryPrice - .sub(bestPrice) - .mul(PRICE_PRECISION) - .div(bestPrice) - .abs(); + const priceImpact = + bestPrice && bestPrice.gt(ZERO) + ? entryPrice.sub(bestPrice).mul(PRICE_PRECISION).div(bestPrice).abs() + : ZERO; return { entryPrice,