@drift-labs/sdk 0.2.0-master.7 → 0.2.0-master.8

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 (65) hide show
  1. package/lib/clearingHouse.js +38 -25
  2. package/lib/constants/banks.js +9 -1
  3. package/package.json +1 -1
  4. package/src/accounts/bulkAccountLoader.js +197 -0
  5. package/src/accounts/bulkUserSubscription.js +33 -0
  6. package/src/accounts/fetch.js +29 -0
  7. package/src/accounts/pollingClearingHouseAccountSubscriber.js +311 -0
  8. package/src/accounts/pollingOracleSubscriber.js +93 -0
  9. package/src/accounts/pollingTokenAccountSubscriber.js +90 -0
  10. package/src/accounts/pollingUserAccountSubscriber.js +132 -0
  11. package/src/accounts/types.js +10 -0
  12. package/src/accounts/utils.js +7 -0
  13. package/src/accounts/webSocketAccountSubscriber.js +93 -0
  14. package/src/accounts/webSocketClearingHouseAccountSubscriber.js +233 -0
  15. package/src/accounts/webSocketUserAccountSubscriber.js +62 -0
  16. package/src/addresses/marketAddresses.js +26 -0
  17. package/src/addresses/pda.js +104 -0
  18. package/src/assert/assert.js +9 -0
  19. package/src/clearingHouse.ts +43 -27
  20. package/src/constants/banks.ts +9 -1
  21. package/src/events/eventList.js +77 -0
  22. package/src/events/eventSubscriber.js +139 -0
  23. package/src/events/fetchLogs.js +50 -0
  24. package/src/events/pollingLogProvider.js +64 -0
  25. package/src/events/sort.js +44 -0
  26. package/src/events/txEventCache.js +71 -0
  27. package/src/events/types.js +20 -0
  28. package/src/events/webSocketLogProvider.js +41 -0
  29. package/src/examples/makeTradeExample.js +80 -0
  30. package/src/factory/bigNum.js +364 -0
  31. package/src/factory/oracleClient.js +20 -0
  32. package/src/index.js +69 -0
  33. package/src/math/amm.js +369 -0
  34. package/src/math/auction.js +42 -0
  35. package/src/math/bankBalance.js +75 -0
  36. package/src/math/conversion.js +11 -0
  37. package/src/math/funding.js +248 -0
  38. package/src/math/market.js +57 -0
  39. package/src/math/oracles.js +26 -0
  40. package/src/math/orders.js +110 -0
  41. package/src/math/position.js +140 -0
  42. package/src/math/repeg.js +128 -0
  43. package/src/math/state.js +15 -0
  44. package/src/math/trade.js +253 -0
  45. package/src/math/utils.js +0 -1
  46. package/src/mockUSDCFaucet.js +171 -0
  47. package/src/oracles/oracleClientCache.js +19 -0
  48. package/src/oracles/pythClient.js +46 -0
  49. package/src/oracles/quoteAssetOracleClient.js +32 -0
  50. package/src/oracles/switchboardClient.js +69 -0
  51. package/src/oracles/types.js +2 -0
  52. package/src/orderParams.js +20 -0
  53. package/src/orders.js +134 -0
  54. package/src/slot/SlotSubscriber.js +39 -0
  55. package/src/token/index.js +38 -0
  56. package/src/tx/retryTxSender.js +188 -0
  57. package/src/tx/types.js +2 -0
  58. package/src/tx/utils.js +17 -0
  59. package/src/types.js +114 -0
  60. package/src/userName.js +20 -0
  61. package/src/util/promiseTimeout.js +14 -0
  62. package/src/util/tps.js +27 -0
  63. package/src/wallet.js +35 -0
  64. package/src/util/computeUnits.js +0 -17
  65. package/src/util/computeUnits.js.map +0 -1
