@drift-labs/sdk 2.149.1 → 2.150.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.env +4 -0
  2. package/VERSION +1 -1
  3. package/lib/browser/constants/perpMarkets.js +11 -0
  4. package/lib/browser/constants/spotMarkets.js +13 -0
  5. package/lib/browser/decode/user.js +2 -2
  6. package/lib/browser/driftClient.d.ts +20 -8
  7. package/lib/browser/driftClient.js +216 -17
  8. package/lib/browser/idl/drift.json +225 -21
  9. package/lib/browser/math/margin.js +2 -1
  10. package/lib/browser/math/position.d.ts +1 -0
  11. package/lib/browser/math/position.js +10 -2
  12. package/lib/browser/math/superStake.d.ts +3 -2
  13. package/lib/browser/types.d.ts +12 -6
  14. package/lib/browser/types.js +11 -6
  15. package/lib/browser/user.d.ts +3 -2
  16. package/lib/browser/user.js +24 -8
  17. package/lib/node/constants/perpMarkets.d.ts.map +1 -1
  18. package/lib/node/constants/perpMarkets.js +11 -0
  19. package/lib/node/constants/spotMarkets.d.ts.map +1 -1
  20. package/lib/node/constants/spotMarkets.js +13 -0
  21. package/lib/node/decode/user.d.ts.map +1 -1
  22. package/lib/node/decode/user.js +2 -2
  23. package/lib/node/driftClient.d.ts +20 -8
  24. package/lib/node/driftClient.d.ts.map +1 -1
  25. package/lib/node/driftClient.js +216 -17
  26. package/lib/node/idl/drift.json +225 -21
  27. package/lib/node/math/margin.d.ts.map +1 -1
  28. package/lib/node/math/margin.js +2 -1
  29. package/lib/node/math/position.d.ts +1 -0
  30. package/lib/node/math/position.d.ts.map +1 -1
  31. package/lib/node/math/position.js +10 -2
  32. package/lib/node/math/spotBalance.d.ts.map +1 -1
  33. package/lib/node/math/superStake.d.ts +3 -2
  34. package/lib/node/math/superStake.d.ts.map +1 -1
  35. package/lib/node/types.d.ts +12 -6
  36. package/lib/node/types.d.ts.map +1 -1
  37. package/lib/node/types.js +11 -6
  38. package/lib/node/user.d.ts +3 -2
  39. package/lib/node/user.d.ts.map +1 -1
  40. package/lib/node/user.js +24 -8
  41. package/package.json +1 -1
  42. package/scripts/deposit-isolated-positions.ts +110 -0
  43. package/scripts/single-grpc-client-test.ts +71 -21
  44. package/scripts/withdraw-isolated-positions.ts +174 -0
  45. package/src/constants/perpMarkets.ts +11 -0
  46. package/src/constants/spotMarkets.ts +14 -0
  47. package/src/decode/user.ts +2 -3
  48. package/src/driftClient.ts +464 -41
  49. package/src/idl/drift.json +226 -22
  50. package/src/margin/README.md +143 -0
  51. package/src/math/margin.ts +3 -4
  52. package/src/math/position.ts +12 -2
  53. package/src/math/spotBalance.ts +0 -1
  54. package/src/types.ts +15 -7
  55. package/src/user.ts +49 -15
  56. package/tests/amm/test.ts +1 -1
  57. package/tests/dlob/helpers.ts +1 -1
  58. package/tests/user/test.ts +0 -7
package/.env ADDED
@@ -0,0 +1,4 @@
1
+ # GRPC_ENDPOINT=https://drift-drift-951a.mainnet.rpcpool.com
2
+ # TOKEN=f1ead98714b94a67f82203cce918
3
+ GRPC_ENDPOINT=https://laserstream-mainnet-ams.helius-rpc.com
4
+ TOKEN=ff40c844-e15b-49d0-9d62-8534705aa48b
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.150.0-beta.0
1
+ 2.150.0-alpha.0
@@ -1327,6 +1327,17 @@ exports.MainnetPerpMarkets = [
1327
1327
  oracleSource: types_1.OracleSource.PYTH_LAZER,
1328
1328
  pythLazerId: 2382,
1329
1329
  },
1330
+ {
1331
+ fullName: 'Monad',
1332
+ category: ['L1'],
1333
+ symbol: '1KMON-PERP',
1334
+ baseAssetSymbol: '1KMON',
1335
+ marketIndex: 83,
1336
+ oracle: new web3_js_1.PublicKey('585jsthKg9BeTfnFGAxgfNie9krGGyPbd5feMpWneHf7'),
1337
+ launchTs: 1763996757000,
1338
+ oracleSource: types_1.OracleSource.PYTH_LAZER_1K,
1339
+ pythLazerId: 2396,
1340
+ },
1330
1341
  ];
1331
1342
  exports.PerpMarkets = {
1332
1343
  devnet: exports.DevnetPerpMarkets,
@@ -869,6 +869,19 @@ exports.MainnetSpotMarkets = [
869
869
  pythLazerId: 2382,
870
870
  launchTs: 1761225524000,
871
871
  },
872
+ {
873
+ symbol: 'CASH',
874
+ marketIndex: 61,
875
+ poolId: 0,
876
+ oracle: new web3_js_1.PublicKey('AK6coxSjfAnuDT4ZUSP3UpeQe2G1tKcALnsdd835eg7T'),
877
+ oracleSource: types_1.OracleSource.PYTH_LAZER_STABLE_COIN,
878
+ mint: new web3_js_1.PublicKey('CASHx9KJUStyftLFWGvEVf59SGeG9sh5FfcnZMVPCASH'),
879
+ precision: new anchor_1.BN(10).pow(numericConstants_1.SIX),
880
+ precisionExp: numericConstants_1.SIX,
881
+ pythFeedId: '0xdf3320ef0f4617337b8dbb924f2aaa4f9db08f522a5435b44f9066c1ac4c7f95',
882
+ pythLazerId: 2323,
883
+ launchTs: 1763677264000,
884
+ },
872
885
  ];
