@drift-labs/sdk 2.42.0-beta.8 → 2.43.0-beta.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 (71) hide show
  1. package/VERSION +1 -1
  2. package/bun.lockb +0 -0
  3. package/lib/accounts/bulkAccountLoader.d.ts +1 -2
  4. package/lib/addresses/pda.d.ts +1 -0
  5. package/lib/adminClient.d.ts +1 -0
  6. package/lib/config.d.ts +1 -0
  7. package/lib/config.js +1 -0
  8. package/lib/constants/numericConstants.d.ts +62 -60
  9. package/lib/constants/perpMarkets.js +42 -2
  10. package/lib/constants/spotMarkets.d.ts +1 -0
  11. package/lib/dlob/DLOB.d.ts +10 -16
  12. package/lib/dlob/DLOB.js +9 -39
  13. package/lib/dlob/DLOBNode.d.ts +1 -0
  14. package/lib/dlob/NodeList.d.ts +1 -0
  15. package/lib/dlob/orderBookLevels.d.ts +2 -1
  16. package/lib/driftClient.d.ts +10 -2
  17. package/lib/driftClient.js +20 -18
  18. package/lib/events/fetchLogs.js +2 -0
  19. package/lib/factory/bigNum.d.ts +8 -7
  20. package/lib/idl/drift.json +251 -239
  21. package/lib/index.d.ts +3 -0
  22. package/lib/index.js +3 -0
  23. package/lib/jupiter/jupiterClient.d.ts +1 -0
  24. package/lib/marinade/index.d.ts +1 -0
  25. package/lib/math/amm.d.ts +2 -1
  26. package/lib/math/auction.d.ts +1 -0
  27. package/lib/math/conversion.d.ts +2 -1
  28. package/lib/math/funding.d.ts +1 -0
  29. package/lib/math/funding.js +1 -1
  30. package/lib/math/insurance.d.ts +1 -0
  31. package/lib/math/margin.d.ts +1 -0
  32. package/lib/math/market.d.ts +1 -0
  33. package/lib/math/oracles.d.ts +1 -0
  34. package/lib/math/orders.d.ts +1 -0
  35. package/lib/math/position.d.ts +1 -0
  36. package/lib/math/repeg.d.ts +1 -0
  37. package/lib/math/spotBalance.d.ts +3 -2
  38. package/lib/math/spotMarket.d.ts +1 -0
  39. package/lib/math/spotPosition.d.ts +1 -0
  40. package/lib/math/superStake.d.ts +1 -0
  41. package/lib/math/trade.d.ts +1 -0
  42. package/lib/math/utils.d.ts +1 -0
  43. package/lib/oracles/pythClient.d.ts +2 -1
  44. package/lib/oracles/strictOraclePrice.d.ts +1 -0
  45. package/lib/oracles/types.d.ts +1 -0
  46. package/lib/orderParams.d.ts +1 -0
  47. package/lib/orderSubscriber/PollingSubscription.d.ts +1 -2
  48. package/lib/phoenix/phoenixSubscriber.d.ts +1 -0
  49. package/lib/priorityFee/priorityFeeSubscriber.d.ts +1 -2
  50. package/lib/serum/serumSubscriber.d.ts +1 -0
  51. package/lib/tokenFaucet.d.ts +1 -0
  52. package/lib/types.d.ts +6 -14
  53. package/lib/types.js +6 -7
  54. package/lib/user.d.ts +6 -5
  55. package/lib/user.js +17 -11
  56. package/package.json +2 -1
  57. package/src/accounts/bulkAccountLoader.ts +1 -1
  58. package/src/config.ts +2 -0
  59. package/src/constants/perpMarkets.ts +42 -2
  60. package/src/dlob/DLOB.ts +23 -67
  61. package/src/driftClient.ts +41 -27
  62. package/src/events/fetchLogs.ts +3 -0
  63. package/src/events/pollingLogProvider.ts +1 -1
  64. package/src/idl/drift.json +251 -239
  65. package/src/index.ts +3 -0
  66. package/src/math/funding.ts +1 -1
  67. package/src/orderSubscriber/PollingSubscription.ts +1 -1
  68. package/src/priorityFee/priorityFeeSubscriber.ts +1 -1
  69. package/src/types.ts +5 -6
  70. package/src/user.ts +49 -42
  71. package/tests/user/helpers.ts +1 -2
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import { SpotMarketAccount, SpotBalanceType, MarginCategory } from '../types';
2
3
  import { BN } from '@coral-xyz/anchor';
