@drift-labs/sdk 2.83.0-beta.1 → 2.83.0-beta.11

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 (56) hide show
  1. package/VERSION +1 -1
  2. package/lib/adminClient.d.ts +2 -2
  3. package/lib/adminClient.js +7 -9
  4. package/lib/clock/clockSubscriber.d.ts +4 -2
  5. package/lib/clock/clockSubscriber.js +8 -2
  6. package/lib/decode/phoenix.d.ts +6 -0
  7. package/lib/decode/phoenix.js +159 -0
  8. package/lib/driftClient.d.ts +5 -2
  9. package/lib/driftClient.js +92 -47
  10. package/lib/idl/drift.json +63 -0
  11. package/lib/index.d.ts +1 -0
  12. package/lib/index.js +1 -0
  13. package/lib/math/auction.js +2 -2
  14. package/lib/math/market.js +4 -1
  15. package/lib/math/orders.js +1 -1
  16. package/lib/phoenix/phoenixSubscriber.d.ts +2 -0
  17. package/lib/phoenix/phoenixSubscriber.js +15 -2
  18. package/lib/priorityFee/priorityFeeSubscriber.js +1 -1
  19. package/lib/tx/baseTxSender.d.ts +5 -2
  20. package/lib/tx/baseTxSender.js +30 -1
  21. package/lib/tx/fastSingleTxSender.d.ts +1 -1
  22. package/lib/tx/fastSingleTxSender.js +1 -0
  23. package/lib/tx/forwardOnlyTxSender.d.ts +1 -1
  24. package/lib/tx/retryTxSender.d.ts +1 -1
  25. package/lib/tx/retryTxSender.js +1 -0
  26. package/lib/tx/txHandler.d.ts +2 -0
  27. package/lib/tx/txHandler.js +16 -9
  28. package/lib/tx/types.d.ts +2 -1
  29. package/lib/tx/whileValidTxSender.d.ts +1 -1
  30. package/lib/tx/whileValidTxSender.js +1 -0
  31. package/lib/types.d.ts +9 -0
  32. package/lib/types.js +6 -1
  33. package/lib/util/computeUnits.d.ts +7 -1
  34. package/lib/util/computeUnits.js +31 -1
  35. package/package.json +1 -1
  36. package/src/adminClient.ts +12 -10
  37. package/src/clock/clockSubscriber.ts +12 -4
  38. package/src/decode/phoenix.ts +207 -0
  39. package/src/driftClient.ts +188 -104
  40. package/src/idl/drift.json +63 -0
  41. package/src/index.ts +1 -0
  42. package/src/math/auction.ts +2 -2
  43. package/src/math/market.ts +4 -1
  44. package/src/math/orders.ts +5 -2
  45. package/src/phoenix/phoenixSubscriber.ts +15 -3
  46. package/src/priorityFee/priorityFeeSubscriber.ts +1 -1
  47. package/src/tx/baseTxSender.ts +59 -2
  48. package/src/tx/fastSingleTxSender.ts +2 -1
  49. package/src/tx/forwardOnlyTxSender.ts +1 -1
  50. package/src/tx/retryTxSender.ts +4 -1
  51. package/src/tx/txHandler.ts +19 -7
  52. package/src/tx/types.ts +11 -0
  53. package/src/tx/whileValidTxSender.ts +4 -1
  54. package/src/types.ts +6 -0
  55. package/src/util/computeUnits.ts +43 -1
  56. package/tests/decode/phoenix.ts +71 -0
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.83.0-beta.1
1
+ 2.83.0-beta.11
@@ -7,10 +7,10 @@ export declare class AdminClient extends DriftClient {
7
7
  initialize(usdcMint: PublicKey, _adminControlsPrices: boolean): Promise<[TransactionSignature]>;
8
8
  initializeSpotMarket(mint: PublicKey, optimalUtilization: number, optimalRate: number, maxRate: number, oracle: PublicKey, oracleSource: OracleSource, initialAssetWeight: number, maintenanceAssetWeight: number, initialLiabilityWeight: number, maintenanceLiabilityWeight: number, imfFactor?: number, liquidatorFee?: number, ifLiquidationFee?: number, activeStatus?: boolean, assetTier?: {
9
9
  collateral: {};
10
- }, scaleInitialAssetWeightStart?: BN, withdrawGuardThreshold?: BN, orderTickSize?: BN, orderStepSize?: BN, ifTotalFactor?: number, name?: string): Promise<TransactionSignature>;
10
+ }, scaleInitialAssetWeightStart?: BN, withdrawGuardThreshold?: BN, orderTickSize?: BN, orderStepSize?: BN, ifTotalFactor?: number, name?: string, marketIndex?: number): Promise<TransactionSignature>;
11
11
  getInitializeSpotMarketIx(mint: PublicKey, optimalUtilization: number, optimalRate: number, maxRate: number, oracle: PublicKey, oracleSource: OracleSource, initialAssetWeight: number, maintenanceAssetWeight: number, initialLiabilityWeight: number, maintenanceLiabilityWeight: number, imfFactor?: number, liquidatorFee?: number, ifLiquidationFee?: number, activeStatus?: boolean, assetTier?: {
12
12
  collateral: {};
13
- }, scaleInitialAssetWeightStart?: BN, withdrawGuardThreshold?: BN, orderTickSize?: BN, orderStepSize?: BN, ifTotalFactor?: number, name?: string): Promise<TransactionInstruction>;
13
+ }, scaleInitialAssetWeightStart?: BN, withdrawGuardThreshold?: BN, orderTickSize?: BN, orderStepSize?: BN, ifTotalFactor?: number, name?: string, marketIndex?: number): Promise<TransactionInstruction>;
14
14
  deleteInitializedSpotMarket(marketIndex: number): Promise<TransactionSignature>;
15
15
  getDeleteInitializedSpotMarketIx(marketIndex: number): Promise<TransactionInstruction>;
