@drift-labs/sdk 2.26.0-beta.0 → 2.26.0-beta.2

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/examples/phoenix.ts +40 -0
  2. package/lib/addresses/pda.d.ts +0 -1
  3. package/lib/adminClient.d.ts +0 -1
  4. package/lib/constants/numericConstants.d.ts +59 -61
  5. package/lib/constants/spotMarkets.d.ts +0 -1
  6. package/lib/dlob/DLOB.d.ts +38 -3
  7. package/lib/dlob/DLOB.js +69 -0
  8. package/lib/dlob/DLOBApiClient.js +1 -1
  9. package/lib/dlob/DLOBNode.d.ts +0 -1
  10. package/lib/dlob/DLOBSubscriber.d.ts +34 -0
  11. package/lib/dlob/DLOBSubscriber.js +100 -0
  12. package/lib/dlob/NodeList.d.ts +0 -1
  13. package/lib/dlob/orderBookLevels.d.ts +44 -0
  14. package/lib/dlob/orderBookLevels.js +137 -0
  15. package/lib/dlob/types.d.ts +2 -0
  16. package/lib/driftClient.d.ts +28 -11
  17. package/lib/driftClient.js +158 -55
  18. package/lib/driftClientConfig.d.ts +3 -0
  19. package/lib/factory/bigNum.d.ts +7 -8
  20. package/lib/idl/drift.json +1 -1
  21. package/lib/index.d.ts +3 -0
  22. package/lib/index.js +3 -0
  23. package/lib/math/amm.d.ts +1 -2
  24. package/lib/math/auction.d.ts +0 -1
  25. package/lib/math/conversion.d.ts +1 -2
  26. package/lib/math/funding.d.ts +0 -1
  27. package/lib/math/insurance.d.ts +0 -1
  28. package/lib/math/margin.d.ts +0 -1
  29. package/lib/math/market.d.ts +0 -1
  30. package/lib/math/oracles.d.ts +0 -1
  31. package/lib/math/orders.d.ts +0 -1
  32. package/lib/math/position.d.ts +0 -1
  33. package/lib/math/repeg.d.ts +0 -1
  34. package/lib/math/spotBalance.d.ts +0 -1
  35. package/lib/math/spotMarket.d.ts +0 -1
  36. package/lib/math/spotPosition.d.ts +0 -1
  37. package/lib/math/trade.d.ts +0 -1
  38. package/lib/math/utils.d.ts +0 -1
  39. package/lib/oracles/pythClient.d.ts +1 -2
  40. package/lib/oracles/types.d.ts +0 -1
  41. package/lib/orderParams.d.ts +0 -1
  42. package/lib/phoenix/phoenixFulfillmentConfigMap.d.ts +10 -0
  43. package/lib/phoenix/phoenixFulfillmentConfigMap.js +17 -0
  44. package/lib/phoenix/phoenixSubscriber.d.ts +34 -0
  45. package/lib/phoenix/phoenixSubscriber.js +79 -0
  46. package/lib/serum/serumSubscriber.d.ts +5 -2
  47. package/lib/serum/serumSubscriber.js +22 -0
  48. package/lib/tokenFaucet.d.ts +0 -1
  49. package/lib/types.d.ts +1 -1
  50. package/lib/user.d.ts +0 -1
  51. package/package.json +1 -1
  52. package/src/assert/assert.js +9 -0
  53. package/src/dlob/DLOB.ts +177 -17
  54. package/src/dlob/DLOBApiClient.ts +3 -1
  55. package/src/dlob/DLOBSubscriber.ts +141 -0
  56. package/src/dlob/orderBookLevels.ts +243 -0
  57. package/src/dlob/types.ts +2 -0
  58. package/src/driftClient.ts +231 -66
  59. package/src/driftClientConfig.ts +3 -0
  60. package/src/idl/drift.json +1 -1
  61. package/src/index.ts +3 -0
  62. package/src/phoenix/phoenixFulfillmentConfigMap.ts +26 -0
  63. package/src/phoenix/phoenixSubscriber.ts +156 -0
  64. package/src/serum/serumSubscriber.ts +27 -1
  65. package/src/token/index.js +38 -0
  66. package/src/types.ts +1 -0
  67. package/src/util/computeUnits.js +27 -0
  68. package/src/util/getTokenAddress.js +9 -0
  69. package/src/util/promiseTimeout.js +14 -0
  70. package/src/util/tps.js +27 -0
  71. package/tests/dlob/helpers.ts +3 -0
