@drift-labs/sdk 0.2.0-master.40 → 0.2.0-master.41

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 (43) hide show
  1. package/lib/accounts/pollingUserAccountSubscriber.d.ts +1 -1
  2. package/lib/accounts/pollingUserAccountSubscriber.js +5 -11
  3. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +1 -1
  4. package/lib/accounts/pollingUserStatsAccountSubscriber.js +5 -11
  5. package/lib/config.js +1 -1
  6. package/lib/dlob/DLOB.js +6 -8
  7. package/lib/driftClient.d.ts +7 -6
  8. package/lib/driftClient.js +24 -12
  9. package/lib/events/types.d.ts +3 -1
  10. package/lib/events/types.js +2 -0
  11. package/lib/idl/drift.json +164 -28
  12. package/lib/math/oracles.js +1 -1
  13. package/lib/math/orders.d.ts +2 -0
  14. package/lib/math/orders.js +10 -3
  15. package/lib/types.d.ts +125 -46
  16. package/lib/types.js +61 -23
  17. package/lib/user.d.ts +2 -0
  18. package/lib/user.js +11 -1
  19. package/package.json +2 -2
  20. package/src/accounts/pollingUserAccountSubscriber.ts +5 -12
  21. package/src/accounts/pollingUserStatsAccountSubscriber.ts +5 -11
  22. package/src/assert/assert.js +9 -0
  23. package/src/config.ts +1 -1
  24. package/src/dlob/DLOB.ts +10 -13
  25. package/src/driftClient.ts +39 -9
  26. package/src/events/eventList.js +77 -0
  27. package/src/events/types.ts +6 -0
  28. package/src/examples/makeTradeExample.js +157 -0
  29. package/src/idl/drift.json +164 -28
  30. package/src/math/oracles.ts +1 -1
  31. package/src/math/orders.ts +9 -4
  32. package/src/token/index.js +38 -0
  33. package/src/tx/types.js +2 -0
  34. package/src/tx/utils.js +17 -0
  35. package/src/types.ts +104 -37
  36. package/src/user.ts +18 -1
  37. package/src/util/computeUnits.js +27 -0
  38. package/src/util/getTokenAddress.js +9 -0
  39. package/src/util/promiseTimeout.js +14 -0
  40. package/src/util/tps.js +27 -0
  41. package/tests/dlob/helpers.ts +19 -10
  42. package/tests/dlob/test.ts +0 -2
  43. package/yarn-error.log +3160 -0
package/src/dlob/DLOB.ts CHANGED
@@ -22,8 +22,9 @@ import {
22
22
  StateAccount,
23
23
  isMarketOrder,
24
24
  isLimitOrder,
25
- hasLimitPrice,
26
25
  getOptionalLimitPrice,
26
+ mustBeTriggered,
27
+ isTriggered,
27
28
  } from '..';
28
29
  import { PublicKey } from '@solana/web3.js';
29
30
  import { DLOBNode, DLOBNodeType, TriggerOrderNode } from '..';
