@drift-labs/sdk 0.2.0-temp.0 → 0.2.0-temp.1

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 (115) hide show
  1. package/lib/admin.d.ts +7 -5
  2. package/lib/admin.js +34 -11
  3. package/lib/clearingHouse.d.ts +23 -9
  4. package/lib/clearingHouse.js +335 -95
  5. package/lib/clearingHouseUser.d.ts +2 -2
  6. package/lib/clearingHouseUser.js +8 -17
  7. package/lib/config.js +1 -1
  8. package/lib/constants/banks.js +9 -2
  9. package/lib/constants/numericConstants.d.ts +1 -0
  10. package/lib/constants/numericConstants.js +2 -1
  11. package/lib/idl/clearing_house.json +689 -153
  12. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  13. package/lib/index.d.ts +3 -2
  14. package/lib/index.js +7 -2
  15. package/lib/math/amm.js +7 -35
  16. package/lib/math/auction.js +4 -1
  17. package/lib/math/orders.d.ts +2 -2
  18. package/lib/math/orders.js +19 -2
  19. package/lib/math/position.js +3 -1
  20. package/lib/math/trade.d.ts +1 -1
  21. package/lib/math/trade.js +7 -10
  22. package/lib/orderParams.d.ts +14 -5
  23. package/lib/orderParams.js +8 -96
  24. package/lib/orders.js +1 -1
  25. package/lib/slot/SlotSubscriber.d.ts +7 -0
  26. package/lib/slot/SlotSubscriber.js +3 -0
  27. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +7 -5
  28. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +41 -40
  29. package/lib/tx/utils.js +1 -1
  30. package/lib/types.d.ts +132 -14
  31. package/lib/types.js +52 -1
  32. package/lib/util/computeUnits.js +1 -1
  33. package/package.json +3 -3
  34. package/src/accounts/bulkAccountLoader.js +197 -0
  35. package/src/accounts/bulkUserSubscription.js +33 -0
  36. package/src/accounts/pollingClearingHouseAccountSubscriber.js +311 -0
  37. package/src/accounts/pollingOracleSubscriber.js +93 -0
  38. package/src/accounts/pollingTokenAccountSubscriber.js +90 -0
  39. package/src/accounts/pollingUserAccountSubscriber.js +132 -0
  40. package/src/accounts/types.js +10 -0
  41. package/src/accounts/utils.js +7 -0
  42. package/src/accounts/webSocketAccountSubscriber.js +93 -0
  43. package/src/accounts/webSocketClearingHouseAccountSubscriber.js +233 -0
  44. package/src/accounts/webSocketUserAccountSubscriber.js +62 -0
  45. package/src/addresses/marketAddresses.js +26 -0
  46. package/src/admin.js +517 -0
  47. package/src/admin.ts +53 -14
  48. package/src/assert/assert.js +9 -0
  49. package/src/clearingHouse.ts +510 -131
  50. package/src/clearingHouseConfig.js +2 -0
  51. package/src/clearingHouseUser.ts +12 -23
  52. package/src/clearingHouseUserConfig.js +2 -0
  53. package/src/config.js +67 -0
  54. package/src/config.ts +1 -1
  55. package/src/constants/banks.js +42 -0
  56. package/src/constants/banks.ts +9 -2
  57. package/src/constants/markets.js +42 -0
  58. package/src/constants/numericConstants.js +41 -0
  59. package/src/constants/numericConstants.ts +1 -0
  60. package/src/events/eventList.js +77 -0
  61. package/src/events/eventSubscriber.js +139 -0
  62. package/src/events/fetchLogs.js +50 -0
  63. package/src/events/pollingLogProvider.js +64 -0
  64. package/src/events/sort.js +44 -0
  65. package/src/events/txEventCache.js +71 -0
  66. package/src/events/types.js +20 -0
  67. package/src/events/webSocketLogProvider.js +41 -0
  68. package/src/examples/makeTradeExample.js +80 -0
  69. package/src/factory/bigNum.js +390 -0
  70. package/src/factory/oracleClient.js +20 -0
  71. package/src/idl/clearing_house.json +689 -153
  72. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  73. package/src/index.js +69 -0
  74. package/src/index.ts +3 -2
  75. package/src/math/amm.js +369 -0
  76. package/src/math/amm.ts +19 -49
  77. package/src/math/auction.js +42 -0
  78. package/src/math/auction.ts +5 -1
  79. package/src/math/conversion.js +11 -0
  80. package/src/math/funding.js +248 -0
  81. package/src/math/oracles.js +26 -0
  82. package/src/math/orders.ts +17 -3
  83. package/src/math/position.ts +5 -1
  84. package/src/math/repeg.js +128 -0
  85. package/src/math/state.js +15 -0
  86. package/src/math/trade.js +253 -0
  87. package/src/math/trade.ts +23 -25
  88. package/src/math/utils.js +0 -1
  89. package/src/mockUSDCFaucet.js +280 -0
  90. package/src/oracles/oracleClientCache.js +19 -0
  91. package/src/oracles/pythClient.js +46 -0
  92. package/src/oracles/quoteAssetOracleClient.js +32 -0
  93. package/src/oracles/switchboardClient.js +69 -0
  94. package/src/oracles/types.js +2 -0
  95. package/src/orderParams.js +20 -0
  96. package/src/orderParams.ts +20 -141
  97. package/src/orders.ts +2 -1
  98. package/src/slot/SlotSubscriber.js +39 -0
  99. package/src/slot/SlotSubscriber.ts +11 -1
  100. package/src/token/index.js +38 -0
  101. package/src/tokenFaucet.js +189 -0
  102. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +48 -59
  103. package/src/tx/types.js +2 -0
  104. package/src/tx/utils.js +17 -0
  105. package/src/tx/utils.ts +1 -1
  106. package/src/types.js +125 -0
  107. package/src/types.ts +128 -15
  108. package/src/userName.js +20 -0
  109. package/src/util/computeUnits.js +21 -11
  110. package/src/util/computeUnits.ts +1 -1
  111. package/src/util/getTokenAddress.js +9 -0
  112. package/src/util/promiseTimeout.js +14 -0
  113. package/src/util/tps.js +27 -0
  114. package/src/wallet.js +35 -0
  115. package/src/util/computeUnits.js.map +0 -1