package/lib/index.d.ts CHANGED
@@ -53,6 +53,8 @@ export * from './config';
53
53
  export * from './constants/numericConstants';
54
54
  export * from './serum/serumSubscriber';
55
55
  export * from './serum/serumFulfillmentConfigMap';
56
+ export * from './phoenix/phoenixSubscriber';
57
+ export * from './phoenix/phoenixFulfillmentConfigMap';
56
58
  export * from './tx/retryTxSender';
57
59
  export * from './util/computeUnits';
58
60
  export * from './util/tps';
@@ -66,6 +68,7 @@ export * from './dlob/DLOBOrders';
66
68
  export * from './dlob/NodeList';
67
69
  export * from './dlob/DLOBSubscriber';
68
70
  export * from './dlob/types';
71
+ export * from './dlob/orderBookLevels';
69
72
  export * from './userMap/userMap';
70
73
  export * from './userMap/userStatsMap';
71
74
  export * from './math/bankruptcy';
package/lib/index.js CHANGED
@@ -77,6 +77,8 @@ __exportStar(require("./config"), exports);
77
77
  __exportStar(require("./constants/numericConstants"), exports);
78
78
  __exportStar(require("./serum/serumSubscriber"), exports);
79
79
  __exportStar(require("./serum/serumFulfillmentConfigMap"), exports);
80
+ __exportStar(require("./phoenix/phoenixSubscriber"), exports);
81
+ __exportStar(require("./phoenix/phoenixFulfillmentConfigMap"), exports);
80
82
  __exportStar(require("./tx/retryTxSender"), exports);
81
83
  __exportStar(require("./util/computeUnits"), exports);
82
84
  __exportStar(require("./util/tps"), exports);
@@ -90,6 +92,7 @@ __exportStar(require("./dlob/DLOBOrders"), exports);
90
92
  __exportStar(require("./dlob/NodeList"), exports);
91
93
  __exportStar(require("./dlob/DLOBSubscriber"), exports);
92
94
  __exportStar(require("./dlob/types"), exports);
95
+ __exportStar(require("./dlob/orderBookLevels"), exports);
93
96
  __exportStar(require("./userMap/userMap"), exports);
94
97
  __exportStar(require("./userMap/userStatsMap"), exports);
95
98
  __exportStar(require("./math/bankruptcy"), exports);
package/lib/math/amm.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { BN } from '@coral-xyz/anchor';
3
2
  import { AMM, PositionDirection, SwapDirection, PerpMarketAccount } from '../types';
4
3
  import { OraclePriceData } from '../oracles/types';