3
4
  import { OraclePriceData } from '../oracles/types';
@@ -50,7 +51,7 @@ export declare function getTokenValue(tokenAmount: BN, spotDecimals: number, ora
50
51
  export declare function calculateAssetWeight(balanceAmount: BN, oraclePrice: BN, spotMarket: SpotMarketAccount, marginCategory: MarginCategory): BN;
51
52
  export declare function calculateScaledInitialAssetWeight(spotMarket: SpotMarketAccount, oraclePrice: BN): BN;
52
53
  export declare function calculateLiabilityWeight(size: BN, spotMarket: SpotMarketAccount, marginCategory: MarginCategory): BN;
53
- export declare function calculateUtilization(bank: SpotMarketAccount, delta?: any): BN;
54
+ export declare function calculateUtilization(bank: SpotMarketAccount, delta?: BN): BN;
54
55
  /**
55
56
  * calculates max borrow amount where rate would stay below targetBorrowRate
56
57
  * @param spotMarketAccount
@@ -61,7 +62,7 @@ export declare function calculateSpotMarketBorrowCapacity(spotMarketAccount: Spo
61
62
  totalCapacity: BN;
62
63
  remainingCapacity: BN;
63
64
  };
64
- export declare function calculateInterestRate(bank: SpotMarketAccount, delta?: any): BN;
65
+ export declare function calculateInterestRate(bank: SpotMarketAccount, delta?: BN): BN;
65
66
  export declare function calculateDepositRate(bank: SpotMarketAccount): BN;
66
67
  export declare function calculateBorrowRate(bank: SpotMarketAccount): BN;
67
68
  export declare function calculateInterestAccumulated(bank: SpotMarketAccount, now: BN): {
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import { BN } from '@coral-xyz/anchor';
2
3
  import { MarginCategory, SpotBalanceType, SpotMarketAccount } from '../types';
3
4
  export declare function castNumberToSpotPrecision(value: number | BN, spotMarket: SpotMarketAccount): BN;
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import { MarginCategory, SpotMarketAccount, SpotPosition } from '../types';
2
3
  import { BN } from '@coral-xyz/anchor';
3
4
  import { StrictOraclePrice } from '../oracles/strictOraclePrice';
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import { AddressLookupTableAccount, PublicKey, TransactionInstruction } from '@solana/web3.js';
2
3
  import { JupiterClient } from '../jupiter/jupiterClient';
3
4
  import { DriftClient } from '../driftClient';
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import { PerpMarketAccount, PositionDirection, SpotMarketAccount } from '../types';
2
3
  import { BN } from '@coral-xyz/anchor';
3
4
  import { AssetType } from './amm';
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import { BN } from '../';
2
3
  export declare function clampBN(x: BN, min: BN, max: BN): BN;
3
4
  export declare const squareRootBN: (n: BN) => BN;
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  /// <reference types="node" />
2
3
  import { Connection, PublicKey } from '@solana/web3.js';
3
4
  import { OracleClient, OraclePriceData } from './types';
@@ -6,7 +7,7 @@ export declare class PythClient implements OracleClient {
6
7
  private connection;
7
8
  private multiple;
8
9
  private stableCoin;
9
- constructor(connection: Connection, multiple?: any, stableCoin?: boolean);
10
+ constructor(connection: Connection, multiple?: BN, stableCoin?: boolean);
10
11
  getOraclePriceData(pricePublicKey: PublicKey): Promise<OraclePriceData>;
11
12
  getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData;
12
13
  }
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import { BN } from '@coral-xyz/anchor';
2
3
  export declare class StrictOraclePrice {
3
4
  current: BN;
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  /// <reference types="node" />
2
3
  import { BN } from '@coral-xyz/anchor';
3
4
  import { PublicKey } from '@solana/web3.js';
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import { OptionalOrderParams, OrderParams, OrderTriggerCondition } from './types';
2
3
  import { BN } from '@coral-xyz/anchor';
3
4
  export declare function getLimitOrderParams(params: Omit<OptionalOrderParams, 'orderType'> & {
@@ -1,9 +1,8 @@
1
- /// <reference types="node" />
2
1
  import { OrderSubscriber } from './OrderSubscriber';
3
2
  export declare class PollingSubscription {
4
3
  private orderSubscriber;
5
4
  private frequency;
6
- intervalId?: NodeJS.Timer;
5
+ intervalId?: ReturnType<typeof setTimeout>;
7
6
  constructor({ orderSubscriber, frequency, }: {
8
7
  orderSubscriber: OrderSubscriber;
9
8
  frequency: number;
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import { Connection, PublicKey } from '@solana/web3.js';
2
3
  import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
3
4
  import { Client, Market } from '@ellipsis-labs/phoenix-sdk';
@@ -1,11 +1,10 @@
1
- /// <reference types="node" />
2
1
  import { Connection, PublicKey } from '@solana/web3.js';
3
2
  export declare class PriorityFeeSubscriber {
4
3
  connection: Connection;
5
4
  frequencyMs: number;
6
5
  addresses: PublicKey[];
7
6
  slotsToCheck: number;
8
- intervalId?: NodeJS.Timer;
7
+ intervalId?: ReturnType<typeof setTimeout>;
9
8
  latestPriorityFee: number;
10
9
  avgPriorityFee: number;
11
10
  maxPriorityFee: number;
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import { Connection, PublicKey } from '@solana/web3.js';
2
3
  import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
3
4
  import { Market, Orderbook } from '@project-serum/serum';
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import * as anchor from '@coral-xyz/anchor';
2
3
  import { AnchorProvider, Program } from '@coral-xyz/anchor';
3
4
  import { Account } from '@solana/spl-token';
package/lib/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /// <reference types="bn.js" />
1
2
  import { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js';
2
3
  import { BN } from '.';
3
4
  export declare enum ExchangeStatus {
@@ -40,19 +41,10 @@ export declare class MarketStatus {
40
41
  delisted: {};
41
42
  };
42
43
  }
43
- export declare class UserStatus {
44
- static readonly ACTIVE: {
45
- active: {};
46
- };
47
- static readonly BEING_LIQUIDATED: {
48
- beingLiquidated: {};
49
- };
50
- static readonly BANKRUPT: {
51
- bankrupt: {};
52
- };
53
- static readonly REDUCE_ONLY: {
54
- reduceOnly: {};
55
- };
44
+ export declare enum UserStatus {
45
+ BEING_LIQUIDATED = 1,
46
+ BANKRUPT = 2,
47
+ REDUCE_ONLY = 4
56
48
  }
57
49
  export declare class ContractType {
58
50
  static readonly PERPETUAL: {
@@ -881,7 +873,7 @@ export type UserAccount = {
881
873
  spotPositions: SpotPosition[];
882
874
  perpPositions: PerpPosition[];
883
875
  orders: Order[];
884
- status: UserStatus;
876
+ status: number;
885
877
  nextLiquidationId: number;
886
878
  nextOrderId: number;
887
879
  maxMarginRatio: number;
package/lib/types.js CHANGED
@@ -27,13 +27,12 @@ MarketStatus.WITHDRAW_PAUSED = { withdrawPaused: {} };
27
27
  MarketStatus.REDUCE_ONLY = { reduceOnly: {} };
28
28
  MarketStatus.SETTLEMENT = { settlement: {} };
29
29
  MarketStatus.DELISTED = { delisted: {} };
30
- class UserStatus {
31
- }
32
- exports.UserStatus = UserStatus;
33
- UserStatus.ACTIVE = { active: {} };
34
- UserStatus.BEING_LIQUIDATED = { beingLiquidated: {} };
35
- UserStatus.BANKRUPT = { bankrupt: {} };
36
- UserStatus.REDUCE_ONLY = { reduceOnly: {} };
30
+ var UserStatus;
31
+ (function (UserStatus) {
32
+ UserStatus[UserStatus["BEING_LIQUIDATED"] = 1] = "BEING_LIQUIDATED";
33
+ UserStatus[UserStatus["BANKRUPT"] = 2] = "BANKRUPT";
34
+ UserStatus[UserStatus["REDUCE_ONLY"] = 4] = "REDUCE_ONLY";
35
+ })(UserStatus = exports.UserStatus || (exports.UserStatus = {}));
37
36
  class ContractType {
38
37
  }
39
38
  exports.ContractType = ContractType;
package/lib/user.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="bn.js" />
2
3
  import { PublicKey } from '@solana/web3.js';
3
4
  import { EventEmitter } from 'events';
4
5
  import StrictEventEmitter from 'strict-event-emitter-types';
5
6
  import { DriftClient } from './driftClient';
6
- import { MarginCategory, Order, UserAccount, PerpPosition, SpotPosition, PerpMarketAccount, HealthComponents } from './types';
7
- import { UserAccountSubscriber, UserAccountEvents, DataAndSlot } from './accounts/types';
8
- import { PositionDirection, BN, SpotMarketAccount, MarketType } from '.';
7
+ import { HealthComponents, MarginCategory, Order, PerpMarketAccount, PerpPosition, SpotPosition, UserAccount } from './types';
8
+ import { DataAndSlot, UserAccountEvents, UserAccountSubscriber } from './accounts/types';
9
+ import { BN, MarketType, PositionDirection, SpotMarketAccount } from '.';
9
10
  import { OraclePriceData } from './oracles/types';
10
11
  import { UserConfig } from './userConfig';
11
12
  import { StrictOraclePrice } from './oracles/strictOraclePrice';
@@ -99,7 +100,7 @@ export declare class User {
99
100
  * calculates Buying Power = free collateral / initial margin ratio
100
101
  * @returns : Precision QUOTE_PRECISION
101
102
  */
102
- getPerpBuyingPower(marketIndex: number, collateralBuffer?: any): BN;
103
+ getPerpBuyingPower(marketIndex: number, collateralBuffer?: BN): BN;
103
104
  getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex: number, freeCollateral: BN, baseAssetAmount: BN): BN;