@@ -253,8 +254,7 @@ export class DLOB {
253
254
 
254
255
  public getListForOrder(order: Order): NodeList<any> | undefined {
255
256
  const isInactiveTriggerOrder =
256
- isOneOfVariant(order.orderType, ['triggerMarket', 'triggerLimit']) &&
257
- !order.triggered;
257
+ mustBeTriggered(order) && !isTriggered(order);
258
258
 
259
259
  let type: DLOBNodeType;
260
260
  if (isInactiveTriggerOrder) {
@@ -651,10 +651,7 @@ export class DLOB {
651
651
  const user = this.userMap.get(
652
652
  bestGenerator.next.value.userAccount.toString()
653
653
  );
654
- if (
655
- user?.getUserAccount().isBeingLiquidated ||
656
- user?.getUserAccount().isBankrupt
657
- ) {
654
+ if (user?.isBeingLiquidated()) {
658
655
  bestGenerator.next = bestGenerator.generator.next();
659
656
  continue;
660
657
  }
@@ -740,10 +737,7 @@ export class DLOB {
740
737
  const user = this.userMap.get(
741
738
  bestGenerator.next.value.userAccount.toString()
742
739
  );
743
- if (
744
- user?.getUserAccount().isBeingLiquidated ||
745
- user?.getUserAccount().isBankrupt
746
- ) {
740
+ if (user?.isBeingLiquidated()) {
747
741
  bestGenerator.next = bestGenerator.generator.next();
748
742
  continue;
749
743
  }
@@ -804,8 +798,11 @@ export class DLOB {
804
798
  bidNode
805
799
  );
806
800
 
807
- // If order doesn't have limit price, cant be maker
808
- if (!hasLimitPrice(makerNode.order, slot)) {
801
+ // If maker is market order and auction is complete, cant be maker
802
+ if (
803
+ isMarketOrder(makerNode.order) &&
804
+ isAuctionComplete(makerNode.order, slot)
805
+ ) {
809
806
  return {
810
807
  crossingNodes: [],
811
808
  exhaustedSide: makerSide,
@@ -586,6 +586,24 @@ export class DriftClient {
586
586
  );
587
587
  }
588
588
 
589
+ public async getUserAccountsForAuthority(
590
+ authority: PublicKey
591
+ ): Promise<UserAccount[]> {
592
+ const programAccounts = await this.program.account.user.all([
593
+ {
594
+ memcmp: {
595
+ offset: 8,
596
+ /** data to match, as base-58 encoded string and limited to less than 129 bytes */
597
+ bytes: bs58.encode(authority.toBuffer()),
598
+ },
599
+ },
600
+ ]);
601
+
602
+ return programAccounts.map(
603
+ (programAccount) => programAccount.account as UserAccount
604
+ );
605
+ }
606
+
589
607
  public async deleteUser(subAccountId = 0): Promise<TransactionSignature> {
590
608
  const userAccountPublicKey = getUserAccountPublicKeySync(
591
609
  this.program.programId,
@@ -2933,7 +2951,8 @@ export class DriftClient {
2933
2951
  userAccount: UserAccount,
2934
2952
  assetMarketIndex: number,
2935
2953
  liabilityMarketIndex: number,
2936
- maxLiabilityTransfer: BN
2954
+ maxLiabilityTransfer: BN,
2955
+ limitPrice?: BN
2937
2956
  ): Promise<TransactionSignature> {
2938
2957
  const { txSig, slot } = await this.txSender.send(
2939
2958
  wrapInTx(
@@ -2942,7 +2961,8 @@ export class DriftClient {
2942
2961
  userAccount,
2943
2962
  assetMarketIndex,
2944
2963
  liabilityMarketIndex,
2945
- maxLiabilityTransfer
2964
+ maxLiabilityTransfer,
2965
+ limitPrice
2946
2966
  )
2947
2967
  ),
2948
2968
  [],
@@ -2958,7 +2978,8 @@ export class DriftClient {
2958
2978
  userAccount: UserAccount,
2959
2979
  assetMarketIndex: number,
2960
2980
  liabilityMarketIndex: number,
2961
- maxLiabilityTransfer: BN
2981
+ maxLiabilityTransfer: BN,
2982
+ limitPrice?: BN
2962
2983
  ): Promise<TransactionInstruction> {
2963
2984
  const userStatsPublicKey = getUserStatsAccountPublicKey(
2964
2985
  this.program.programId,
@@ -2978,6 +2999,7 @@ export class DriftClient {
2978
2999
  assetMarketIndex,
2979
3000
  liabilityMarketIndex,
2980
3001
  maxLiabilityTransfer,
3002
+ limitPrice || null,
2981
3003
  {
2982
3004
  accounts: {
2983
3005
  state: await this.getStatePublicKey(),
@@ -2997,7 +3019,8 @@ export class DriftClient {
2997
3019
  userAccount: UserAccount,
2998
3020
  perpMarketIndex: number,
2999
3021
  liabilityMarketIndex: number,
3000
- maxLiabilityTransfer: BN
3022
+ maxLiabilityTransfer: BN,
3023
+ limitPrice?: BN
3001
3024
  ): Promise<TransactionSignature> {
3002
3025
  const { txSig, slot } = await this.txSender.send(
3003
3026
  wrapInTx(
@@ -3006,7 +3029,8 @@ export class DriftClient {
3006
3029
  userAccount,
3007
3030
  perpMarketIndex,
3008
3031
  liabilityMarketIndex,
3009
- maxLiabilityTransfer
3032
+ maxLiabilityTransfer,
3033
+ limitPrice
3010
3034
  )
3011
3035
  ),
3012
3036
  [],
@@ -3022,7 +3046,8 @@ export class DriftClient {
3022
3046
  userAccount: UserAccount,
3023
3047
  perpMarketIndex: number,
3024
3048
  liabilityMarketIndex: number,
3025
- maxLiabilityTransfer: BN
3049
+ maxLiabilityTransfer: BN,
3050
+ limitPrice?: BN
3026
3051
  ): Promise<TransactionInstruction> {
3027
3052
  const userStatsPublicKey = getUserStatsAccountPublicKey(
3028
3053
  this.program.programId,
@@ -3042,6 +3067,7 @@ export class DriftClient {
3042
3067
  perpMarketIndex,
3043
3068
  liabilityMarketIndex,
3044
3069
  maxLiabilityTransfer,
3070
+ limitPrice || null,
3045
3071
  {
3046
3072
  accounts: {
3047
3073
  state: await this.getStatePublicKey(),
@@ -3061,7 +3087,8 @@ export class DriftClient {
3061
3087
  userAccount: UserAccount,
3062
3088
  perpMarketIndex: number,
3063
3089
  assetMarketIndex: number,
3064
- maxPnlTransfer: BN
3090
+ maxPnlTransfer: BN,
3091
+ limitPrice?: BN
3065
3092
  ): Promise<TransactionSignature> {
3066
3093
  const { txSig, slot } = await this.txSender.send(
3067
3094
  wrapInTx(
@@ -3070,7 +3097,8 @@ export class DriftClient {
3070
3097
  userAccount,
3071
3098
  perpMarketIndex,
3072
3099
  assetMarketIndex,
3073
- maxPnlTransfer
3100
+ maxPnlTransfer,
3101
+ limitPrice
3074
3102
  )
3075
3103
  ),
3076
3104
  [],
@@ -3086,7 +3114,8 @@ export class DriftClient {
3086
3114
  userAccount: UserAccount,
3087
3115
  perpMarketIndex: number,
3088
3116
  assetMarketIndex: number,
3089
- maxPnlTransfer: BN
3117
+ maxPnlTransfer: BN,
3118
+ limitPrice?: BN
3090
3119
  ): Promise<TransactionInstruction> {
3091
3120
  const userStatsPublicKey = getUserStatsAccountPublicKey(
3092
3121
  this.program.programId,
@@ -3106,6 +3135,7 @@ export class DriftClient {
3106
3135
  perpMarketIndex,
3107
3136
  assetMarketIndex,
3108
3137
  maxPnlTransfer,
3138
+ limitPrice || null,
3109
3139
  {
3110
3140
  accounts: {
3111
3141
  state: await this.getStatePublicKey(),
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EventList = void 0;
4
+ class Node {
5
+ constructor(event, next, prev) {
6
+ this.event = event;
7
+ this.next = next;
8
+ this.prev = prev;
9
+ }
10
+ }
11
+ class EventList {
12
+ constructor(eventType, maxSize, sortFn, orderDirection) {
13
+ this.eventType = eventType;
14
+ this.maxSize = maxSize;
15
+ this.sortFn = sortFn;
16
+ this.orderDirection = orderDirection;
17
+ this.size = 0;
18
+ }
19
+ insert(event) {
20
+ this.size++;
21
+ const newNode = new Node(event);
22
+ if (this.head === undefined) {
23
+ this.head = this.tail = newNode;
24
+ return;
25
+ }
26
+ if (this.sortFn(this.head.event, newNode.event) ===
27
+ (this.orderDirection === 'asc' ? 'less than' : 'greater than')) {
28
+ this.head.prev = newNode;
29
+ newNode.next = this.head;
30
+ this.head = newNode;
31
+ }
32
+ else {
33
+ let currentNode = this.head;
34
+ while (currentNode.next !== undefined &&
35
+ this.sortFn(currentNode.next.event, newNode.event) !==
36
+ (this.orderDirection === 'asc' ? 'less than' : 'greater than')) {
37
+ currentNode = currentNode.next;
38
+ }
39
+ newNode.next = currentNode.next;
40
+ if (currentNode.next !== undefined) {
41
+ newNode.next.prev = newNode;
42
+ }
43
+ currentNode.next = newNode;
44
+ newNode.prev = currentNode;
45
+ }
46
+ if (this.size > this.maxSize) {
47
+ this.detach();
48
+ }
49
+ }
50
+ detach() {
51
+ const node = this.tail;
52
+ if (node.prev !== undefined) {
53
+ node.prev.next = node.next;
54
+ }
55
+ else {
56
+ this.head = node.next;
57
+ }
58
+ if (node.next !== undefined) {
59
+ node.next.prev = node.prev;
60
+ }
61
+ else {
62
+ this.tail = node.prev;
63
+ }
64
+ this.size--;
65
+ }
66
+ toArray() {
67
+ return Array.from(this);
68
+ }
69
+ *[Symbol.iterator]() {
70
+ let node = this.head;
71
+ while (node) {
72
+ yield node.event;
73
+ node = node.next;
74
+ }
75
+ }
76
+ }
77
+ exports.EventList = EventList;
@@ -11,6 +11,8 @@ import {
11
11
  LPRecord,
12
12
  InsuranceFundRecord,
13
13
  SpotInterestRecord,
14
+ InsuranceFundStakeRecord,
15
+ CurveRecord,
14
16
  } from '../index';
15
17
 
16
18
  export type EventSubscriptionOptions = {
@@ -39,6 +41,8 @@ export const DefaultEventSubscriptionOptions: EventSubscriptionOptions = {
39
41
  'LPRecord',
40
42
  'InsuranceFundRecord',
41
43
  'SpotInterestRecord',
44
+ 'InsuranceFundStakeRecord',
45
+ 'CurveRecord',
42
46
  ],
43
47
  maxEventsPerType: 4096,
44
48
  orderBy: 'blockchain',
@@ -77,6 +81,8 @@ export type EventMap = {
77
81
  LPRecord: Event<LPRecord>;
78
82
  InsuranceFundRecord: Event<InsuranceFundRecord>;
79
83
  SpotInterestRecord: Event<SpotInterestRecord>;
84
+ InsuranceFundStakeRecord: Event<InsuranceFundStakeRecord>;
85
+ CurveRecord: Event<CurveRecord>;
80
86
  };
81
87
 
82
88
  export type EventType = keyof EventMap;
@@ -0,0 +1,157 @@
1
+ 'use strict';
2
+ var __awaiter =
3
+ (this && this.__awaiter) ||
4
+ function (thisArg, _arguments, P, generator) {
5
+ function adopt(value) {
6
+ return value instanceof P
7
+ ? value
8
+ : new P(function (resolve) {
9
+ resolve(value);
10
+ });
11
+ }
12
+ return new (P || (P = Promise))(function (resolve, reject) {
13
+ function fulfilled(value) {
14
+ try {
15
+ step(generator.next(value));
16
+ } catch (e) {
17
+ reject(e);
18
+ }
19
+ }
20
+ function rejected(value) {
21
+ try {
22
+ step(generator['throw'](value));
23
+ } catch (e) {
24
+ reject(e);
25
+ }
26
+ }
27
+ function step(result) {
28
+ result.done
29
+ ? resolve(result.value)
30
+ : adopt(result.value).then(fulfilled, rejected);
31
+ }
32
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
33
+ });
34
+ };
35
+ Object.defineProperty(exports, '__esModule', { value: true });
36
+ exports.getTokenAddress = void 0;
37
+ const anchor_1 = require('@project-serum/anchor');
38
+ const __1 = require('..');
39
+ const spl_token_1 = require('@solana/spl-token');
40
+ const web3_js_1 = require('@solana/web3.js');
41
+ const __2 = require('..');
42
+ const banks_1 = require('../constants/spotMarkets');
43
+ const getTokenAddress = (mintAddress, userPubKey) => {
44
+ return spl_token_1.Token.getAssociatedTokenAddress(
45
+ new web3_js_1.PublicKey(`ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`),
46
+ spl_token_1.TOKEN_PROGRAM_ID,
47
+ new web3_js_1.PublicKey(mintAddress),
48
+ new web3_js_1.PublicKey(userPubKey)
49
+ );
50
+ };
51
+ exports.getTokenAddress = getTokenAddress;
52
+ const main = () =>
53
+ __awaiter(void 0, void 0, void 0, function* () {
54
+ // Initialize Drift SDK
55
+ const sdkConfig = __2.initialize({ env: 'devnet' });
56
+ // Set up the Wallet and Provider
57
+ const privateKey = process.env.BOT_PRIVATE_KEY; // stored as an array string
58
+ const keypair = web3_js_1.Keypair.fromSecretKey(
59
+ Uint8Array.from(JSON.parse(privateKey))
60
+ );
61
+ const wallet = new __1.Wallet(keypair);
62
+ // Set up the Connection
63
+ const rpcAddress = process.env.RPC_ADDRESS; // can use: https://api.devnet.solana.com for devnet; https://api.mainnet-beta.solana.com for mainnet;
64
+ const connection = new web3_js_1.Connection(rpcAddress);
65
+ // Set up the Provider
66
+ const provider = new anchor_1.AnchorProvider(
67
+ connection,
68
+ wallet,
69
+ anchor_1.AnchorProvider.defaultOptions()
70
+ );
71
+ // Check SOL Balance
72
+ const lamportsBalance = yield connection.getBalance(wallet.publicKey);
73
+ console.log('SOL balance:', lamportsBalance / Math.pow(10, 9));
74
+ // Misc. other things to set up
75
+ const usdcTokenAddress = yield exports.getTokenAddress(
76
+ sdkConfig.USDC_MINT_ADDRESS,
77
+ wallet.publicKey.toString()
78
+ );
79
+ // Set up the Drift Clearing House
80
+ const clearingHousePublicKey = new web3_js_1.PublicKey(
81
+ sdkConfig.CLEARING_HOUSE_PROGRAM_ID
82
+ );
83
+ const clearingHouse = new __2.ClearingHouse({
84
+ connection,
85
+ wallet: provider.wallet,
86
+ programID: clearingHousePublicKey,
87
+ });
88
+ yield clearingHouse.subscribe();
89
+ // Set up Clearing House user client
90
+ const user = new __2.ClearingHouseUser({
91
+ clearingHouse,
92
+ userAccountPublicKey: yield clearingHouse.getUserAccountPublicKey(),
93
+ });
94
+ //// Check if clearing house account exists for the current wallet
95
+ const userAccountExists = yield user.exists();
96
+ if (!userAccountExists) {
97
+ //// Create a Clearing House account by Depositing some USDC ($10,000 in this case)
98
+ const depositAmount = new anchor_1.BN(10000).mul(__2.QUOTE_PRECISION);
99
+ yield clearingHouse.initializeUserAccountAndDepositCollateral(
100
+ depositAmount,
101
+ yield exports.getTokenAddress(
102
+ usdcTokenAddress.toString(),
103
+ wallet.publicKey.toString()
104
+ ),
105
+ banks_1.SpotMarkets['devnet'][0].marketIndex
106
+ );
107
+ }
108
+ yield user.subscribe();
109
+ // Get current price
110
+ const solMarketInfo = sdkConfig.PERP_MARKETS.find(
111
+ (market) => market.baseAssetSymbol === 'SOL'
112
+ );
113
+ const currentMarketPrice = __2.calculateMarkPrice(
114
+ clearingHouse.getMarketAccount(solMarketInfo.marketIndex),
115
+ undefined
116
+ );
117
+ const formattedPrice = __2.convertToNumber(
118
+ currentMarketPrice,
119
+ __2.PRICE_PRECISION
120
+ );
121
+ console.log(`Current Market Price is $${formattedPrice}`);
122
+ // Estimate the slippage for a $5000 LONG trade
123
+ const solMarketAccount = clearingHouse.getMarketAccount(
124
+ solMarketInfo.marketIndex
125
+ );
126
+ const longAmount = new anchor_1.BN(5000).mul(__2.QUOTE_PRECISION);
127
+ const slippage = __2.convertToNumber(
128
+ __2.calculateTradeSlippage(
129
+ __2.PositionDirection.LONG,
130
+ longAmount,
131
+ solMarketAccount,
132
+ 'quote',
133
+ undefined
134
+ )[0],
135
+ __2.PRICE_PRECISION
136
+ );
137
+ console.log(
138
+ `Slippage for a $5000 LONG on the SOL market would be $${slippage}`
139
+ );
140
+ // Make a $5000 LONG trade
141
+ yield clearingHouse.openPosition(
142
+ __2.PositionDirection.LONG,
143
+ longAmount,
144
+ solMarketInfo.marketIndex
145
+ );
146
+ console.log(`LONGED $5000 SOL`);
147
+ // Reduce the position by $2000
148
+ const reduceAmount = new anchor_1.BN(2000).mul(__2.QUOTE_PRECISION);
149
+ yield clearingHouse.openPosition(
150
+ __2.PositionDirection.SHORT,
151
+ reduceAmount,
152
+ solMarketInfo.marketIndex
153
+ );
154
+ // Close the rest of the position
155
+ yield clearingHouse.closePosition(solMarketInfo.marketIndex);
156
+ });
157
+ main();