@@ -87,7 +86,7 @@ export declare function getSwapDirection(inputAssetType: AssetType, positionDire
87
86
  * @param market
88
87
  * @returns cost : Precision PRICE_PRECISION
89
88
  */
90
- export declare function calculateTerminalPrice(market: PerpMarketAccount): BN;
89
+ export declare function calculateTerminalPrice(market: PerpMarketAccount): any;
91
90
  export declare function calculateMaxBaseAssetAmountToTrade(amm: AMM, limit_price: BN, direction: PositionDirection, oraclePriceData?: OraclePriceData, now?: BN): [BN, PositionDirection];
92
91
  export declare function calculateQuoteAssetAmountSwapped(quoteAssetReserves: BN, pegMultiplier: BN, swapDirection: SwapDirection): BN;
93
92
  export declare function calculateMaxBaseAssetAmountFillable(amm: AMM, orderDirection: PositionDirection): BN;
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { Order } from '../types';
3
2
  import { BN } from '../.';
4
3
  export declare function isAuctionComplete(order: Order, slot: number): boolean;
@@ -1,2 +1 @@
1
- import { BN } from '../';
2
- export declare const convertToNumber: (bigNumber: BN, precision?: BN) => number;
1
+ export declare const convertToNumber: (bigNumber: BN, precision?: BN) => any;
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { BN } from '@coral-xyz/anchor';
3
2
  import { PerpMarketAccount } from '../types';
4
3
  import { OraclePriceData } from '../oracles/types';
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { BN } from '../index';
3
2
  export declare function stakeAmountToShares(amount: BN, totalIfShares: BN, insuranceFundVaultBalance: BN): BN;
4
3
  export declare function unstakeSharesToAmount(nShares: BN, totalIfShares: BN, insuranceFundVaultBalance: BN): BN;
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { BN } from '@coral-xyz/anchor';
3
2
  import { OraclePriceData } from '../oracles/types';
4
3
  import { PerpMarketAccount, PerpPosition } from '..';
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { BN } from '@coral-xyz/anchor';
3
2
  import { PerpMarketAccount, PositionDirection, MarginCategory, SpotMarketAccount } from '../types';
4
3
  import { OraclePriceData } from '../oracles/types';
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { AMM, OracleGuardRails } from '../types';
3
2
  import { OraclePriceData } from '../oracles/types';
4
3
  import { BN, HistoricalOracleData, PerpMarketAccount } from '../index';
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { User } from '../user';
3
2
  import { PerpMarketAccount, AMM, Order } from '../types';
4
3
  import { BN } from '@coral-xyz/anchor';
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { BN, SpotMarketAccount } from '../';
3
2
  import { OraclePriceData } from '../oracles/types';
4
3
  import { PerpMarketAccount, PositionDirection, PerpPosition } from '../types';
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { BN } from '@coral-xyz/anchor';
3
2
  import { AMM } from '../types';
4
3
  /**
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { SpotMarketAccount, SpotBalanceType, MarginCategory } from '../types';
3
2
  import { BN } from '@coral-xyz/anchor';
4
3
  import { OraclePriceData } from '../oracles/types';
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { BN } from '@coral-xyz/anchor';
3
2
  import { MarginCategory, SpotBalanceType, SpotMarketAccount } from '../types';
4
3
  export declare function castNumberToSpotPrecision(value: number, spotMarket: SpotMarketAccount): BN;
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { SpotMarketAccount, SpotPosition } from '../types';
3
2
  import { BN } from '@coral-xyz/anchor';
4
3
  import { OraclePriceData } from '../oracles/types';
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { PerpMarketAccount, PositionDirection, SpotMarketAccount } from '../types';
3
2
  import { BN } from '@coral-xyz/anchor';
4
3
  import { AssetType } from './amm';
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { BN } from '../';
3
2
  export declare function clampBN(x: BN, min: BN, max: BN): BN;
4
3
  export declare const squareRootBN: (n: BN) => BN;
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  /// <reference types="node" />
3
2
  import { Connection, PublicKey } from '@solana/web3.js';
4
3
  import { OracleClient, OraclePriceData } from './types';
@@ -7,7 +6,7 @@ export declare class PythClient implements OracleClient {
7
6
  private connection;
8
7
  private multiple;
9
8
  private stableCoin;
10
- constructor(connection: Connection, multiple?: BN, stableCoin?: boolean);
9
+ constructor(connection: Connection, multiple?: any, stableCoin?: boolean);
11
10
  getOraclePriceData(pricePublicKey: PublicKey): Promise<OraclePriceData>;
12
11
  getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData;
13
12
  }
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  /// <reference types="node" />
3
2
  import { BN } from '@coral-xyz/anchor';
4
3
  import { PublicKey } from '@solana/web3.js';
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { OptionalOrderParams, OrderTriggerCondition } from './types';
3
2
  import { BN } from '@coral-xyz/anchor';
4
3
  export declare function getLimitOrderParams(params: Omit<OptionalOrderParams, 'orderType' | 'marketType'> & {
@@ -0,0 +1,10 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import { PhoenixV1FulfillmentConfigAccount } from '../types';
3
+ import { DriftClient } from '../driftClient';
4
+ export declare class PhoenixFulfillmentConfigMap {
5
+ driftClient: DriftClient;
6
+ map: Map<number, PhoenixV1FulfillmentConfigAccount>;
7
+ constructor(driftClient: DriftClient);
8
+ add(marketIndex: number, phoenixMarketAddress: PublicKey): Promise<void>;
9
+ get(marketIndex: number): PhoenixV1FulfillmentConfigAccount;
10
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PhoenixFulfillmentConfigMap = void 0;
4
+ class PhoenixFulfillmentConfigMap {
5
+ constructor(driftClient) {
6
+ this.map = new Map();
7
+ this.driftClient = driftClient;
8
+ }
9
+ async add(marketIndex, phoenixMarketAddress) {
10
+ const account = await this.driftClient.getPhoenixV1FulfillmentConfig(phoenixMarketAddress);
11
+ this.map.set(marketIndex, account);
12
+ }
13
+ get(marketIndex) {
14
+ return this.map.get(marketIndex);
15
+ }
16
+ }
17
+ exports.PhoenixFulfillmentConfigMap = PhoenixFulfillmentConfigMap;
@@ -0,0 +1,34 @@
1
+ import { Connection, PublicKey } from '@solana/web3.js';
2
+ import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
3
+ import { MarketData, Client } from '@ellipsis-labs/phoenix-sdk';
4
+ import { BN } from '@coral-xyz/anchor';
5
+ export type PhoenixMarketSubscriberConfig = {
6
+ connection: Connection;
7
+ programId: PublicKey;
8
+ marketAddress: PublicKey;
9
+ accountSubscription: {
10
+ type: 'polling';
11
+ accountLoader: BulkAccountLoader;
12
+ } | {
13
+ type: 'websocket';
14
+ };
15
+ };
16
+ export declare class PhoenixSubscriber {
17
+ connection: Connection;
18
+ client: Client;
19
+ programId: PublicKey;
20
+ marketAddress: PublicKey;
21
+ subscriptionType: 'polling' | 'websocket';
22
+ accountLoader: BulkAccountLoader | undefined;
23
+ market: MarketData;
24
+ marketCallbackId: string | number;
25
+ clockCallbackId: string | number;
26
+ subscribed: boolean;
27
+ lastSlot: number;
28
+ lastUnixTimestamp: number;
29
+ constructor(config: PhoenixMarketSubscriberConfig);
30
+ subscribe(): Promise<void>;
31
+ getBestBid(): BN;
32
+ getBestAsk(): BN;
33
+ unsubscribe(): Promise<void>;
34
+ }
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PhoenixSubscriber = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const phoenix_sdk_1 = require("@ellipsis-labs/phoenix-sdk");
6
+ const numericConstants_1 = require("../constants/numericConstants");
7
+ const anchor_1 = require("@coral-xyz/anchor");
8
+ class PhoenixSubscriber {
9
+ constructor(config) {
10
+ this.connection = config.connection;
11
+ this.programId = config.programId;
12
+ this.marketAddress = config.marketAddress;
13
+ if (config.accountSubscription.type === 'polling') {
14
+ this.subscriptionType = 'polling';
15
+ this.accountLoader = config.accountSubscription.accountLoader;
16
+ }
17
+ else {
18
+ this.subscriptionType = 'websocket';
19
+ }
20
+ this.lastSlot = 0;
21
+ this.lastUnixTimestamp = 0;
22
+ }
23
+ async subscribe() {
24
+ if (this.subscribed) {
25
+ return;
26
+ }
27
+ this.market = (0, phoenix_sdk_1.deserializeMarketData)((await this.connection.getAccountInfo(this.marketAddress, 'confirmed'))
28
+ .data);
29
+ const clock = (0, phoenix_sdk_1.deserializeClockData)((await this.connection.getAccountInfo(web3_js_1.SYSVAR_CLOCK_PUBKEY, 'confirmed'))
30
+ .data);
31
+ this.lastUnixTimestamp = (0, phoenix_sdk_1.toNum)(clock.unixTimestamp);
32
+ if (this.subscriptionType === 'websocket') {
33
+ this.marketCallbackId = this.connection.onAccountChange(this.marketAddress, (accountInfo, _ctx) => {
34
+ this.market = (0, phoenix_sdk_1.deserializeMarketData)(accountInfo.data);
35
+ });
36
+ this.clockCallbackId = this.connection.onAccountChange(web3_js_1.SYSVAR_CLOCK_PUBKEY, (accountInfo, ctx) => {
37
+ this.lastSlot = ctx.slot;
38
+ const clock = (0, phoenix_sdk_1.deserializeClockData)(accountInfo.data);
39
+ this.lastUnixTimestamp = (0, phoenix_sdk_1.toNum)(clock.unixTimestamp);
40
+ });
41
+ }
42
+ else {
43
+ this.marketCallbackId = await this.accountLoader.addAccount(this.marketAddress, (buffer, slot) => {
44
+ this.lastSlot = slot;
45
+ this.market = (0, phoenix_sdk_1.deserializeMarketData)(buffer);
46
+ });
47
+ this.clockCallbackId = await this.accountLoader.addAccount(web3_js_1.SYSVAR_CLOCK_PUBKEY, (buffer, slot) => {
48
+ this.lastSlot = slot;
49
+ const clock = (0, phoenix_sdk_1.deserializeClockData)(buffer);
50
+ this.lastUnixTimestamp = (0, phoenix_sdk_1.toNum)(clock.unixTimestamp);
51
+ });
52
+ }
53
+ this.subscribed = true;
54
+ }
55
+ getBestBid() {
56
+ const ladder = (0, phoenix_sdk_1.getMarketUiLadder)(this.market, this.lastSlot, this.lastUnixTimestamp, 1);
57
+ return new anchor_1.BN(Math.floor(ladder.bids[0][0] * numericConstants_1.PRICE_PRECISION.toNumber()));
58
+ }
59
+ getBestAsk() {
60
+ const ladder = (0, phoenix_sdk_1.getMarketUiLadder)(this.market, this.lastSlot, this.lastUnixTimestamp, 1);
61
+ return new anchor_1.BN(Math.floor(ladder.asks[0][0] * numericConstants_1.PRICE_PRECISION.toNumber()));
62
+ }
63
+ async unsubscribe() {
64
+ if (!this.subscribed) {
65
+ return;
66
+ }
67
+ // remove listeners
68
+ if (this.subscriptionType === 'websocket') {
69
+ await this.connection.removeAccountChangeListener(this.marketCallbackId);
70
+ await this.connection.removeAccountChangeListener(this.clockCallbackId);
71
+ }
72
+ else {
73
+ this.accountLoader.removeAccount(this.marketAddress, this.marketCallbackId);
74
+ this.accountLoader.removeAccount(web3_js_1.SYSVAR_CLOCK_PUBKEY, this.clockCallbackId);
75
+ }
76
+ this.subscribed = false;
77
+ }
78
+ }
79
+ exports.PhoenixSubscriber = PhoenixSubscriber;
@@ -1,10 +1,10 @@
1
- /// <reference types="bn.js" />
2
1
  import { Connection, PublicKey } from '@solana/web3.js';
3
2
  import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
4
3
  import { Market, Orderbook } from '@project-serum/serum';
5
4
  import { SerumMarketSubscriberConfig } from './types';
6
5
  import { BN } from '@coral-xyz/anchor';
7
- export declare class SerumSubscriber {
6
+ import { L2Level, L2OrderBookGenerator } from '../dlob/orderBookLevels';
7
+ export declare class SerumSubscriber implements L2OrderBookGenerator {
8
8
  connection: Connection;
9
9
  programId: PublicKey;
10
10
  marketAddress: PublicKey;
@@ -24,5 +24,8 @@ export declare class SerumSubscriber {
24
24
  subscribe(): Promise<void>;
25
25
  getBestBid(): BN | undefined;
26
26
  getBestAsk(): BN | undefined;
27
+ getL2Bids(): Generator<L2Level>;
28
+ getL2Asks(): Generator<L2Level>;
29
+ getL2Levels(side: 'bids' | 'asks'): Generator<L2Level>;
27
30
  unsubscribe(): Promise<void>;
28
31
  }
@@ -66,6 +66,28 @@ class SerumSubscriber {
66
66
  }
67
67
  return new anchor_1.BN(bestAsk[0] * numericConstants_1.PRICE_PRECISION.toNumber());
68
68
  }
69
+ getL2Bids() {
70
+ return this.getL2Levels('bids');
71
+ }
72
+ getL2Asks() {
73
+ return this.getL2Levels('asks');
74
+ }
75
+ *getL2Levels(side) {
76
+ // @ts-ignore
77
+ const basePrecision = Math.pow(10, this.market._baseSplTokenDecimals);
78
+ const pricePrecision = numericConstants_1.PRICE_PRECISION.toNumber();
79
+ for (let { price, size } of this[side].items(side === 'bids')) {
80
+ price = new anchor_1.BN(price * pricePrecision);
81
+ size = new anchor_1.BN(size * basePrecision);
82
+ yield {
83
+ price,
84
+ size,
85
+ sources: {
86
+ serum: size,
87
+ },
88
+ };
89
+ }
90
+ }
69
91
  async unsubscribe() {
70
92
  if (!this.subscribed) {
71
93
  return;
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import * as anchor from '@coral-xyz/anchor';
3
2
  import { AnchorProvider, Program } from '@coral-xyz/anchor';
4
3
  import { AccountInfo } from '@solana/spl-token';
package/lib/types.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="bn.js" />
2
1
  import { PublicKey, Transaction } from '@solana/web3.js';
3
2
  import { BN } from '.';
4
3
  export declare enum ExchangeStatus {
@@ -661,6 +660,7 @@ export type HistoricalIndexData = {
661
660
  export type SpotMarketAccount = {
662
661
  status: MarketStatus;
663
662
  assetTier: AssetTier;
663
+ name: number[];
664
664
  marketIndex: number;
665
665
  pubkey: PublicKey;
666
666
  mint: PublicKey;
package/lib/user.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  /// <reference types="node" />
2
- /// <reference types="bn.js" />
3
2
  import { PublicKey } from '@solana/web3.js';
4
3
  import { EventEmitter } from 'events';
5
4
  import StrictEventEmitter from 'strict-event-emitter-types';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.26.0-beta.0",
3
+ "version": "2.26.0-beta.2",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assert = void 0;
4
+ function assert(condition, error) {
5
+ if (!condition) {
6
+ throw new Error(error || 'Unspecified AssertionError');
7
+ }
8
+ }
9
+ exports.assert = assert;
package/src/dlob/DLOB.ts CHANGED
@@ -1,37 +1,48 @@
1
1
  import { getOrderSignature, getVammNodeGenerator, NodeList } from './NodeList';
2
2
  import {
3
- MarketType,
4
3
  BN,
5
4
  calculateAskPrice,
6
5
  calculateBidPrice,
7
- DriftClient,
8
6
  convertToNumber,
9
- isOrderExpired,
7
+ DLOBNode,
8
+ DLOBNodeType,
9
+ DriftClient,
10
+ getLimitPrice,
11
+ getVariant,
12
+ isFallbackAvailableLiquiditySource,
10
13
  isOneOfVariant,
14
+ isOrderExpired,
15
+ isRestingLimitOrder,
16
+ isTakingOrder,
17
+ isTriggered,
11
18
  isVariant,
12
- getVariant,
19
+ MarketType,
20
+ MarketTypeStr,
21
+ mustBeTriggered,
22
+ OraclePriceData,
13
23
  Order,
14
- PRICE_PRECISION,
15
- SpotMarketAccount,
24
+ OrderActionRecord,
25
+ OrderRecord,
16
26
  PerpMarketAccount,
17
- OraclePriceData,
27
+ PRICE_PRECISION,
18
28
  SlotSubscriber,
19
- MarketTypeStr,
29
+ SpotMarketAccount,
20
30
  StateAccount,
21
- mustBeTriggered,
22
- isTriggered,
23
- getLimitPrice,
31
+ TriggerOrderNode,
24
32
  UserMap,
25
- OrderRecord,
26
- OrderActionRecord,
27
- isRestingLimitOrder,
28
- isTakingOrder,
29
- isFallbackAvailableLiquiditySource,
30
33
  } from '..';
31
34
  import { PublicKey } from '@solana/web3.js';
32
- import { DLOBNode, DLOBNodeType, TriggerOrderNode } from '..';
33
35
  import { ammPaused, exchangePaused, fillPaused } from '../math/exchangeStatus';
34
36
  import { DLOBOrders } from './DLOBOrders';
37
+ import {
38
+ createL2Levels,
39
+ getL2GeneratorFromDLOBNodes,
40
+ L2OrderBook,
41
+ L2OrderBookGenerator,
42
+ L3Level,
43
+ L3OrderBook,
44
+ mergeL2LevelGenerators,
45
+ } from './orderBookLevels';
35
46
 
36
47
  export type MarketNodeLists = {
37
48
  restingLimit: {
@@ -1689,4 +1700,153 @@ export class DLOB {
1689
1700
  yield nodeLists.trigger.below;
1690
1701
  }
1691
1702
  }
1703
+
1704
+ /**
1705
+ * Get an L2 view of the order book for a given market.
1706
+ *
1707
+ * @param marketIndex
1708
+ * @param marketType
1709
+ * @param slot
1710
+ * @param oraclePriceData
1711
+ * @param depth how many levels of the order book to return
1712
+ * @param fallbackAsk best ask for fallback liquidity, only relevant for perps
1713
+ * @param fallbackBid best bid for fallback liquidity, only relevant for perps
1714
+ * @param fallbackL2Generators L2 generators for fallback liquidity e.g. vAMM {@link getVammL2Generator}, openbook {@link SerumSubscriber}
1715
+ */
1716
+ public getL2({
1717
+ marketIndex,
1718
+ marketType,
1719
+ slot,
1720
+ oraclePriceData,
1721
+ depth,
1722
+ fallbackAsk,
1723
+ fallbackBid,
1724
+ fallbackL2Generators = [],
1725
+ }: {
1726
+ marketIndex: number;
1727
+ marketType: MarketType;
1728
+ slot: number;
1729
+ oraclePriceData: OraclePriceData;
1730
+ depth: number;
1731
+ fallbackAsk?: BN;
1732
+ fallbackBid?: BN;
1733
+ fallbackL2Generators?: L2OrderBookGenerator[];
1734
+ }): L2OrderBook {
1735
+ const makerAskL2LevelGenerator = getL2GeneratorFromDLOBNodes(
1736
+ this.getMakerLimitAsks(
1737
+ marketIndex,
1738
+ slot,
1739
+ marketType,
1740
+ oraclePriceData,
1741
+ fallbackBid
1742
+ ),
1743
+ oraclePriceData,
1744
+ slot
1745
+ );
1746
+
1747
+ const fallbackAskGenerators = fallbackL2Generators.map(
1748
+ (fallbackL2Generator) => {
1749
+ return fallbackL2Generator.getL2Asks();
1750
+ }
1751
+ );
1752
+
1753
+ const askL2LevelGenerator = mergeL2LevelGenerators(
1754
+ [makerAskL2LevelGenerator, ...fallbackAskGenerators],
1755
+ (a, b) => {
1756
+ return a.price.lt(b.price);
1757
+ }
1758
+ );
1759
+
1760
+ const asks = createL2Levels(askL2LevelGenerator, depth);
1761
+
1762
+ const makerBidGenerator = getL2GeneratorFromDLOBNodes(
1763
+ this.getMakerLimitBids(
1764
+ marketIndex,
1765
+ slot,
1766
+ marketType,
1767
+ oraclePriceData,
1768
+ fallbackAsk
1769
+ ),
1770
+ oraclePriceData,
1771
+ slot
1772
+ );
1773
+
1774
+ const fallbackBidGenerators = fallbackL2Generators.map((fallbackOrders) => {
1775
+ return fallbackOrders.getL2Bids();
1776
+ });
1777
+
1778
+ const bidL2LevelGenerator = mergeL2LevelGenerators(
1779
+ [makerBidGenerator, ...fallbackBidGenerators],
1780
+ (a, b) => {
1781
+ return a.price.gt(b.price);
1782
+ }
1783
+ );
1784
+
1785
+ const bids = createL2Levels(bidL2LevelGenerator, depth);
1786
+
1787
+ return {
1788
+ bids,
1789
+ asks,
1790
+ };
1791
+ }
1792
+
1793
+ /**
1794
+ * Get an L3 view of the order book for a given market. Does not include fallback liquidity sources
1795
+ *
1796
+ * @param marketIndex
1797
+ * @param marketType
1798
+ * @param slot
1799
+ * @param oraclePriceData
1800
+ */
1801
+ public getL3({
1802
+ marketIndex,
1803
+ marketType,
1804
+ slot,
1805
+ oraclePriceData,
1806
+ }: {
1807
+ marketIndex: number;
1808
+ marketType: MarketType;
1809
+ slot: number;
1810
+ oraclePriceData: OraclePriceData;
1811
+ }): L3OrderBook {
1812
+ const bids: L3Level[] = [];
1813
+ const asks: L3Level[] = [];
1814
+
1815
+ const restingAsks = this.getRestingLimitAsks(
1816
+ marketIndex,
1817
+ slot,
1818
+ marketType,
1819
+ oraclePriceData
1820
+ );
1821
+
1822
+ for (const ask of restingAsks) {
1823
+ asks.push({
1824
+ price: ask.getPrice(oraclePriceData, slot),
1825
+ size: ask.order.baseAssetAmount.sub(ask.order.baseAssetAmountFilled),
1826
+ maker: ask.userAccount,
1827
+ orderId: ask.order.orderId,
1828
+ });
1829
+ }
1830
+
1831
+ const restingBids = this.getRestingLimitBids(
1832
+ marketIndex,
1833
+ slot,
1834
+ marketType,
1835
+ oraclePriceData
1836
+ );
1837
+
1838
+ for (const bid of restingBids) {
1839
+ bids.push({
1840
+ price: bid.getPrice(oraclePriceData, slot),
1841
+ size: bid.order.baseAssetAmount.sub(bid.order.baseAssetAmountFilled),
1842
+ maker: bid.userAccount,
1843
+ orderId: bid.order.orderId,
1844
+ });
1845
+ }
1846
+
1847
+ return {
1848
+ bids,
1849
+ asks,
1850
+ };
1851
+ }
1692
1852
  }
@@ -19,7 +19,9 @@ export class DLOBApiClient {
19
19
  public async getDLOB(slot: number): Promise<DLOB> {
20
20
  const r = await fetch(this.url);
21
21
  if (!r.ok) {
22
- throw new Error(`Failed to fetch DLOB from ${this.url}`);
22
+ throw new Error(
23
+ `Failed to fetch DLOB from ${this.url}. Status: ${r.status}, ${r.statusText}`
24
+ );
23
25
  }
24
26
 
25
27
  const resp = await r.json();