@drift-labs/sdk 2.40.0-beta.1 → 2.40.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 (55) hide show
  1. package/README.md +0 -1
  2. package/VERSION +1 -1
  3. package/bun.lockb +0 -0
  4. package/lib/accounts/types.d.ts +5 -1
  5. package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -1
  6. package/lib/accounts/webSocketAccountSubscriber.js +28 -2
  7. package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +2 -1
  8. package/lib/accounts/webSocketDriftClientAccountSubscriber.js +6 -5
  9. package/lib/accounts/webSocketProgramAccountSubscriber.d.ts +32 -0
  10. package/lib/accounts/webSocketProgramAccountSubscriber.js +99 -0
  11. package/lib/accounts/webSocketUserAccountSubscriber.d.ts +2 -1
  12. package/lib/accounts/webSocketUserAccountSubscriber.js +3 -2
  13. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +2 -1
  14. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +3 -2
  15. package/lib/auctionSubscriber/auctionSubscriber.d.ts +3 -2
  16. package/lib/auctionSubscriber/auctionSubscriber.js +15 -7
  17. package/lib/auctionSubscriber/types.d.ts +1 -0
  18. package/lib/driftClient.d.ts +2 -1
  19. package/lib/driftClient.js +5 -4
  20. package/lib/driftClientConfig.d.ts +1 -0
  21. package/lib/idl/drift.json +51 -0
  22. package/lib/jupiter/jupiterClient.d.ts +3 -1
  23. package/lib/jupiter/jupiterClient.js +3 -1
  24. package/lib/math/amm.js +7 -2
  25. package/lib/math/superStake.d.ts +51 -4
  26. package/lib/math/superStake.js +173 -21
  27. package/lib/math/utils.d.ts +1 -0
  28. package/lib/math/utils.js +10 -1
  29. package/lib/orderSubscriber/OrderSubscriber.d.ts +1 -3
  30. package/lib/orderSubscriber/OrderSubscriber.js +4 -3
  31. package/lib/orderSubscriber/WebsocketSubscription.d.ts +4 -2
  32. package/lib/orderSubscriber/WebsocketSubscription.js +15 -12
  33. package/lib/orderSubscriber/types.d.ts +1 -0
  34. package/lib/user.d.ts +2 -2
  35. package/lib/user.js +5 -5
  36. package/package.json +1 -1
  37. package/src/accounts/types.ts +8 -1
  38. package/src/accounts/webSocketAccountSubscriber.ts +36 -2
  39. package/src/accounts/webSocketDriftClientAccountSubscriber.ts +15 -5
  40. package/src/accounts/webSocketProgramAccountSubscriber.ts +152 -0
  41. package/src/accounts/webSocketUserAccountSubscriber.ts +10 -2
  42. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +10 -2
  43. package/src/auctionSubscriber/auctionSubscriber.ts +30 -21
  44. package/src/auctionSubscriber/types.ts +1 -0
  45. package/src/driftClient.ts +5 -1
  46. package/src/driftClientConfig.ts +1 -0
  47. package/src/idl/drift.json +51 -0
  48. package/src/jupiter/jupiterClient.ts +3 -0
  49. package/src/math/amm.ts +9 -2
  50. package/src/math/superStake.ts +248 -24
  51. package/src/math/utils.ts +12 -0
  52. package/src/orderSubscriber/OrderSubscriber.ts +12 -7
  53. package/src/orderSubscriber/WebsocketSubscription.ts +34 -23
  54. package/src/orderSubscriber/types.ts +1 -0
  55. package/src/user.ts +7 -5
@@ -31,6 +31,7 @@ export class WebSocketDriftClientAccountSubscriber
31
31
  oracleInfos: OracleInfo[];
32
32
  oracleClientCache = new OracleClientCache();
33
33
 
34
+ resubTimeoutMs?: number;
34
35
  shouldFindAllMarketsAndOracles: boolean;
35
36
 
36
37
  eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
@@ -54,7 +55,8 @@ export class WebSocketDriftClientAccountSubscriber
54
55
  perpMarketIndexes: number[],
55
56
  spotMarketIndexes: number[],
56
57
  oracleInfos: OracleInfo[],
