@drift-labs/sdk 2.87.0-beta.0 → 2.87.0-beta.10

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 (54) hide show
  1. package/VERSION +1 -1
  2. package/lib/addresses/pda.d.ts +2 -0
  3. package/lib/addresses/pda.js +9 -1
  4. package/lib/adminClient.d.ts +2 -0
  5. package/lib/adminClient.js +27 -4
  6. package/lib/bankrun/bankrunConnection.js +1 -1
  7. package/lib/config.d.ts +1 -0
  8. package/lib/config.js +2 -0
  9. package/lib/constants/perpMarkets.js +12 -12
  10. package/lib/constants/spotMarkets.d.ts +1 -0
  11. package/lib/constants/spotMarkets.js +13 -3
  12. package/lib/dlob/orderBookLevels.d.ts +1 -1
  13. package/lib/driftClient.d.ts +15 -5
  14. package/lib/driftClient.js +155 -41
  15. package/lib/events/types.d.ts +3 -2
  16. package/lib/events/types.js +1 -0
  17. package/lib/factory/oracleClient.js +4 -0
  18. package/lib/idl/drift.json +147 -5
  19. package/lib/idl/openbook.json +3854 -0
  20. package/lib/idl/switchboard_on_demand_30.json +4383 -0
  21. package/lib/index.d.ts +2 -0
  22. package/lib/index.js +2 -0
  23. package/lib/math/spotMarket.d.ts +6 -0
  24. package/lib/math/spotMarket.js +16 -1
  25. package/lib/math/superStake.d.ts +3 -2
  26. package/lib/openbook/openbookV2FulfillmentConfigMap.d.ts +10 -0
  27. package/lib/openbook/openbookV2FulfillmentConfigMap.js +17 -0
  28. package/lib/openbook/openbookV2Subscriber.d.ts +36 -0
  29. package/lib/openbook/openbookV2Subscriber.js +102 -0
  30. package/lib/oracles/switchboardOnDemandClient.d.ts +11 -0
  31. package/lib/oracles/switchboardOnDemandClient.js +32 -0
  32. package/lib/types.d.ts +13 -0
  33. package/lib/types.js +1 -0
  34. package/package.json +6 -2
  35. package/src/addresses/pda.ts +10 -0
  36. package/src/adminClient.ts +47 -4
  37. package/src/bankrun/bankrunConnection.ts +2 -2
  38. package/src/config.ts +3 -0
  39. package/src/constants/perpMarkets.ts +12 -12
  40. package/src/constants/spotMarkets.ts +15 -3
  41. package/src/dlob/orderBookLevels.ts +1 -1
  42. package/src/driftClient.ts +229 -52
  43. package/src/events/types.ts +5 -1
  44. package/src/factory/oracleClient.ts +5 -0
  45. package/src/idl/drift.json +147 -5
  46. package/src/idl/switchboard_on_demand_30.json +4383 -0
  47. package/src/index.ts +2 -0
  48. package/src/math/spotMarket.ts +28 -2
  49. package/src/openbook/openbookV2FulfillmentConfigMap.ts +29 -0
  50. package/src/openbook/openbookV2Subscriber.ts +165 -0
  51. package/src/oracles/switchboardOnDemandClient.ts +56 -0
  52. package/src/types.ts +13 -0
  53. package/tests/ci/verifyConstants.ts +3 -6
  54. package/tests/subscriber/openbook.ts +58 -0
package/lib/index.d.ts CHANGED
@@ -72,6 +72,8 @@ export * from './serum/serumFulfillmentConfigMap';
72
72
  export * from './phoenix/phoenixSubscriber';
73
73
  export * from './priorityFee';
74
74
  export * from './phoenix/phoenixFulfillmentConfigMap';
75
+ export * from './openbook/openbookV2Subscriber';
76
+ export * from './openbook/openbookV2FulfillmentConfigMap';
75
77
  export * from './tx/fastSingleTxSender';
76
78
  export * from './tx/retryTxSender';
77
79
  export * from './tx/whileValidTxSender';
package/lib/index.js CHANGED
@@ -95,6 +95,8 @@ __exportStar(require("./serum/serumFulfillmentConfigMap"), exports);
95
95
  __exportStar(require("./phoenix/phoenixSubscriber"), exports);
96
96
  __exportStar(require("./priorityFee"), exports);
97
97
  __exportStar(require("./phoenix/phoenixFulfillmentConfigMap"), exports);