16
16
  initializeSerumFulfillmentConfig(marketIndex: number, serumMarket: PublicKey, serumProgram: PublicKey): Promise<TransactionSignature>;
@@ -61,12 +61,11 @@ class AdminClient extends driftClient_1.DriftClient {
61
61
  const { txSig } = await super.sendTransaction(tx, [], this.opts);
62
62
  return [txSig];
63
63
  }
64
- async initializeSpotMarket(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor = 0, liquidatorFee = 0, ifLiquidationFee = 0, activeStatus = true, assetTier = types_1.AssetTier.COLLATERAL, scaleInitialAssetWeightStart = numericConstants_1.ZERO, withdrawGuardThreshold = numericConstants_1.ZERO, orderTickSize = numericConstants_1.ONE, orderStepSize = numericConstants_1.ONE, ifTotalFactor = 0, name = userName_1.DEFAULT_MARKET_NAME) {
65
- const spotMarketIndex = this.getStateAccount().numberOfSpotMarkets;
66
- const initializeIx = await this.getInitializeSpotMarketIx(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor, liquidatorFee, ifLiquidationFee, activeStatus, assetTier, scaleInitialAssetWeightStart, withdrawGuardThreshold, orderTickSize, orderStepSize, ifTotalFactor, name);
64
+ async initializeSpotMarket(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor = 0, liquidatorFee = 0, ifLiquidationFee = 0, activeStatus = true, assetTier = types_1.AssetTier.COLLATERAL, scaleInitialAssetWeightStart = numericConstants_1.ZERO, withdrawGuardThreshold = numericConstants_1.ZERO, orderTickSize = numericConstants_1.ONE, orderStepSize = numericConstants_1.ONE, ifTotalFactor = 0, name = userName_1.DEFAULT_MARKET_NAME, marketIndex) {
65
+ const spotMarketIndex = marketIndex !== null && marketIndex !== void 0 ? marketIndex : this.getStateAccount().numberOfSpotMarkets;
66
+ const initializeIx = await this.getInitializeSpotMarketIx(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor, liquidatorFee, ifLiquidationFee, activeStatus, assetTier, scaleInitialAssetWeightStart, withdrawGuardThreshold, orderTickSize, orderStepSize, ifTotalFactor, name, marketIndex);
67
67
  const tx = await this.buildTransaction(initializeIx);
68
68
  const { txSig } = await this.sendTransaction(tx, [], this.opts);
69
- // const { txSig } = await this.sendTransaction(initializeTx, [], this.opts);
70
69
  await this.accountSubscriber.addSpotMarket(spotMarketIndex);
71
70
  await this.accountSubscriber.addOracle({
72
71
  source: oracleSource,
@@ -75,8 +74,8 @@ class AdminClient extends driftClient_1.DriftClient {
75
74
  await this.accountSubscriber.setSpotOracleMap();
76
75
  return txSig;
77
76
  }
78
- async getInitializeSpotMarketIx(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor = 0, liquidatorFee = 0, ifLiquidationFee = 0, activeStatus = true, assetTier = types_1.AssetTier.COLLATERAL, scaleInitialAssetWeightStart = numericConstants_1.ZERO, withdrawGuardThreshold = numericConstants_1.ZERO, orderTickSize = numericConstants_1.ONE, orderStepSize = numericConstants_1.ONE, ifTotalFactor = 0, name = userName_1.DEFAULT_MARKET_NAME) {
79
- const spotMarketIndex = this.getStateAccount().numberOfSpotMarkets;
77
+ async getInitializeSpotMarketIx(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor = 0, liquidatorFee = 0, ifLiquidationFee = 0, activeStatus = true, assetTier = types_1.AssetTier.COLLATERAL, scaleInitialAssetWeightStart = numericConstants_1.ZERO, withdrawGuardThreshold = numericConstants_1.ZERO, orderTickSize = numericConstants_1.ONE, orderStepSize = numericConstants_1.ONE, ifTotalFactor = 0, name = userName_1.DEFAULT_MARKET_NAME, marketIndex) {
78
+ const spotMarketIndex = marketIndex !== null && marketIndex !== void 0 ? marketIndex : this.getStateAccount().numberOfSpotMarkets;
80
79
  const spotMarket = await (0, pda_1.getSpotMarketPublicKey)(this.program.programId, spotMarketIndex);
81
80
  const spotMarketVault = await (0, pda_1.getSpotMarketVaultPublicKey)(this.program.programId, spotMarketIndex);
82
81
  const insuranceFundVault = await (0, pda_1.getInsuranceFundVaultPublicKey)(this.program.programId, spotMarketIndex);
@@ -184,7 +183,7 @@ class AdminClient extends driftClient_1.DriftClient {
184
183
  while (this.getStateAccount().numberOfMarkets <= currentPerpMarketIndex) {
185
184
  await this.fetchAccounts();
186
185
  }
187
- await this.accountSubscriber.addPerpMarket(currentPerpMarketIndex);
186
+ await this.accountSubscriber.addPerpMarket(marketIndex);
188
187
  await this.accountSubscriber.addOracle({
189
188
  source: oracleSource,
190
189
  publicKey: priceOracle,
@@ -193,8 +192,7 @@ class AdminClient extends driftClient_1.DriftClient {
193
192
  return txSig;
194
193
  }
195
194
  async getInitializePerpMarketIx(marketIndex, priceOracle, baseAssetReserve, quoteAssetReserve, periodicity, pegMultiplier = numericConstants_1.PEG_PRECISION, oracleSource = types_1.OracleSource.PYTH, contractTier = types_1.ContractTier.SPECULATIVE, marginRatioInitial = 2000, marginRatioMaintenance = 500, liquidatorFee = 0, ifLiquidatorFee = 10000, imfFactor = 0, activeStatus = true, baseSpread = 0, maxSpread = 142500, maxOpenInterest = numericConstants_1.ZERO, maxRevenueWithdrawPerPeriod = numericConstants_1.ZERO, quoteMaxInsurance = numericConstants_1.ZERO, orderStepSize = numericConstants_1.BASE_PRECISION.divn(10000), orderTickSize = numericConstants_1.PRICE_PRECISION.divn(100000), minOrderSize = numericConstants_1.BASE_PRECISION.divn(10000), concentrationCoefScale = numericConstants_1.ONE, curveUpdateIntensity = 0, ammJitIntensity = 0, name = userName_1.DEFAULT_MARKET_NAME) {
196
- const currentPerpMarketIndex = this.getStateAccount().numberOfMarkets;
197
- const perpMarketPublicKey = await (0, pda_1.getPerpMarketPublicKey)(this.program.programId, currentPerpMarketIndex);
195
+ const perpMarketPublicKey = await (0, pda_1.getPerpMarketPublicKey)(this.program.programId, marketIndex);
198
196
  const nameBuffer = (0, userName_1.encodeName)(name);
199
197
  return await this.program.instruction.initializePerpMarket(marketIndex, baseAssetReserve, quoteAssetReserve, periodicity, pegMultiplier, oracleSource, contractTier, marginRatioInitial, marginRatioMaintenance, liquidatorFee, ifLiquidatorFee, imfFactor, activeStatus, baseSpread, maxSpread, maxOpenInterest, maxRevenueWithdrawPerPeriod, quoteMaxInsurance, orderStepSize, orderTickSize, minOrderSize, concentrationCoefScale, curveUpdateIntensity, ammJitIntensity, nameBuffer, {
200
198
  accounts: {
@@ -11,11 +11,13 @@ export interface ClockSubscriberEvent {
11
11
  }
12
12
  export declare class ClockSubscriber {
13
13
  private connection;
14
- private latestSlot;
15
- currentTs: number;
14
+ private _latestSlot;
15
+ private _currentTs;
16
16
  private subscriptionId;
17
17
  commitment: Commitment;
18
18
  eventEmitter: StrictEventEmitter<EventEmitter, ClockSubscriberEvent>;
19
+ get latestSlot(): number;
20
+ get currentTs(): number;
19
21
  private timeoutId?;
20
22
  private resubTimeoutMs?;
21
23
  private isUnsubscribing;
@@ -5,6 +5,12 @@ const web3_js_1 = require("@solana/web3.js");
5
5
  const events_1 = require("events");
6
6
  const __1 = require("..");
7
7
  class ClockSubscriber {
8
+ get latestSlot() {
9
+ return this._latestSlot;
10
+ }
11
+ get currentTs() {
12
+ return this._currentTs;
13
+ }
8
14
  constructor(connection, config) {
9
15
  this.connection = connection;
10
16
  this.isUnsubscribing = false;
@@ -27,8 +33,8 @@ class ClockSubscriber {
27
33
  clearTimeout(this.timeoutId);
28
34
  this.setTimeout();
29
35
  }
30
- this.latestSlot = context.slot;
31
- this.currentTs = new __1.BN(acctInfo.data.subarray(32, 39), undefined, 'le').toNumber();
36
+ this._latestSlot = context.slot;
37
+ this._currentTs = new __1.BN(acctInfo.data.subarray(32, 39), undefined, 'le').toNumber();
32
38
  this.eventEmitter.emit('clockUpdate', this.currentTs);
33
39
  }
34
40
  }, this.commitment);
@@ -0,0 +1,6 @@
1
+ /// <reference types="node" />
2
+ import { MarketData, OrderId, RestingOrder } from '@ellipsis-labs/phoenix-sdk';
3
+ import * as beet from '@metaplex-foundation/beet';
4
+ export declare const orderIdBeet: beet.BeetArgsStruct<OrderId>;
5
+ export declare const restingOrderBeet: beet.BeetArgsStruct<RestingOrder>;
6
+ export declare const fastDecode: (buffer: Buffer) => MarketData;
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.fastDecode = exports.restingOrderBeet = exports.orderIdBeet = void 0;
27
+ const phoenix_sdk_1 = require("@ellipsis-labs/phoenix-sdk");
28
+ const beet = __importStar(require("@metaplex-foundation/beet"));
29
+ exports.orderIdBeet = new beet.BeetArgsStruct([
30
+ ['priceInTicks', beet.u64],
31
+ ['orderSequenceNumber', beet.u64],
32
+ ], 'fIFOOrderId');
33
+ exports.restingOrderBeet = new beet.BeetArgsStruct([
34
+ ['traderIndex', beet.u64],
35
+ ['numBaseLots', beet.u64],
36
+ ['lastValidSlot', beet.u64],
37
+ ['lastValidUnixTimestampInSeconds', beet.u64],
38
+ ], 'fIFORestingOrder');
39
+ function deserializeRedBlackTree(data, keyDeserializer, valueDeserializer) {
40
+ const tree = new Map();
41
+ const treeNodes = deserializeRedBlackTreeNodes(data, keyDeserializer, valueDeserializer);
42
+ const nodes = treeNodes[0];
43
+ const freeNodes = treeNodes[1];
44
+ for (const [index, [key, value]] of nodes.entries()) {
45
+ if (!freeNodes.has(index)) {
46
+ tree.set(key, value);
47
+ }
48
+ }
49
+ return tree;
50
+ }
51
+ function deserializeRedBlackTreeNodes(data, keyDeserializer, valueDeserializer) {
52
+ let offset = 0;
53
+ const keySize = keyDeserializer.byteSize;
54
+ const valueSize = valueDeserializer.byteSize;
55
+ const nodes = new Array();
56
+ // Skip RBTree header
57
+ offset += 16;
58
+ // Skip node allocator size
59
+ offset += 8;
60
+ const bumpIndex = data.readInt32LE(offset);
61
+ offset += 4;
62
+ let freeListHead = data.readInt32LE(offset);
63
+ offset += 4;
64
+ const freeListPointers = new Array();
65
+ for (let index = 0; offset < data.length && index < bumpIndex - 1; index++) {
66
+ const registers = new Array();
67
+ for (let i = 0; i < 4; i++) {
68
+ registers.push(data.readInt32LE(offset)); // skip padding
69
+ offset += 4;
70
+ }
71
+ const [key] = keyDeserializer.deserialize(data.subarray(offset, offset + keySize));
72
+ offset += keySize;
73
+ const [value] = valueDeserializer.deserialize(data.subarray(offset, offset + valueSize));
74
+ offset += valueSize;
75
+ nodes.push([key, value]);
76
+ freeListPointers.push([index, registers[0]]);
77
+ }
78
+ const freeNodes = new Set();
79
+ let indexToRemove = freeListHead - 1;
80
+ let counter = 0;
81
+ // If there's an infinite loop here, that means that the state is corrupted
82
+ while (freeListHead < bumpIndex) {
83
+ // We need to subtract 1 because the node allocator is 1-indexed
84
+ const next = freeListPointers[freeListHead - 1];
85
+ [indexToRemove, freeListHead] = next;
86
+ freeNodes.add(indexToRemove);
87
+ counter += 1;
88
+ if (counter > bumpIndex) {
89
+ throw new Error('Infinite loop detected');
90
+ }
91
+ }
92
+ return [nodes, freeNodes];
93
+ }
94
+ const fastDecode = (buffer) => {
95
+ let offset = phoenix_sdk_1.marketHeaderBeet.byteSize;
96
+ const [header] = phoenix_sdk_1.marketHeaderBeet.deserialize(buffer.subarray(0, offset));
97
+ const paddingLen = 8 * 32;
98
+ let remaining = buffer.subarray(offset + paddingLen);
99
+ offset = 0;
100
+ const baseLotsPerBaseUnit = Number(remaining.readBigUInt64LE(offset));
101
+ offset += 8;
102
+ const quoteLotsPerBaseUnitPerTick = Number(remaining.readBigUInt64LE(offset));
103
+ offset += 8;
104
+ const sequenceNumber = Number(remaining.readBigUInt64LE(offset));
105
+ offset += 8;
106
+ const takerFeeBps = Number(remaining.readBigUInt64LE(offset));
107
+ offset += 8;
108
+ const collectedQuoteLotFees = Number(remaining.readBigUInt64LE(offset));
109
+ offset += 8;
110
+ const unclaimedQuoteLotFees = Number(remaining.readBigUInt64LE(offset));
111
+ offset += 8;
112
+ remaining = remaining.subarray(offset);
113
+ const totalNumBids = (0, phoenix_sdk_1.toNum)(header.marketSizeParams.bidsSize);
114
+ const totalNumAsks = (0, phoenix_sdk_1.toNum)(header.marketSizeParams.asksSize);
115
+ const totalBidsSize = 16 +
116
+ 16 +
117
+ (16 + exports.orderIdBeet.byteSize + exports.restingOrderBeet.byteSize) * totalNumBids;
118
+ const totalAsksSize = 16 +
119
+ 16 +
120
+ (16 + exports.orderIdBeet.byteSize + exports.restingOrderBeet.byteSize) * totalNumAsks;
121
+ offset = 0;
122
+ const bidBuffer = remaining.subarray(offset, offset + totalBidsSize);
123
+ offset += totalBidsSize;
124
+ const askBuffer = remaining.subarray(offset, offset + totalAsksSize);
125
+ const bidsUnsorted = deserializeRedBlackTree(bidBuffer, exports.orderIdBeet, exports.restingOrderBeet);
126
+ const asksUnsorted = deserializeRedBlackTree(askBuffer, exports.orderIdBeet, exports.restingOrderBeet);
127
+ const bids = [...bidsUnsorted].sort((a, b) => {
128
+ const priceComparison = (0, phoenix_sdk_1.sign)((0, phoenix_sdk_1.toBN)(b[0].priceInTicks).sub((0, phoenix_sdk_1.toBN)(a[0].priceInTicks)));
129
+ if (priceComparison !== 0) {
130
+ return priceComparison;
131
+ }
132
+ return (0, phoenix_sdk_1.sign)((0, phoenix_sdk_1.getUiOrderSequenceNumber)(a[0]).sub((0, phoenix_sdk_1.getUiOrderSequenceNumber)(b[0])));
133
+ });
134
+ const asks = [...asksUnsorted].sort((a, b) => {
135
+ const priceComparison = (0, phoenix_sdk_1.sign)((0, phoenix_sdk_1.toBN)(a[0].priceInTicks).sub((0, phoenix_sdk_1.toBN)(b[0].priceInTicks)));
136
+ if (priceComparison !== 0) {
137
+ return priceComparison;
138
+ }
139
+ return (0, phoenix_sdk_1.sign)((0, phoenix_sdk_1.getUiOrderSequenceNumber)(a[0]).sub((0, phoenix_sdk_1.getUiOrderSequenceNumber)(b[0])));
140
+ });
141
+ const traders = new Map();
142
+ const traderPubkeyToTraderIndex = new Map();
143
+ const traderIndexToTraderPubkey = new Map();
144
+ return {
145
+ header,
146
+ baseLotsPerBaseUnit,
147
+ quoteLotsPerBaseUnitPerTick,
148
+ sequenceNumber,
149
+ takerFeeBps,
150
+ collectedQuoteLotFees,
151
+ unclaimedQuoteLotFees,
152
+ bids,
153
+ asks,
154
+ traders,
155
+ traderPubkeyToTraderIndex,
156
+ traderIndexToTraderPubkey,
157
+ };
158
+ };
159
+ exports.fastDecode = fastDecode;
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="bn.js" />
3
3
  import { AnchorProvider, BN, Program, ProgramAccount } from '@coral-xyz/anchor';
4
- import { StateAccount, IWallet, PositionDirection, UserAccount, PerpMarketAccount, OrderParams, Order, SpotMarketAccount, SpotPosition, MakerInfo, TakerInfo, OptionalOrderParams, ReferrerInfo, MarketType, TxParams, SerumV3FulfillmentConfigAccount, ReferrerNameAccount, OrderTriggerCondition, PerpMarketExtendedInfo, UserStatsAccount, PhoenixV1FulfillmentConfigAccount, ModifyOrderPolicy, SwapReduceOnly } from './types';
4
+ import { StateAccount, IWallet, PositionDirection, UserAccount, PerpMarketAccount, OrderParams, Order, SpotMarketAccount, SpotPosition, MakerInfo, TakerInfo, OptionalOrderParams, ReferrerInfo, MarketType, TxParams, SerumV3FulfillmentConfigAccount, ReferrerNameAccount, OrderTriggerCondition, PerpMarketExtendedInfo, UserStatsAccount, PhoenixV1FulfillmentConfigAccount, ModifyOrderPolicy, SwapReduceOnly, SettlePnlMode } from './types';
5
5
  import * as anchor from '@coral-xyz/anchor';
6
6
  import { Connection, PublicKey, TransactionSignature, ConfirmOptions, Transaction, TransactionInstruction, AccountMeta, Signer, AddressLookupTableAccount, TransactionVersion, VersionedTransaction, BlockhashWithExpiryBlockHeight } from '@solana/web3.js';
7
7
  import { TokenFaucet } from './tokenFaucet';
@@ -447,7 +447,7 @@ export declare class DriftClient {
447
447
  updateUserOpenOrdersCount(userAccountPublicKey: PublicKey, user: UserAccount, txParams?: TxParams, fillerPublicKey?: PublicKey): Promise<TransactionSignature>;
448
448
  getUpdateUserOpenOrdersCountIx(userAccountPublicKey: PublicKey, userAccount: UserAccount, fillerPublicKey?: PublicKey): Promise<TransactionInstruction>;
449
449
  placeAndTakePerpOrder(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
450
- placeAndTakePerpWithAdditionalOrders(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, bracketOrdersParams?: OptionalOrderParams[], txParams?: TxParams, subAccountId?: number, cancelExistingOrders?: boolean, settlePnl?: boolean, simulateFirst?: boolean): Promise<{
450
+ placeAndTakePerpWithAdditionalOrders(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, bracketOrdersParams?: OptionalOrderParams[], txParams?: TxParams, subAccountId?: number, cancelExistingOrders?: boolean, settlePnl?: boolean, exitEarlyIfSimFails?: boolean): Promise<{
451
451
  txSig: TransactionSignature;
452
452
  signedCancelExistingOrdersTx?: Transaction;
453
453
  signedSettlePnlTx?: Transaction;
@@ -600,6 +600,8 @@ export declare class DriftClient {
600
600
  }[], marketIndexes: number[]): Promise<Array<TransactionInstruction>>;
601
601
  settlePNL(settleeUserAccountPublicKey: PublicKey, settleeUserAccount: UserAccount, marketIndex: number, txParams?: TxParams): Promise<TransactionSignature>;
602
602
  settlePNLIx(settleeUserAccountPublicKey: PublicKey, settleeUserAccount: UserAccount, marketIndex: number): Promise<TransactionInstruction>;
603
+ settleMultiplePNLs(settleeUserAccountPublicKey: PublicKey, settleeUserAccount: UserAccount, marketIndexes: number[], mode: SettlePnlMode, txParams?: TxParams): Promise<TransactionSignature>;
604
+ settleMultiplePNLsIx(settleeUserAccountPublicKey: PublicKey, settleeUserAccount: UserAccount, marketIndexes: number[], mode: SettlePnlMode): Promise<TransactionInstruction>;
603
605
  liquidatePerp(userAccountPublicKey: PublicKey, userAccount: UserAccount, marketIndex: number, maxBaseAssetAmount: BN, limitPrice?: BN, txParams?: TxParams, liquidatorSubAccountId?: number): Promise<TransactionSignature>;
604
606
  getLiquidatePerpIx(userAccountPublicKey: PublicKey, userAccount: UserAccount, marketIndex: number, maxBaseAssetAmount: BN, limitPrice?: BN, liquidatorSubAccountId?: number): Promise<TransactionInstruction>;
605
607
  liquidateSpot(userAccountPublicKey: PublicKey, userAccount: UserAccount, assetMarketIndex: number, liabilityMarketIndex: number, maxLiabilityTransfer: BN, limitPrice?: BN, txParams?: TxParams, liquidatorSubAccountId?: number): Promise<TransactionSignature>;
@@ -680,6 +682,7 @@ export declare class DriftClient {
680
682
  marketType: MarketType;
681
683
  } | undefined;
682
684
  private handleSignedTransaction;
685
+ private handlePreSignedTransaction;
683
686
  private isVersionedTransaction;
684
687
  sendTransaction(tx: Transaction | VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
685
688
  buildTransaction(instructions: TransactionInstruction | TransactionInstruction[], txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[], forceVersionedTransaction?: boolean, recentBlockHash?: BlockhashWithExpiryBlockHeight): Promise<Transaction | VersionedTransaction>;
@@ -104,6 +104,7 @@ class DriftClient {
104
104
  opts: {
105
105
  returnBlockHeightsWithSignedTxCallbackData: config.enableMetricsEvents,
106
106
  onSignedCb: this.handleSignedTransaction.bind(this),
107
+ preSignedCb: this.handlePreSignedTransaction.bind(this),
107
108
  },
108
109
  });
109
110
  if (config.includeDelegates && config.subAccountIds) {
@@ -2499,63 +2500,82 @@ class DriftClient {
2499
2500
  this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2500
2501
  return txSig;
2501
2502
  }
2502
- async placeAndTakePerpWithAdditionalOrders(orderParams, makerInfo, referrerInfo, bracketOrdersParams = new Array(), txParams, subAccountId, cancelExistingOrders, settlePnl, simulateFirst) {
2503
- var _a;
2503
+ async placeAndTakePerpWithAdditionalOrders(orderParams, makerInfo, referrerInfo, bracketOrdersParams = new Array(), txParams, subAccountId, cancelExistingOrders, settlePnl, exitEarlyIfSimFails) {
2504
2504
  const placeAndTakeIxs = [];
2505
- const placeAndTakeIx = await this.getPlaceAndTakePerpOrderIx(orderParams, makerInfo, referrerInfo, subAccountId);
2506
2505
  const txsToSign = [];
2507
2506
  const keys = {
2508
2507
  placeAndTakeIx: 'placeAndTakeIx',
2509
2508
  cancelExistingOrdersTx: 'cancelExistingOrdersTx',
2510
2509
  settlePnlTx: 'settlePnlTx',
2511
2510
  };
2512
- placeAndTakeIxs.push(placeAndTakeIx);
2513
- if (bracketOrdersParams.length > 0) {
2514
- const bracketOrdersIx = await this.getPlaceOrdersIx(bracketOrdersParams, subAccountId);
2515
- placeAndTakeIxs.push(bracketOrdersIx);
2516
- }
2517
- const shouldUseSimulationComputeUnits = txParams === null || txParams === void 0 ? void 0 : txParams.useSimulatedComputeUnits;
2518
- const shouldExitIfSimulationFails = simulateFirst;
2519
- const txParamsWithoutImplicitSimulation = {
2520
- ...txParams,
2521
- useSimulatedComputeUnits: false,
2522
- };
2523
2511
  // Get recent block hash so that we can re-use it for all transactions. Makes this logic run faster with fewer RPC requests
2524
2512
  const recentBlockHash = await this.txHandler.getLatestBlockhashForTransaction();
2525
- if (shouldUseSimulationComputeUnits || shouldExitIfSimulationFails) {
2526
- const placeAndTakeTxToSim = (await this.buildTransaction(placeAndTakeIxs, txParamsWithoutImplicitSimulation, undefined, undefined, true, recentBlockHash));
2527
- const simulationResult = await txParamProcessor_1.TransactionParamProcessor.getTxSimComputeUnits(placeAndTakeTxToSim, this.connection, (_a = txParams.computeUnitsBufferMultiplier) !== null && _a !== void 0 ? _a : 1.2);
2528
- if (shouldExitIfSimulationFails && !simulationResult.success) {
2529
- return;
2513
+ let earlyExitFailedPlaceAndTakeSim = false;
2514
+ const prepPlaceAndTakeTx = async () => {
2515
+ var _a;
2516
+ const placeAndTakeIx = await this.getPlaceAndTakePerpOrderIx(orderParams, makerInfo, referrerInfo, subAccountId);
2517
+ placeAndTakeIxs.push(placeAndTakeIx);
2518
+ if (bracketOrdersParams.length > 0) {
2519
+ const bracketOrdersIx = await this.getPlaceOrdersIx(bracketOrdersParams, subAccountId);
2520
+ placeAndTakeIxs.push(bracketOrdersIx);
2530
2521
  }
2531
- txsToSign.push({
2532
- key: keys.placeAndTakeIx,
2533
- tx: await this.buildTransaction(placeAndTakeIxs, {
2534
- ...txParamsWithoutImplicitSimulation,
2535
- computeUnits: simulationResult.computeUnits,
2536
- }, undefined, undefined, undefined, recentBlockHash),
2537
- });
2538
- }
2539
- else {
2540
- txsToSign.push({
2541
- key: keys.placeAndTakeIx,
2542
- tx: await this.buildTransaction(placeAndTakeIxs, txParams, undefined, undefined, undefined, recentBlockHash),
2543
- });
2544
- }
2545
- if (cancelExistingOrders && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
2546
- const cancelOrdersIx = await this.getCancelOrdersIx(orderParams.marketType, orderParams.marketIndex, null, subAccountId);
2547
- txsToSign.push({
2548
- key: keys.cancelExistingOrdersTx,
2549
- tx: await this.buildTransaction([cancelOrdersIx], txParams, this.txVersion, undefined, undefined, recentBlockHash),
2550
- });
2551
- }
2552
- if (settlePnl && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
2553
- const userAccountPublicKey = await this.getUserAccountPublicKey(subAccountId);
2554
- const settlePnlIx = await this.settlePNLIx(userAccountPublicKey, this.getUserAccount(subAccountId), orderParams.marketIndex);
2555
- txsToSign.push({
2556
- key: keys.settlePnlTx,
2557
- tx: await this.buildTransaction([settlePnlIx], txParams, this.txVersion, undefined, undefined, recentBlockHash),
2558
- });
2522
+ const shouldUseSimulationComputeUnits = txParams === null || txParams === void 0 ? void 0 : txParams.useSimulatedComputeUnits;
2523
+ const shouldExitIfSimulationFails = exitEarlyIfSimFails;
2524
+ const txParamsWithoutImplicitSimulation = {
2525
+ ...txParams,
2526
+ useSimulatedComputeUnits: false,
2527
+ };
2528
+ if (shouldUseSimulationComputeUnits || shouldExitIfSimulationFails) {
2529
+ const placeAndTakeTxToSim = (await this.buildTransaction(placeAndTakeIxs, txParams, undefined, undefined, true, recentBlockHash));
2530
+ const simulationResult = await txParamProcessor_1.TransactionParamProcessor.getTxSimComputeUnits(placeAndTakeTxToSim, this.connection, (_a = txParams.computeUnitsBufferMultiplier) !== null && _a !== void 0 ? _a : 1.2);
2531
+ if (shouldExitIfSimulationFails && !simulationResult.success) {
2532
+ earlyExitFailedPlaceAndTakeSim = true;
2533
+ return;
2534
+ }
2535
+ txsToSign.push({
2536
+ key: keys.placeAndTakeIx,
2537
+ tx: await this.buildTransaction(placeAndTakeIxs, {
2538
+ ...txParamsWithoutImplicitSimulation,
2539
+ computeUnits: simulationResult.computeUnits,
2540
+ }, undefined, undefined, undefined, recentBlockHash),
2541
+ });
2542
+ }
2543
+ else {
2544
+ txsToSign.push({
2545
+ key: keys.placeAndTakeIx,
2546
+ tx: await this.buildTransaction(placeAndTakeIxs, txParams, undefined, undefined, undefined, recentBlockHash),
2547
+ });
2548
+ }
2549
+ return;
2550
+ };
2551
+ const prepCancelOrderTx = async () => {
2552
+ if (cancelExistingOrders && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
2553
+ const cancelOrdersIx = await this.getCancelOrdersIx(orderParams.marketType, orderParams.marketIndex, null, subAccountId);
2554
+ txsToSign.push({
2555
+ key: keys.cancelExistingOrdersTx,
2556
+ tx: await this.buildTransaction([cancelOrdersIx], txParams, this.txVersion, undefined, undefined, recentBlockHash),
2557
+ });
2558
+ }
2559
+ return;
2560
+ };
2561
+ const prepSettlePnlTx = async () => {
2562
+ if (settlePnl && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
2563
+ const userAccountPublicKey = await this.getUserAccountPublicKey(subAccountId);
2564
+ const settlePnlIx = await this.settlePNLIx(userAccountPublicKey, this.getUserAccount(subAccountId), orderParams.marketIndex);
2565
+ txsToSign.push({
2566
+ key: keys.settlePnlTx,
2567
+ tx: await this.buildTransaction([settlePnlIx], txParams, this.txVersion, undefined, undefined, recentBlockHash),
2568
+ });
2569
+ }
2570
+ return;
2571
+ };
2572
+ await Promise.all([
2573
+ prepPlaceAndTakeTx(),
2574
+ prepCancelOrderTx(),
2575
+ prepSettlePnlTx(),
2576
+ ]);
2577
+ if (earlyExitFailedPlaceAndTakeSim) {
2578
+ return null;
2559
2579
  }
2560
2580
  const signedTxs = await this.txHandler.getSignedTransactionMap(txsToSign.map((tx) => tx.tx), txsToSign.map((tx) => tx.key), this.provider.wallet);
2561
2581
  const { txSig, slot } = await this.sendTransaction(signedTxs[keys.placeAndTakeIx], [], this.opts, true);
@@ -2984,6 +3004,26 @@ class DriftClient {
2984
3004
  remainingAccounts: remainingAccounts,
2985
3005
  });
2986
3006
  }
3007
+ async settleMultiplePNLs(settleeUserAccountPublicKey, settleeUserAccount, marketIndexes, mode, txParams) {
3008
+ const { txSig } = await this.sendTransaction(await this.buildTransaction(await this.settleMultiplePNLsIx(settleeUserAccountPublicKey, settleeUserAccount, marketIndexes, mode), txParams), [], this.opts);
3009
+ return txSig;
3010
+ }
3011
+ async settleMultiplePNLsIx(settleeUserAccountPublicKey, settleeUserAccount, marketIndexes, mode) {
3012
+ const remainingAccounts = this.getRemainingAccounts({
3013
+ userAccounts: [settleeUserAccount],
3014
+ writablePerpMarketIndexes: marketIndexes,
3015
+ writableSpotMarketIndexes: [numericConstants_1.QUOTE_SPOT_MARKET_INDEX],
3016
+ });
3017
+ return await this.program.instruction.settleMultiplePnls(marketIndexes, mode, {
3018
+ accounts: {
3019
+ state: await this.getStatePublicKey(),
3020
+ authority: this.wallet.publicKey,
3021
+ user: settleeUserAccountPublicKey,
3022
+ spotMarketVault: this.getQuoteSpotMarketAccount().vault,
3023
+ },
3024
+ remainingAccounts: remainingAccounts,
3025
+ });
3026
+ }
2987
3027
  async liquidatePerp(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount, limitPrice, txParams, liquidatorSubAccountId) {
2988
3028
  const { txSig, slot } = await this.sendTransaction(await this.buildTransaction(await this.getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount, limitPrice, liquidatorSubAccountId), txParams), [], this.opts);
2989
3029
  this.perpMarketLastSlotCache.set(marketIndex, slot);
@@ -3574,6 +3614,11 @@ class DriftClient {
3574
3614
  this.metricsEventEmitter.emit('txSigned', signedTxs);
3575
3615
  }
3576
3616
  }
3617
+ handlePreSignedTransaction() {
3618
+ if (this.enableMetricsEvents && this.metricsEventEmitter) {
3619
+ this.metricsEventEmitter.emit('preTxSigned');
3620
+ }
3621
+ }
3577
3622
  isVersionedTransaction(tx) {
3578
3623
  const version = tx === null || tx === void 0 ? void 0 : tx.version;
3579
3624
  const isVersionedTx = tx instanceof web3_js_1.VersionedTransaction || version !== undefined;
@@ -1527,6 +1527,45 @@
1527
1527
  }
1528
1528
  ]
1529
1529
  },
1530
+ {
1531
+ "name": "settleMultiplePnls",
1532
+ "accounts": [
1533
+ {
1534
+ "name": "state",
1535
+ "isMut": false,
1536
+ "isSigner": false
1537
+ },
1538
+ {
1539
+ "name": "user",
1540
+ "isMut": true,
1541
+ "isSigner": false
1542
+ },
1543
+ {
1544
+ "name": "authority",
1545
+ "isMut": false,
1546
+ "isSigner": true
1547
+ },
1548
+ {
1549
+ "name": "spotMarketVault",
1550
+ "isMut": false,
1551
+ "isSigner": false
1552
+ }
1553
+ ],
1554
+ "args": [
1555
+ {
1556
+ "name": "marketIndexes",
1557
+ "type": {
1558
+ "vec": "u16"
1559
+ }
1560
+ },
1561
+ {
1562
+ "name": "mode",
1563
+ "type": {
1564
+ "defined": "SettlePnlMode"
1565
+ }
1566
+ }
1567
+ ]
1568
+ },
1530
1569
  {
1531
1570
  "name": "settleFundingPayment",
1532
1571
  "accounts": [
@@ -9411,6 +9450,20 @@
9411
9450
  ]
9412
9451
  }
9413
9452
  },
9453
+ {
9454
+ "name": "SettlePnlMode",
9455
+ "type": {
9456
+ "kind": "enum",
9457
+ "variants": [
9458
+ {
9459
+ "name": "MustSettle"
9460
+ },
9461
+ {
9462
+ "name": "TrySettle"
9463
+ }
9464
+ ]
9465
+ }
9466
+ },
9414
9467
  {
9415
9468
  "name": "SpotBalanceType",
9416
9469
  "type": {
@@ -11899,6 +11952,16 @@
11899
11952
  "code": 6258,
11900
11953
  "name": "InsuranceFundOperationPaused",
11901
11954
  "msg": "InsuranceFundOperationPaused"
11955
+ },
11956
+ {
11957
+ "code": 6259,
11958
+ "name": "NoUnsettledPnl",
11959
+ "msg": "NoUnsettledPnl"
11960
+ },
11961
+ {
11962
+ "code": 6260,
11963
+ "name": "PnlPoolCantSettleUser",
11964
+ "msg": "PnlPoolCantSettleUser"
11902
11965
  }
11903
11966
  ]
11904
11967
  }
package/lib/index.d.ts CHANGED
@@ -77,6 +77,7 @@ export * from './tx/whileValidTxSender';
77
77
  export * from './tx/priorityFeeCalculator';
78
78
  export * from './tx/forwardOnlyTxSender';
79
79
  export * from './tx/types';
80
+ export * from './tx/txHandler';
80
81
  export * from './util/computeUnits';
81
82
  export * from './util/tps';
82
83
  export * from './util/promiseTimeout';
package/lib/index.js CHANGED
@@ -100,6 +100,7 @@ __exportStar(require("./tx/whileValidTxSender"), exports);
100
100
  __exportStar(require("./tx/priorityFeeCalculator"), exports);
101
101
  __exportStar(require("./tx/forwardOnlyTxSender"), exports);
102
102
  __exportStar(require("./tx/types"), exports);
103
+ __exportStar(require("./tx/txHandler"), exports);
103
104
  __exportStar(require("./util/computeUnits"), exports);
104
105
  __exportStar(require("./util/tps"), exports);
105
106
  __exportStar(require("./util/promiseTimeout"), exports);
@@ -69,7 +69,7 @@ function getAuctionPriceForOracleOffsetAuction(order, slot, oraclePrice) {
69
69
  const deltaDenominator = new _1.BN(order.auctionDuration);
70
70
  const deltaNumerator = _1.BN.min(slotsElapsed, deltaDenominator);
71
71
  if (deltaDenominator.eq(_1.ZERO)) {
72
- return oraclePrice.add(order.auctionEndPrice);
72
+ return _1.BN.max(oraclePrice.add(order.auctionEndPrice), _1.ONE);
73
73
  }
74
74
  let priceOffsetDelta;
75
75
  if ((0, types_1.isVariant)(order.direction, 'long')) {
@@ -91,7 +91,7 @@ function getAuctionPriceForOracleOffsetAuction(order, slot, oraclePrice) {
91
91
  else {
92
92
  priceOffset = order.auctionStartPrice.sub(priceOffsetDelta);
93
93
  }
94
- return oraclePrice.add(priceOffset);
94
+ return _1.BN.max(oraclePrice.add(priceOffset), _1.ONE);
95
95
  }
96
96
  exports.getAuctionPriceForOracleOffsetAuction = getAuctionPriceForOracleOffsetAuction;
97
97
  function deriveOracleAuctionParams({ direction, oraclePrice, auctionStartPrice, auctionEndPrice, limitPrice, }) {
@@ -112,10 +112,13 @@ function calculateMarketMaxAvailableInsurance(perpMarket, spotMarket) {
112
112
  exports.calculateMarketMaxAvailableInsurance = calculateMarketMaxAvailableInsurance;
113
113
  function calculateNetUserPnl(perpMarket, oraclePriceData) {
114
114
  const netUserPositionValue = perpMarket.amm.baseAssetAmountWithAmm
115
+ .add(perpMarket.amm.baseAssetAmountWithUnsettledLp)
115
116
  .mul(oraclePriceData.price)
116
117
  .div(numericConstants_1.BASE_PRECISION)
117
118
  .div(numericConstants_1.PRICE_TO_QUOTE_PRECISION);
118
- const netUserCostBasis = perpMarket.amm.quoteAssetAmount;
119
+ const netUserCostBasis = perpMarket.amm.quoteAssetAmount
120
+ .add(perpMarket.amm.quoteAssetAmountWithUnsettledLp)
121
+ .add(perpMarket.amm.netUnsettledFundingPnl);
119
122
  const netUserPnl = netUserPositionValue.add(netUserCostBasis);
120
123
  return netUserPnl;
121
124
  }
@@ -102,7 +102,7 @@ function getLimitPrice(order, oraclePriceData, slot, fallbackPrice) {
102
102
  limitPrice = (0, auction_1.getAuctionPrice)(order, slot, oraclePriceData.price);
103
103
  }
104
104
  else if (order.oraclePriceOffset !== 0) {
105
- limitPrice = oraclePriceData.price.add(new anchor_1.BN(order.oraclePriceOffset));
105
+ limitPrice = anchor_1.BN.max(oraclePriceData.price.add(new anchor_1.BN(order.oraclePriceOffset)), numericConstants_1.ONE);
106
106
  }
107
107
  else if (order.price.eq(numericConstants_1.ZERO)) {
108
108
  limitPrice = fallbackPrice;