From d69a73ed25ce7fe0986ae305501d881aecd9acb9 Mon Sep 17 00:00:00 2001 From: lowkeynicc Date: Fri, 5 Jan 2024 17:43:43 -0500 Subject: [PATCH 1/5] changes for bracket orders and placeandtake --- sdk/src/driftClient.ts | 158 +++++++++++++++++++++++++---------------- 1 file changed, 96 insertions(+), 62 deletions(-) diff --git a/sdk/src/driftClient.ts b/sdk/src/driftClient.ts index df1aa534b..15d3b973b 100644 --- a/sdk/src/driftClient.ts +++ b/sdk/src/driftClient.ts @@ -2520,19 +2520,22 @@ export class DriftClient { limitPrice?: BN, subAccountId?: number ): Promise { - return await this.placeAndTakePerpOrder( - { - orderType: OrderType.MARKET, - marketIndex, - direction, - baseAssetAmount: amount, - price: limitPrice, - }, - undefined, - undefined, - undefined, - subAccountId - ); + return ( + await this.placeAndTakePerpOrder( + { + orderType: OrderType.MARKET, + marketIndex, + direction, + baseAssetAmount: amount, + price: limitPrice, + }, + undefined, + undefined, + undefined, + undefined, + subAccountId + ) + )?.txSig; } public async sendSignedTx(tx: Transaction): Promise { @@ -2573,21 +2576,12 @@ export class DriftClient { }> { const marketIndex = orderParams.marketIndex; const orderId = userAccount.nextOrderId; - const bracketOrderIxs = []; - const placePerpOrderIx = await this.getPlacePerpOrderIx( - orderParams, + const ordersIx = await this.getPlaceOrdersIx( + [orderParams, ...bracketOrdersParams], userAccount.subAccountId ); - for (const bracketOrderParams of bracketOrdersParams) { - const placeBracketOrderIx = await this.getPlacePerpOrderIx( - bracketOrderParams, - userAccount.subAccountId - ); - bracketOrderIxs.push(placeBracketOrderIx); - } - let cancelOrdersIx: TransactionInstruction; let cancelExistingOrdersTx: Transaction; if (cancelExistingOrders && isVariant(orderParams.marketType, 'perp')) { @@ -2609,7 +2603,7 @@ export class DriftClient { // use versioned transactions if there is a lookup table account and wallet is compatible if (this.txVersion === 0) { const versionedMarketOrderTx = await this.buildTransaction( - [placePerpOrderIx].concat(bracketOrderIxs), + ordersIx, txParams, 0 ); @@ -2658,14 +2652,14 @@ export class DriftClient { }; } else { const marketOrderTx = wrapInTx( - placePerpOrderIx, + ordersIx, txParams?.computeUnits, txParams?.computeUnitsPrice ); - if (bracketOrderIxs.length > 0) { - marketOrderTx.add(...bracketOrderIxs); - } + // if (bracketOrderIxs.length > 0) { + // marketOrderTx.add(...bracketOrderIxs); + // } // Apply the latest blockhash to the txs so that we can sign before sending them const currentBlockHash = ( @@ -3093,7 +3087,7 @@ export class DriftClient { } public async getPlaceOrdersIx( - params: OrderParams[], + params: OptionalOrderParams[], subAccountId?: number ): Promise { const user = await this.getUserAccountPublicKey(subAccountId); @@ -3277,9 +3271,8 @@ export class DriftClient { subAccountId?: number ): Promise { orderParams = getOrderParams(orderParams, { marketType: MarketType.SPOT }); - const userAccountPublicKey = await this.getUserAccountPublicKey( - subAccountId - ); + const userAccountPublicKey = + await this.getUserAccountPublicKey(subAccountId); const remainingAccounts = this.getRemainingAccounts({ userAccounts: [this.getUserAccount(subAccountId)], @@ -4314,24 +4307,63 @@ export class DriftClient { orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, + bracketOrdersParams = new Array(), txParams?: TxParams, - subAccountId?: number - ): Promise { + subAccountId?: number, + cancelExistingOrders?: boolean + ): Promise<{ + txSig: TransactionSignature; + signedCancelExistingOrdersTx?: Transaction; + }> { + let signedCancelExistingOrdersTx: Transaction; + + if (cancelExistingOrders && isVariant(orderParams.marketType, 'perp')) { + const cancelOrdersIx = await this.getCancelOrdersIx( + orderParams.marketType, + orderParams.marketIndex, + null, + subAccountId + ); + + const cancelExistingOrdersTx = await this.buildTransaction( + [cancelOrdersIx], + txParams, + this.txVersion + ); + + // @ts-ignore + signedCancelExistingOrdersTx = await this.provider.wallet.signTransaction( + cancelExistingOrdersTx + ); + } + + const ixs = []; + + const placeAndTakeIx = await this.getPlaceAndTakePerpOrderIx( + orderParams, + makerInfo, + referrerInfo, + subAccountId + ); + + ixs.push(placeAndTakeIx); + + if (bracketOrdersParams.length > 0) { + const bracketOrdersIx = await this.getPlaceOrdersIx( + bracketOrdersParams, + subAccountId + ); + ixs.push(bracketOrdersIx); + } + const { txSig, slot } = await this.sendTransaction( - await this.buildTransaction( - await this.getPlaceAndTakePerpOrderIx( - orderParams, - makerInfo, - referrerInfo, - subAccountId - ), - txParams - ), + await this.buildTransaction(ixs, txParams), [], this.opts ); this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot); - return txSig; + + return { txSig, signedCancelExistingOrdersTx }; } public async getPlaceAndTakePerpOrderIx( @@ -4686,20 +4718,23 @@ export class DriftClient { throw Error(`No position in market ${marketIndex.toString()}`); } - return await this.placeAndTakePerpOrder( - { - orderType: OrderType.MARKET, - marketIndex, - direction: findDirectionToClose(userPosition), - baseAssetAmount: userPosition.baseAssetAmount.abs(), - reduceOnly: true, - price: limitPrice, - }, - undefined, - undefined, - undefined, - subAccountId - ); + return ( + await this.placeAndTakePerpOrder( + { + orderType: OrderType.MARKET, + marketIndex, + direction: findDirectionToClose(userPosition), + baseAssetAmount: userPosition.baseAssetAmount.abs(), + reduceOnly: true, + price: limitPrice, + }, + undefined, + undefined, + undefined, + this.txParams, + subAccountId + ) + )?.txSig; } /** @@ -5788,9 +5823,8 @@ export class DriftClient { } if (initializeStakeAccount) { - const initializeIx = await this.getInitializeInsuranceFundStakeIx( - marketIndex - ); + const initializeIx = + await this.getInitializeInsuranceFundStakeIx(marketIndex); addIfStakeIxs.push(initializeIx); } From ebf6529bceacfe539df58c38883b8c6e0742c864 Mon Sep 17 00:00:00 2001 From: lowkeynicc Date: Sat, 6 Jan 2024 14:31:27 -0500 Subject: [PATCH 2/5] updates --- sdk/src/driftClient.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdk/src/driftClient.ts b/sdk/src/driftClient.ts index 15d3b973b..440a67647 100644 --- a/sdk/src/driftClient.ts +++ b/sdk/src/driftClient.ts @@ -3112,7 +3112,9 @@ export class DriftClient { useMarketLastSlotCache: true, }); - return await this.program.instruction.placeOrders(params, { + const formattedParams = params.map((item) => getOrderParams(item)); + + return await this.program.instruction.placeOrders(formattedParams, { accounts: { state: await this.getStatePublicKey(), user, From ac639c2f602570e49550f271bdc587ed3457e64b Mon Sep 17 00:00:00 2001 From: lowkeynicc Date: Sat, 6 Jan 2024 14:39:34 -0500 Subject: [PATCH 3/5] remove comment + update changelog --- CHANGELOG.md | 3 +++ sdk/src/driftClient.ts | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d65095b44..058a52d03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Features +- sdk: move bracket orders into single instruction +- sdk: add ability to do placeAndTake order with bracket orders attached +- sdk: add option to cancel existing orders in market for place and take order ### Fixes diff --git a/sdk/src/driftClient.ts b/sdk/src/driftClient.ts index 440a67647..43e0f1661 100644 --- a/sdk/src/driftClient.ts +++ b/sdk/src/driftClient.ts @@ -2657,10 +2657,6 @@ export class DriftClient { txParams?.computeUnitsPrice ); - // if (bracketOrderIxs.length > 0) { - // marketOrderTx.add(...bracketOrderIxs); - // } - // Apply the latest blockhash to the txs so that we can sign before sending them const currentBlockHash = ( await this.connection.getLatestBlockhash('finalized') From 1a436b72f04e0a289fce28b3f60bc75a6af7bbe8 Mon Sep 17 00:00:00 2001 From: lowkeynicc Date: Sat, 6 Jan 2024 15:46:11 -0500 Subject: [PATCH 4/5] separate functions --- sdk/src/driftClient.ts | 84 +++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/sdk/src/driftClient.ts b/sdk/src/driftClient.ts index 43e0f1661..8984f9a9d 100644 --- a/sdk/src/driftClient.ts +++ b/sdk/src/driftClient.ts @@ -2520,22 +2520,19 @@ export class DriftClient { limitPrice?: BN, subAccountId?: number ): Promise { - return ( - await this.placeAndTakePerpOrder( - { - orderType: OrderType.MARKET, - marketIndex, - direction, - baseAssetAmount: amount, - price: limitPrice, - }, - undefined, - undefined, - undefined, - undefined, - subAccountId - ) - )?.txSig; + return await this.placeAndTakePerpOrder( + { + orderType: OrderType.MARKET, + marketIndex, + direction, + baseAssetAmount: amount, + price: limitPrice, + }, + undefined, + undefined, + undefined, + subAccountId + ); } public async sendSignedTx(tx: Transaction): Promise { @@ -4302,6 +4299,30 @@ export class DriftClient { } public async placeAndTakePerpOrder( + orderParams: OptionalOrderParams, + makerInfo?: MakerInfo | MakerInfo[], + referrerInfo?: ReferrerInfo, + txParams?: TxParams, + subAccountId?: number + ): Promise { + const { txSig, slot } = await this.sendTransaction( + await this.buildTransaction( + await this.getPlaceAndTakePerpOrderIx( + orderParams, + makerInfo, + referrerInfo, + subAccountId + ), + txParams + ), + [], + this.opts + ); + this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot); + return txSig; + } + + public async placeAndTakePerpWithAdditionalOrders( orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, @@ -4716,23 +4737,20 @@ export class DriftClient { throw Error(`No position in market ${marketIndex.toString()}`); } - return ( - await this.placeAndTakePerpOrder( - { - orderType: OrderType.MARKET, - marketIndex, - direction: findDirectionToClose(userPosition), - baseAssetAmount: userPosition.baseAssetAmount.abs(), - reduceOnly: true, - price: limitPrice, - }, - undefined, - undefined, - undefined, - this.txParams, - subAccountId - ) - )?.txSig; + return await this.placeAndTakePerpOrder( + { + orderType: OrderType.MARKET, + marketIndex, + direction: findDirectionToClose(userPosition), + baseAssetAmount: userPosition.baseAssetAmount.abs(), + reduceOnly: true, + price: limitPrice, + }, + undefined, + undefined, + undefined, + subAccountId + ); } /** From 36dfcd600c205a171a851eac9840b7d3645043f7 Mon Sep 17 00:00:00 2001 From: lowkeynicc Date: Sat, 6 Jan 2024 15:52:22 -0500 Subject: [PATCH 5/5] prettify --- sdk/src/driftClient.ts | 10 +-- sdk/src/marinade/types.ts | 140 +++++++++++++++++++------------------- 2 files changed, 76 insertions(+), 74 deletions(-) diff --git a/sdk/src/driftClient.ts b/sdk/src/driftClient.ts index 8984f9a9d..f086d7a76 100644 --- a/sdk/src/driftClient.ts +++ b/sdk/src/driftClient.ts @@ -3266,8 +3266,9 @@ export class DriftClient { subAccountId?: number ): Promise { orderParams = getOrderParams(orderParams, { marketType: MarketType.SPOT }); - const userAccountPublicKey = - await this.getUserAccountPublicKey(subAccountId); + const userAccountPublicKey = await this.getUserAccountPublicKey( + subAccountId + ); const remainingAccounts = this.getRemainingAccounts({ userAccounts: [this.getUserAccount(subAccountId)], @@ -5839,8 +5840,9 @@ export class DriftClient { } if (initializeStakeAccount) { - const initializeIx = - await this.getInitializeInsuranceFundStakeIx(marketIndex); + const initializeIx = await this.getInitializeInsuranceFundStakeIx( + marketIndex + ); addIfStakeIxs.push(initializeIx); } diff --git a/sdk/src/marinade/types.ts b/sdk/src/marinade/types.ts index 57561d670..58e9e7afe 100644 --- a/sdk/src/marinade/types.ts +++ b/sdk/src/marinade/types.ts @@ -57,7 +57,7 @@ export type MarinadeFinance = { name: 'msolLeg'; isMut: false; isSigner: false; - } + }, ]; }, { @@ -74,7 +74,7 @@ export type MarinadeFinance = { name: 'rent'; isMut: false; isSigner: false; - } + }, ]; args: [ { @@ -82,7 +82,7 @@ export type MarinadeFinance = { type: { defined: 'InitializeData'; }; - } + }, ]; }, { @@ -97,7 +97,7 @@ export type MarinadeFinance = { name: 'adminAuthority'; isMut: false; isSigner: true; - } + }, ]; args: [ { @@ -105,7 +105,7 @@ export type MarinadeFinance = { type: { defined: 'ChangeAuthorityData'; }; - } + }, ]; }, { @@ -155,13 +155,13 @@ export type MarinadeFinance = { name: 'systemProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { name: 'score'; type: 'u32'; - } + }, ]; }, { @@ -191,7 +191,7 @@ export type MarinadeFinance = { name: 'operationalSolAccount'; isMut: true; isSigner: false; - } + }, ]; args: [ { @@ -201,7 +201,7 @@ export type MarinadeFinance = { { name: 'validatorVote'; type: 'publicKey'; - } + }, ]; }, { @@ -221,7 +221,7 @@ export type MarinadeFinance = { name: 'validatorList'; isMut: true; isSigner: false; - } + }, ]; args: [ { @@ -235,7 +235,7 @@ export type MarinadeFinance = { { name: 'score'; type: 'u32'; - } + }, ]; }, { @@ -250,13 +250,13 @@ export type MarinadeFinance = { name: 'managerAuthority'; isMut: false; isSigner: true; - } + }, ]; args: [ { name: 'extraRuns'; type: 'u32'; - } + }, ]; }, { @@ -316,13 +316,13 @@ export type MarinadeFinance = { name: 'tokenProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { name: 'lamports'; type: 'u64'; - } + }, ]; }, { @@ -402,13 +402,13 @@ export type MarinadeFinance = { name: 'stakeProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { name: 'validatorIndex'; type: 'u32'; - } + }, ]; }, { @@ -463,13 +463,13 @@ export type MarinadeFinance = { name: 'tokenProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { name: 'msolAmount'; type: 'u64'; - } + }, ]; }, { @@ -519,13 +519,13 @@ export type MarinadeFinance = { name: 'tokenProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { name: 'lamports'; type: 'u64'; - } + }, ]; }, { @@ -585,13 +585,13 @@ export type MarinadeFinance = { name: 'tokenProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { name: 'tokens'; type: 'u64'; - } + }, ]; }, { @@ -606,7 +606,7 @@ export type MarinadeFinance = { name: 'adminAuthority'; isMut: false; isSigner: true; - } + }, ]; args: [ { @@ -614,7 +614,7 @@ export type MarinadeFinance = { type: { defined: 'ConfigLpParams'; }; - } + }, ]; }, { @@ -629,7 +629,7 @@ export type MarinadeFinance = { name: 'adminAuthority'; isMut: false; isSigner: true; - } + }, ]; args: [ { @@ -637,7 +637,7 @@ export type MarinadeFinance = { type: { defined: 'ConfigMarinadeParams'; }; - } + }, ]; }, { @@ -682,13 +682,13 @@ export type MarinadeFinance = { name: 'tokenProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { name: 'msolAmount'; type: 'u64'; - } + }, ]; }, { @@ -723,7 +723,7 @@ export type MarinadeFinance = { name: 'systemProgram'; isMut: false; isSigner: false; - } + }, ]; args: []; }, @@ -799,13 +799,13 @@ export type MarinadeFinance = { name: 'stakeProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { name: 'validatorIndex'; type: 'u32'; - } + }, ]; }, { @@ -873,14 +873,14 @@ export type MarinadeFinance = { name: 'tokenProgram'; isMut: false; isSigner: false; - } + }, ]; }, { name: 'validatorList'; isMut: true; isSigner: false; - } + }, ]; args: [ { @@ -890,7 +890,7 @@ export type MarinadeFinance = { { name: 'validatorIndex'; type: 'u32'; - } + }, ]; }, { @@ -958,7 +958,7 @@ export type MarinadeFinance = { name: 'tokenProgram'; isMut: false; isSigner: false; - } + }, ]; }, { @@ -970,13 +970,13 @@ export type MarinadeFinance = { name: 'systemProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { name: 'stakeIndex'; type: 'u32'; - } + }, ]; }, { @@ -1051,7 +1051,7 @@ export type MarinadeFinance = { name: 'stakeProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { @@ -1061,7 +1061,7 @@ export type MarinadeFinance = { { name: 'validatorIndex'; type: 'u32'; - } + }, ]; }, { @@ -1106,7 +1106,7 @@ export type MarinadeFinance = { name: 'stakeProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { @@ -1116,7 +1116,7 @@ export type MarinadeFinance = { { name: 'validatorIndex'; type: 'u32'; - } + }, ]; }, { @@ -1191,7 +1191,7 @@ export type MarinadeFinance = { name: 'stakeProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { @@ -1205,7 +1205,7 @@ export type MarinadeFinance = { { name: 'desiredUnstakeAmount'; type: 'u64'; - } + }, ]; }, { @@ -1265,7 +1265,7 @@ export type MarinadeFinance = { name: 'stakeProgram'; isMut: false; isSigner: false; - } + }, ]; args: [ { @@ -1279,9 +1279,9 @@ export type MarinadeFinance = { { name: 'validatorIndex'; type: 'u32'; - } + }, ]; - } + }, ]; accounts: [ { @@ -1361,7 +1361,7 @@ export type MarinadeFinance = { { name: 'circulatingTicketBalance'; docs: [ - 'total lamports amount of generated and not claimed yet tickets' + 'total lamports amount of generated and not claimed yet tickets', ]; type: 'u64'; }, @@ -1384,7 +1384,7 @@ export type MarinadeFinance = { { name: 'emergencyCoolingDown'; type: 'u64'; - } + }, ]; }; }, @@ -1408,10 +1408,10 @@ export type MarinadeFinance = { { name: 'createdEpoch'; type: 'u64'; - } + }, ]; }; - } + }, ]; types: [ { @@ -1442,7 +1442,7 @@ export type MarinadeFinance = { { name: 'lpLiquidityTarget'; docs: [ - 'Liquidity target. If the Liquidity reach this amount, the fee reaches lp_min_discount_fee' + 'Liquidity target. If the Liquidity reach this amount, the fee reaches lp_min_discount_fee', ]; type: 'u64'; }, @@ -1478,7 +1478,7 @@ export type MarinadeFinance = { { name: 'liquiditySolCap'; type: 'u64'; - } + }, ]; }; }, @@ -1506,7 +1506,7 @@ export type MarinadeFinance = { { name: 'copiedCount'; type: 'u32'; - } + }, ]; }; }, @@ -1530,7 +1530,7 @@ export type MarinadeFinance = { { name: 'isEmergencyUnstaking'; type: 'u8'; - } + }, ]; }; }, @@ -1560,7 +1560,7 @@ export type MarinadeFinance = { { name: 'slotsForStakeDelta'; docs: [ - 'set by admin, how much slots before the end of the epoch, stake-delta can start' + 'set by admin, how much slots before the end of the epoch, stake-delta can start', ]; type: 'u64'; }, @@ -1569,7 +1569,7 @@ export type MarinadeFinance = { docs: [ 'Marks the start of stake-delta operations, meaning that if somebody starts a delayed-unstake ticket', 'after this var is set with epoch_num the ticket will have epoch_created = current_epoch+1', - '(the user must wait one more epoch, because their unstake-delta will be execute in this epoch)' + '(the user must wait one more epoch, because their unstake-delta will be execute in this epoch)', ]; type: 'u64'; }, @@ -1581,10 +1581,10 @@ export type MarinadeFinance = { name: 'extraStakeDeltaRuns'; docs: [ 'can be set by validator-manager-auth to allow a second run of stake-delta to stake late stakers in the last minute of the epoch', - "so we maximize user's rewards" + "so we maximize user's rewards", ]; type: 'u32'; - } + }, ]; }; }, @@ -1614,7 +1614,7 @@ export type MarinadeFinance = { { name: 'duplicationFlagBumpSeed'; type: 'u8'; - } + }, ]; }; }, @@ -1645,10 +1645,10 @@ export type MarinadeFinance = { { name: 'autoAddValidatorEnabled'; docs: [ - 'allow & auto-add validator when a user deposits a stake-account of a non-listed validator' + 'allow & auto-add validator when a user deposits a stake-account of a non-listed validator', ]; type: 'u8'; - } + }, ]; }; }, @@ -1660,7 +1660,7 @@ export type MarinadeFinance = { { name: 'basisPoints'; type: 'u32'; - } + }, ]; }; }, @@ -1704,7 +1704,7 @@ export type MarinadeFinance = { { name: 'slotsForStakeDelta'; type: 'u64'; - } + }, ]; }; }, @@ -1734,7 +1734,7 @@ export type MarinadeFinance = { type: { defined: 'Fee'; }; - } + }, ]; }; }, @@ -1766,7 +1766,7 @@ export type MarinadeFinance = { type: { option: 'publicKey'; }; - } + }, ]; }; }, @@ -1804,7 +1804,7 @@ export type MarinadeFinance = { defined: 'Fee'; }; }; - } + }, ]; }; }, @@ -1862,7 +1862,7 @@ export type MarinadeFinance = { type: { option: 'bool'; }; - } + }, ]; }; }, @@ -1954,10 +1954,10 @@ export type MarinadeFinance = { }, { name: 'InvalidValidator'; - } + }, ]; }; - } + }, ]; };