57
- shouldFindAllMarketsAndOracles: boolean
58
+ shouldFindAllMarketsAndOracles: boolean,
59
+ resubTimeoutMs?: number
58
60
  ) {
59
61
  this.isSubscribed = false;
60
62
  this.program = program;
@@ -63,6 +65,7 @@ export class WebSocketDriftClientAccountSubscriber
63
65
  this.spotMarketIndexes = spotMarketIndexes;
64
66
  this.oracleInfos = oracleInfos;
65
67
  this.shouldFindAllMarketsAndOracles = shouldFindAllMarketsAndOracles;
68
+ this.resubTimeoutMs = resubTimeoutMs;
66
69
  }
67
70
 
68
71
  public async subscribe(): Promise<boolean> {
@@ -96,7 +99,9 @@ export class WebSocketDriftClientAccountSubscriber
96
99
  this.stateAccountSubscriber = new WebSocketAccountSubscriber(
97
100
  'state',
98
101
  this.program,
99
- statePublicKey
102
+ statePublicKey,
103
+ undefined,
104
+ this.resubTimeoutMs
100
105
  );
101
106
  await this.stateAccountSubscriber.subscribe((data: StateAccount) => {
102
107
  this.eventEmitter.emit('stateAccountUpdate', data);
@@ -136,7 +141,9 @@ export class WebSocketDriftClientAccountSubscriber
136
141
  const accountSubscriber = new WebSocketAccountSubscriber<PerpMarketAccount>(
137
142
  'perpMarket',
138
143
  this.program,
139
- perpMarketPublicKey
144
+ perpMarketPublicKey,
145
+ undefined,
146
+ this.resubTimeoutMs
140
147
  );
141
148
  await accountSubscriber.subscribe((data: PerpMarketAccount) => {
142
149
  this.eventEmitter.emit('perpMarketAccountUpdate', data);
@@ -161,7 +168,9 @@ export class WebSocketDriftClientAccountSubscriber
161
168
  const accountSubscriber = new WebSocketAccountSubscriber<SpotMarketAccount>(
162
169
  'spotMarket',
163
170
  this.program,
164
- marketPublicKey
171
+ marketPublicKey,
172
+ undefined,
173
+ this.resubTimeoutMs
165
174
  );
166
175
  await accountSubscriber.subscribe((data: SpotMarketAccount) => {
167
176
  this.eventEmitter.emit('spotMarketAccountUpdate', data);
@@ -192,7 +201,8 @@ export class WebSocketDriftClientAccountSubscriber
192
201
  oracleInfo.publicKey,
193
202
  (buffer: Buffer) => {
194
203
  return client.getOraclePriceDataFromBuffer(buffer);
195
- }
204
+ },
205
+ this.resubTimeoutMs
196
206
  );
197
207
 
198
208
  await accountSubscriber.subscribe((data: OraclePriceData) => {
@@ -0,0 +1,152 @@
1
+ import { DataAndSlot, BufferAndSlot, ProgramAccountSubscriber } from './types';
2
+ import { AnchorProvider, Program } from '@coral-xyz/anchor';
3
+ import {
4
+ Commitment,
5
+ Context,
6
+ KeyedAccountInfo,
7
+ MemcmpFilter,
8
+ PublicKey,
9
+ } from '@solana/web3.js';
10
+ import * as Buffer from 'buffer';
11
+
12
+ export class WebSocketProgramAccountSubscriber<T>
13
+ implements ProgramAccountSubscriber<T>
14
+ {
15
+ subscriptionName: string;
16
+ accountDiscriminator: string;
17
+ dataAndSlot?: DataAndSlot<T> & { accountId: PublicKey };
18
+ bufferAndSlot?: BufferAndSlot;
19
+ program: Program;
20
+ decodeBuffer: (accountName: string, ix: Buffer) => T;
21
+ onChange: (accountId: PublicKey, data: T, context: Context) => void;
22
+ listenerId?: number;
23
+ resubTimeoutMs?: number;
24
+ timeoutId?: NodeJS.Timeout;
25
+ options: { filters: MemcmpFilter[]; commitment?: Commitment };
26
+
27
+ receivingData = false;
28
+
29
+ public constructor(
30
+ subscriptionName: string,
31
+ accountDiscriminator: string,
32
+ program: Program,
33
+ decodeBufferFn: (accountName: string, ix: Buffer) => T,
34
+ options: { filters: MemcmpFilter[]; commitment?: Commitment } = {
35
+ filters: [],
36
+ },
37
+ resubTimeoutMs?: number
38
+ ) {
39
+ this.subscriptionName = subscriptionName;
40
+ this.accountDiscriminator = accountDiscriminator;
41
+ this.program = program;
42
+ this.decodeBuffer = decodeBufferFn;
43
+ this.resubTimeoutMs = resubTimeoutMs;
44
+ this.options = options;
45
+ this.receivingData = false;
46
+ }
47
+
48
+ async subscribe(
49
+ onChange: (accountId: PublicKey, data: T, context: Context) => void
50
+ ): Promise<void> {
51
+ if (this.listenerId) {
52
+ return;
53
+ }
54
+
55
+ this.onChange = onChange;
56
+
57
+ this.listenerId = this.program.provider.connection.onProgramAccountChange(
58
+ this.program.programId,
59
+ (keyedAccountInfo, context) => {
60
+ if (this.resubTimeoutMs) {
61
+ this.receivingData = true;
62
+ clearTimeout(this.timeoutId);
63
+ this.handleRpcResponse(context, keyedAccountInfo);
64
+ this.setTimeout();
65
+ } else {
66
+ this.handleRpcResponse(context, keyedAccountInfo);
67
+ }
68
+ },
69
+ this.options.commitment ??
70
+ (this.program.provider as AnchorProvider).opts.commitment,
71
+ this.options.filters
72
+ );
73
+
74
+ if (this.resubTimeoutMs) {
75
+ this.setTimeout();
76
+ }
77
+ }
78
+
79
+ private setTimeout(): void {
80
+ if (!this.onChange) {
81
+ throw new Error('onChange callback function must be set');
82
+ }
83
+ this.timeoutId = setTimeout(async () => {
84
+ if (this.receivingData) {
85
+ console.log(
86
+ `No ws data from ${this.subscriptionName} in ${this.resubTimeoutMs}ms, resubscribing`
87
+ );
88
+ await this.unsubscribe();
89
+ this.receivingData = false;
90
+ await this.subscribe(this.onChange);
91
+ }
92
+ }, this.resubTimeoutMs);
93
+ }
94
+
95
+ handleRpcResponse(
96
+ context: Context,
97
+ keyedAccountInfo: KeyedAccountInfo
98
+ ): void {
99
+ const newSlot = context.slot;
100
+ let newBuffer: Buffer | undefined = undefined;
101
+ if (keyedAccountInfo) {
102
+ newBuffer = keyedAccountInfo.accountInfo.data;
103
+ }
104
+
105
+ if (!this.bufferAndSlot) {
106
+ this.bufferAndSlot = {
107
+ buffer: newBuffer,
108
+ slot: newSlot,
109
+ };
110
+ if (newBuffer) {
111
+ const account = this.decodeBuffer(this.accountDiscriminator, newBuffer);
112
+ this.dataAndSlot = {
113
+ data: account,
114
+ slot: newSlot,
115
+ accountId: keyedAccountInfo.accountId,
116
+ };
117
+ this.onChange(keyedAccountInfo.accountId, account, context);
118
+ }
119
+ return;
120
+ }
121
+
122
+ if (newSlot <= this.bufferAndSlot.slot) {
123
+ return;
124
+ }
125
+
126
+ const oldBuffer = this.bufferAndSlot.buffer;
127
+ if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
128
+ this.bufferAndSlot = {
129
+ buffer: newBuffer,
130
+ slot: newSlot,
131
+ };
132
+ const account = this.decodeBuffer(this.accountDiscriminator, newBuffer);
133
+ this.dataAndSlot = {
134
+ data: account,
135
+ slot: newSlot,
136
+ accountId: keyedAccountInfo.accountId,
137
+ };
138
+ this.onChange(keyedAccountInfo.accountId, account, context);
139
+ }
140
+ }
141
+
142
+ unsubscribe(): Promise<void> {
143
+ if (this.listenerId) {
144
+ const promise =
145
+ this.program.provider.connection.removeAccountChangeListener(
146
+ this.listenerId
147
+ );
148
+ this.listenerId = undefined;
149
+ return promise;
150
+ }
151
+ }
152
+ }
@@ -14,17 +14,23 @@ import { UserAccount } from '../types';
14
14
 
15
15
  export class WebSocketUserAccountSubscriber implements UserAccountSubscriber {
16
16
  isSubscribed: boolean;
17
+ reconnectTimeoutMs?: number;
17
18
  program: Program;
18
19
  eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
19
20
  userAccountPublicKey: PublicKey;
20
21
 
21
22
  userDataAccountSubscriber: AccountSubscriber<UserAccount>;
22
23
 
23
- public constructor(program: Program, userAccountPublicKey: PublicKey) {
24
+ public constructor(
25
+ program: Program,
26
+ userAccountPublicKey: PublicKey,
27
+ reconnectTimeoutMs?: number
28
+ ) {
24
29
  this.isSubscribed = false;
25
30
  this.program = program;
26
31
  this.userAccountPublicKey = userAccountPublicKey;
27
32
  this.eventEmitter = new EventEmitter();
33
+ this.reconnectTimeoutMs = reconnectTimeoutMs;
28
34
  }
29
35
 
30
36
  async subscribe(userAccount?: UserAccount): Promise<boolean> {
@@ -35,7 +41,9 @@ export class WebSocketUserAccountSubscriber implements UserAccountSubscriber {
35
41
  this.userDataAccountSubscriber = new WebSocketAccountSubscriber(
36
42
  'user',
37
43
  this.program,
38
- this.userAccountPublicKey
44
+ this.userAccountPublicKey,
45
+ undefined,
46
+ this.reconnectTimeoutMs
39
47
  );
40
48
 
41
49
  if (userAccount) {
@@ -16,17 +16,23 @@ export class WebSocketUserStatsAccountSubscriber
16
16
  implements UserStatsAccountSubscriber
17
17
  {
18
18
  isSubscribed: boolean;
19
+ reconnectTimeoutMs?: number;
19
20
  program: Program;
20
21
  eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
21
22
  userStatsAccountPublicKey: PublicKey;
22
23
 
23
24
  userStatsAccountSubscriber: AccountSubscriber<UserStatsAccount>;
24
25
 
25
- public constructor(program: Program, userStatsAccountPublicKey: PublicKey) {
26
+ public constructor(
27
+ program: Program,
28
+ userStatsAccountPublicKey: PublicKey,
29
+ reconnectTimeoutMs?: number
30
+ ) {
26
31
  this.isSubscribed = false;
27
32
  this.program = program;
28
33
  this.userStatsAccountPublicKey = userStatsAccountPublicKey;
29
34
  this.eventEmitter = new EventEmitter();
35
+ this.reconnectTimeoutMs = reconnectTimeoutMs;
30
36
  }
31
37
 
32
38
  async subscribe(userStatsAccount?: UserStatsAccount): Promise<boolean> {
@@ -37,7 +43,9 @@ export class WebSocketUserStatsAccountSubscriber
37
43
  this.userStatsAccountSubscriber = new WebSocketAccountSubscriber(
38
44
  'userStats',
39
45
  this.program,
40
- this.userStatsAccountPublicKey
46
+ this.userStatsAccountPublicKey,
47
+ undefined,
48
+ this.reconnectTimeoutMs
41
49
  );
42
50
 
43
51
  if (userStatsAccount) {
@@ -4,48 +4,57 @@ import { getUserFilter, getUserWithAuctionFilter } from '../memcmp';
4
4
  import StrictEventEmitter from 'strict-event-emitter-types';
5
5
  import { EventEmitter } from 'events';
6
6
  import { UserAccount } from '../types';
7
- import { ConfirmOptions } from '@solana/web3.js';
7
+ import { ConfirmOptions, Context, PublicKey } from '@solana/web3.js';
8
+ import { WebSocketProgramAccountSubscriber } from '../accounts/webSocketProgramAccountSubscriber';
8
9
 
9
10
  export class AuctionSubscriber {
10
11
  private driftClient: DriftClient;
11
12
  private opts: ConfirmOptions;
13
+ private resubTimeoutMs?: number;
12
14
 
13
15
  eventEmitter: StrictEventEmitter<EventEmitter, AuctionSubscriberEvents>;
16
+ private subscriber: WebSocketProgramAccountSubscriber<UserAccount>;
14
17
 
15
- private websocketId: number;
16
-
17
- constructor({ driftClient, opts }: AuctionSubscriberConfig) {
18
+ constructor({ driftClient, opts, resubTimeoutMs }: AuctionSubscriberConfig) {
18
19
  this.driftClient = driftClient;
19
20
  this.opts = opts || this.driftClient.opts;
20
21
  this.eventEmitter = new EventEmitter();
22
+ this.resubTimeoutMs = resubTimeoutMs;
21
23
  }
22
24
 
23
25
  public async subscribe() {
24
- this.websocketId = this.driftClient.connection.onProgramAccountChange(
25
- this.driftClient.program.programId,
26
- (keyAccountInfo, context) => {
27
- const userAccount =
28
- this.driftClient.program.account.user.coder.accounts.decode(
29
- 'User',
30
- keyAccountInfo.accountInfo.data
31
- ) as UserAccount;
26
+ if (!this.subscriber) {
27
+ this.subscriber = new WebSocketProgramAccountSubscriber<UserAccount>(
28
+ 'AuctionSubscriber',
29
+ 'User',
30
+ this.driftClient.program,
31
+ this.driftClient.program.account.user.coder.accounts.decode.bind(
32
+ this.driftClient.program.account.user.coder.accounts
33
+ ),
34
+ {
35
+ filters: [getUserFilter(), getUserWithAuctionFilter()],
36
+ commitment: this.driftClient.opts.commitment,
37
+ },
38
+ this.resubTimeoutMs
39
+ );
40
+ }
41
+
42
+ await this.subscriber.subscribe(
43
+ (accountId: PublicKey, data: UserAccount, context: Context) => {
32
44
  this.eventEmitter.emit(
33
45
  'onAccountUpdate',
34
- userAccount,
35
- keyAccountInfo.accountId,
46
+ data,
47
+ accountId,
36
48
  context.slot
37
49
  );
38
- },
39
- this.driftClient.opts.commitment,
40
- [getUserFilter(), getUserWithAuctionFilter()]
50
+ }
41
51
  );
42
52
  }
43
53
 
44
54
  public async unsubscribe() {
45
- if (this.websocketId) {
46
- await this.driftClient.connection.removeProgramAccountChangeListener(
47
- this.websocketId
48
- );
55
+ if (!this.subscriber) {
56
+ return;
49
57
  }
58
+ this.subscriber.unsubscribe();
50
59
  }
51
60
  }
@@ -5,6 +5,7 @@ import { ConfirmOptions, PublicKey } from '@solana/web3.js';
5
5
  export type AuctionSubscriberConfig = {
6
6
  driftClient: DriftClient;
7
7
  opts?: ConfirmOptions;
8
+ resubTimeoutMs?: number;
8
9
  };
9
10
 
10
11
  export interface AuctionSubscriberEvents {
@@ -278,7 +278,8 @@ export class DriftClient {
278
278
  config.perpMarketIndexes ?? [],
279
279
  config.spotMarketIndexes ?? [],
280
280
  config.oracleInfos ?? [],
281
- noMarketsAndOraclesSpecified
281
+ noMarketsAndOraclesSpecified,
282
+ config.accountSubscription?.resubTimeoutMs
282
283
  );
283
284
  }
284
285
  this.eventEmitter = this.accountSubscriber.eventEmitter;
@@ -3424,6 +3425,7 @@ export class DriftClient {
3424
3425
  reduceOnly,
3425
3426
  txParams,
3426
3427
  v6,
3428
+ onlyDirectRoutes = false,
3427
3429
  }: {
3428
3430
  jupiterClient: JupiterClient;
3429
3431
  outMarketIndex: number;
@@ -3436,6 +3438,7 @@ export class DriftClient {
3436
3438
  route?: Route;
3437
3439
  reduceOnly?: SwapReduceOnly;
3438
3440
  txParams?: TxParams;
3441
+ onlyDirectRoutes?: boolean;
3439
3442
  v6?: {
3440
3443
  quote?: QuoteResponse;
3441
3444
  };
@@ -3455,6 +3458,7 @@ export class DriftClient {
3455
3458
  swapMode,
3456
3459
  quote: v6.quote,
3457
3460
  reduceOnly,
3461
+ onlyDirectRoutes,
3458
3462
  });
3459
3463
  ixs = res.ixs;
3460
3464
  lookupTables = res.lookupTables;
@@ -36,6 +36,7 @@ export type DriftClientConfig = {
36
36
  export type DriftClientSubscriptionConfig =
37
37
  | {
38
38
  type: 'websocket';
39
+ resubTimeoutMs?: number;
39
40
  }
40
41
  | {
41
42
  type: 'polling';
@@ -6314,6 +6314,24 @@
6314
6314
  ]
6315
6315
  }
6316
6316
  },
6317
+ {
6318
+ "name": "MarketIdentifier",
6319
+ "type": {
6320
+ "kind": "struct",
6321
+ "fields": [
6322
+ {
6323
+ "name": "marketType",
6324
+ "type": {
6325
+ "defined": "MarketType"
6326
+ }
6327
+ },
6328
+ {
6329
+ "name": "marketIndex",
6330
+ "type": "u16"
6331
+ }
6332
+ ]
6333
+ }
6334
+ },
6317
6335
  {
6318
6336
  "name": "HistoricalOracleData",
6319
6337
  "type": {
@@ -8198,6 +8216,34 @@
8198
8216
  ]
8199
8217
  }
8200
8218
  },
8219
+ {
8220
+ "name": "MarginCalculationMode",
8221
+ "type": {
8222
+ "kind": "enum",
8223
+ "variants": [
8224
+ {
8225
+ "name": "Standard"
8226
+ },
8227
+ {
8228
+ "name": "Liquidation",
8229
+ "fields": [
8230
+ {
8231
+ "name": "margin_buffer",
8232
+ "type": "u128"
8233
+ },
8234
+ {
8235
+ "name": "market_to_track_margin_requirement",
8236
+ "type": {
8237
+ "option": {
8238
+ "defined": "MarketIdentifier"
8239
+ }
8240
+ }
8241
+ }
8242
+ ]
8243
+ }
8244
+ ]
8245
+ }
8246
+ },
8201
8247
  {
8202
8248
  "name": "OracleSource",
8203
8249
  "type": {
@@ -10781,6 +10827,11 @@
10781
10827
  "code": 6254,
10782
10828
  "name": "UserReduceOnly",
10783
10829
  "msg": "UserReduceOnly"
10830
+ },
10831
+ {
10832
+ "code": 6255,
10833
+ "name": "InvalidMarginCalculation",
10834
+ "msg": "InvalidMarginCalculation"
10784
10835
  }
10785
10836
  ]
10786
10837
  }
@@ -275,6 +275,7 @@ export class JupiterClient {
275
275
  inputMint,
276
276
  outputMint,
277
277
  amount,
278
+ maxAccounts = 52, // 52 is an estimated amount with buffer
278
279
  slippageBps = 50,
279
280
  swapMode = 'ExactIn',
280
281
  onlyDirectRoutes = false,
@@ -282,6 +283,7 @@ export class JupiterClient {
282
283
  inputMint: PublicKey;
283
284
  outputMint: PublicKey;
284
285
  amount: BN;
286
+ maxAccounts?: number;
285
287
  slippageBps?: number;
286
288
  swapMode?: SwapMode;
287
289
  onlyDirectRoutes?: boolean;
@@ -293,6 +295,7 @@ export class JupiterClient {
293
295
  slippageBps: slippageBps.toString(),
294
296
  swapMode,
295
297
  onlyDirectRoutes: onlyDirectRoutes.toString(),
298
+ maxAccounts: maxAccounts.toString(),
296
299
  }).toString();
297
300
  const quote = await (await fetch(`${this.url}/v6/quote?${params}`)).json();
298
301
  return quote;
package/src/math/amm.ts CHANGED
@@ -471,12 +471,19 @@ export function calculateVolSpreadBN(
471
471
  clampMax
472
472
  );
473
473
 
474
+ // only consider confidence interval at full value when above 25 bps
475
+ let confComponent = lastOracleConfPct;
476
+
477
+ if (lastOracleConfPct.lte(PRICE_PRECISION.div(new BN(400)))) {
478
+ confComponent = lastOracleConfPct.div(new BN(10));
479
+ }
480
+
474
481
  const longVolSpread = BN.max(
475
- lastOracleConfPct,
482
+ confComponent,
476
483
  volSpread.mul(longVolSpreadFactor).div(PERCENTAGE_PRECISION)
477
484
  );
478
485
  const shortVolSpread = BN.max(
479
- lastOracleConfPct,
486
+ confComponent,
480
487
  volSpread.mul(shortVolSpreadFactor).div(PERCENTAGE_PRECISION)
481
488
  );
482
489