873
886
  exports.SpotMarkets = {
874
887
  devnet: exports.DevnetSpotMarkets,
@@ -71,7 +71,7 @@ function decodeUser(buffer) {
71
71
  const quoteAssetAmount = readSignedBigInt64LE(buffer, offset + 16);
72
72
  const lpShares = readUnsignedBigInt64LE(buffer, offset + 64);
73
73
  const openOrders = buffer.readUInt8(offset + 94);
74
- const positionFlag = buffer.readUInt8(offset + 95);
74
+ const positionFlag = 0;
75
75
  const isolatedPositionScaledBalance = readUnsignedBigInt64LE(buffer, offset + 96);
76
76
  if (baseAssetAmount.eq(numericConstants_1.ZERO) &&
77
77
  openOrders === 0 &&
@@ -119,8 +119,8 @@ function decodeUser(buffer) {
119
119
  openOrders,
120
120
  perLpBase,
121
121
  maxMarginRatio,
122
- isolatedPositionScaledBalance,
123
122
  positionFlag,
123
+ isolatedPositionScaledBalance,
124
124
  });
125
125
  }
126
126
  const orders = [];
@@ -5,7 +5,7 @@
5
5
  import * as anchor from '@coral-xyz/anchor';
6
6
  import { AnchorProvider, BN, Program, ProgramAccount } from '@coral-xyz/anchor';
7
7
  import { Idl as Idl30, Program as Program30 } from '@coral-xyz/anchor-30';
8
- import { DriftClientMetricsEvents, HighLeverageModeConfig, IWallet, MakerInfo, MappedRecord, MarketType, ModifyOrderPolicy, OpenbookV2FulfillmentConfigAccount, OptionalOrderParams, OracleSource, Order, OrderParams, OrderTriggerCondition, PerpMarketAccount, PerpMarketExtendedInfo, PhoenixV1FulfillmentConfigAccount, PlaceAndTakeOrderSuccessCondition, PositionDirection, ReferrerInfo, ReferrerNameAccount, SerumV3FulfillmentConfigAccount, SettlePnlMode, SignedTxData, SpotMarketAccount, SpotPosition, StateAccount, SwapReduceOnly, SignedMsgOrderParamsMessage, TakerInfo, TxParams, UserAccount, UserStatsAccount, ProtectedMakerModeConfig, SignedMsgOrderParamsDelegateMessage, PostOnlyParams, LPPoolAccount, ConstituentAccount, ConstituentTargetBaseAccount, AmmCache } from './types';
8
+ import { DriftClientMetricsEvents, HighLeverageModeConfig, IWallet, MakerInfo, MappedRecord, MarketType, ModifyOrderPolicy, OpenbookV2FulfillmentConfigAccount, OptionalOrderParams, OracleSource, Order, OrderParams, OrderTriggerCondition, PerpMarketAccount, PerpMarketExtendedInfo, PhoenixV1FulfillmentConfigAccount, PlaceAndTakeOrderSuccessCondition, PositionDirection, ReferrerInfo, ReferrerNameAccount, SerumV3FulfillmentConfigAccount, SettlePnlMode, SignedTxData, SpotMarketAccount, SpotPosition, StateAccount, SwapReduceOnly, SignedMsgOrderParamsMessage, TxParams, UserAccount, UserStatsAccount, ProtectedMakerModeConfig, SignedMsgOrderParamsDelegateMessage, PostOnlyParams, LPPoolAccount, ConstituentAccount, ConstituentTargetBaseAccount, AmmCache } from './types';
9
9
  import { AccountMeta, AddressLookupTableAccount, BlockhashWithExpiryBlockHeight, ConfirmOptions, Connection, Keypair, PublicKey, Signer, Transaction, TransactionInstruction, TransactionSignature, TransactionVersion, VersionedTransaction } from '@solana/web3.js';
10
10
  import { TokenFaucet } from './tokenFaucet';
11
11
  import { EventEmitter } from 'events';
@@ -26,6 +26,7 @@ import { WormholeCoreBridgeSolana } from '@pythnetwork/pyth-solana-receiver/lib/
26
26
  import { PythSolanaReceiver } from '@pythnetwork/pyth-solana-receiver/lib/idl/pyth_solana_receiver';
27
27
  import { Slothash } from './slot/SlothashSubscriber';
28
28
  import { SignedMsgOrderParams } from './types';
29
+ import { TakerInfo } from './types';
29
30
  import { ConstituentMap } from './constituentMap/constituentMap';
30
31
  import { RevenueShareEscrowMap } from './userMap/revenueShareEscrowMap';
31
32
  import { TitanClient } from './titan/titanClient';
@@ -89,6 +90,7 @@ export declare class DriftClient {
89
90
  sbOnDemandProgram?: Program30<Idl30>;
90
91
  sbProgramFeedConfigs?: Map<string, any>;
91
92
  get isSubscribed(): boolean;
93
+ private getPrePlaceOrderIxs;
92
94
  set isSubscribed(val: boolean);
93
95
  constructor(config: DriftClientConfig);
94
96
  getUserMapKey(subAccountId: number, authority: PublicKey): string;
@@ -306,6 +308,7 @@ export declare class DriftClient {
306
308
  getUserAccountAndSlot(subAccountId?: number, authority?: PublicKey): DataAndSlot<UserAccount> | undefined;
307
309
  getSpotPosition(marketIndex: number, subAccountId?: number): SpotPosition | undefined;
308
310
  getQuoteAssetTokenAmount(): BN;
311
+ getIsolatedPerpPositionTokenAmount(perpMarketIndex: number, subAccountId?: number): BN;
309
312
  /**
310
313
  * Returns the token amount for a given market. The spot market precision is based on the token mint decimals.
311
314
  * Positive if it is a deposit, negative if it is a borrow.
@@ -450,6 +453,13 @@ export declare class DriftClient {
450
453
  getTransferPoolsIx(depositFromMarketIndex: number, depositToMarketIndex: number, borrowFromMarketIndex: number, borrowToMarketIndex: number, depositAmount: BN | undefined, borrowAmount: BN | undefined, fromSubAccountId: number, toSubAccountId: number, isToNewSubAccount?: boolean): Promise<TransactionInstruction>;
451
454
  transferPerpPosition(fromSubAccountId: number, toSubAccountId: number, marketIndex: number, amount: BN, txParams?: TxParams): Promise<TransactionSignature>;
452
455
  getTransferPerpPositionIx(fromSubAccountId: number, toSubAccountId: number, marketIndex: number, amount: BN): Promise<TransactionInstruction>;
456
+ depositIntoIsolatedPerpPosition(amount: BN, perpMarketIndex: number, userTokenAccount: PublicKey, subAccountId?: number, txParams?: TxParams): Promise<TransactionSignature>;
457
+ getDepositIntoIsolatedPerpPositionIx(amount: BN, perpMarketIndex: number, userTokenAccount: PublicKey, subAccountId?: number): Promise<TransactionInstruction>;
458
+ transferIsolatedPerpPositionDeposit(amount: BN, perpMarketIndex: number, subAccountId?: number, txParams?: TxParams, trySettle?: boolean): Promise<TransactionSignature>;
459
+ getTransferIsolatedPerpPositionDepositIx(amount: BN, perpMarketIndex: number, subAccountId?: number, noAmountBuffer?: boolean): Promise<TransactionInstruction>;
460
+ withdrawFromIsolatedPerpPosition(amount: BN, perpMarketIndex: number, userTokenAccount: PublicKey, subAccountId?: number, txParams?: TxParams): Promise<TransactionSignature>;
461
+ getWithdrawFromIsolatedPerpPositionIxsBundle(amount: BN, perpMarketIndex: number, subAccountId?: number, userTokenAccount?: PublicKey): Promise<TransactionInstruction[]>;
462
+ getWithdrawFromIsolatedPerpPositionIx(amount: BN, perpMarketIndex: number, userTokenAccount: PublicKey, subAccountId?: number): Promise<TransactionInstruction>;
453
463
  updateSpotMarketCumulativeInterest(marketIndex: number, txParams?: TxParams): Promise<TransactionSignature>;
454
464
  updateSpotMarketCumulativeInterestIx(marketIndex: number): Promise<TransactionInstruction>;
455
465
  settleLP(settleeUserAccountPublicKey: PublicKey, marketIndex: number, txParams?: TxParams): Promise<TransactionSignature>;
@@ -466,7 +476,7 @@ export declare class DriftClient {
466
476
  */
467
477
  openPosition(direction: PositionDirection, amount: BN, marketIndex: number, limitPrice?: BN, subAccountId?: number): Promise<TransactionSignature>;
468
478
  sendSignedTx(tx: Transaction | VersionedTransaction, opts?: ConfirmOptions): Promise<TransactionSignature>;
469
- prepareMarketOrderTxs(orderParams: OptionalOrderParams, userAccountPublicKey: PublicKey, userAccount: UserAccount, makerInfo?: MakerInfo | MakerInfo[], txParams?: TxParams, bracketOrdersParams?: OptionalOrderParams[], referrerInfo?: ReferrerInfo, cancelExistingOrders?: boolean, settlePnl?: boolean, positionMaxLev?: number): Promise<{
479
+ prepareMarketOrderTxs(orderParams: OptionalOrderParams, userAccountPublicKey: PublicKey, userAccount: UserAccount, makerInfo?: MakerInfo | MakerInfo[], txParams?: TxParams, bracketOrdersParams?: OptionalOrderParams[], referrerInfo?: ReferrerInfo, cancelExistingOrders?: boolean, settlePnl?: boolean, positionMaxLev?: number, isolatedPositionDepositAmount?: BN): Promise<{
470
480
  cancelExistingOrdersTx?: Transaction | VersionedTransaction;
471
481
  settlePnlTx?: Transaction | VersionedTransaction;
472
482
  fillTx?: Transaction | VersionedTransaction;
@@ -489,7 +499,7 @@ export declare class DriftClient {
489
499
  signedCancelExistingOrdersTx?: Transaction;
490
500
  signedSettlePnlTx?: Transaction;
491
501
  }>;
492
- placePerpOrder(orderParams: OptionalOrderParams, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
502
+ placePerpOrder(orderParams: OptionalOrderParams, txParams?: TxParams, subAccountId?: number, isolatedPositionDepositAmount?: BN): Promise<TransactionSignature>;
493
503
  getPlacePerpOrderIx(orderParams: OptionalOrderParams, subAccountId?: number, depositToTradeArgs?: {
494
504
  isMakingNewAccount: boolean;
495
505
  depositMarketIndex: number;
@@ -500,7 +510,9 @@ export declare class DriftClient {
500
510
  getSettleExpiredMarketIx(marketIndex: number): Promise<TransactionInstruction>;
501
511
  settleExpiredMarketPoolsToRevenuePool(marketIndex: number, txParams?: TxParams): Promise<TransactionSignature>;
502
512
  getSettleExpiredMarketPoolsToRevenuePoolIx(perpMarketIndex: number): Promise<TransactionInstruction>;
503
- cancelOrder(orderId?: number, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
513
+ cancelOrder(orderId?: number, txParams?: TxParams, subAccountId?: number, overrides?: {
514
+ withdrawIsolatedDepositAmount?: BN;
515
+ }): Promise<TransactionSignature>;
504
516
  getCancelOrderIx(orderId?: number, subAccountId?: number): Promise<TransactionInstruction>;
505
517
  cancelOrderByUserId(userOrderId: number, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
506
518
  getCancelOrderByUserIdIx(userOrderId: number, subAccountId?: number): Promise<TransactionInstruction>;
@@ -534,8 +546,8 @@ export declare class DriftClient {
534
546
  marketIndex?: number;
535
547
  direction?: PositionDirection;
536
548
  }, placeOrderParams: OrderParams[], txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
537
- placeOrders(params: OrderParams[], txParams?: TxParams, subAccountId?: number, optionalIxs?: TransactionInstruction[]): Promise<TransactionSignature>;
538
- preparePlaceOrdersTx(params: OrderParams[], txParams?: TxParams, subAccountId?: number, optionalIxs?: TransactionInstruction[]): Promise<{
549
+ placeOrders(params: OrderParams[], txParams?: TxParams, subAccountId?: number, optionalIxs?: TransactionInstruction[], isolatedPositionDepositAmount?: BN): Promise<TransactionSignature>;
550
+ preparePlaceOrdersTx(params: OrderParams[], txParams?: TxParams, subAccountId?: number, optionalIxs?: TransactionInstruction[], isolatedPositionDepositAmount?: BN): Promise<{
539
551
  placeOrdersTx: anchor.web3.Transaction | anchor.web3.VersionedTransaction;
540
552
  }>;
541
553
  getPlaceOrdersIx(params: OptionalOrderParams[], subAccountId?: number, overrides?: {
@@ -692,7 +704,7 @@ export declare class DriftClient {
692
704
  updateUserOpenOrdersCount(userAccountPublicKey: PublicKey, user: UserAccount, txParams?: TxParams, fillerPublicKey?: PublicKey): Promise<TransactionSignature>;
693
705
  getUpdateUserOpenOrdersCountIx(userAccountPublicKey: PublicKey, userAccount: UserAccount, fillerPublicKey?: PublicKey): Promise<TransactionInstruction>;
694
706
  placeAndTakePerpOrder(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, successCondition?: PlaceAndTakeOrderSuccessCondition, auctionDurationPercentage?: number, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
695
- preparePlaceAndTakePerpOrderWithAdditionalOrders(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, bracketOrdersParams?: OptionalOrderParams[], txParams?: TxParams, subAccountId?: number, cancelExistingOrders?: boolean, settlePnl?: boolean, exitEarlyIfSimFails?: boolean, auctionDurationPercentage?: number, optionalIxs?: TransactionInstruction[]): Promise<{
707
+ preparePlaceAndTakePerpOrderWithAdditionalOrders(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, bracketOrdersParams?: OptionalOrderParams[], txParams?: TxParams, subAccountId?: number, cancelExistingOrders?: boolean, settlePnl?: boolean, exitEarlyIfSimFails?: boolean, auctionDurationPercentage?: number, optionalIxs?: TransactionInstruction[], isolatedPositionDepositAmount?: BN): Promise<{
696
708
  placeAndTakeTx: Transaction | VersionedTransaction;
697
709
  cancelExistingOrdersTx: Transaction | VersionedTransaction;
698
710
  settlePnlTx: Transaction | VersionedTransaction;
@@ -891,7 +903,6 @@ export declare class DriftClient {
891
903
  bitFlags?: number;
892
904
  policy?: ModifyOrderPolicy;
893
905
  maxTs?: BN;
894
- txParams?: TxParams;
895
906
  }, subAccountId?: number): Promise<TransactionInstruction>;
896
907
  settlePNLs(users: {
897
908
  settleeUserAccountPublicKey: PublicKey;
@@ -1232,5 +1243,6 @@ export declare class DriftClient {
1232
1243
  signedTxMap: MappedRecord<Record<string, anchor.web3.TransactionInstruction | anchor.web3.TransactionInstruction[]>, anchor.web3.Transaction | anchor.web3.VersionedTransaction>;
1233
1244
  signedTxData: SignedTxData[];
1234
1245
  }>;
1246
+ isOrderIncreasingPosition(orderParams: OptionalOrderParams, subAccountId: number): boolean;
1235
1247
  }
1236
1248
  export {};
@@ -71,6 +71,7 @@ const on_demand_1 = require("@switchboard-xyz/on-demand");
71
71
  const grpcDriftClientAccountSubscriber_1 = require("./accounts/grpcDriftClientAccountSubscriber");
72
72
  const tweetnacl_1 = __importDefault(require("tweetnacl"));
73
73
  const oracleId_1 = require("./oracles/oracleId");
74
+ // BN is already imported globally in this file via other imports
74
75
  const sha256_1 = require("@noble/hashes/sha256");
75
76
  const utils_3 = require("./oracles/utils");
76
77
  const orders_1 = require("./math/orders");
@@ -85,6 +86,22 @@ class DriftClient {
85
86
  get isSubscribed() {
86
87
  return this._isSubscribed && this.accountSubscriber.isSubscribed;
87
88
  }
89
+ async getPrePlaceOrderIxs(orderParams, userAccount, options) {
90
+ var _a;
91
+ const preIxs = [];
92
+ if ((0, types_1.isVariant)(orderParams.marketType, 'perp')) {
93
+ const { positionMaxLev, isolatedPositionDepositAmount } = options !== null && options !== void 0 ? options : {};
94
+ if (((_a = isolatedPositionDepositAmount === null || isolatedPositionDepositAmount === void 0 ? void 0 : isolatedPositionDepositAmount.gt) === null || _a === void 0 ? void 0 : _a.call(isolatedPositionDepositAmount, numericConstants_1.ZERO)) &&
95
+ this.isOrderIncreasingPosition(orderParams, userAccount.subAccountId)) {
96
+ preIxs.push(await this.getTransferIsolatedPerpPositionDepositIx(isolatedPositionDepositAmount, orderParams.marketIndex, userAccount.subAccountId));
97
+ }
98
+ if (positionMaxLev) {
99
+ const marginRatio = Math.floor((1 / positionMaxLev) * numericConstants_1.MARGIN_PRECISION.toNumber());
100
+ preIxs.push(await this.getUpdateUserPerpPositionCustomMarginRatioIx(orderParams.marketIndex, marginRatio, userAccount.subAccountId));
101
+ }
102
+ }
103
+ return preIxs;
104
+ }
88
105
  set isSubscribed(val) {
89
106
  this._isSubscribed = val;
90
107
  }
@@ -1382,6 +1399,9 @@ class DriftClient {
1382
1399
  getQuoteAssetTokenAmount() {
1383
1400
  return this.getTokenAmount(numericConstants_1.QUOTE_SPOT_MARKET_INDEX);
1384
1401
  }
1402
+ getIsolatedPerpPositionTokenAmount(perpMarketIndex, subAccountId) {
1403
+ return this.getUser(subAccountId).getIsolatePerpPositionTokenAmount(perpMarketIndex);
1404
+ }
1385
1405
  /**
1386
1406
  * Returns the token amount for a given market. The spot market precision is based on the token mint decimals.
1387
1407
  * Positive if it is a deposit, negative if it is a borrow.
@@ -2139,6 +2159,129 @@ class DriftClient {
2139
2159
  remainingAccounts,
2140
2160
  });
2141
2161
  }
2162
+ async depositIntoIsolatedPerpPosition(amount, perpMarketIndex, userTokenAccount, subAccountId, txParams) {
2163
+ const { txSig } = await this.sendTransaction(await this.buildTransaction(await this.getDepositIntoIsolatedPerpPositionIx(amount, perpMarketIndex, userTokenAccount, subAccountId), txParams), [], this.opts);
2164
+ return txSig;
2165
+ }
2166
+ async getDepositIntoIsolatedPerpPositionIx(amount, perpMarketIndex, userTokenAccount, subAccountId) {
2167
+ const userAccountPublicKey = await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.authority, subAccountId !== null && subAccountId !== void 0 ? subAccountId : this.activeSubAccountId);
2168
+ const perpMarketAccount = this.getPerpMarketAccount(perpMarketIndex);
2169
+ const spotMarketIndex = perpMarketAccount.quoteSpotMarketIndex;
2170
+ const spotMarketAccount = this.getSpotMarketAccount(spotMarketIndex);
2171
+ const remainingAccounts = this.getRemainingAccounts({
2172
+ userAccounts: [],
2173
+ writableSpotMarketIndexes: [spotMarketIndex],
2174
+ readablePerpMarketIndex: [perpMarketIndex],
2175
+ });
2176
+ const tokenProgram = this.getTokenProgramForSpotMarket(spotMarketAccount);
2177
+ return await this.program.instruction.depositIntoIsolatedPerpPosition(spotMarketIndex, perpMarketIndex, amount, {
2178
+ accounts: {
2179
+ state: await this.getStatePublicKey(),
2180
+ spotMarketVault: spotMarketAccount.vault,
2181
+ user: userAccountPublicKey,
2182
+ userStats: this.getUserStatsAccountPublicKey(),
2183
+ userTokenAccount: userTokenAccount,
2184
+ authority: this.wallet.publicKey,
2185
+ tokenProgram,
2186
+ },
2187
+ remainingAccounts,
2188
+ });
2189
+ }
2190
+ async transferIsolatedPerpPositionDeposit(amount, perpMarketIndex, subAccountId, txParams, trySettle) {
2191
+ const ixs = [];
2192
+ const tokenAmountDeposited = this.getIsolatedPerpPositionTokenAmount(perpMarketIndex);
2193
+ const transferIx = await this.getTransferIsolatedPerpPositionDepositIx(amount, perpMarketIndex, subAccountId);
2194
+ const needsToSettle = amount.gt(tokenAmountDeposited) || amount.eq(numericConstants_1.MIN_I64) || trySettle;
2195
+ if (needsToSettle) {
2196
+ const settleIx = await this.settleMultiplePNLsIx(await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.authority, subAccountId !== null && subAccountId !== void 0 ? subAccountId : this.activeSubAccountId), this.getUserAccount(subAccountId), [perpMarketIndex], types_1.SettlePnlMode.TRY_SETTLE);
2197
+ ixs.push(settleIx);
2198
+ }
2199
+ ixs.push(transferIx);
2200
+ const tx = await this.buildTransaction(ixs, txParams);
2201
+ const { txSig } = await this.sendTransaction(tx, [], {
2202
+ ...this.opts,
2203
+ skipPreflight: true,
2204
+ });
2205
+ return txSig;
2206
+ }
2207
+ async getTransferIsolatedPerpPositionDepositIx(amount, perpMarketIndex, subAccountId, noAmountBuffer) {
2208
+ const userAccountPublicKey = await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.authority, subAccountId !== null && subAccountId !== void 0 ? subAccountId : this.activeSubAccountId);
2209
+ const perpMarketAccount = this.getPerpMarketAccount(perpMarketIndex);
2210
+ const spotMarketIndex = perpMarketAccount.quoteSpotMarketIndex;
2211
+ const spotMarketAccount = this.getSpotMarketAccount(spotMarketIndex);
2212
+ const user = await this.getUserAccount(subAccountId);
2213
+ const remainingAccounts = this.getRemainingAccounts({
2214
+ userAccounts: [user],
2215
+ writableSpotMarketIndexes: [spotMarketIndex],
2216
+ readablePerpMarketIndex: [perpMarketIndex],
2217
+ });
2218
+ const amountWithBuffer = noAmountBuffer || amount.eq(numericConstants_1.MIN_I64)
2219
+ ? amount
2220
+ : amount.add(amount.div(new anchor_1.BN(200))); // .5% buffer
2221
+ return await this.program.instruction.transferIsolatedPerpPositionDeposit(spotMarketIndex, perpMarketIndex, amountWithBuffer, {
2222
+ accounts: {
2223
+ state: await this.getStatePublicKey(),
2224
+ spotMarketVault: spotMarketAccount.vault,
2225
+ user: userAccountPublicKey,
2226
+ userStats: this.getUserStatsAccountPublicKey(),
2227
+ authority: this.wallet.publicKey,
2228
+ },
2229
+ remainingAccounts,
2230
+ });
2231
+ }
2232
+ async withdrawFromIsolatedPerpPosition(amount, perpMarketIndex, userTokenAccount, subAccountId, txParams) {
2233
+ const instructions = await this.getWithdrawFromIsolatedPerpPositionIxsBundle(amount, perpMarketIndex, subAccountId, userTokenAccount);
2234
+ const { txSig } = await this.sendTransaction(await this.buildTransaction(instructions, txParams));
2235
+ return txSig;
2236
+ }
2237
+ async getWithdrawFromIsolatedPerpPositionIxsBundle(amount, perpMarketIndex, subAccountId, userTokenAccount) {
2238
+ const userAccountPublicKey = await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.authority, subAccountId !== null && subAccountId !== void 0 ? subAccountId : this.activeSubAccountId);
2239
+ const userAccount = this.getUserAccount(subAccountId);
2240
+ const tokenAmountDeposited = this.getIsolatedPerpPositionTokenAmount(perpMarketIndex);
2241
+ const isolatedPositionUnrealizedPnl = (0, position_1.calculateClaimablePnl)(this.getPerpMarketAccount(perpMarketIndex), this.getSpotMarketAccount(this.getPerpMarketAccount(perpMarketIndex).quoteSpotMarketIndex), userAccount.perpPositions.find((p) => p.marketIndex === perpMarketIndex), this.getOracleDataForSpotMarket(this.getPerpMarketAccount(perpMarketIndex).quoteSpotMarketIndex));
2242
+ const depositAmountPlusUnrealizedPnl = tokenAmountDeposited.add(isolatedPositionUnrealizedPnl);
2243
+ const amountToWithdraw = amount.gt(depositAmountPlusUnrealizedPnl)
2244
+ ? numericConstants_1.MIN_I64 // min i64
2245
+ : amount;
2246
+ let associatedTokenAccount = userTokenAccount;
2247
+ if (!associatedTokenAccount) {
2248
+ const perpMarketAccount = this.getPerpMarketAccount(perpMarketIndex);
2249
+ const quoteSpotMarketIndex = perpMarketAccount.quoteSpotMarketIndex;
2250
+ associatedTokenAccount = await this.getAssociatedTokenAccount(quoteSpotMarketIndex);
2251
+ }
2252
+ const withdrawIx = await this.getWithdrawFromIsolatedPerpPositionIx(amountToWithdraw, perpMarketIndex, associatedTokenAccount, subAccountId);
2253
+ const ixs = [withdrawIx];
2254
+ const needsToSettle = amount.gt(tokenAmountDeposited) && isolatedPositionUnrealizedPnl.gt(numericConstants_1.ZERO);
2255
+ if (needsToSettle) {
2256
+ const settleIx = await this.settleMultiplePNLsIx(userAccountPublicKey, userAccount, [perpMarketIndex], types_1.SettlePnlMode.TRY_SETTLE);
2257
+ ixs.push(settleIx);
2258
+ }
2259
+ return ixs;
2260
+ }
2261
+ async getWithdrawFromIsolatedPerpPositionIx(amount, perpMarketIndex, userTokenAccount, subAccountId) {
2262
+ const userAccountPublicKey = await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.authority, subAccountId !== null && subAccountId !== void 0 ? subAccountId : this.activeSubAccountId);
2263
+ const perpMarketAccount = this.getPerpMarketAccount(perpMarketIndex);
2264
+ const spotMarketIndex = perpMarketAccount.quoteSpotMarketIndex;
2265
+ const spotMarketAccount = this.getSpotMarketAccount(spotMarketIndex);
2266
+ const remainingAccounts = this.getRemainingAccounts({
2267
+ userAccounts: [this.getUserAccount(subAccountId)],
2268
+ writableSpotMarketIndexes: [spotMarketIndex],
2269
+ readablePerpMarketIndex: [perpMarketIndex],
2270
+ });
2271
+ return await this.program.instruction.withdrawFromIsolatedPerpPosition(spotMarketIndex, perpMarketIndex, amount, {
2272
+ accounts: {
2273
+ state: await this.getStatePublicKey(),
2274
+ spotMarketVault: spotMarketAccount.vault,
2275
+ user: userAccountPublicKey,
2276
+ userStats: this.getUserStatsAccountPublicKey(),
2277
+ authority: this.wallet.publicKey,
2278
+ userTokenAccount: userTokenAccount,
2279
+ tokenProgram: this.getTokenProgramForSpotMarket(spotMarketAccount),
2280
+ driftSigner: this.getSignerPublicKey(),
2281
+ },
2282
+ remainingAccounts,
2283
+ });
2284
+ }
2142
2285
  async updateSpotMarketCumulativeInterest(marketIndex, txParams) {
2143
2286
  const { txSig } = await this.sendTransaction(await this.buildTransaction(await this.updateSpotMarketCumulativeInterestIx(marketIndex), txParams), [], this.opts);
2144
2287
  return txSig;
@@ -2271,7 +2414,7 @@ class DriftClient {
2271
2414
  const { txSig } = await this.sendTransaction(tx, undefined, opts !== null && opts !== void 0 ? opts : this.opts, true);
2272
2415
  return txSig;
2273
2416
  }
2274
- async prepareMarketOrderTxs(orderParams, userAccountPublicKey, userAccount, makerInfo, txParams, bracketOrdersParams = new Array(), referrerInfo, cancelExistingOrders, settlePnl, positionMaxLev) {
2417
+ async prepareMarketOrderTxs(orderParams, userAccountPublicKey, userAccount, makerInfo, txParams, bracketOrdersParams = new Array(), referrerInfo, cancelExistingOrders, settlePnl, positionMaxLev, isolatedPositionDepositAmount) {
2275
2418
  const marketIndex = orderParams.marketIndex;
2276
2419
  const orderId = userAccount.nextOrderId;
2277
2420
  const ixPromisesForTxs = {
@@ -2281,10 +2424,17 @@ class DriftClient {
2281
2424
  marketOrderTx: undefined,
2282
2425
  };
2283
2426
  const txKeys = Object.keys(ixPromisesForTxs);
2284
- const marketOrderTxIxs = positionMaxLev
2285
- ? this.getPlaceOrdersAndSetPositionMaxLevIx([orderParams, ...bracketOrdersParams], positionMaxLev, userAccount.subAccountId)
2286
- : this.getPlaceOrdersIx([orderParams, ...bracketOrdersParams], userAccount.subAccountId);
2287
- ixPromisesForTxs.marketOrderTx = marketOrderTxIxs;
2427
+ const preIxs = await this.getPrePlaceOrderIxs(orderParams, userAccount, {
2428
+ positionMaxLev,
2429
+ isolatedPositionDepositAmount,
2430
+ });
2431
+ ixPromisesForTxs.marketOrderTx = (async () => {
2432
+ const placeOrdersIx = await this.getPlaceOrdersIx([orderParams, ...bracketOrdersParams], userAccount.subAccountId);
2433
+ if (preIxs.length) {
2434
+ return [...preIxs, placeOrdersIx];
2435
+ }
2436
+ return placeOrdersIx;
2437
+ })();
2288
2438
  /* Cancel open orders in market if requested */
2289
2439
  if (cancelExistingOrders && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
2290
2440
  ixPromisesForTxs.cancelExistingOrdersTx = this.getCancelOrdersIx(orderParams.marketType, orderParams.marketIndex, null, userAccount.subAccountId);
@@ -2331,8 +2481,14 @@ class DriftClient {
2331
2481
  signedSettlePnlTx: signedTxs.settlePnlTx,
2332
2482
  };
2333
2483
  }
2334
- async placePerpOrder(orderParams, txParams, subAccountId) {
2335
- const { txSig, slot } = await this.sendTransaction(await this.buildTransaction(await this.getPlacePerpOrderIx(orderParams, subAccountId), txParams), [], this.opts);
2484
+ async placePerpOrder(orderParams, txParams, subAccountId, isolatedPositionDepositAmount) {
2485
+ var _a;
2486
+ const preIxs = [];
2487
+ if (((_a = isolatedPositionDepositAmount === null || isolatedPositionDepositAmount === void 0 ? void 0 : isolatedPositionDepositAmount.gt) === null || _a === void 0 ? void 0 : _a.call(isolatedPositionDepositAmount, numericConstants_1.ZERO)) &&
2488
+ this.isOrderIncreasingPosition(orderParams, subAccountId)) {
2489
+ preIxs.push(await this.getTransferIsolatedPerpPositionDepositIx(isolatedPositionDepositAmount, orderParams.marketIndex, subAccountId));
2490
+ }
2491
+ const { txSig, slot } = await this.sendTransaction(await this.buildTransaction(await this.getPlacePerpOrderIx(orderParams, subAccountId), txParams, undefined, undefined, undefined, undefined, preIxs), [], this.opts);
2336
2492
  this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2337
2493
  return txSig;
2338
2494
  }
@@ -2438,8 +2594,19 @@ class DriftClient {
2438
2594
  },
2439
2595
  });
2440
2596
  }
2441
- async cancelOrder(orderId, txParams, subAccountId) {
2442
- const { txSig } = await this.sendTransaction(await this.buildTransaction(await this.getCancelOrderIx(orderId, subAccountId), txParams), [], this.opts);
2597
+ async cancelOrder(orderId, txParams, subAccountId, overrides) {
2598
+ const cancelIx = await this.getCancelOrderIx(orderId, subAccountId);
2599
+ const instructions = [cancelIx];
2600
+ if ((overrides === null || overrides === void 0 ? void 0 : overrides.withdrawIsolatedDepositAmount) !== undefined) {
2601
+ const order = this.getOrder(orderId, subAccountId);
2602
+ const perpMarketIndex = order === null || order === void 0 ? void 0 : order.marketIndex;
2603
+ const withdrawAmount = overrides.withdrawIsolatedDepositAmount;
2604
+ if (withdrawAmount.gt(numericConstants_1.ZERO)) {
2605
+ const withdrawIxs = await this.getWithdrawFromIsolatedPerpPositionIxsBundle(withdrawAmount, perpMarketIndex, subAccountId);
2606
+ instructions.push(...withdrawIxs);
2607
+ }
2608
+ }
2609
+ const { txSig } = await this.sendTransaction(await this.buildTransaction(instructions, txParams), [], this.opts);
2443
2610
  return txSig;
2444
2611
  }
2445
2612
  async getCancelOrderIx(orderId, subAccountId) {
@@ -2558,13 +2725,23 @@ class DriftClient {
2558
2725
  const { txSig } = await this.sendTransaction(tx, [], this.opts);
2559
2726
  return txSig;
2560
2727
  }
2561
- async placeOrders(params, txParams, subAccountId, optionalIxs) {
2562
- const { txSig } = await this.sendTransaction((await this.preparePlaceOrdersTx(params, txParams, subAccountId, optionalIxs)).placeOrdersTx, [], this.opts, false);
2728
+ async placeOrders(params, txParams, subAccountId, optionalIxs, isolatedPositionDepositAmount) {
2729
+ const { txSig } = await this.sendTransaction((await this.preparePlaceOrdersTx(params, txParams, subAccountId, optionalIxs, isolatedPositionDepositAmount)).placeOrdersTx, [], this.opts, false);
2563
2730
  return txSig;
2564
2731
  }
2565
- async preparePlaceOrdersTx(params, txParams, subAccountId, optionalIxs) {
2732
+ async preparePlaceOrdersTx(params, txParams, subAccountId, optionalIxs, isolatedPositionDepositAmount) {
2733
+ var _a;
2566
2734
  const lookupTableAccounts = await this.fetchAllLookupTableAccounts();
2567
- const tx = await this.buildTransaction(await this.getPlaceOrdersIx(params, subAccountId), txParams, undefined, lookupTableAccounts, undefined, undefined, optionalIxs);
2735
+ const preIxs = [];
2736
+ if ((params === null || params === void 0 ? void 0 : params.length) === 1) {
2737
+ const p = params[0];
2738
+ if ((0, types_1.isVariant)(p.marketType, 'perp') &&
2739
+ ((_a = isolatedPositionDepositAmount === null || isolatedPositionDepositAmount === void 0 ? void 0 : isolatedPositionDepositAmount.gt) === null || _a === void 0 ? void 0 : _a.call(isolatedPositionDepositAmount, numericConstants_1.ZERO)) &&
2740
+ this.isOrderIncreasingPosition(p, subAccountId)) {
2741
+ preIxs.push(await this.getTransferIsolatedPerpPositionDepositIx(isolatedPositionDepositAmount, p.marketIndex, subAccountId));
2742
+ }
2743
+ }
2744
+ const tx = await this.buildTransaction(await this.getPlaceOrdersIx(params, subAccountId), txParams, undefined, lookupTableAccounts, undefined, undefined, [...preIxs, ...(optionalIxs !== null && optionalIxs !== void 0 ? optionalIxs : [])]);
2568
2745
  return {
2569
2746
  placeOrdersTx: tx,
2570
2747
  };
@@ -2653,7 +2830,7 @@ class DriftClient {
2653
2830
  remainingAccounts,
2654
2831
  });
2655
2832
  const marginRatio = Math.floor((1 / positionMaxLev) * numericConstants_1.MARGIN_PRECISION.toNumber());
2656
- // TODO: Handle multiple markets?
2833
+ // Keep existing behavior but note: prefer using getPostPlaceOrderIxs path
2657
2834
  const setPositionMaxLevIxs = await this.getUpdateUserPerpPositionCustomMarginRatioIx(readablePerpMarketIndex[0], marginRatio, subAccountId);
2658
2835
  return [placeOrdersIxs, setPositionMaxLevIxs];
2659
2836
  }
@@ -3654,7 +3831,7 @@ class DriftClient {
3654
3831
  this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
3655
3832
  return txSig;
3656
3833
  }
3657
- async preparePlaceAndTakePerpOrderWithAdditionalOrders(orderParams, makerInfo, referrerInfo, bracketOrdersParams = new Array(), txParams, subAccountId, cancelExistingOrders, settlePnl, exitEarlyIfSimFails, auctionDurationPercentage, optionalIxs) {
3834
+ async preparePlaceAndTakePerpOrderWithAdditionalOrders(orderParams, makerInfo, referrerInfo, bracketOrdersParams = new Array(), txParams, subAccountId, cancelExistingOrders, settlePnl, exitEarlyIfSimFails, auctionDurationPercentage, optionalIxs, isolatedPositionDepositAmount) {
3658
3835
  const placeAndTakeIxs = [];
3659
3836
  const txsToSign = {
3660
3837
  placeAndTakeTx: undefined,
@@ -3666,13 +3843,22 @@ class DriftClient {
3666
3843
  const lookupTableAccounts = await this.fetchAllLookupTableAccounts();
3667
3844
  let earlyExitFailedPlaceAndTakeSim = false;
3668
3845
  const prepPlaceAndTakeTx = async () => {
3669
- var _a;
3846
+ var _a, _b;
3670
3847
  const placeAndTakeIx = await this.getPlaceAndTakePerpOrderIx(orderParams, makerInfo, referrerInfo, undefined, auctionDurationPercentage, subAccountId);
3848
+ if ((0, types_1.isVariant)(orderParams.marketType, 'perp') &&
3849
+ ((_a = isolatedPositionDepositAmount === null || isolatedPositionDepositAmount === void 0 ? void 0 : isolatedPositionDepositAmount.gt) === null || _a === void 0 ? void 0 : _a.call(isolatedPositionDepositAmount, numericConstants_1.ZERO)) &&
3850
+ this.isOrderIncreasingPosition(orderParams, subAccountId)) {
3851
+ placeAndTakeIxs.push(await this.getTransferIsolatedPerpPositionDepositIx(isolatedPositionDepositAmount, orderParams.marketIndex, subAccountId));
3852
+ }
3671
3853
  placeAndTakeIxs.push(placeAndTakeIx);
3672
3854
  if (bracketOrdersParams.length > 0) {
3673
3855
  const bracketOrdersIx = await this.getPlaceOrdersIx(bracketOrdersParams, subAccountId);
3674
3856
  placeAndTakeIxs.push(bracketOrdersIx);
3675
3857
  }
3858
+ // Optional extra ixs can be appended at the front
3859
+ if (optionalIxs === null || optionalIxs === void 0 ? void 0 : optionalIxs.length) {
3860
+ placeAndTakeIxs.unshift(...optionalIxs);
3861
+ }
3676
3862
  const shouldUseSimulationComputeUnits = txParams === null || txParams === void 0 ? void 0 : txParams.useSimulatedComputeUnits;
3677
3863
  const shouldExitIfSimulationFails = exitEarlyIfSimFails;
3678
3864
  const txParamsWithoutImplicitSimulation = {
@@ -3681,7 +3867,7 @@ class DriftClient {
3681
3867
  };
3682
3868
  if (shouldUseSimulationComputeUnits || shouldExitIfSimulationFails) {
3683
3869
  const placeAndTakeTxToSim = (await this.buildTransaction(placeAndTakeIxs, txParams, undefined, lookupTableAccounts, true, recentBlockHash, optionalIxs));
3684
- const simulationResult = await txParamProcessor_1.TransactionParamProcessor.getTxSimComputeUnits(placeAndTakeTxToSim, this.connection, (_a = txParams.computeUnitsBufferMultiplier) !== null && _a !== void 0 ? _a : 1.2, txParams.lowerBoundCu);
3870
+ const simulationResult = await txParamProcessor_1.TransactionParamProcessor.getTxSimComputeUnits(placeAndTakeTxToSim, this.connection, (_b = txParams.computeUnitsBufferMultiplier) !== null && _b !== void 0 ? _b : 1.2, txParams.lowerBoundCu);
3685
3871
  if (shouldExitIfSimulationFails && !simulationResult.success) {
3686
3872
  earlyExitFailedPlaceAndTakeSim = true;
3687
3873
  return;
@@ -6486,5 +6672,18 @@ class DriftClient {
6486
6672
  forceVersionedTransaction,
6487
6673
  });
6488
6674
  }
6675
+ isOrderIncreasingPosition(orderParams, subAccountId) {
6676
+ const userAccount = this.getUserAccount(subAccountId);
6677
+ const perpPosition = userAccount.perpPositions.find((p) => p.marketIndex === orderParams.marketIndex);
6678
+ if (!perpPosition)
6679
+ return true;
6680
+ const currentBase = perpPosition.baseAssetAmount;
6681
+ if (currentBase.eq(numericConstants_1.ZERO))
6682
+ return true;
6683
+ const orderBaseAmount = (0, types_1.isVariant)(orderParams.direction, 'long')
6684
+ ? orderParams.baseAssetAmount
6685
+ : orderParams.baseAssetAmount.neg();
6686
+ return currentBase.add(orderBaseAmount).abs().gt(currentBase.abs());
6687
+ }
6489
6688
  }
6490
6689
  exports.DriftClient = DriftClient;