104
105
  /**
105
106
  * calculates Free Collateral = Total collateral - margin requirement
@@ -365,7 +366,7 @@ export declare class User {
365
366
  depositAmount: BN;
366
367
  maxDepositAmount: BN;
367
368
  };
368
- canMakeIdle(slot: BN, slotsBeforeIdle: BN): boolean;
369
+ canMakeIdle(slot: BN): boolean;
369
370
  getSafestTiers(): {
370
371
  perpTier: number;
371
372
  spotTier: number;
package/lib/user.js CHANGED
@@ -670,9 +670,7 @@ class User {
670
670
  * @returns : number (value from [0, 100])
671
671
  */
672
672
  getHealth() {
673
- const userAccount = this.getUserAccount();
674
- if ((0, types_1.isVariant)(userAccount.status, 'beingLiquidated') ||
675
- (0, types_1.isVariant)(userAccount.status, 'bankrupt')) {
673
+ if (this.isBeingLiquidated()) {
676
674
  return 0;
677
675
  }
678
676
  const totalCollateral = this.getTotalCollateral('Maintenance');
@@ -1004,13 +1002,12 @@ class User {
1004
1002
  };
1005
1003
  }
1006
1004
  isBeingLiquidated() {
1007
- return (0, types_1.isOneOfVariant)(this.getUserAccount().status, [
1008
- 'beingLiquidated',
1009
- 'bankrupt',
1010
- ]);
1005
+ return ((this.getUserAccount().status &
1006
+ (types_1.UserStatus.BEING_LIQUIDATED | types_1.UserStatus.BANKRUPT)) >
1007
+ 0);
1011
1008
  }
1012
1009
  isBankrupt() {
1013
- return (0, types_1.isVariant)(this.getUserAccount().status, 'bankrupt');
1010
+ return (this.getUserAccount().status & types_1.UserStatus.BANKRUPT) > 0;
1014
1011
  }
1015
1012
  /**
1016
1013
  * Checks if any user position cumulative funding differs from respective market cumulative funding
@@ -1335,7 +1332,7 @@ class User {
1335
1332
  const outContributionInitial = this.calculateSpotPositionFreeCollateralContribution(outSpotPosition, outStrictOraclePrice);
1336
1333
  const { totalAssetValue: outTotalAssetValueInitial, totalLiabilityValue: outTotalLiabilityValueInitial, } = this.calculateSpotPositionLeverageContribution(outSpotPosition, outStrictOraclePrice);
1337
1334
  const initialContribution = inContributionInitial.add(outContributionInitial);
1338
- const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } = this.getLeverageComponents(undefined, 'Initial');
1335
+ const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } = this.getLeverageComponents();
1339
1336
  if (!calculateSwap) {
1340
1337
  calculateSwap = (inSwap) => {
1341
1338
  return inSwap
@@ -1490,7 +1487,7 @@ class User {
1490
1487
  this.getEmptySpotPosition(outMarketIndex);
1491
1488
  const { totalAssetValue: inTotalAssetValueInitial, totalLiabilityValue: inTotalLiabilityValueInitial, } = this.calculateSpotPositionLeverageContribution(inSpotPosition, inStrictOraclePrice);
1492
1489
  const { totalAssetValue: outTotalAssetValueInitial, totalLiabilityValue: outTotalLiabilityValueInitial, } = this.calculateSpotPositionLeverageContribution(outSpotPosition, outStrictOraclePrice);
1493
- const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } = this.getLeverageComponents(undefined, 'Initial');
1490
+ const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } = this.getLeverageComponents();
1494
1491
  const inPositionAfter = this.cloneAndUpdateSpotPosition(inSpotPosition, inAmount.abs().neg(), inMarket);
1495
1492
  const outPositionAfter = this.cloneAndUpdateSpotPosition(outSpotPosition, outAmount.abs(), outMarket);
1496
1493
  const { totalAssetValue: inTotalAssetValueAfter, totalLiabilityValue: inTotalLiabilityValueAfter, } = this.calculateSpotPositionLeverageContribution(inPositionAfter, inStrictOraclePrice);
@@ -1741,11 +1738,20 @@ class User {
1741
1738
  depositAmount,
1742
1739
  };
1743
1740
  }
1744
- canMakeIdle(slot, slotsBeforeIdle) {
1741
+ canMakeIdle(slot) {
1745
1742
  const userAccount = this.getUserAccount();
1746
1743
  if (userAccount.idle) {
1747
1744
  return false;
1748
1745
  }
1746
+ const { totalAssetValue, totalLiabilityValue } = this.getSpotMarketAssetAndLiabilityValue();
1747
+ const equity = totalAssetValue.sub(totalLiabilityValue);
1748
+ let slotsBeforeIdle;
1749
+ if (equity.lt(numericConstants_1.QUOTE_PRECISION)) {
1750
+ slotsBeforeIdle = new _1.BN(9000); // 1 hour
1751
+ }
1752
+ else {
1753
+ slotsBeforeIdle = new _1.BN(1512000); // 1 week
1754
+ }
1749
1755
  const userLastActiveSlot = userAccount.lastActiveSlot;
1750
1756
  const slotsSinceLastActive = slot.sub(userLastActiveSlot);
1751
1757
  if (slotsSinceLastActive.lt(slotsBeforeIdle)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.42.0-beta.8",
3
+ "version": "2.43.0-beta.0",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -45,6 +45,7 @@
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/big.js": "^6.2.0",
48
+ "@types/bn.js": "^5.1.3",
48
49
  "@types/chai": "^4.3.1",
49
50
  "@types/jest": "^28.1.3",
50
51
  "@types/mocha": "^9.1.1",
@@ -19,7 +19,7 @@ export class BulkAccountLoader {
19
19
  accountsToLoad = new Map<string, AccountToLoad>();
20
20
  bufferAndSlotMap = new Map<string, BufferAndSlot>();
21
21
  errorCallbacks = new Map<string, (e) => void>();
22
- intervalId?: NodeJS.Timer;
22
+ intervalId?: ReturnType<typeof setTimeout>;
23
23
  // to handle clients spamming load
24
24
  loadPromise?: Promise<void>;
25
25
  loadPromiseResolver: () => void;
package/src/config.ts CHANGED
@@ -26,6 +26,7 @@ type DriftConfig = {
26
26
  PERP_MARKETS: PerpMarketConfig[];
27
27
  SPOT_MARKETS: SpotMarketConfig[];
28
28
  MARKET_LOOKUP_TABLE: string;
29
+ SERUM_LOOKUP_TABLE?: string;
29
30
  };
30
31
 
31
32
  export type DriftEnv = 'devnet' | 'mainnet-beta';
@@ -60,6 +61,7 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
60
61
  PERP_MARKETS: MainnetPerpMarkets,
61
62
  SPOT_MARKETS: MainnetSpotMarkets,
62
63
  MARKET_LOOKUP_TABLE: 'D9cnvzswDikQDf53k4HpQ3KJ9y1Fv3HGGDFYMXnK5T6c',
64
+ SERUM_LOOKUP_TABLE: 'GPZkp76cJtNL2mphCvT6FXkJCVPpouidnacckR6rzKDN',
63
65
  },
64
66
  };
65
67
 
@@ -161,7 +161,27 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
161
161
  baseAssetSymbol: 'HNT',
162
162
  marketIndex: 14,
163
163
  oracle: new PublicKey('6Eg8YdfFJQF2HHonzPUBSCCmyUEhrStg9VBLK957sBe6'),
164
- launchTs: 16922949550000,
164
+ launchTs: 1692294955000,
165
+ oracleSource: OracleSource.PYTH,
166
+ },
167
+ {
168
+ fullName: 'INJ',
169
+ category: ['L1', 'Exchange'],
170
+ symbol: 'INJ-PERP',
171
+ baseAssetSymbol: 'INJ',
172
+ marketIndex: 15,
173
+ oracle: new PublicKey('44uRsNnT35kjkscSu59MxRr9CfkLZWf6gny8bWqUbVxE'),
174
+ launchTs: 1698074659000,
175
+ oracleSource: OracleSource.PYTH,
176
+ },
177
+ {
178
+ fullName: 'LINK',
179
+ category: ['Oracle'],
180
+ symbol: 'LINK-PERP',
181
+ baseAssetSymbol: 'LINK',
182
+ marketIndex: 16,
183
+ oracle: new PublicKey('9sGidS4qUXS2WvHZFhzw4df1jNd5TvUGZXZVsSjXo7UF'),
184
+ launchTs: 1698074659000,
165
185
  oracleSource: OracleSource.PYTH,
166
186
  },
167
187
  ];
@@ -314,7 +334,27 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
314
334
  baseAssetSymbol: 'HNT',
315
335
  marketIndex: 14,
316
336
  oracle: new PublicKey('7moA1i5vQUpfDwSpK6Pw9s56ahB7WFGidtbL2ujWrVvm'),
317
- launchTs: 16922949550000,
337
+ launchTs: 1692294955000,
338
+ oracleSource: OracleSource.PYTH,
339
+ },
340
+ {
341
+ fullName: 'INJ',
342
+ category: ['L1', 'Exchange'],
343
+ symbol: 'INJ-PERP',
344
+ baseAssetSymbol: 'INJ',
345
+ marketIndex: 15,
346
+ oracle: new PublicKey('9EdtbaivHQYA4Nh3XzGR6DwRaoorqXYnmpfsnFhvwuVj'),
347
+ launchTs: 1698074659000,
348
+ oracleSource: OracleSource.PYTH,
349
+ },
350
+ {
351
+ fullName: 'LINK',
352
+ category: ['Oracle'],
353
+ symbol: 'LINK-PERP',
354
+ baseAssetSymbol: 'LINK',
355
+ marketIndex: 16,
356
+ oracle: new PublicKey('ALdkqQDMfHNg77oCNskfX751kHys4KE7SFuZzuKaN536'),
357
+ launchTs: 1698074659000,
318
358
  oracleSource: OracleSource.PYTH,
319
359
  },
320
360
  ];
package/src/dlob/DLOB.ts CHANGED
@@ -73,6 +73,14 @@ export type MarketNodeLists = {
73
73
 
74
74
  type OrderBookCallback = () => void;
75
75
 
76
+ /**
77
+ * Receives a DLOBNode and is expected to return true if the node should
78
+ * be taken into account when generating, or false otherwise.
79
+ *
80
+ * Currently used in getRestingLimitBids and getRestingLimitAsks.
81
+ */
82
+ export type DLOBFilterFcn = (node: DLOBNode) => boolean;
83
+
76
84
  export type NodeToFill = {
77
85
  node: DLOBNode;
78
86
  makerNodes: DLOBNode[];
@@ -1065,7 +1073,8 @@ export class DLOB {
1065
1073
  currentDLOBNode: DLOBNode,
1066
1074
  slot: number,
1067
1075
  oraclePriceData: OraclePriceData
1068
- ) => boolean
1076
+ ) => boolean,
1077
+ filterFcn?: DLOBFilterFcn
1069
1078
  ): Generator<DLOBNode> {
1070
1079
  const generators = generatorList.map((generator) => {
1071
1080
  return {
@@ -1102,6 +1111,11 @@ export class DLOB {
1102
1111
  continue;
1103
1112
  }
1104
1113
 
1114
+ if (filterFcn && filterFcn(bestGenerator.next.value)) {
1115
+ bestGenerator.next = bestGenerator.generator.next();
1116
+ continue;
1117
+ }
1118
+
1105
1119
  yield bestGenerator.next.value;
1106
1120
  bestGenerator.next = bestGenerator.generator.next();
1107
1121
  } else {
@@ -1114,7 +1128,8 @@ export class DLOB {
1114
1128
  marketIndex: number,
1115
1129
  slot: number,
1116
1130
  marketType: MarketType,
1117
- oraclePriceData: OraclePriceData
1131
+ oraclePriceData: OraclePriceData,
1132
+ filterFcn?: DLOBFilterFcn
1118
1133
  ): Generator<DLOBNode> {
1119
1134
  if (isVariant(marketType, 'spot') && !oraclePriceData) {
1120
1135
  throw new Error('Must provide OraclePriceData to get spot asks');
@@ -1142,46 +1157,17 @@ export class DLOB {
1142
1157
  return bestNode
1143
1158
  .getPrice(oraclePriceData, slot)
1144
1159
  .lt(currentNode.getPrice(oraclePriceData, slot));
1145
- }
1160
+ },
1161
+ filterFcn
1146
1162
  );
1147
1163
  }
1148
1164
 
1149
- /**
1150
- * Filters the limit asks that are resting and do not cross fallback bid
1151
- * Taking orders can only fill against orders that meet this criteria
1152
- *
1153
- * @returns
1154
- */
1155
- *getMakerLimitAsks(
1156
- marketIndex: number,
1157
- slot: number,
1158
- marketType: MarketType,
1159
- oraclePriceData: OraclePriceData,
1160
- fallbackBid?: BN
1161
- ): Generator<DLOBNode> {
1162
- const isPerpMarket = isVariant(marketType, 'perp');
1163
- for (const node of this.getRestingLimitAsks(
1164
- marketIndex,
1165
- slot,
1166
- marketType,
1167
- oraclePriceData
1168
- )) {
1169
- if (
1170
- isPerpMarket &&
1171
- fallbackBid &&
1172
- node.getPrice(oraclePriceData, slot).lte(fallbackBid)
1173
- ) {
1174
- continue;
1175
- }
1176
- yield node;
1177
- }
1178
- }
1179
-
1180
1165
  *getRestingLimitBids(
1181
1166
  marketIndex: number,
1182
1167
  slot: number,
1183
1168
  marketType: MarketType,
1184
- oraclePriceData: OraclePriceData
1169
+ oraclePriceData: OraclePriceData,
1170
+ filterFcn?: DLOBFilterFcn
1185
1171
  ): Generator<DLOBNode> {
1186
1172
  if (isVariant(marketType, 'spot') && !oraclePriceData) {
1187
1173
  throw new Error('Must provide OraclePriceData to get spot bids');
@@ -1209,41 +1195,11 @@ export class DLOB {
1209
1195
  return bestNode
1210
1196
  .getPrice(oraclePriceData, slot)
1211
1197
  .gt(currentNode.getPrice(oraclePriceData, slot));
1212
- }
1198
+ },
1199
+ filterFcn
1213
1200
  );
1214
1201
  }
1215
1202
 
1216
- /**
1217
- * Filters the limit bids that are post only, have been place for sufficiently long or are below the fallback ask
1218
- * Market orders can only fill against orders that meet this criteria
1219
- *
1220
- * @returns
1221
- */
1222
- *getMakerLimitBids(
1223
- marketIndex: number,
1224
- slot: number,
1225
- marketType: MarketType,
1226
- oraclePriceData: OraclePriceData,
1227
- fallbackAsk?: BN
1228
- ): Generator<DLOBNode> {
1229
- const isPerpMarket = isVariant(marketType, 'perp');
1230
- for (const node of this.getRestingLimitBids(
1231
- marketIndex,
1232
- slot,
1233
- marketType,
1234
- oraclePriceData
1235
- )) {
1236
- if (
1237
- isPerpMarket &&
1238
- fallbackAsk &&
1239
- node.getPrice(oraclePriceData, slot).gte(fallbackAsk)
1240
- ) {
1241
- continue;
1242
- }
1243
- yield node;
1244
- }
1245
- }
1246
-
1247
1203
  *getAsks(
1248
1204
  marketIndex: number,
1249
1205
  fallbackAsk: BN | undefined,
@@ -875,21 +875,48 @@ export class DriftClient {
875
875
  }
876
876
 
877
877
  public async updateUserCustomMarginRatio(
878
+ updates: { marginRatio: number; subAccountId: number }[]
879
+ ): Promise<TransactionSignature> {
880
+ const ixs = await Promise.all(
881
+ updates.map(async ({ marginRatio, subAccountId }) => {
882
+ const ix = await this.getUpdateUserCustomMarginRatioIx(
883
+ marginRatio,
884
+ subAccountId
885
+ );
886
+ return ix;
887
+ })
888
+ );
889
+
890
+ const tx = await this.buildTransaction(ixs, this.txParams);
891
+
892
+ const { txSig } = await this.sendTransaction(tx, [], this.opts);
893
+ return txSig;
894
+ }
895
+
896
+ public async getUpdateUserCustomMarginRatioIx(
878
897
  marginRatio: number,
879
898
  subAccountId = 0
880
- ): Promise<TransactionSignature> {
881
- const tx = await this.program.transaction.updateUserCustomMarginRatio(
899
+ ): Promise<TransactionInstruction> {
900
+ const userAccountPublicKey = getUserAccountPublicKeySync(
901
+ this.program.programId,
902
+ this.wallet.publicKey,
903
+ subAccountId
904
+ );
905
+
906
+ await this.addUser(subAccountId, this.wallet.publicKey);
907
+
908
+ const ix = this.program.instruction.updateUserCustomMarginRatio(
882
909
  subAccountId,
883
910
  marginRatio,
884
911
  {
885
912
  accounts: {
886
- user: await this.getUserAccountPublicKey(),
913
+ user: userAccountPublicKey,
887
914
  authority: this.wallet.publicKey,
888
915
  },
889
916
  }
890
917
  );
891
- const { txSig } = await this.sendTransaction(tx, [], this.opts);
892
- return txSig;
918
+
919
+ return ix;
893
920
  }
894
921
 
895
922
  public async getUpdateUserMarginTradingEnabledIx(
@@ -930,31 +957,18 @@ export class DriftClient {
930
957
  }
931
958
 
932
959
  public async updateUserMarginTradingEnabled(
933
- marginTradingEnabled: boolean,
934
- subAccountId = 0
960
+ updates: { marginTradingEnabled: boolean; subAccountId: number }[]
935
961
  ): Promise<TransactionSignature> {
936
- const userAccountPublicKey = getUserAccountPublicKeySync(
937
- this.program.programId,
938
- this.wallet.publicKey,
939
- subAccountId
962
+ const ixs = await Promise.all(
963
+ updates.map(async ({ marginTradingEnabled, subAccountId }) => {
964
+ return await this.getUpdateUserMarginTradingEnabledIx(
965
+ marginTradingEnabled,
966
+ subAccountId
967
+ );
968
+ })
940
969
  );
941
970
 
942
- await this.addUser(subAccountId, this.wallet.publicKey);
943
- const remainingAccounts = this.getRemainingAccounts({
944
- userAccounts: [this.getUserAccount(subAccountId)],
945
- });
946
-
947
- const tx = await this.program.transaction.updateUserMarginTradingEnabled(
948
- subAccountId,
949
- marginTradingEnabled,
950
- {
951
- accounts: {
952
- user: userAccountPublicKey,
953
- authority: this.wallet.publicKey,
954
- },
955
- remainingAccounts,
956
- }
957
- );
971
+ const tx = await this.buildTransaction(ixs, this.txParams);
958
972
 
959
973
  const { txSig } = await this.sendTransaction(tx, [], this.opts);
960
974
  return txSig;
@@ -150,6 +150,9 @@ export class LogParser {
150
150
 
151
151
  public parseEventsFromLogs(event: Log): WrappedEvents {
152
152
  const records: WrappedEvents = [];
153
+
154
+ if (!event.logs) return records;
155
+
153
156
  // @ts-ignore
154
157
  const eventGenerator = this.program._events._eventParser.parseLogs(
155
158
  event.logs,
@@ -10,7 +10,7 @@ import { fetchLogs } from './fetchLogs';
10
10
 
11
11
  export class PollingLogProvider implements LogProvider {
12
12
  private finality: Finality;
13
- private intervalId: NodeJS.Timer;
13
+ private intervalId: ReturnType<typeof setTimeout>;
14
14
  private mostRecentSeenTx?: TransactionSignature;
15
15
  private mutex: number;
16
16
  private firstFetch = true;