98
+ __exportStar(require("./openbook/openbookV2Subscriber"), exports);
99
+ __exportStar(require("./openbook/openbookV2FulfillmentConfigMap"), exports);
98
100
  __exportStar(require("./tx/fastSingleTxSender"), exports);
99
101
  __exportStar(require("./tx/retryTxSender"), exports);
100
102
  __exportStar(require("./tx/whileValidTxSender"), exports);
@@ -3,3 +3,9 @@ import { BN } from '@coral-xyz/anchor';
3
3
  import { MarginCategory, SpotBalanceType, SpotMarketAccount } from '../types';
4
4
  export declare function castNumberToSpotPrecision(value: number | BN, spotMarket: SpotMarketAccount): BN;
5
5
  export declare function calculateSpotMarketMarginRatio(market: SpotMarketAccount, oraclePrice: BN, marginCategory: MarginCategory, size: BN, balanceType: SpotBalanceType, customMarginRatio?: number): number;
6
+ /**
7
+ * Returns the maximum remaining deposit that can be made to the spot market. If the maxTokenDeposits on the market is zero then there is no limit and this function will also return zero. (so that needs to be checked)
8
+ * @param market
9
+ * @returns
10
+ */
11
+ export declare function calculateMaxRemainingDeposit(market: SpotMarketAccount): BN;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateSpotMarketMarginRatio = exports.castNumberToSpotPrecision = void 0;
3
+ exports.calculateMaxRemainingDeposit = exports.calculateSpotMarketMarginRatio = exports.castNumberToSpotPrecision = void 0;
4
4
  const anchor_1 = require("@coral-xyz/anchor");
5
5
  const types_1 = require("../types");
6
6
  const spotBalance_1 = require("./spotBalance");
@@ -32,3 +32,18 @@ function calculateSpotMarketMarginRatio(market, oraclePrice, marginCategory, siz
32
32
  return marginRatio;
33
33
  }
34
34
  exports.calculateSpotMarketMarginRatio = calculateSpotMarketMarginRatio;
35
+ /**
36
+ * Returns the maximum remaining deposit that can be made to the spot market. If the maxTokenDeposits on the market is zero then there is no limit and this function will also return zero. (so that needs to be checked)
37
+ * @param market
38
+ * @returns
39
+ */
40
+ function calculateMaxRemainingDeposit(market) {
41
+ const marketMaxTokenDeposits = market.maxTokenDeposits;
42
+ if (marketMaxTokenDeposits.eq(numericConstants_1.ZERO)) {
43
+ // If the maxTokenDeposits is set to zero then that means there is no limit. Return the largest number we can to represent infinite available deposit.
44
+ return numericConstants_1.ZERO;
45
+ }
46
+ const totalDepositsTokenAmount = (0, spotBalance_1.getTokenAmount)(market.depositBalance, market, types_1.SpotBalanceType.DEPOSIT);
47
+ return marketMaxTokenDeposits.sub(totalDepositsTokenAmount);
48
+ }
49
+ exports.calculateMaxRemainingDeposit = calculateMaxRemainingDeposit;
@@ -5,6 +5,7 @@ import { DriftClient } from '../driftClient';
5
5
  import { BN } from '@coral-xyz/anchor';
6
6
  import { User } from '../user';
7
7
  import { DepositRecord } from '../types';
