@drift-labs/sdk 2.142.0-beta.2 → 2.142.0-beta.20
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.
- package/VERSION +1 -1
- package/lib/browser/accounts/grpcDriftClientAccountSubscriberV2.d.ts +52 -4
- package/lib/browser/accounts/grpcDriftClientAccountSubscriberV2.js +315 -38
- package/lib/browser/accounts/grpcMultiAccountSubscriber.d.ts +11 -4
- package/lib/browser/accounts/grpcMultiAccountSubscriber.js +124 -18
- package/lib/browser/adminClient.d.ts +2 -0
- package/lib/browser/adminClient.js +17 -0
- package/lib/browser/constants/spotMarkets.js +4 -4
- package/lib/browser/driftClient.d.ts +19 -0
- package/lib/browser/driftClient.js +19 -0
- package/lib/browser/events/types.d.ts +3 -3
- package/lib/browser/idl/drift.json +72 -0
- package/lib/browser/types.d.ts +22 -1
- package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.d.ts +52 -4
- package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.d.ts.map +1 -1
- package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.js +315 -38
- package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts +11 -4
- package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts.map +1 -1
- package/lib/node/accounts/grpcMultiAccountSubscriber.js +124 -18
- package/lib/node/adminClient.d.ts +2 -0
- package/lib/node/adminClient.d.ts.map +1 -1
- package/lib/node/adminClient.js +17 -0
- package/lib/node/constants/spotMarkets.js +4 -4
- package/lib/node/driftClient.d.ts +19 -0
- package/lib/node/driftClient.d.ts.map +1 -1
- package/lib/node/driftClient.js +19 -0
- package/lib/node/events/types.d.ts +3 -3
- package/lib/node/events/types.d.ts.map +1 -1
- package/lib/node/idl/drift.json +72 -0
- package/lib/node/types.d.ts +22 -1
- package/lib/node/types.d.ts.map +1 -1
- package/package.json +8 -2
- package/scripts/client-test.ts +361 -75
- package/src/accounts/grpcDriftClientAccountSubscriberV2.ts +517 -77
- package/src/accounts/grpcMultiAccountSubscriber.ts +179 -32
- package/src/adminClient.ts +34 -0
- package/src/constants/spotMarkets.ts +4 -4
- package/src/driftClient.ts +19 -0
- package/src/events/types.ts +4 -2
- package/src/idl/drift.json +72 -0
- package/src/types.ts +25 -2
|
@@ -31,12 +31,27 @@ const web3_js_1 = require("@solana/web3.js");
|
|
|
31
31
|
const Buffer = __importStar(require("buffer"));
|
|
32
32
|
const bs58_1 = __importDefault(require("bs58"));
|
|
33
33
|
const grpc_1 = require("../isomorphic/grpc");
|
|
34
|
+
function commitmentLevelToCommitment(commitmentLevel) {
|
|
35
|
+
switch (commitmentLevel) {
|
|
36
|
+
case grpc_1.CommitmentLevel.PROCESSED:
|
|
37
|
+
return 'processed';
|
|
38
|
+
case grpc_1.CommitmentLevel.CONFIRMED:
|
|
39
|
+
return 'confirmed';
|
|
40
|
+
case grpc_1.CommitmentLevel.FINALIZED:
|
|
41
|
+
return 'finalized';
|
|
42
|
+
default:
|
|
43
|
+
return 'confirmed';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
34
46
|
class grpcMultiAccountSubscriber {
|
|
35
|
-
constructor(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe) {
|
|
47
|
+
constructor(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe, accountPropsMap) {
|
|
36
48
|
this.isUnsubscribing = false;
|
|
37
49
|
this.receivingData = false;
|
|
38
50
|
this.subscribedAccounts = new Set();
|
|
39
51
|
this.onChangeMap = new Map();
|
|
52
|
+
this.dataMap = new Map();
|
|
53
|
+
this.accountPropsMap = new Map();
|
|
54
|
+
this.bufferMap = new Map();
|
|
40
55
|
this.client = client;
|
|
41
56
|
this.commitmentLevel = commitmentLevel;
|
|
42
57
|
this.accountName = accountName;
|
|
@@ -44,8 +59,9 @@ class grpcMultiAccountSubscriber {
|
|
|
44
59
|
this.decodeBufferFn = decodeBuffer;
|
|
45
60
|
this.resubOpts = resubOpts;
|
|
46
61
|
this.onUnsubscribe = onUnsubscribe;
|
|
62
|
+
this.accountPropsMap = accountPropsMap;
|
|
47
63
|
}
|
|
48
|
-
static async create(grpcConfigs, accountName, program, decodeBuffer, resubOpts, clientProp, onUnsubscribe) {
|
|
64
|
+
static async create(grpcConfigs, accountName, program, decodeBuffer, resubOpts, clientProp, onUnsubscribe, accountPropsMap) {
|
|
49
65
|
var _a, _b;
|
|
50
66
|
const client = clientProp
|
|
51
67
|
? clientProp
|
|
@@ -53,9 +69,71 @@ class grpcMultiAccountSubscriber {
|
|
|
53
69
|
const commitmentLevel =
|
|
54
70
|
// @ts-ignore :: isomorphic exported enum fails typescript but will work at runtime
|
|
55
71
|
(_b = grpcConfigs.commitmentLevel) !== null && _b !== void 0 ? _b : grpc_1.CommitmentLevel.CONFIRMED;
|
|
56
|
-
return new grpcMultiAccountSubscriber(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe);
|
|
72
|
+
return new grpcMultiAccountSubscriber(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe, accountPropsMap);
|
|
73
|
+
}
|
|
74
|
+
setAccountData(accountPubkey, data, slot) {
|
|
75
|
+
this.dataMap.set(accountPubkey, { data, slot });
|
|
76
|
+
}
|
|
77
|
+
getAccountData(accountPubkey) {
|
|
78
|
+
return this.dataMap.get(accountPubkey);
|
|
79
|
+
}
|
|
80
|
+
getAccountDataMap() {
|
|
81
|
+
return this.dataMap;
|
|
82
|
+
}
|
|
83
|
+
async fetch() {
|
|
84
|
+
var _a;
|
|
85
|
+
try {
|
|
86
|
+
// Chunk account IDs into groups of 100 (getMultipleAccounts limit)
|
|
87
|
+
const chunkSize = 100;
|
|
88
|
+
const chunks = [];
|
|
89
|
+
const accountIds = Array.from(this.subscribedAccounts.values());
|
|
90
|
+
for (let i = 0; i < accountIds.length; i += chunkSize) {
|
|
91
|
+
chunks.push(accountIds.slice(i, i + chunkSize));
|
|
92
|
+
}
|
|
93
|
+
// Process all chunks concurrently
|
|
94
|
+
await Promise.all(chunks.map(async (chunk) => {
|
|
95
|
+
const accountAddresses = chunk.map((accountId) => new web3_js_1.PublicKey(accountId));
|
|
96
|
+
const rpcResponseAndContext = await this.program.provider.connection.getMultipleAccountsInfoAndContext(accountAddresses, {
|
|
97
|
+
commitment: commitmentLevelToCommitment(this.commitmentLevel),
|
|
98
|
+
});
|
|
99
|
+
const rpcResponse = rpcResponseAndContext.value;
|
|
100
|
+
const currentSlot = rpcResponseAndContext.context.slot;
|
|
101
|
+
for (let i = 0; i < chunk.length; i++) {
|
|
102
|
+
const accountId = chunk[i];
|
|
103
|
+
const accountInfo = rpcResponse[i];
|
|
104
|
+
if (accountInfo) {
|
|
105
|
+
const prev = this.bufferMap.get(accountId);
|
|
106
|
+
const newBuffer = accountInfo.data;
|
|
107
|
+
if (prev && currentSlot < prev.slot) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (prev &&
|
|
111
|
+
prev.buffer &&
|
|
112
|
+
newBuffer &&
|
|
113
|
+
newBuffer.equals(prev.buffer)) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
this.bufferMap.set(accountId, {
|
|
117
|
+
buffer: newBuffer,
|
|
118
|
+
slot: currentSlot,
|
|
119
|
+
});
|
|
120
|
+
const accountDecoded = this.program.coder.accounts.decode(this.capitalize(this.accountName), newBuffer);
|
|
121
|
+
this.setAccountData(accountId, accountDecoded, currentSlot);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
|
|
128
|
+
console.log(`[${this.accountName}] grpcMultiAccountSubscriber error fetching accounts:`, error);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
57
131
|
}
|
|
58
132
|
async subscribe(accounts, onChange) {
|
|
133
|
+
var _a;
|
|
134
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
|
|
135
|
+
console.log(`[${this.accountName}] grpcMultiAccountSubscriber subscribe`);
|
|
136
|
+
}
|
|
59
137
|
if (this.listenerId != null || this.isUnsubscribing) {
|
|
60
138
|
return;
|
|
61
139
|
}
|
|
@@ -63,7 +141,10 @@ class grpcMultiAccountSubscriber {
|
|
|
63
141
|
for (const pk of accounts) {
|
|
64
142
|
const key = pk.toBase58();
|
|
65
143
|
this.subscribedAccounts.add(key);
|
|
66
|
-
this.onChangeMap.set(key, (data, ctx, buffer) =>
|
|
144
|
+
this.onChangeMap.set(key, (data, ctx, buffer, accountProps) => {
|
|
145
|
+
this.setAccountData(key, data, ctx.slot);
|
|
146
|
+
onChange(new web3_js_1.PublicKey(key), data, ctx, buffer, accountProps);
|
|
147
|
+
});
|
|
67
148
|
}
|
|
68
149
|
this.stream =
|
|
69
150
|
(await this.client.subscribe());
|
|
@@ -85,7 +166,7 @@ class grpcMultiAccountSubscriber {
|
|
|
85
166
|
transactionsStatus: {},
|
|
86
167
|
};
|
|
87
168
|
this.stream.on('data', (chunk) => {
|
|
88
|
-
var _a;
|
|
169
|
+
var _a, _b;
|
|
89
170
|
if (!chunk.account) {
|
|
90
171
|
return;
|
|
91
172
|
}
|
|
@@ -95,6 +176,17 @@ class grpcMultiAccountSubscriber {
|
|
|
95
176
|
if (!accountPubkey || !this.subscribedAccounts.has(accountPubkey)) {
|
|
96
177
|
return;
|
|
97
178
|
}
|
|
179
|
+
// Touch resub timer on any incoming account update for subscribed keys
|
|
180
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs) {
|
|
181
|
+
this.receivingData = true;
|
|
182
|
+
clearTimeout(this.timeoutId);
|
|
183
|
+
this.setTimeout();
|
|
184
|
+
}
|
|
185
|
+
// Skip processing if we already have data for this account at a newer slot
|
|
186
|
+
const existing = this.dataMap.get(accountPubkey);
|
|
187
|
+
if ((existing === null || existing === void 0 ? void 0 : existing.slot) !== undefined && existing.slot > slot) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
98
190
|
const accountInfo = {
|
|
99
191
|
owner: new web3_js_1.PublicKey(chunk.account.account.owner),
|
|
100
192
|
lamports: Number(chunk.account.account.lamports),
|
|
@@ -104,21 +196,36 @@ class grpcMultiAccountSubscriber {
|
|
|
104
196
|
};
|
|
105
197
|
const context = { slot };
|
|
106
198
|
const buffer = accountInfo.data;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
199
|
+
// Check existing buffer for this account and skip if unchanged or slot regressed
|
|
200
|
+
const prevBuffer = this.bufferMap.get(accountPubkey);
|
|
201
|
+
if (prevBuffer && slot < prevBuffer.slot) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (prevBuffer &&
|
|
205
|
+
prevBuffer.buffer &&
|
|
206
|
+
buffer &&
|
|
207
|
+
buffer.equals(prevBuffer.buffer)) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
this.bufferMap.set(accountPubkey, { buffer, slot });
|
|
211
|
+
const accountProps = (_b = this.accountPropsMap) === null || _b === void 0 ? void 0 : _b.get(accountPubkey);
|
|
212
|
+
const handleDataBuffer = (context, buffer, accountProps) => {
|
|
213
|
+
const data = this.decodeBufferFn
|
|
214
|
+
? this.decodeBufferFn(buffer, accountPubkey, accountProps)
|
|
215
|
+
: this.program.account[this.accountName].coder.accounts.decode(this.capitalize(this.accountName), buffer);
|
|
216
|
+
const handler = this.onChangeMap.get(accountPubkey);
|
|
217
|
+
if (handler) {
|
|
218
|
+
handler(data, context, buffer, accountProps);
|
|
117
219
|
}
|
|
118
|
-
|
|
119
|
-
|
|
220
|
+
};
|
|
221
|
+
if (Array.isArray(accountProps)) {
|
|
222
|
+
for (const props of accountProps) {
|
|
223
|
+
handleDataBuffer(context, buffer, props);
|
|
120
224
|
}
|
|
121
225
|
}
|
|
226
|
+
else {
|
|
227
|
+
handleDataBuffer(context, buffer, accountProps);
|
|
228
|
+
}
|
|
122
229
|
});
|
|
123
230
|
return new Promise((resolve, reject) => {
|
|
124
231
|
this.stream.write(request, (err) => {
|
|
@@ -127,7 +234,6 @@ class grpcMultiAccountSubscriber {
|
|
|
127
234
|
this.listenerId = 1;
|
|
128
235
|
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs) {
|
|
129
236
|
this.receivingData = true;
|
|
130
|
-
this.setTimeout();
|
|
131
237
|
}
|
|
132
238
|
resolve();
|
|
133
239
|
}
|
|
@@ -246,4 +246,6 @@ export declare class AdminClient extends DriftClient {
|
|
|
246
246
|
getUpdateFeatureBitFlagsBuilderCodesIx(enable: boolean): Promise<TransactionInstruction>;
|
|
247
247
|
updateFeatureBitFlagsBuilderReferral(enable: boolean): Promise<TransactionSignature>;
|
|
248
248
|
getUpdateFeatureBitFlagsBuilderReferralIx(enable: boolean): Promise<TransactionInstruction>;
|
|
249
|
+
adminDisableUpdatePerpBidAskTwap(authority: PublicKey, disable: boolean): Promise<TransactionSignature>;
|
|
250
|
+
getAdminDisableUpdatePerpBidAskTwapIx(authority: PublicKey, disable: boolean): Promise<TransactionInstruction>;
|
|
249
251
|
}
|
|
@@ -2248,5 +2248,22 @@ class AdminClient extends driftClient_1.DriftClient {
|
|
|
2248
2248
|
},
|
|
2249
2249
|
});
|
|
2250
2250
|
}
|
|
2251
|
+
async adminDisableUpdatePerpBidAskTwap(authority, disable) {
|
|
2252
|
+
const disableBidAskTwapUpdateIx = await this.getAdminDisableUpdatePerpBidAskTwapIx(authority, disable);
|
|
2253
|
+
const tx = await this.buildTransaction(disableBidAskTwapUpdateIx);
|
|
2254
|
+
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
2255
|
+
return txSig;
|
|
2256
|
+
}
|
|
2257
|
+
async getAdminDisableUpdatePerpBidAskTwapIx(authority, disable) {
|
|
2258
|
+
return await this.program.instruction.adminDisableUpdatePerpBidAskTwap(disable, {
|
|
2259
|
+
accounts: {
|
|
2260
|
+
admin: this.useHotWalletAdmin
|
|
2261
|
+
? this.wallet.publicKey
|
|
2262
|
+
: this.getStateAccount().admin,
|
|
2263
|
+
state: await this.getStatePublicKey(),
|
|
2264
|
+
userStats: (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, authority),
|
|
2265
|
+
},
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2251
2268
|
}
|
|
2252
2269
|
exports.AdminClient = AdminClient;
|
|
@@ -11,8 +11,8 @@ exports.DevnetSpotMarkets = [
|
|
|
11
11
|
symbol: 'USDC',
|
|
12
12
|
marketIndex: 0,
|
|
13
13
|
poolId: 0,
|
|
14
|
-
oracle: new web3_js_1.PublicKey('
|
|
15
|
-
oracleSource: types_1.OracleSource.
|
|
14
|
+
oracle: new web3_js_1.PublicKey('9VCioxmni2gDLv11qufWzT3RDERhQE4iY5Gf7NTfYyAV'),
|
|
15
|
+
oracleSource: types_1.OracleSource.PYTH_LAZER_STABLE_COIN,
|
|
16
16
|
mint: new web3_js_1.PublicKey('8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2'),
|
|
17
17
|
precision: new anchor_1.BN(10).pow(numericConstants_1.SIX),
|
|
18
18
|
precisionExp: numericConstants_1.SIX,
|
|
@@ -23,8 +23,8 @@ exports.DevnetSpotMarkets = [
|
|
|
23
23
|
symbol: 'SOL',
|
|
24
24
|
marketIndex: 1,
|
|
25
25
|
poolId: 0,
|
|
26
|
-
oracle: new web3_js_1.PublicKey('
|
|
27
|
-
oracleSource: types_1.OracleSource.
|
|
26
|
+
oracle: new web3_js_1.PublicKey('3m6i4RFWEDw2Ft4tFHPJtYgmpPe21k56M3FHeWYrgGBz'),
|
|
27
|
+
oracleSource: types_1.OracleSource.PYTH_LAZER,
|
|
28
28
|
mint: new web3_js_1.PublicKey(exports.WRAPPED_SOL_MINT),
|
|
29
29
|
precision: numericConstants_1.LAMPORTS_PRECISION,
|
|
30
30
|
precisionExp: numericConstants_1.LAMPORTS_EXP,
|
|
@@ -180,7 +180,26 @@ export declare class DriftClient {
|
|
|
180
180
|
getMigrateReferrerIx(authority: PublicKey): Promise<TransactionInstruction>;
|
|
181
181
|
resizeRevenueShareEscrowOrders(authority: PublicKey, numOrders: number, txParams?: TxParams): Promise<TransactionSignature>;
|
|
182
182
|
getResizeRevenueShareEscrowOrdersIx(authority: PublicKey, numOrders: number): Promise<TransactionInstruction>;
|
|
183
|
+
/**
|
|
184
|
+
* Creates the transaction to add or update an approved builder.
|
|
185
|
+
* This allows the builder to receive revenue share from referrals.
|
|
186
|
+
*
|
|
187
|
+
* @param builder - The public key of the builder to add or update.
|
|
188
|
+
* @param maxFeeTenthBps - The maximum fee tenth bps to set for the builder.
|
|
189
|
+
* @param add - Whether to add or update the builder. If the builder already exists, `add = true` will update the `maxFeeTenthBps`, otherwise it will add the builder. If `add = false`, the builder's `maxFeeTenthBps` will be set to 0.
|
|
190
|
+
* @param txParams - The transaction parameters to use for the transaction.
|
|
191
|
+
* @returns The transaction to add or update an approved builder.
|
|
192
|
+
*/
|
|
183
193
|
changeApprovedBuilder(builder: PublicKey, maxFeeTenthBps: number, add: boolean, txParams?: TxParams): Promise<TransactionSignature>;
|
|
194
|
+
/**
|
|
195
|
+
* Creates the transaction instruction to add or update an approved builder.
|
|
196
|
+
* This allows the builder to receive revenue share from referrals.
|
|
197
|
+
*
|
|
198
|
+
* @param builder - The public key of the builder to add or update.
|
|
199
|
+
* @param maxFeeTenthBps - The maximum fee tenth bps to set for the builder.
|
|
200
|
+
* @param add - Whether to add or update the builder. If the builder already exists, `add = true` will update the `maxFeeTenthBps`, otherwise it will add the builder. If `add = false`, the builder's `maxFeeTenthBps` will be set to 0.
|
|
201
|
+
* @returns The transaction instruction to add or update an approved builder.
|
|
202
|
+
*/
|
|
184
203
|
getChangeApprovedBuilderIx(builder: PublicKey, maxFeeTenthBps: number, add: boolean): Promise<TransactionInstruction>;
|
|
185
204
|
addSignedMsgWsDelegate(authority: PublicKey, delegate: PublicKey, txParams?: TxParams): Promise<TransactionSignature>;
|
|
186
205
|
getAddSignedMsgWsDelegateIx(authority: PublicKey, delegate: PublicKey): Promise<TransactionInstruction>;
|
|
@@ -768,12 +768,31 @@ class DriftClient {
|
|
|
768
768
|
},
|
|
769
769
|
});
|
|
770
770
|
}
|
|
771
|
+
/**
|
|
772
|
+
* Creates the transaction to add or update an approved builder.
|
|
773
|
+
* This allows the builder to receive revenue share from referrals.
|
|
774
|
+
*
|
|
775
|
+
* @param builder - The public key of the builder to add or update.
|
|
776
|
+
* @param maxFeeTenthBps - The maximum fee tenth bps to set for the builder.
|
|
777
|
+
* @param add - Whether to add or update the builder. If the builder already exists, `add = true` will update the `maxFeeTenthBps`, otherwise it will add the builder. If `add = false`, the builder's `maxFeeTenthBps` will be set to 0.
|
|
778
|
+
* @param txParams - The transaction parameters to use for the transaction.
|
|
779
|
+
* @returns The transaction to add or update an approved builder.
|
|
780
|
+
*/
|
|
771
781
|
async changeApprovedBuilder(builder, maxFeeTenthBps, add, txParams) {
|
|
772
782
|
const ix = await this.getChangeApprovedBuilderIx(builder, maxFeeTenthBps, add);
|
|
773
783
|
const tx = await this.buildTransaction([ix], txParams);
|
|
774
784
|
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
775
785
|
return txSig;
|
|
776
786
|
}
|
|
787
|
+
/**
|
|
788
|
+
* Creates the transaction instruction to add or update an approved builder.
|
|
789
|
+
* This allows the builder to receive revenue share from referrals.
|
|
790
|
+
*
|
|
791
|
+
* @param builder - The public key of the builder to add or update.
|
|
792
|
+
* @param maxFeeTenthBps - The maximum fee tenth bps to set for the builder.
|
|
793
|
+
* @param add - Whether to add or update the builder. If the builder already exists, `add = true` will update the `maxFeeTenthBps`, otherwise it will add the builder. If `add = false`, the builder's `maxFeeTenthBps` will be set to 0.
|
|
794
|
+
* @returns The transaction instruction to add or update an approved builder.
|
|
795
|
+
*/
|
|
777
796
|
async getChangeApprovedBuilderIx(builder, maxFeeTenthBps, add) {
|
|
778
797
|
const authority = this.wallet.publicKey;
|
|
779
798
|
const escrow = (0, pda_1.getRevenueShareEscrowAccountPublicKey)(this.program.programId, authority);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Commitment, PublicKey, TransactionSignature } from '@solana/web3.js';
|
|
3
|
-
import { DepositRecord, FundingPaymentRecord, FundingRateRecord, LiquidationRecord, NewUserRecord, OrderActionRecord, OrderRecord, SettlePnlRecord, LPRecord, InsuranceFundRecord, SpotInterestRecord, InsuranceFundStakeRecord, CurveRecord, SwapRecord, SpotMarketVaultDepositRecord, SignedMsgOrderRecord, DeleteUserRecord, FuelSweepRecord, FuelSeasonRecord, InsuranceFundSwapRecord, TransferProtocolIfSharesToRevenuePoolRecord, LPMintRedeemRecord, LPSettleRecord, LPSwapRecord } from '../types';
|
|
3
|
+
import { DepositRecord, FundingPaymentRecord, FundingRateRecord, LiquidationRecord, NewUserRecord, OrderActionRecord, OrderRecord, SettlePnlRecord, LPRecord, InsuranceFundRecord, SpotInterestRecord, InsuranceFundStakeRecord, CurveRecord, SwapRecord, SpotMarketVaultDepositRecord, SignedMsgOrderRecord, DeleteUserRecord, FuelSweepRecord, FuelSeasonRecord, InsuranceFundSwapRecord, TransferProtocolIfSharesToRevenuePoolRecord, LPMintRedeemRecord, LPSettleRecord, LPSwapRecord, LPBorrowLendDepositRecord } from '../types';
|
|
4
4
|
import { EventEmitter } from 'events';
|
|
5
5
|
export type EventSubscriptionOptions = {
|
|
6
6
|
address?: PublicKey;
|
|
@@ -47,12 +47,12 @@ export type EventMap = {
|
|
|
47
47
|
FuelSeasonRecord: Event<FuelSeasonRecord>;
|
|
48
48
|
InsuranceFundSwapRecord: Event<InsuranceFundSwapRecord>;
|
|
49
49
|
TransferProtocolIfSharesToRevenuePoolRecord: Event<TransferProtocolIfSharesToRevenuePoolRecord>;
|
|
50
|
-
LPMintRedeemRecord: Event<LPMintRedeemRecord>;
|
|
51
50
|
LPSettleRecord: Event<LPSettleRecord>;
|
|
51
|
+
LPMintRedeemRecord: Event<LPMintRedeemRecord>;
|
|
52
52
|
LPSwapRecord: Event<LPSwapRecord>;
|
|
53
53
|
};
|
|
54
54
|
export type EventType = keyof EventMap;
|
|
55
|
-
export type DriftEvent = Event<DepositRecord> | Event<FundingPaymentRecord> | Event<LiquidationRecord> | Event<FundingRateRecord> | Event<OrderRecord> | Event<OrderActionRecord> | Event<SettlePnlRecord> | Event<NewUserRecord> | Event<LPRecord> | Event<InsuranceFundRecord> | Event<SpotInterestRecord> | Event<InsuranceFundStakeRecord> | Event<CurveRecord> | Event<SwapRecord> | Event<SpotMarketVaultDepositRecord> | Event<SignedMsgOrderRecord> | Event<DeleteUserRecord> | Event<FuelSweepRecord> | Event<FuelSeasonRecord> | Event<InsuranceFundSwapRecord> | Event<TransferProtocolIfSharesToRevenuePoolRecord> | Event<LPSettleRecord> | Event<LPSwapRecord> | Event<
|
|
55
|
+
export type DriftEvent = Event<DepositRecord> | Event<FundingPaymentRecord> | Event<LiquidationRecord> | Event<FundingRateRecord> | Event<OrderRecord> | Event<OrderActionRecord> | Event<SettlePnlRecord> | Event<NewUserRecord> | Event<LPRecord> | Event<InsuranceFundRecord> | Event<SpotInterestRecord> | Event<InsuranceFundStakeRecord> | Event<CurveRecord> | Event<SwapRecord> | Event<SpotMarketVaultDepositRecord> | Event<SignedMsgOrderRecord> | Event<DeleteUserRecord> | Event<FuelSweepRecord> | Event<FuelSeasonRecord> | Event<InsuranceFundSwapRecord> | Event<TransferProtocolIfSharesToRevenuePoolRecord> | Event<LPSettleRecord> | Event<LPMintRedeemRecord> | Event<LPSwapRecord> | Event<LPBorrowLendDepositRecord>;
|
|
56
56
|
export interface EventSubscriberEvents {
|
|
57
57
|
newEvent: (event: WrappedEvent<EventType>) => void;
|
|
58
58
|
}
|
|
@@ -14875,6 +14875,11 @@
|
|
|
14875
14875
|
"name": "lpPrice",
|
|
14876
14876
|
"type": "u128",
|
|
14877
14877
|
"index": false
|
|
14878
|
+
},
|
|
14879
|
+
{
|
|
14880
|
+
"name": "lpPool",
|
|
14881
|
+
"type": "publicKey",
|
|
14882
|
+
"index": false
|
|
14878
14883
|
}
|
|
14879
14884
|
]
|
|
14880
14885
|
},
|
|
@@ -14985,6 +14990,11 @@
|
|
|
14985
14990
|
"name": "outSwapId",
|
|
14986
14991
|
"type": "u64",
|
|
14987
14992
|
"index": false
|
|
14993
|
+
},
|
|
14994
|
+
{
|
|
14995
|
+
"name": "lpPool",
|
|
14996
|
+
"type": "publicKey",
|
|
14997
|
+
"index": false
|
|
14988
14998
|
}
|
|
14989
14999
|
]
|
|
14990
15000
|
},
|
|
@@ -15080,6 +15090,68 @@
|
|
|
15080
15090
|
"name": "inMarketTargetWeight",
|
|
15081
15091
|
"type": "i64",
|
|
15082
15092
|
"index": false
|
|
15093
|
+
},
|
|
15094
|
+
{
|
|
15095
|
+
"name": "lpPool",
|
|
15096
|
+
"type": "publicKey",
|
|
15097
|
+
"index": false
|
|
15098
|
+
}
|
|
15099
|
+
]
|
|
15100
|
+
},
|
|
15101
|
+
{
|
|
15102
|
+
"name": "LPBorrowLendDepositRecord",
|
|
15103
|
+
"fields": [
|
|
15104
|
+
{
|
|
15105
|
+
"name": "ts",
|
|
15106
|
+
"type": "i64",
|
|
15107
|
+
"index": false
|
|
15108
|
+
},
|
|
15109
|
+
{
|
|
15110
|
+
"name": "slot",
|
|
15111
|
+
"type": "u64",
|
|
15112
|
+
"index": false
|
|
15113
|
+
},
|
|
15114
|
+
{
|
|
15115
|
+
"name": "spotMarketIndex",
|
|
15116
|
+
"type": "u16",
|
|
15117
|
+
"index": false
|
|
15118
|
+
},
|
|
15119
|
+
{
|
|
15120
|
+
"name": "constituentIndex",
|
|
15121
|
+
"type": "u16",
|
|
15122
|
+
"index": false
|
|
15123
|
+
},
|
|
15124
|
+
{
|
|
15125
|
+
"name": "direction",
|
|
15126
|
+
"type": {
|
|
15127
|
+
"defined": "DepositDirection"
|
|
15128
|
+
},
|
|
15129
|
+
"index": false
|
|
15130
|
+
},
|
|
15131
|
+
{
|
|
15132
|
+
"name": "tokenBalance",
|
|
15133
|
+
"type": "i64",
|
|
15134
|
+
"index": false
|
|
15135
|
+
},
|
|
15136
|
+
{
|
|
15137
|
+
"name": "lastTokenBalance",
|
|
15138
|
+
"type": "i64",
|
|
15139
|
+
"index": false
|
|
15140
|
+
},
|
|
15141
|
+
{
|
|
15142
|
+
"name": "interestAccruedTokenAmount",
|
|
15143
|
+
"type": "i64",
|
|
15144
|
+
"index": false
|
|
15145
|
+
},
|
|
15146
|
+
{
|
|
15147
|
+
"name": "amountDepositWithdraw",
|
|
15148
|
+
"type": "u64",
|
|
15149
|
+
"index": false
|
|
15150
|
+
},
|
|
15151
|
+
{
|
|
15152
|
+
"name": "lpPool",
|
|
15153
|
+
"type": "publicKey",
|
|
15154
|
+
"index": false
|
|
15083
15155
|
}
|
|
15084
15156
|
]
|
|
15085
15157
|
}
|
package/lib/browser/types.d.ts
CHANGED
|
@@ -866,6 +866,7 @@ export type LPSwapRecord = {
|
|
|
866
866
|
outMarketTargetWeight: BN;
|
|
867
867
|
inSwapId: BN;
|
|
868
868
|
outSwapId: BN;
|
|
869
|
+
lpPool: PublicKey;
|
|
869
870
|
};
|
|
870
871
|
export type LPMintRedeemRecord = {
|
|
871
872
|
ts: BN;
|
|
@@ -887,6 +888,7 @@ export type LPMintRedeemRecord = {
|
|
|
887
888
|
lastAumSlot: BN;
|
|
888
889
|
inMarketCurrentWeight: BN;
|
|
889
890
|
inMarketTargetWeight: BN;
|
|
891
|
+
lpPool: PublicKey;
|
|
890
892
|
};
|
|
891
893
|
export type LPSettleRecord = {
|
|
892
894
|
recordId: BN;
|
|
@@ -900,6 +902,19 @@ export type LPSettleRecord = {
|
|
|
900
902
|
perpAmmExFeeDelta: BN;
|
|
901
903
|
lpAum: BN;
|
|
902
904
|
lpPrice: BN;
|
|
905
|
+
lpPool: PublicKey;
|
|
906
|
+
};
|
|
907
|
+
export type LPBorrowLendDepositRecord = {
|
|
908
|
+
ts: BN;
|
|
909
|
+
slot: BN;
|
|
910
|
+
spotMarketIndex: number;
|
|
911
|
+
constituentIndex: number;
|
|
912
|
+
direction: DepositDirection;
|
|
913
|
+
tokenBalance: BN;
|
|
914
|
+
lastTokenBalance: BN;
|
|
915
|
+
interestAccruedTokenAmount: BN;
|
|
916
|
+
amountDepositWithdraw: BN;
|
|
917
|
+
lpPool: PublicKey;
|
|
903
918
|
};
|
|
904
919
|
export type StateAccount = {
|
|
905
920
|
admin: PublicKey;
|
|
@@ -971,6 +986,10 @@ export type PerpMarketAccount = {
|
|
|
971
986
|
protectedMakerLimitPriceDivisor: number;
|
|
972
987
|
protectedMakerDynamicDivisor: number;
|
|
973
988
|
lastFillPrice: BN;
|
|
989
|
+
lpFeeTransferScalar: number;
|
|
990
|
+
lpExchangeFeeExcluscionScalar: number;
|
|
991
|
+
lpStatus: number;
|
|
992
|
+
lpPausedOperations: number;
|
|
974
993
|
};
|
|
975
994
|
export type HistoricalOracleData = {
|
|
976
995
|
lastOraclePrice: BN;
|
|
@@ -1649,12 +1668,14 @@ export type RevenueShareEscrowAccount = {
|
|
|
1649
1668
|
approvedBuilders: BuilderInfo[];
|
|
1650
1669
|
};
|
|
1651
1670
|
export type RevenueShareOrder = {
|
|
1652
|
-
builderIdx: number;
|
|
1653
1671
|
feesAccrued: BN;
|
|
1654
1672
|
orderId: number;
|
|
1655
1673
|
feeTenthBps: number;
|
|
1656
1674
|
marketIndex: number;
|
|
1675
|
+
subAccountId: number;
|
|
1676
|
+
builderIdx: number;
|
|
1657
1677
|
bitFlags: number;
|
|
1678
|
+
userOrderIndex: number;
|
|
1658
1679
|
marketType: MarketType;
|
|
1659
1680
|
padding: number[];
|
|
1660
1681
|
};
|
|
@@ -1,17 +1,65 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
3
|
+
import { EventEmitter } from 'events';
|
|
4
|
+
import { OracleInfo, OraclePriceData } from '../oracles/types';
|
|
3
5
|
import { Program } from '@coral-xyz/anchor';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
+
import { PublicKey } from '@solana/web3.js';
|
|
7
|
+
import { AccountSubscriber, DataAndSlot, DelistedMarketSetting, DriftClientAccountEvents, DriftClientAccountSubscriber, GrpcConfigs, ResubOpts } from './types';
|
|
8
|
+
import { PerpMarketAccount, SpotMarketAccount, StateAccount } from '../types';
|
|
9
|
+
import { OracleClientCache } from '../oracles/oracleClientCache';
|
|
10
|
+
export declare class grpcDriftClientAccountSubscriberV2 implements DriftClientAccountSubscriber {
|
|
6
11
|
private grpcConfigs;
|
|
7
12
|
private perpMarketsSubscriber?;
|
|
8
13
|
private spotMarketsSubscriber?;
|
|
9
14
|
private oracleMultiSubscriber?;
|
|
15
|
+
private perpMarketIndexToAccountPubkeyMap;
|
|
16
|
+
private spotMarketIndexToAccountPubkeyMap;
|
|
17
|
+
private delistedMarketSetting;
|
|
18
|
+
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
19
|
+
isSubscribed: boolean;
|
|
20
|
+
isSubscribing: boolean;
|
|
21
|
+
program: Program;
|
|
22
|
+
perpMarketIndexes: number[];
|
|
23
|
+
spotMarketIndexes: number[];
|
|
24
|
+
shouldFindAllMarketsAndOracles: boolean;
|
|
25
|
+
oracleInfos: OracleInfo[];
|
|
26
|
+
initialPerpMarketAccountData: Map<number, PerpMarketAccount>;
|
|
27
|
+
initialSpotMarketAccountData: Map<number, SpotMarketAccount>;
|
|
28
|
+
initialOraclePriceData: Map<string, OraclePriceData>;
|
|
29
|
+
perpOracleMap: Map<number, PublicKey>;
|
|
30
|
+
perpOracleStringMap: Map<number, string>;
|
|
31
|
+
spotOracleMap: Map<number, PublicKey>;
|
|
32
|
+
spotOracleStringMap: Map<number, string>;
|
|
33
|
+
private oracleIdToOracleDataMap;
|
|
34
|
+
stateAccountSubscriber?: AccountSubscriber<StateAccount>;
|
|
35
|
+
oracleClientCache: OracleClientCache;
|
|
36
|
+
private resubOpts?;
|
|
37
|
+
private subscriptionPromise;
|
|
38
|
+
protected subscriptionPromiseResolver: (val: boolean) => void;
|
|
10
39
|
constructor(grpcConfigs: GrpcConfigs, program: Program, perpMarketIndexes: number[], spotMarketIndexes: number[], oracleInfos: OracleInfo[], shouldFindAllMarketsAndOracles: boolean, delistedMarketSetting: DelistedMarketSetting, resubOpts?: ResubOpts);
|
|
40
|
+
chunks: <T>(array: readonly T[], size: number) => T[][];
|
|
41
|
+
setInitialData(): Promise<void>;
|
|
42
|
+
addPerpMarket(_marketIndex: number): Promise<boolean>;
|
|
43
|
+
addSpotMarket(_marketIndex: number): Promise<boolean>;
|
|
44
|
+
addOracle(oracleInfo: OracleInfo): Promise<boolean>;
|
|
11
45
|
subscribe(): Promise<boolean>;
|
|
46
|
+
fetch(): Promise<void>;
|
|
47
|
+
private assertIsSubscribed;
|
|
48
|
+
getStateAccountAndSlot(): DataAndSlot<StateAccount>;
|
|
49
|
+
getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[];
|
|
50
|
+
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
51
|
+
getMarketAccountAndSlot(marketIndex: number): DataAndSlot<PerpMarketAccount> | undefined;
|
|
52
|
+
getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
|
|
53
|
+
getOraclePriceDataAndSlot(oracleId: string): DataAndSlot<OraclePriceData> | undefined;
|
|
54
|
+
getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
55
|
+
getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
56
|
+
setPerpOracleMap(): Promise<void>;
|
|
57
|
+
setSpotOracleMap(): Promise<void>;
|
|
12
58
|
subscribeToPerpMarketAccounts(): Promise<boolean>;
|
|
13
59
|
subscribeToSpotMarketAccounts(): Promise<boolean>;
|
|
14
60
|
subscribeToOracles(): Promise<boolean>;
|
|
61
|
+
handleDelistedMarkets(): Promise<void>;
|
|
62
|
+
removeInitialData(): void;
|
|
15
63
|
unsubscribeFromOracles(): Promise<void>;
|
|
16
64
|
unsubscribe(): Promise<void>;
|
|
17
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grpcDriftClientAccountSubscriberV2.d.ts","sourceRoot":"","sources":["../../../src/accounts/grpcDriftClientAccountSubscriberV2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"grpcDriftClientAccountSubscriberV2.d.ts","sourceRoot":"","sources":["../../../src/accounts/grpcDriftClientAccountSubscriberV2.ts"],"names":[],"mappings":"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"}
|