@@ -674,44 +674,57 @@ class ClearingHouse {
674
674
  const fillerPublicKey = await this.getUserAccountPublicKey();
675
675
  const marketIndex = order.marketIndex;
676
676
  const marketAccount = this.getMarketAccount(marketIndex);
677
- const bankAccountInfos = [
678
- {
679
- pubkey: this.getQuoteAssetBankAccount().pubkey,
680
- isSigner: false,
681
- isWritable: true,
682
- },
683
- ];
684
- const marketAccountInfos = [
685
- {
686
- pubkey: marketAccount.pubkey,
687
- isWritable: true,
688
- isSigner: false,
689
- },
690
- ];
691
- const oracleAccountInfos = [
692
- {
693
- pubkey: marketAccount.amm.oracle,
694
- isWritable: false,
695
- isSigner: false,
696
- },
697
- ];
677
+ const oracleAccountMap = new Map();
678
+ const bankAccountMap = new Map();
679
+ const marketAccountMap = new Map();
680
+ marketAccountMap.set(marketIndex.toNumber(), {
681
+ pubkey: marketAccount.pubkey,
682
+ isWritable: true,
683
+ isSigner: false,
684
+ });
685
+ oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
686
+ pubkey: marketAccount.amm.oracle,
687
+ isWritable: false,
688
+ isSigner: false,
689
+ });
690
+ for (const bankBalance of userAccount.bankBalances) {
691
+ if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
692
+ const bankAccount = this.getBankAccount(bankBalance.bankIndex);
693
+ bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
694
+ pubkey: bankAccount.pubkey,
695
+ isSigner: false,
696
+ isWritable: true,
697
+ });
698
+ if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
699
+ oracleAccountMap.set(bankAccount.oracle.toString(), {
700
+ pubkey: bankAccount.oracle,
701
+ isSigner: false,
702
+ isWritable: false,
703
+ });
704
+ }
705
+ }
706
+ }
698
707
  for (const position of userAccount.positions) {
699
708
  if (!(0, position_1.positionIsAvailable)(position) &&
700
709
  !position.marketIndex.eq(order.marketIndex)) {
701
710
  const market = this.getMarketAccount(position.marketIndex);
702
- marketAccountInfos.push({
711
+ marketAccountMap.set(position.marketIndex.toNumber(), {
703
712
  pubkey: market.pubkey,
704
- isWritable: false,
713
+ isWritable: true,
705
714
  isSigner: false,
706
715
  });
707
- oracleAccountInfos.push({
716
+ oracleAccountMap.set(market.amm.oracle.toString(), {
708
717
  pubkey: market.amm.oracle,
709
718
  isWritable: false,
710
719
  isSigner: false,
711
720
  });
712
721
  }
713
722
  }
714
- const remainingAccounts = oracleAccountInfos.concat(bankAccountInfos.concat(marketAccountInfos));
723
+ const remainingAccounts = [
724
+ ...oracleAccountMap.values(),
725
+ ...bankAccountMap.values(),
726
+ ...marketAccountMap.values(),
727
+ ];
715
728
  const orderId = order.orderId;
716
729
  return await this.program.instruction.triggerOrder(orderId, {
717
730
  accounts: {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Banks = exports.MainnetBanks = exports.DevnetBanks = void 0;
4
4
  const __1 = require("../");
5
5
  const web3_js_1 = require("@solana/web3.js");
6
+ const token_instructions_1 = require("@project-serum/serum/lib/token-instructions");
6
7
  exports.DevnetBanks = [
7
8
  {
8
9
  symbol: 'USDC',
@@ -12,8 +13,15 @@ exports.DevnetBanks = [
12
13
  mint: new web3_js_1.PublicKey('8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2'),
13
14
  },
14
15
  {
15
- symbol: 'BTC',
16
+ symbol: 'SOL',
16
17
  bankIndex: new __1.BN(1),
18
+ oracle: new web3_js_1.PublicKey('J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix'),
19
+ oracleSource: __1.OracleSource.PYTH,
20
+ mint: token_instructions_1.WRAPPED_SOL_MINT,
21
+ },
22
+ {
23
+ symbol: 'BTC',
24
+ bankIndex: new __1.BN(2),
17
25
  oracle: new web3_js_1.PublicKey('HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J'),
18
26
  oracleSource: __1.OracleSource.PYTH,
19
27
  mint: new web3_js_1.PublicKey('Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "0.2.0-master.7",
3
+ "version": "0.2.0-master.8",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.BulkAccountLoader = void 0;
13
+ const uuid_1 = require("uuid");
14
+ const promiseTimeout_1 = require("../util/promiseTimeout");
15
+ const GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE = 99;
16
+ const oneMinute = 60 * 1000;
17
+ class BulkAccountLoader {
18
+ constructor(connection, commitment, pollingFrequency) {
19
+ this.accountsToLoad = new Map();
20
+ this.bufferAndSlotMap = new Map();
21
+ this.errorCallbacks = new Map();
22
+ this.lastTimeLoadingPromiseCleared = Date.now();
23
+ this.mostRecentSlot = 0;
24
+ this.connection = connection;
25
+ this.commitment = commitment;
26
+ this.pollingFrequency = pollingFrequency;
27
+ }
28
+ addAccount(publicKey, callback) {
29
+ const existingSize = this.accountsToLoad.size;
30
+ const callbackId = uuid_1.v4();
31
+ const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
32
+ if (existingAccountToLoad) {
33
+ existingAccountToLoad.callbacks.set(callbackId, callback);
34
+ }
35
+ else {
36
+ const callbacks = new Map();
37
+ callbacks.set(callbackId, callback);
38
+ const newAccountToLoad = {
39
+ publicKey,
40
+ callbacks,
41
+ };
42
+ this.accountsToLoad.set(publicKey.toString(), newAccountToLoad);
43
+ }
44
+ if (existingSize === 0) {
45
+ this.startPolling();
46
+ }
47
+ // if a new account needs to be polled, remove the cached loadPromise in case client calls load immediately after
48
+ this.loadPromise = undefined;
49
+ return callbackId;
50
+ }
51
+ removeAccount(publicKey, callbackId) {
52
+ const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
53
+ if (existingAccountToLoad) {
54
+ existingAccountToLoad.callbacks.delete(callbackId);
55
+ if (existingAccountToLoad.callbacks.size === 0) {
56
+ this.accountsToLoad.delete(existingAccountToLoad.publicKey.toString());
57
+ }
58
+ }
59
+ if (this.accountsToLoad.size === 0) {
60
+ this.stopPolling();
61
+ }
62
+ }
63
+ addErrorCallbacks(callback) {
64
+ const callbackId = uuid_1.v4();
65
+ this.errorCallbacks.set(callbackId, callback);
66
+ return callbackId;
67
+ }
68
+ removeErrorCallbacks(callbackId) {
69
+ this.errorCallbacks.delete(callbackId);
70
+ }
71
+ chunks(array, size) {
72
+ return new Array(Math.ceil(array.length / size))
73
+ .fill(null)
74
+ .map((_, index) => index * size)
75
+ .map((begin) => array.slice(begin, begin + size));
76
+ }
77
+ load() {
78
+ return __awaiter(this, void 0, void 0, function* () {
79
+ if (this.loadPromise) {
80
+ const now = Date.now();
81
+ if (now - this.lastTimeLoadingPromiseCleared > oneMinute) {
82
+ this.loadPromise = undefined;
83
+ }
84
+ else {
85
+ return this.loadPromise;
86
+ }
87
+ }
88
+ this.loadPromise = new Promise((resolver) => {
89
+ this.loadPromiseResolver = resolver;
90
+ });
91
+ this.lastTimeLoadingPromiseCleared = Date.now();
92
+ try {
93
+ const chunks = this.chunks(Array.from(this.accountsToLoad.values()), GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE);
94
+ yield Promise.all(chunks.map((chunk) => {
95
+ return this.loadChunk(chunk);
96
+ }));
97
+ }
98
+ catch (e) {
99
+ console.error(`Error in bulkAccountLoader.load()`);
100
+ console.error(e);
101
+ for (const [_, callback] of this.errorCallbacks) {
102
+ callback(e);
103
+ }
104
+ }
105
+ finally {
106
+ this.loadPromiseResolver();
107
+ this.loadPromise = undefined;
108
+ }
109
+ });
110
+ }
111
+ loadChunk(accountsToLoad) {
112
+ return __awaiter(this, void 0, void 0, function* () {
113
+ if (accountsToLoad.length === 0) {
114
+ return;
115
+ }
116
+ const args = [
117
+ accountsToLoad.map((accountToLoad) => {
118
+ return accountToLoad.publicKey.toBase58();
119
+ }),
120
+ { commitment: this.commitment },
121
+ ];
122
+ const rpcResponse = yield promiseTimeout_1.promiseTimeout(
123
+ // @ts-ignore
124
+ this.connection._rpcRequest('getMultipleAccounts', args), 10 * 1000 // 30 second timeout
125
+ );
126
+ if (rpcResponse === null) {
127
+ this.log('request to rpc timed out');
128
+ return;
129
+ }
130
+ const newSlot = rpcResponse.result.context.slot;
131
+ if (newSlot > this.mostRecentSlot) {
132
+ this.mostRecentSlot = newSlot;
133
+ }
134
+ for (const i in accountsToLoad) {
135
+ const accountToLoad = accountsToLoad[i];
136
+ const key = accountToLoad.publicKey.toString();
137
+ const oldRPCResponse = this.bufferAndSlotMap.get(key);
138
+ let newBuffer = undefined;
139
+ if (rpcResponse.result.value[i]) {
140
+ const raw = rpcResponse.result.value[i].data[0];
141
+ const dataType = rpcResponse.result.value[i].data[1];
142
+ newBuffer = Buffer.from(raw, dataType);
143
+ }
144
+ if (!oldRPCResponse) {
145
+ this.bufferAndSlotMap.set(key, {
146
+ slot: newSlot,
147
+ buffer: newBuffer,
148
+ });
149
+ this.handleAccountCallbacks(accountToLoad, newBuffer, newSlot);
150
+ continue;
151
+ }
152
+ if (newSlot <= oldRPCResponse.slot) {
153
+ continue;
154
+ }
155
+ const oldBuffer = oldRPCResponse.buffer;
156
+ if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
157
+ this.bufferAndSlotMap.set(key, {
158
+ slot: newSlot,
159
+ buffer: newBuffer,
160
+ });
161
+ this.handleAccountCallbacks(accountToLoad, newBuffer, newSlot);
162
+ }
163
+ }
164
+ });
165
+ }
166
+ handleAccountCallbacks(accountToLoad, buffer, slot) {
167
+ for (const [_, callback] of accountToLoad.callbacks) {
168
+ callback(buffer, slot);
169
+ }
170
+ }
171
+ getBufferAndSlot(publicKey) {
172
+ return this.bufferAndSlotMap.get(publicKey.toString());
173
+ }
174
+ startPolling() {
175
+ if (this.intervalId) {
176
+ return;
177
+ }
178
+ this.intervalId = setInterval(this.load.bind(this), this.pollingFrequency);
179
+ }
180
+ stopPolling() {
181
+ if (this.intervalId) {
182
+ clearInterval(this.intervalId);
183
+ this.intervalId = undefined;
184
+ }
185
+ }
186
+ log(msg) {
187
+ console.log(msg);
188
+ }
189
+ updatePollingFrequency(pollingFrequency) {
190
+ this.stopPolling();
191
+ this.pollingFrequency = pollingFrequency;
192
+ if (this.accountsToLoad.size > 0) {
193
+ this.startPolling();
194
+ }
195
+ }
196
+ }
197
+ exports.BulkAccountLoader = BulkAccountLoader;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.bulkPollingUserSubscribe = void 0;
13
+ /**
14
+ * @param users
15
+ * @param accountLoader
16
+ */
17
+ function bulkPollingUserSubscribe(users, accountLoader) {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ if (users.length === 0) {
20
+ yield accountLoader.load();
21
+ return;
22
+ }
23
+ yield Promise.all(users.map((user) => {
24
+ // Pull the keys from the authority map so we can skip fetching them in addToAccountLoader
25
+ return user.accountSubscriber.addToAccountLoader();
26
+ }));
27
+ yield accountLoader.load();
28
+ yield Promise.all(users.map((user) => __awaiter(this, void 0, void 0, function* () {
29
+ return user.subscribe();
30
+ })));
31
+ });
32
+ }
33
+ exports.bulkPollingUserSubscribe = bulkPollingUserSubscribe;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.fetchUserAccounts = void 0;
13
+ const pda_1 = require("../addresses/pda");
14
+ function fetchUserAccounts(connection, program, authority, limit = 8) {
15
+ return __awaiter(this, void 0, void 0, function* () {
16
+ const userAccountPublicKeys = new Array();
17
+ for (let i = 0; i < limit; i++) {
18
+ userAccountPublicKeys.push(yield pda_1.getUserAccountPublicKey(program.programId, authority, i));
19
+ }
20
+ const accountInfos = yield connection.getMultipleAccountsInfo(userAccountPublicKeys, 'confirmed');
21
+ return accountInfos.map((accountInfo) => {
22
+ if (!accountInfo) {
23
+ return undefined;
24
+ }
25
+ return program.account.user.coder.accounts.decode('User', accountInfo.data);
26
+ });
27
+ });
28
+ }
29
+ exports.fetchUserAccounts = fetchUserAccounts;