@@ -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,311 @@
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.PollingClearingHouseAccountSubscriber = void 0;
13
+ const types_1 = require("./types");
14
+ const events_1 = require("events");
15
+ const pda_1 = require("../addresses/pda");
16
+ const utils_1 = require("./utils");
17
+ const web3_js_1 = require("@solana/web3.js");
18
+ const oracleClientCache_1 = require("../oracles/oracleClientCache");
19
+ const quoteAssetOracleClient_1 = require("../oracles/quoteAssetOracleClient");
20
+ class PollingClearingHouseAccountSubscriber {
21
+ constructor(program, accountLoader, marketIndexes, bankIndexes, oracleInfos) {
22
+ this.oracleClientCache = new oracleClientCache_1.OracleClientCache();
23
+ this.accountsToPoll = new Map();
24
+ this.oraclesToPoll = new Map();
25
+ this.market = new Map();
26
+ this.bank = new Map();
27
+ this.oracles = new Map();
28
+ this.isSubscribing = false;
29
+ this.isSubscribed = false;
30
+ this.program = program;
31
+ this.eventEmitter = new events_1.EventEmitter();
32
+ this.accountLoader = accountLoader;
33
+ this.marketIndexes = marketIndexes;
34
+ this.bankIndexes = bankIndexes;
35
+ this.oracleInfos = oracleInfos;
36
+ }
37
+ subscribe() {
38
+ return __awaiter(this, void 0, void 0, function* () {
39
+ if (this.isSubscribed) {
40
+ return true;
41
+ }
42
+ if (this.isSubscribing) {
43
+ return yield this.subscriptionPromise;
44
+ }
45
+ this.isSubscribing = true;
46
+ this.subscriptionPromise = new Promise((res) => {
47
+ this.subscriptionPromiseResolver = res;
48
+ });
49
+ yield this.updateAccountsToPoll();
50
+ yield this.updateOraclesToPoll();
51
+ yield this.addToAccountLoader();
52
+ let subscriptionSucceeded = false;
53
+ let retries = 0;
54
+ while (!subscriptionSucceeded && retries < 5) {
55
+ yield this.fetch();
56
+ subscriptionSucceeded = this.didSubscriptionSucceed();
57
+ retries++;
58
+ }
59
+ if (subscriptionSucceeded) {
60
+ this.eventEmitter.emit('update');
61
+ }
62
+ this.isSubscribing = false;
63
+ this.isSubscribed = subscriptionSucceeded;
64
+ this.subscriptionPromiseResolver(subscriptionSucceeded);
65
+ return subscriptionSucceeded;
66
+ });
67
+ }
68
+ updateAccountsToPoll() {
69
+ return __awaiter(this, void 0, void 0, function* () {
70
+ if (this.accountsToPoll.size > 0) {
71
+ return;
72
+ }
73
+ const accounts = yield this.getClearingHouseAccounts();
74
+ this.accountsToPoll.set(accounts.state.toString(), {
75
+ key: 'state',
76
+ publicKey: accounts.state,
77
+ eventType: 'stateAccountUpdate',
78
+ });
79
+ yield this.updateMarketAccountsToPoll();
80
+ yield this.updateBankAccountsToPoll();
81
+ });
82
+ }
83
+ updateMarketAccountsToPoll() {
84
+ return __awaiter(this, void 0, void 0, function* () {
85
+ for (const marketIndex of this.marketIndexes) {
86
+ yield this.addMarketAccountToPoll(marketIndex);
87
+ }
88
+ return true;
89
+ });
90
+ }
91
+ addMarketAccountToPoll(marketIndex) {
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ const marketPublicKey = yield pda_1.getMarketPublicKey(this.program.programId, marketIndex);
94
+ this.accountsToPoll.set(marketPublicKey.toString(), {
95
+ key: 'market',
96
+ publicKey: marketPublicKey,
97
+ eventType: 'marketAccountUpdate',
98
+ mapKey: marketIndex.toNumber(),
99
+ });
100
+ return true;
101
+ });
102
+ }
103
+ updateBankAccountsToPoll() {
104
+ return __awaiter(this, void 0, void 0, function* () {
105
+ for (const bankIndex of this.bankIndexes) {
106
+ yield this.addBankAccountToPoll(bankIndex);
107
+ }
108
+ return true;
109
+ });
110
+ }
111
+ addBankAccountToPoll(bankIndex) {
112
+ return __awaiter(this, void 0, void 0, function* () {
113
+ const bankPublicKey = yield pda_1.getBankPublicKey(this.program.programId, bankIndex);
114
+ this.accountsToPoll.set(bankPublicKey.toString(), {
115
+ key: 'bank',
116
+ publicKey: bankPublicKey,
117
+ eventType: 'bankAccountUpdate',
118
+ mapKey: bankIndex.toNumber(),
119
+ });
120
+ return true;
121
+ });
122
+ }
123
+ updateOraclesToPoll() {
124
+ for (const oracleInfo of this.oracleInfos) {
125
+ if (!oracleInfo.publicKey.equals(web3_js_1.PublicKey.default)) {
126
+ this.addOracleToPoll(oracleInfo);
127
+ }
128
+ }
129
+ return true;
130
+ }
131
+ addOracleToPoll(oracleInfo) {
132
+ this.oraclesToPoll.set(oracleInfo.publicKey.toString(), {
133
+ publicKey: oracleInfo.publicKey,
134
+ source: oracleInfo.source,
135
+ });
136
+ return true;
137
+ }
138
+ getClearingHouseAccounts() {
139
+ return __awaiter(this, void 0, void 0, function* () {
140
+ const statePublicKey = yield pda_1.getClearingHouseStateAccountPublicKey(this.program.programId);
141
+ const accounts = {
142
+ state: statePublicKey,
143
+ };
144
+ return accounts;
145
+ });
146
+ }
147
+ addToAccountLoader() {
148
+ return __awaiter(this, void 0, void 0, function* () {
149
+ for (const [_, accountToPoll] of this.accountsToPoll) {
150
+ this.addAccountToAccountLoader(accountToPoll);
151
+ }
152
+ for (const [_, oracleToPoll] of this.oraclesToPoll) {
153
+ this.addOracleToAccountLoader(oracleToPoll);
154
+ }
155
+ this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
156
+ this.eventEmitter.emit('error', error);
157
+ });
158
+ });
159
+ }
160
+ addAccountToAccountLoader(accountToPoll) {
161
+ accountToPoll.callbackId = this.accountLoader.addAccount(accountToPoll.publicKey, (buffer, slot) => {
162
+ if (!buffer)
163
+ return;
164
+ const account = this.program.account[accountToPoll.key].coder.accounts.decode(utils_1.capitalize(accountToPoll.key), buffer);
165
+ const dataAndSlot = {
166
+ data: account,
167
+ slot,
168
+ };
169
+ if (accountToPoll.mapKey != undefined) {
170
+ this[accountToPoll.key].set(accountToPoll.mapKey, dataAndSlot);
171
+ }
172
+ else {
173
+ this[accountToPoll.key] = dataAndSlot;
174
+ }
175
+ // @ts-ignore
176
+ this.eventEmitter.emit(accountToPoll.eventType, account);
177
+ this.eventEmitter.emit('update');
178
+ if (!this.isSubscribed) {
179
+ this.isSubscribed = this.didSubscriptionSucceed();
180
+ }
181
+ });
182
+ }
183
+ addOracleToAccountLoader(oracleToPoll) {
184
+ const oracleClient = this.oracleClientCache.get(oracleToPoll.source, this.program.provider.connection);
185
+ oracleToPoll.callbackId = this.accountLoader.addAccount(oracleToPoll.publicKey, (buffer, slot) => {
186
+ if (!buffer)
187
+ return;
188
+ const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(buffer);
189
+ const dataAndSlot = {
190
+ data: oraclePriceData,
191
+ slot,
192
+ };
193
+ this.oracles.set(oracleToPoll.publicKey.toString(), dataAndSlot);
194
+ this.eventEmitter.emit('oraclePriceUpdate', oracleToPoll.publicKey, oraclePriceData);
195
+ this.eventEmitter.emit('update');
196
+ });
197
+ }
198
+ fetch() {
199
+ return __awaiter(this, void 0, void 0, function* () {
200
+ yield this.accountLoader.load();
201
+ for (const [_, accountToPoll] of this.accountsToPoll) {
202
+ const { buffer, slot } = this.accountLoader.getBufferAndSlot(accountToPoll.publicKey);
203
+ if (buffer) {
204
+ const account = this.program.account[accountToPoll.key].coder.accounts.decode(utils_1.capitalize(accountToPoll.key), buffer);
205
+ if (accountToPoll.mapKey != undefined) {
206
+ this[accountToPoll.key].set(accountToPoll.mapKey, {
207
+ data: account,
208
+ slot,
209
+ });
210
+ }
211
+ else {
212
+ this[accountToPoll.key] = {
213
+ data: account,
214
+ slot,
215
+ };
216
+ }
217
+ }
218
+ }
219
+ for (const [_, oracleToPoll] of this.oraclesToPoll) {
220
+ const { buffer, slot } = this.accountLoader.getBufferAndSlot(oracleToPoll.publicKey);
221
+ if (buffer) {
222
+ const oracleClient = this.oracleClientCache.get(oracleToPoll.source, this.program.provider.connection);
223
+ const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(buffer);
224
+ this.oracles.set(oracleToPoll.publicKey.toString(), {
225
+ data: oraclePriceData,
226
+ slot,
227
+ });
228
+ }
229
+ }
230
+ });
231
+ }
232
+ didSubscriptionSucceed() {
233
+ if (this.state)
234
+ return true;
235
+ return false;
236
+ }
237
+ unsubscribe() {
238
+ return __awaiter(this, void 0, void 0, function* () {
239
+ if (!this.isSubscribed) {
240
+ return;
241
+ }
242
+ for (const [_, accountToPoll] of this.accountsToPoll) {
243
+ this.accountLoader.removeAccount(accountToPoll.publicKey, accountToPoll.callbackId);
244
+ }
245
+ for (const [_, oracleToPoll] of this.oraclesToPoll) {
246
+ this.accountLoader.removeAccount(oracleToPoll.publicKey, oracleToPoll.callbackId);
247
+ }
248
+ this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
249
+ this.errorCallbackId = undefined;
250
+ this.accountsToPoll.clear();
251
+ this.oraclesToPoll.clear();
252
+ this.isSubscribed = false;
253
+ });
254
+ }
255
+ addBank(bankIndex) {
256
+ return __awaiter(this, void 0, void 0, function* () {
257
+ yield this.addBankAccountToPoll(bankIndex);
258
+ const accountToPoll = this.accountsToPoll.get(bankIndex.toString());
259
+ this.addAccountToAccountLoader(accountToPoll);
260
+ return true;
261
+ });
262
+ }
263
+ addMarket(marketIndex) {
264
+ return __awaiter(this, void 0, void 0, function* () {
265
+ yield this.addMarketAccountToPoll(marketIndex);
266
+ const accountToPoll = this.accountsToPoll.get(marketIndex.toString());
267
+ this.addAccountToAccountLoader(accountToPoll);
268
+ return true;
269
+ });
270
+ }
271
+ addOracle(oracleInfo) {
272
+ return __awaiter(this, void 0, void 0, function* () {
273
+ if (oracleInfo.publicKey.equals(web3_js_1.PublicKey.default)) {
274
+ return true;
275
+ }
276
+ this.addOracleToPoll(oracleInfo);
277
+ const oracleToPoll = this.oraclesToPoll.get(oracleInfo.publicKey.toString());
278
+ this.addOracleToAccountLoader(oracleToPoll);
279
+ return true;
280
+ });
281
+ }
282
+ assertIsSubscribed() {
283
+ if (!this.isSubscribed) {
284
+ throw new types_1.NotSubscribedError('You must call `subscribe` before using this function');
285
+ }
286
+ }
287
+ getStateAccountAndSlot() {
288
+ this.assertIsSubscribed();
289
+ return this.state;
290
+ }
291
+ getMarketAccountAndSlot(marketIndex) {
292
+ return this.market.get(marketIndex.toNumber());
293
+ }
294
+ getMarketAccountsAndSlots() {
295
+ return Array.from(this.market.values());
296
+ }
297
+ getBankAccountAndSlot(bankIndex) {
298
+ return this.bank.get(bankIndex.toNumber());
299
+ }
300
+ getOraclePriceDataAndSlot(oraclePublicKey) {
301
+ this.assertIsSubscribed();
302
+ if (oraclePublicKey.equals(web3_js_1.PublicKey.default)) {
303
+ return {
304
+ data: quoteAssetOracleClient_1.QUOTE_ORACLE_PRICE_DATA,
305
+ slot: 0,
306
+ };
307
+ }
308
+ return this.oracles.get(oraclePublicKey.toString());
309
+ }
310
+ }
311
+ exports.PollingClearingHouseAccountSubscriber = PollingClearingHouseAccountSubscriber;
@@ -0,0 +1,93 @@
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.PollingOracleSubscriber = void 0;
13
+ const types_1 = require("./types");
14
+ const events_1 = require("events");
15
+ class PollingOracleSubscriber {
16
+ constructor(publicKey, oracleClient, accountLoader) {
17
+ this.isSubscribed = false;
18
+ this.publicKey = publicKey;
19
+ this.oracleClient = oracleClient;
20
+ this.accountLoader = accountLoader;
21
+ this.eventEmitter = new events_1.EventEmitter();
22
+ }
23
+ subscribe() {
24
+ return __awaiter(this, void 0, void 0, function* () {
25
+ if (this.isSubscribed) {
26
+ return true;
27
+ }
28
+ this.addToAccountLoader();
29
+ let subscriptionSucceeded = false;
30
+ let retries = 0;
31
+ while (!subscriptionSucceeded && retries < 5) {
32
+ yield this.fetch();
33
+ subscriptionSucceeded = this.didSubscriptionSucceed();
34
+ retries++;
35
+ }
36
+ if (subscriptionSucceeded) {
37
+ this.eventEmitter.emit('update');
38
+ }
39
+ this.isSubscribed = subscriptionSucceeded;
40
+ return subscriptionSucceeded;
41
+ });
42
+ }
43
+ addToAccountLoader() {
44
+ if (this.callbackId) {
45
+ return;
46
+ }
47
+ this.callbackId = this.accountLoader.addAccount(this.publicKey, (buffer, slot) => __awaiter(this, void 0, void 0, function* () {
48
+ const oraclePriceData = yield this.oracleClient.getOraclePriceDataFromBuffer(buffer);
49
+ this.oraclePriceData = { data: oraclePriceData, slot };
50
+ // @ts-ignore
51
+ this.eventEmitter.emit('oracleUpdate', oraclePriceData);
52
+ this.eventEmitter.emit('update');
53
+ }));
54
+ this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
55
+ this.eventEmitter.emit('error', error);
56
+ });
57
+ }
58
+ fetch() {
59
+ return __awaiter(this, void 0, void 0, function* () {
60
+ yield this.accountLoader.load();
61
+ const { buffer, slot } = this.accountLoader.getBufferAndSlot(this.publicKey);
62
+ this.oraclePriceData = {
63
+ data: yield this.oracleClient.getOraclePriceDataFromBuffer(buffer),
64
+ slot,
65
+ };
66
+ });
67
+ }
68
+ unsubscribe() {
69
+ return __awaiter(this, void 0, void 0, function* () {
70
+ if (!this.isSubscribed) {
71
+ return;
72
+ }
73
+ this.accountLoader.removeAccount(this.publicKey, this.callbackId);
74
+ this.callbackId = undefined;
75
+ this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
76
+ this.errorCallbackId = undefined;
77
+ this.isSubscribed = false;
78
+ });
79
+ }
80
+ assertIsSubscribed() {
81
+ if (!this.isSubscribed) {
82
+ throw new types_1.NotSubscribedError('You must call `subscribe` before using this function');
83
+ }
84
+ }
85
+ getOraclePriceData() {
86
+ this.assertIsSubscribed();
87
+ return this.oraclePriceData;
88
+ }
89
+ didSubscriptionSucceed() {
90
+ return !!this.oraclePriceData;
91
+ }
92
+ }
93
+ exports.PollingOracleSubscriber = PollingOracleSubscriber;