8
+ import fetch from 'node-fetch';
8
9
  export type BSOL_STATS_API_RESPONSE = {
9
10
  success: boolean;
10
11
  stats?: {
@@ -27,8 +28,8 @@ export type BSOL_EMISSIONS_API_RESPONSE = {
27
28
  lend: number;
28
29
  };
29
30
  };
30
- export declare function fetchBSolMetrics(): Promise<any>;
31
- export declare function fetchBSolDriftEmissions(): Promise<any>;
31
+ export declare function fetchBSolMetrics(): Promise<fetch.Response>;
32
+ export declare function fetchBSolDriftEmissions(): Promise<fetch.Response>;
32
33
  export declare function findBestSuperStakeIxs({ marketIndex, amount, jupiterClient, driftClient, userAccountPublicKey, price, forceMarinade, onlyDirectRoutes, jupiterQuote, }: {
33
34
  marketIndex: number;
34
35
  amount: BN;
@@ -0,0 +1,10 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import { OpenbookV2FulfillmentConfigAccount } from '../types';
3
+ import { DriftClient } from '../driftClient';
4
+ export declare class OpenbookV2FulfillmentConfigMap {
5
+ driftClient: DriftClient;
6
+ map: Map<number, OpenbookV2FulfillmentConfigAccount>;
7
+ constructor(driftClient: DriftClient);
8
+ add(marketIndex: number, openbookV2MarketAddress: PublicKey): Promise<void>;
9
+ get(marketIndex: number): OpenbookV2FulfillmentConfigAccount | undefined;
10
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpenbookV2FulfillmentConfigMap = void 0;
4
+ class OpenbookV2FulfillmentConfigMap {
5
+ constructor(driftClient) {
6
+ this.map = new Map();
7
+ this.driftClient = driftClient;
8
+ }
9
+ async add(marketIndex, openbookV2MarketAddress) {
10
+ const account = await this.driftClient.getOpenbookV2FulfillmentConfig(openbookV2MarketAddress);
11
+ this.map.set(marketIndex, account);
12
+ }
13
+ get(marketIndex) {
14
+ return this.map.get(marketIndex);
15
+ }
16
+ }
17
+ exports.OpenbookV2FulfillmentConfigMap = OpenbookV2FulfillmentConfigMap;
@@ -0,0 +1,36 @@
1
+ /// <reference types="bn.js" />
2
+ import { Connection, PublicKey } from '@solana/web3.js';
3
+ import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
4
+ import { BN } from '@coral-xyz/anchor';
5
+ import { L2Level, L2OrderBookGenerator } from '../dlob/orderBookLevels';
6
+ import { Market, OpenBookV2Client } from '@openbook-dex/openbook-v2';
7
+ export type OpenbookV2SubscriberConfig = {
8
+ connection: Connection;
9
+ programId: PublicKey;
10
+ marketAddress: PublicKey;
11
+ accountSubscription: {
12
+ type: 'polling';
13
+ accountLoader: BulkAccountLoader;
14
+ } | {
15
+ type: 'websocket';
16
+ };
17
+ };
18
+ export declare class OpenbookV2Subscriber implements L2OrderBookGenerator {
19
+ connection: Connection;
20
+ programId: PublicKey;
21
+ marketAddress: PublicKey;
22
+ subscriptionType: 'polling' | 'websocket';
23
+ accountLoader: BulkAccountLoader | undefined;
24
+ subscribed: boolean;
25
+ market: Market;
26
+ marketCallbackId: string | number;
27
+ client: OpenBookV2Client;
28
+ constructor(config: OpenbookV2SubscriberConfig);
29
+ subscribe(): Promise<void>;
30
+ getBestBid(): BN | undefined;
31
+ getBestAsk(): BN | undefined;
32
+ getL2Bids(): Generator<L2Level>;
33
+ getL2Asks(): Generator<L2Level>;
34
+ getL2Levels(side: 'bids' | 'asks'): Generator<L2Level>;
35
+ unsubscribe(): Promise<void>;
36
+ }
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.OpenbookV2Subscriber = void 0;
7
+ const web3_js_1 = require("@solana/web3.js");
8
+ const numericConstants_1 = require("../constants/numericConstants");
9
+ const anchor_1 = require("@coral-xyz/anchor");
10
+ const openbook_v2_1 = require("@openbook-dex/openbook-v2");
11
+ const openbook_json_1 = __importDefault(require("../idl/openbook.json"));
12
+ class OpenbookV2Subscriber {
13
+ constructor(config) {
14
+ this.connection = config.connection;
15
+ this.programId = config.programId;
16
+ this.marketAddress = config.marketAddress;
17
+ this.subscribed = false;
18
+ if (config.accountSubscription.type === 'polling') {
19
+ this.subscriptionType = 'polling';
20
+ this.accountLoader = config.accountSubscription.accountLoader;
21
+ }
22
+ else {
23
+ this.subscriptionType = 'websocket';
24
+ }
25
+ }
26
+ async subscribe() {
27
+ if (this.subscribed === true) {
28
+ return;
29
+ }
30
+ const anchorProvider = new anchor_1.AnchorProvider(this.connection, new anchor_1.Wallet(web3_js_1.Keypair.generate()), {});
31
+ const openbookV2Program = new anchor_1.Program(openbook_json_1.default, this.programId, anchorProvider);
32
+ this.client = new openbook_v2_1.OpenBookV2Client(anchorProvider);
33
+ const market = await openbook_v2_1.Market.load(this.client, this.marketAddress);
34
+ this.market = await market.loadOrderBook();
35
+ if (this.subscriptionType === 'websocket') {
36
+ this.marketCallbackId = this.connection.onAccountChange(this.marketAddress, async (accountInfo, _) => {
37
+ const marketRaw = openbookV2Program.coder.accounts.decode('Market', accountInfo.data);
38
+ this.market = new openbook_v2_1.Market(this.client, this.marketAddress, marketRaw);
39
+ await this.market.loadOrderBook();
40
+ });
41
+ }
42
+ else {
43
+ this.marketCallbackId = await this.accountLoader.addAccount(this.marketAddress, (buffer, _) => {
44
+ const marketRaw = openbookV2Program.coder.accounts.decode('Market', buffer);
45
+ this.market = new openbook_v2_1.Market(this.client, this.marketAddress, marketRaw);
46
+ (async () => {
47
+ await this.market.loadOrderBook();
48
+ })();
49
+ });
50
+ }
51
+ this.subscribed = true;
52
+ }
53
+ getBestBid() {
54
+ const bestBid = this.market.bids.best();
55
+ if (bestBid === undefined) {
56
+ return undefined;
57
+ }
58
+ return new anchor_1.BN(Math.floor(bestBid.price * numericConstants_1.PRICE_PRECISION.toNumber()));
59
+ }
60
+ getBestAsk() {
61
+ const bestAsk = this.market.asks.best();
62
+ if (bestAsk === undefined) {
63
+ return undefined;
64
+ }
65
+ return new anchor_1.BN(Math.floor(bestAsk.price * numericConstants_1.PRICE_PRECISION.toNumber()));
66
+ }
67
+ getL2Bids() {
68
+ return this.getL2Levels('bids');
69
+ }
70
+ getL2Asks() {
71
+ return this.getL2Levels('asks');
72
+ }
73
+ *getL2Levels(side) {
74
+ const basePrecision = Math.ceil(1 / this.market.baseNativeFactor.toNumber());
75
+ const pricePrecision = numericConstants_1.PRICE_PRECISION.toNumber();
76
+ const levels = side === 'bids' ? this.market.bids : this.market.asks;
77
+ for (const order of levels.items()) {
78
+ const size = new anchor_1.BN(order.size * basePrecision);
79
+ const price = new anchor_1.BN(order.price * pricePrecision);
80
+ yield {
81
+ price,
82
+ size,
83
+ sources: {
84
+ openbook: size,
85
+ },
86
+ };
87
+ }
88
+ }
89
+ async unsubscribe() {
90
+ if (!this.subscribed) {
91
+ return;
92
+ }
93
+ if (this.subscriptionType === 'websocket') {
94
+ await this.connection.removeAccountChangeListener(this.marketCallbackId);
95
+ }
96
+ else {
97
+ this.accountLoader.removeAccount(this.marketAddress, this.marketCallbackId);
98
+ }
99
+ this.subscribed = false;
100
+ }
101
+ }
102
+ exports.OpenbookV2Subscriber = OpenbookV2Subscriber;
@@ -0,0 +1,11 @@
1
+ /// <reference types="node" />
2
+ import { Connection, PublicKey } from '@solana/web3.js';
3
+ import { OracleClient, OraclePriceData } from './types';
4
+ import { BorshAccountsCoder as BorshAccountsCoder30 } from '@coral-xyz/anchor-30';
5
+ export declare class SwitchboardOnDemandClient implements OracleClient {
6
+ connection: Connection;
7
+ coder: BorshAccountsCoder30;
8
+ constructor(connection: Connection);
9
+ getOraclePriceData(pricePublicKey: PublicKey): Promise<OraclePriceData>;
10
+ getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData;
11
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SwitchboardOnDemandClient = void 0;
7
+ const anchor_1 = require("@coral-xyz/anchor");
8
+ const switchboard_on_demand_30_json_1 = __importDefault(require("../idl/switchboard_on_demand_30.json"));
9
+ const numericConstants_1 = require("../constants/numericConstants");
10
+ const anchor_30_1 = require("@coral-xyz/anchor-30");
11
+ const SB_PRECISION_EXP = new anchor_1.BN(18);
12
+ const SB_PRECISION = new anchor_1.BN(10).pow(SB_PRECISION_EXP.sub(numericConstants_1.PRICE_PRECISION_EXP));
13
+ class SwitchboardOnDemandClient {
14
+ constructor(connection) {
15
+ this.connection = connection;
16
+ this.coder = new anchor_30_1.BorshAccountsCoder(switchboard_on_demand_30_json_1.default);
17
+ }
18
+ async getOraclePriceData(pricePublicKey) {
19
+ const accountInfo = await this.connection.getAccountInfo(pricePublicKey);
20
+ return this.getOraclePriceDataFromBuffer(accountInfo.data);
21
+ }
22
+ getOraclePriceDataFromBuffer(buffer) {
23
+ const pullFeedAccountData = this.coder.decodeUnchecked('PullFeedAccountData', buffer);
24
+ return {
25
+ price: pullFeedAccountData.result.value.div(SB_PRECISION),
26
+ slot: pullFeedAccountData.result.slot,
27
+ confidence: pullFeedAccountData.result.range.div(SB_PRECISION),
28
+ hasSufficientNumberOfDataPoints: true,
29
+ };
30
+ }
31
+ }
32
+ exports.SwitchboardOnDemandClient = SwitchboardOnDemandClient;
package/lib/types.d.ts CHANGED
@@ -182,6 +182,9 @@ export declare class OracleSource {
182
182
  static readonly Prelaunch: {
183
183
  prelaunch: {};
184
184
  };
185
+ static readonly SWITCHBOARD_ON_DEMAND: {
186
+ switchboardOnDemand: {};
187
+ };
185
188
  }
186
189
  export declare class OrderType {
187
190
  static readonly LIMIT: {
@@ -671,6 +674,15 @@ export type SwapRecord = {
671
674
  inOraclePrice: BN;
672
675
  fee: BN;
673
676
  };
677
+ export type SpotMarketVaultDepositRecord = {
678
+ ts: BN;
679
+ marketIndex: number;
680
+ depositBalance: BN;
681
+ cumulativeDepositInterestBefore: BN;
682
+ cumulativeDepositInterestAfter: BN;
683
+ depositTokenAmountBefore: BN;
684
+ amount: BN;
685
+ };
674
686
  export type StateAccount = {
675
687
  admin: PublicKey;
676
688
  exchangeStatus: number;
@@ -821,6 +833,7 @@ export type SpotMarketAccount = {
821
833
  fuelBoostTaker: number;
822
834
  fuelBoostMaker: number;
823
835
  fuelBoostInsurance: number;
836
+ tokenProgram: number;
824
837
  };
825
838
  export type PoolBalance = {
826
839
  scaledBalance: BN;
package/lib/types.js CHANGED
@@ -114,6 +114,7 @@ OracleSource.QUOTE_ASSET = { quoteAsset: {} };
114
114
  OracleSource.PYTH_STABLE_COIN = { pythStableCoin: {} };
115
115
  OracleSource.PYTH_STABLE_COIN_PULL = { pythStableCoinPull: {} };
116
116
  OracleSource.Prelaunch = { prelaunch: {} };
117
+ OracleSource.SWITCHBOARD_ON_DEMAND = { switchboardOnDemand: {} };
117
118
  class OrderType {
118
119
  }
119
120
  exports.OrderType = OrderType;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.87.0-beta.0",
3
+ "version": "2.87.0-beta.10",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -35,13 +35,16 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@coral-xyz/anchor": "0.28.0",
38
+ "@coral-xyz/anchor-30": "npm:@coral-xyz/anchor@0.30.1",
38
39
  "@ellipsis-labs/phoenix-sdk": "^1.4.2",
40
+ "@openbook-dex/openbook-v2": "^0.2.10",
39
41
  "@project-serum/serum": "^0.13.38",
40
42
  "@pythnetwork/client": "2.5.3",
41
43
  "@pythnetwork/price-service-sdk": "^1.7.1",
42
44
  "@pythnetwork/pyth-solana-receiver": "^0.7.0",
43
45
  "@solana/spl-token": "0.3.7",
44
46
  "@solana/web3.js": "1.92.3",
47
+ "@switchboard-xyz/on-demand": "^1.2.1",
45
48
  "anchor-bankrun": "^0.3.0",
46
49
  "rpc-websockets": "7.5.1",
47
50
  "solana-bankrun": "^0.3.0",
@@ -75,6 +78,7 @@
75
78
  "node": ">=18"
76
79
  },
77
80
  "resolutions": {
78
- "@solana/errors": "2.0.0-preview.4"
81
+ "@solana/errors": "2.0.0-preview.4",
82
+ "@solana/codecs-data-structures": "2.0.0-preview.4"
79
83
  }
80
84
  }
@@ -1,6 +1,8 @@
1
1
  import { PublicKey } from '@solana/web3.js';
2
2
  import * as anchor from '@coral-xyz/anchor';
3
3
  import { BN } from '@coral-xyz/anchor';
4
+ import { TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@solana/spl-token';
5
+ import { SpotMarketAccount } from '..';
4
6
 
5
7
  export async function getDriftStateAccountPublicKeyAndNonce(
6
8
  programId: PublicKey
@@ -264,3 +266,11 @@ export function getPythPullOraclePublicKey(
264
266
  progarmId
265
267
  )[0];
266
268
  }
269
+ export function getTokenProgramForSpotMarket(
270
+ spotMarketAccount: SpotMarketAccount
271
+ ): PublicKey {
272
+ if (spotMarketAccount.tokenProgram === 1) {
273
+ return TOKEN_2022_PROGRAM_ID;
274
+ }
275
+ return TOKEN_PROGRAM_ID;
276
+ }
@@ -198,6 +198,8 @@ export class AdminClient extends DriftClient {
198
198
  spotMarketIndex
199
199
  );
200
200
 
201
+ const tokenProgram = (await this.connection.getAccountInfo(mint)).owner;
202
+
201
203
  const nameBuffer = encodeName(name);
202
204
  const initializeIx = await this.program.instruction.initializeSpotMarket(
203
205
  optimalUtilization,
@@ -233,7 +235,7 @@ export class AdminClient extends DriftClient {
233
235
  oracle,
234
236
  rent: SYSVAR_RENT_PUBKEY,
235
237
  systemProgram: anchor.web3.SystemProgram.programId,
236
- tokenProgram: TOKEN_PROGRAM_ID,
238
+ tokenProgram,
237
239
  },
238
240
  }
239
241
  );
@@ -997,6 +999,49 @@ export class AdminClient extends DriftClient {
997
999
  });
998
1000
  }
999
1001
 
1002
+ public async depositIntoSpotMarketVault(
1003
+ spotMarketIndex: number,
1004
+ amount: BN,
1005
+ sourceVault: PublicKey
1006
+ ): Promise<TransactionSignature> {
1007
+ const depositIntoPerpMarketFeePoolIx =
1008
+ await this.getDepositIntoSpotMarketVaultIx(
1009
+ spotMarketIndex,
1010
+ amount,
1011
+ sourceVault
1012
+ );
1013
+
1014
+ const tx = await this.buildTransaction(depositIntoPerpMarketFeePoolIx);
1015
+
1016
+ const { txSig } = await this.sendTransaction(tx, [], this.opts);
1017
+
1018
+ return txSig;
1019
+ }
1020
+
1021
+ public async getDepositIntoSpotMarketVaultIx(
1022
+ spotMarketIndex: number,
1023
+ amount: BN,
1024
+ sourceVault: PublicKey
1025
+ ): Promise<TransactionInstruction> {
1026
+ const spotMarket = this.getSpotMarketAccount(spotMarketIndex);
1027
+
1028
+ const remainingAccounts = [];
1029
+ this.addTokenMintToRemainingAccounts(spotMarket, remainingAccounts);
1030
+ const tokenProgram = this.getTokenProgramForSpotMarket(spotMarket);
1031
+ return await this.program.instruction.depositIntoSpotMarketVault(amount, {
1032
+ accounts: {
1033
+ admin: this.isSubscribed
1034
+ ? this.getStateAccount().admin
1035
+ : this.wallet.publicKey,
1036
+ state: await this.getStatePublicKey(),
1037
+ sourceVault,
1038
+ spotMarket: spotMarket.pubkey,
1039
+ spotMarketVault: spotMarket.vault,
1040
+ tokenProgram,
1041
+ },
1042
+ });
1043
+ }
1044
+
1000
1045
  public async updateAdmin(admin: PublicKey): Promise<TransactionSignature> {
1001
1046
  const updateAdminIx = await this.getUpdateAdminIx(admin);
1002
1047
 
@@ -1115,9 +1160,7 @@ export class AdminClient extends DriftClient {
1115
1160
  },
1116
1161
  {
1117
1162
  accounts: {
1118
- admin: this.isSubscribed
1119
- ? this.getStateAccount().admin
1120
- : this.wallet.publicKey,
1163
+ admin: this.wallet.publicKey,
1121
1164
  state: await this.getStatePublicKey(),
1122
1165
  perpMarket: await getPerpMarketPublicKey(
1123
1166
  this.program.programId,
@@ -35,7 +35,7 @@ import {
35
35
  import { BankrunProvider } from 'anchor-bankrun';
36
36
  import bs58 from 'bs58';
37
37
  import { BN, Wallet } from '@coral-xyz/anchor';
38
- import { Account, TOKEN_PROGRAM_ID, unpackAccount } from '@solana/spl-token';
38
+ import { Account, unpackAccount } from '@solana/spl-token';
39
39
 
40
40
  export type Connection = SolanaConnection | BankrunConnection;
41
41
 
@@ -164,7 +164,7 @@ export class BankrunConnection {
164
164
 
165
165
  async getTokenAccount(publicKey: PublicKey): Promise<Account> {
166
166
  const info = await this.getAccountInfo(publicKey);
167
- return unpackAccount(publicKey, info, TOKEN_PROGRAM_ID);
167
+ return unpackAccount(publicKey, info, info.owner);
168
168
  }
169
169
 
170
170
  async getMultipleAccountsInfo(
package/src/config.ts CHANGED
@@ -23,6 +23,7 @@ type DriftConfig = {
23
23
  USDC_MINT_ADDRESS: string;
24
24
  SERUM_V3: string;
25
25
  PHOENIX: string;
26
+ OPENBOOK: string;
26
27
  V2_ALPHA_TICKET_MINT_ADDRESS: string;
27
28
  PERP_MARKETS: PerpMarketConfig[];
28
29
  SPOT_MARKETS: SpotMarketConfig[];
@@ -46,6 +47,7 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
46
47
  USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
47
48
  SERUM_V3: 'DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY',
48
49
  PHOENIX: 'PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY',
50
+ OPENBOOK: 'opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb',
49
51
  V2_ALPHA_TICKET_MINT_ADDRESS:
50
52
  'DeEiGWfCMP9psnLGkxGrBBMEAW5Jv8bBGMN8DCtFRCyB',
51
53
  PERP_MARKETS: DevnetPerpMarkets,
@@ -61,6 +63,7 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
61
63
  USDC_MINT_ADDRESS: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
62
64
  SERUM_V3: 'srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX',
63
65
  PHOENIX: 'PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY',
66
+ OPENBOOK: 'opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb',
64
67
  V2_ALPHA_TICKET_MINT_ADDRESS:
65
68
  'Cmvhycb6LQvvzaShGw4iDHRLzeSSryioAsU98DSSkMNa',
66
69
  PERP_MARKETS: MainnetPerpMarkets,
@@ -160,16 +160,16 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
160
160
  '0x385f64d993f7b77d8182ed5003d97c60aa3361f3cecfe711544d2d59165e9bdf',
161
161
  },
162
162
  {
163
- fullName: 'RNDR',
163
+ fullName: 'RENDER',
164
164
  category: ['Infra'],
165
- symbol: 'RNDR-PERP',
166
- baseAssetSymbol: 'RNDR',
165
+ symbol: 'RENDER-PERP',
166
+ baseAssetSymbol: 'RENDER',
167
167
  marketIndex: 12,
168
- oracle: new PublicKey('F3mPHRtJqqq57JPDBmUwUVhpyPLmjE5dAzDfpVgpFkug'),
168
+ oracle: new PublicKey('8TQztfGcNjHGRusX4ejQQtPZs3Ypczt9jWF6pkgQMqUX'),
169
169
  launchTs: 1687201081000,
170
170
  oracleSource: OracleSource.PYTH_PULL,
171
171
  pythFeedId:
172
- '0xab7347771135fc733f8f38db462ba085ed3309955f42554a14fa13e855ac0e2f',
172
+ '0x3d4a2bd9535be6ce8059d75eadeba507b043257321aa544717c56fa19b49e35d',
173
173
  },
174
174
  {
175
175
  fullName: 'XRP',
@@ -297,9 +297,9 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
297
297
  symbol: 'W-PERP',
298
298
  baseAssetSymbol: 'W',
299
299
  marketIndex: 23,
300
- oracle: new PublicKey('4HbitGsdcFbtFotmYscikQFAAKJ3nYx4t7sV7fTvsk8U'),
300
+ oracle: new PublicKey('4iCi4DvXrubHQne8jzbMaWL3pd7v1Fip8iTe4H9vHNXB'),
301
301
  launchTs: 1709852537000,
302
- oracleSource: OracleSource.PYTH_PULL,
302
+ oracleSource: OracleSource.SWITCHBOARD_ON_DEMAND,
303
303
  pythFeedId:
304
304
  '0xeff7446475e218517566ea99e72a4abec2e1bd8498b43b7d8331e29dcb059389',
305
305
  },
@@ -475,16 +475,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
475
475
  '0x385f64d993f7b77d8182ed5003d97c60aa3361f3cecfe711544d2d59165e9bdf',
476
476
  },
477
477
  {
478
- fullName: 'RNDR',
478
+ fullName: 'RENDER',
479
479
  category: ['Infra', 'Solana'],
480
- symbol: 'RNDR-PERP',
481
- baseAssetSymbol: 'RNDR',
480
+ symbol: 'RENDER-PERP',
481
+ baseAssetSymbol: 'RENDER',
482
482
  marketIndex: 12,
483
- oracle: new PublicKey('F3mPHRtJqqq57JPDBmUwUVhpyPLmjE5dAzDfpVgpFkug'),
483
+ oracle: new PublicKey('8TQztfGcNjHGRusX4ejQQtPZs3Ypczt9jWF6pkgQMqUX'),
484
484
  launchTs: 1687201081000,
485
485
  oracleSource: OracleSource.PYTH_PULL,
486
486
  pythFeedId:
487
- '0xab7347771135fc733f8f38db462ba085ed3309955f42554a14fa13e855ac0e2f',
487
+ '0x3d4a2bd9535be6ce8059d75eadeba507b043257321aa544717c56fa19b49e35d',
488
488
  },
489
489
  {
490
490
  fullName: 'XRP',
@@ -20,6 +20,7 @@ export type SpotMarketConfig = {
20
20
  precisionExp: BN;
21
21
  serumMarket?: PublicKey;
22
22
  phoenixMarket?: PublicKey;
23
+ openbookMarket?: PublicKey;
23
24
  launchTs?: number;
24
25
  pythFeedId?: string;
25
26
  };
@@ -67,6 +68,17 @@ export const DevnetSpotMarkets: SpotMarketConfig[] = [
67
68
  pythFeedId:
68
69
  '0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43',
69
70
  },
71
+ {
72
+ symbol: 'PYUSD',
73
+ marketIndex: 3,
74
+ oracle: new PublicKey('HpMoKp3TCd3QT4MWYUKk2zCBwmhr5Df45fB6wdxYqEeh'),
75
+ oracleSource: OracleSource.PYTH_PULL,
76
+ mint: new PublicKey('GLfF72ZCUnS6N9iDJw8kedHzd6WFVf3VbpwdKKy76FRk'),
77
+ precision: new BN(10).pow(SIX),
78
+ precisionExp: SIX,
79
+ pythFeedId:
80
+ '0xc1da1b73d7f01e7ddd54b3766cf7fcd644395ad14f70aa706ec5384c59e76692',
81
+ },
70
82
  ];
71
83
 
72
84
  export const MainnetSpotMarkets: SpotMarketConfig[] = [
@@ -235,9 +247,9 @@ export const MainnetSpotMarkets: SpotMarketConfig[] = [
235
247
  '0x0a0408d619e9380abad35060f9192039ed5042fa6f82301d0e48bb52be830996',
236
248
  },
237
249
  {
238
- symbol: 'RNDR',
250
+ symbol: 'RENDER',
239
251
  marketIndex: 12,
240
- oracle: new PublicKey('F3mPHRtJqqq57JPDBmUwUVhpyPLmjE5dAzDfpVgpFkug'),
252
+ oracle: new PublicKey('8TQztfGcNjHGRusX4ejQQtPZs3Ypczt9jWF6pkgQMqUX'),
241
253
  oracleSource: OracleSource.PYTH_PULL,
242
254
  mint: new PublicKey('rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof'),
243
255
  precision: new BN(10).pow(EIGHT),
@@ -245,7 +257,7 @@ export const MainnetSpotMarkets: SpotMarketConfig[] = [
245
257
  serumMarket: new PublicKey('2m7ZLEKtxWF29727DSb5D91erpXPUY1bqhRWRC3wQX7u'),
246
258
  launchTs: 1708964021000,
247
259
  pythFeedId:
248
- '0xab7347771135fc733f8f38db462ba085ed3309955f42554a14fa13e855ac0e2f',
260
+ '0x3d4a2bd9535be6ce8059d75eadeba507b043257321aa544717c56fa19b49e35d',
249
261
  },
250
262
  {
251
263
  symbol: 'W',
@@ -21,7 +21,7 @@ import {
21
21
  import { PublicKey } from '@solana/web3.js';
22
22
  import { assert } from '../assert/assert';
23
23
 
24
- type liquiditySource = 'serum' | 'vamm' | 'dlob' | 'phoenix';
24
+ type liquiditySource = 'serum' | 'vamm' | 'dlob' | 'phoenix' | 'openbook';
25
25
 
26
26
  export type L2Level = {
27
27
  price: BN;