@drift-labs/sdk 2.67.0-beta.1 → 2.67.0-beta.3
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/accounts/pollingDriftClientAccountSubscriber.d.ts +1 -0
- package/lib/accounts/pollingDriftClientAccountSubscriber.js +33 -18
- package/lib/accounts/webSocketDriftClientAccountSubscriber.js +20 -18
- package/lib/driftClient.js +5 -2
- package/lib/factory/oracleClient.js +4 -3
- package/lib/idl/switchboard.json +8354 -0
- package/lib/oracles/switchboardClient.d.ts +11 -0
- package/lib/oracles/switchboardClient.js +40 -0
- package/lib/types.d.ts +3 -0
- package/lib/types.js +1 -1
- package/package.json +1 -1
- package/src/accounts/pollingDriftClientAccountSubscriber.ts +43 -20
- package/src/accounts/webSocketDriftClientAccountSubscriber.ts +20 -18
- package/src/driftClient.ts +6 -2
- package/src/factory/oracleClient.ts +4 -3
- package/src/idl/switchboard.json +8354 -0
- package/src/oracles/switchboardClient.ts +74 -0
- package/src/types.ts +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Connection, PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { OracleClient, OraclePriceData } from './types';
|
|
4
|
+
import { BorshAccountsCoder } from '@coral-xyz/anchor';
|
|
5
|
+
export declare class SwitchboardClient implements OracleClient {
|
|
6
|
+
connection: Connection;
|
|
7
|
+
coder: BorshAccountsCoder;
|
|
8
|
+
constructor(connection: Connection);
|
|
9
|
+
getOraclePriceData(pricePublicKey: PublicKey): Promise<OraclePriceData>;
|
|
10
|
+
getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData;
|
|
11
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SwitchboardClient = void 0;
|
|
7
|
+
const numericConstants_1 = require("../constants/numericConstants");
|
|
8
|
+
const switchboard_json_1 = __importDefault(require("../idl/switchboard.json"));
|
|
9
|
+
const anchor_1 = require("@coral-xyz/anchor");
|
|
10
|
+
class SwitchboardClient {
|
|
11
|
+
constructor(connection) {
|
|
12
|
+
this.connection = connection;
|
|
13
|
+
this.coder = new anchor_1.BorshAccountsCoder(switchboard_json_1.default);
|
|
14
|
+
}
|
|
15
|
+
async getOraclePriceData(pricePublicKey) {
|
|
16
|
+
const accountInfo = await this.connection.getAccountInfo(pricePublicKey);
|
|
17
|
+
return this.getOraclePriceDataFromBuffer(accountInfo.data);
|
|
18
|
+
}
|
|
19
|
+
getOraclePriceDataFromBuffer(buffer) {
|
|
20
|
+
const aggregatorAccountData = this.coder.decodeUnchecked('AggregatorAccountData', buffer);
|
|
21
|
+
const price = convertSwitchboardDecimal(aggregatorAccountData.latestConfirmedRound.result);
|
|
22
|
+
const confidence = convertSwitchboardDecimal(aggregatorAccountData.latestConfirmedRound.stdDeviation);
|
|
23
|
+
const hasSufficientNumberOfDataPoints = aggregatorAccountData.latestConfirmedRound.numSuccess >=
|
|
24
|
+
aggregatorAccountData.minOracleResults;
|
|
25
|
+
const slot = aggregatorAccountData.latestConfirmedRound.roundOpenSlot;
|
|
26
|
+
return {
|
|
27
|
+
price,
|
|
28
|
+
slot,
|
|
29
|
+
confidence,
|
|
30
|
+
hasSufficientNumberOfDataPoints,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.SwitchboardClient = SwitchboardClient;
|
|
35
|
+
function convertSwitchboardDecimal(switchboardDecimal) {
|
|
36
|
+
const switchboardPrecision = numericConstants_1.TEN.pow(new anchor_1.BN(switchboardDecimal.scale));
|
|
37
|
+
return switchboardDecimal.mantissa
|
|
38
|
+
.mul(numericConstants_1.PRICE_PRECISION)
|
|
39
|
+
.div(switchboardPrecision);
|
|
40
|
+
}
|
package/lib/types.d.ts
CHANGED
package/lib/types.js
CHANGED
|
@@ -95,7 +95,7 @@ exports.OracleSource = OracleSource;
|
|
|
95
95
|
OracleSource.PYTH = { pyth: {} };
|
|
96
96
|
OracleSource.PYTH_1K = { pyth1K: {} };
|
|
97
97
|
OracleSource.PYTH_1M = { pyth1M: {} };
|
|
98
|
-
|
|
98
|
+
OracleSource.SWITCHBOARD = { switchboard: {} };
|
|
99
99
|
OracleSource.QUOTE_ASSET = { quoteAsset: {} };
|
|
100
100
|
OracleSource.PYTH_STABLE_COIN = { pythStableCoin: {} };
|
|
101
101
|
class OrderType {
|
package/package.json
CHANGED
|
@@ -116,8 +116,8 @@ export class PollingDriftClientAccountSubscriber
|
|
|
116
116
|
this.eventEmitter.emit('update');
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
this.setPerpOracleMap();
|
|
120
|
-
this.setSpotOracleMap();
|
|
119
|
+
await this.setPerpOracleMap();
|
|
120
|
+
await this.setSpotOracleMap();
|
|
121
121
|
|
|
122
122
|
this.isSubscribing = false;
|
|
123
123
|
this.isSubscribed = subscriptionSucceeded;
|
|
@@ -389,7 +389,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
389
389
|
await this.addPerpMarketAccountToPoll(marketIndex);
|
|
390
390
|
const accountToPoll = this.accountsToPoll.get(marketPublicKey.toString());
|
|
391
391
|
await this.addAccountToAccountLoader(accountToPoll);
|
|
392
|
-
this.setPerpOracleMap();
|
|
392
|
+
await this.setPerpOracleMap();
|
|
393
393
|
return true;
|
|
394
394
|
}
|
|
395
395
|
|
|
@@ -402,29 +402,60 @@ export class PollingDriftClientAccountSubscriber
|
|
|
402
402
|
}
|
|
403
403
|
|
|
404
404
|
this.addOracleToPoll(oracleInfo);
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
);
|
|
405
|
+
const oracleString = oracleInfo.publicKey.toBase58();
|
|
406
|
+
const oracleToPoll = this.oraclesToPoll.get(oracleString);
|
|
408
407
|
await this.addOracleToAccountLoader(oracleToPoll);
|
|
408
|
+
|
|
409
|
+
await this.pauseForOracleToBeAdded(3, oracleString);
|
|
410
|
+
|
|
409
411
|
return true;
|
|
410
412
|
}
|
|
411
413
|
|
|
412
|
-
private
|
|
414
|
+
private async pauseForOracleToBeAdded(
|
|
415
|
+
tries: number,
|
|
416
|
+
oracle: string
|
|
417
|
+
): Promise<void> {
|
|
418
|
+
let i = 0;
|
|
419
|
+
while (i < tries) {
|
|
420
|
+
await new Promise((r) =>
|
|
421
|
+
setTimeout(r, this.accountLoader.pollingFrequency)
|
|
422
|
+
);
|
|
423
|
+
if (this.accountLoader.bufferAndSlotMap.has(oracle)) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
i++;
|
|
427
|
+
}
|
|
428
|
+
console.log(`Pausing to find oracle ${oracle} failed`);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
private async setPerpOracleMap() {
|
|
413
432
|
const perpMarkets = this.getMarketAccountsAndSlots();
|
|
414
433
|
for (const perpMarket of perpMarkets) {
|
|
415
434
|
const perpMarketAccount = perpMarket.data;
|
|
416
435
|
const perpMarketIndex = perpMarketAccount.marketIndex;
|
|
417
436
|
const oracle = perpMarketAccount.amm.oracle;
|
|
437
|
+
if (!this.oracles.has(oracle.toBase58())) {
|
|
438
|
+
await this.addOracle({
|
|
439
|
+
publicKey: oracle,
|
|
440
|
+
source: perpMarketAccount.amm.oracleSource,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
418
443
|
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
419
444
|
}
|
|
420
445
|
}
|
|
421
446
|
|
|
422
|
-
private setSpotOracleMap() {
|
|
447
|
+
private async setSpotOracleMap() {
|
|
423
448
|
const spotMarkets = this.getSpotMarketAccountsAndSlots();
|
|
424
449
|
for (const spotMarket of spotMarkets) {
|
|
425
450
|
const spotMarketAccount = spotMarket.data;
|
|
426
451
|
const spotMarketIndex = spotMarketAccount.marketIndex;
|
|
427
452
|
const oracle = spotMarketAccount.oracle;
|
|
453
|
+
if (!this.oracles.has(oracle.toBase58())) {
|
|
454
|
+
await this.addOracle({
|
|
455
|
+
publicKey: oracle,
|
|
456
|
+
source: spotMarketAccount.oracleSource,
|
|
457
|
+
});
|
|
458
|
+
}
|
|
428
459
|
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
429
460
|
}
|
|
430
461
|
}
|
|
@@ -481,18 +512,14 @@ export class PollingDriftClientAccountSubscriber
|
|
|
481
512
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
482
513
|
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
483
514
|
const oracle = this.perpOracleMap.get(marketIndex);
|
|
515
|
+
|
|
484
516
|
if (!perpMarketAccount || !oracle) {
|
|
485
517
|
return undefined;
|
|
486
518
|
}
|
|
487
519
|
|
|
488
520
|
if (!perpMarketAccount.data.amm.oracle.equals(oracle)) {
|
|
489
521
|
// If the oracle has changed, we need to update the oracle map in background
|
|
490
|
-
this.
|
|
491
|
-
source: perpMarketAccount.data.amm.oracleSource,
|
|
492
|
-
publicKey: perpMarketAccount.data.amm.oracle,
|
|
493
|
-
}).then(() => {
|
|
494
|
-
this.setPerpOracleMap();
|
|
495
|
-
});
|
|
522
|
+
this.setPerpOracleMap();
|
|
496
523
|
}
|
|
497
524
|
|
|
498
525
|
return this.getOraclePriceDataAndSlot(oracle);
|
|
@@ -506,14 +533,10 @@ export class PollingDriftClientAccountSubscriber
|
|
|
506
533
|
if (!spotMarketAccount || !oracle) {
|
|
507
534
|
return undefined;
|
|
508
535
|
}
|
|
536
|
+
|
|
509
537
|
if (!spotMarketAccount.data.oracle.equals(oracle)) {
|
|
510
538
|
// If the oracle has changed, we need to update the oracle map in background
|
|
511
|
-
this.
|
|
512
|
-
source: spotMarketAccount.data.oracleSource,
|
|
513
|
-
publicKey: spotMarketAccount.data.oracle,
|
|
514
|
-
}).then(() => {
|
|
515
|
-
this.setSpotOracleMap();
|
|
516
|
-
});
|
|
539
|
+
this.setSpotOracleMap();
|
|
517
540
|
}
|
|
518
541
|
|
|
519
542
|
return this.getOraclePriceDataAndSlot(oracle);
|
|
@@ -125,8 +125,8 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
125
125
|
|
|
126
126
|
this.eventEmitter.emit('update');
|
|
127
127
|
|
|
128
|
-
this.setPerpOracleMap();
|
|
129
|
-
this.setSpotOracleMap();
|
|
128
|
+
await this.setPerpOracleMap();
|
|
129
|
+
await this.setSpotOracleMap();
|
|
130
130
|
|
|
131
131
|
this.isSubscribing = false;
|
|
132
132
|
this.isSubscribed = true;
|
|
@@ -286,7 +286,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
286
286
|
return true;
|
|
287
287
|
}
|
|
288
288
|
const subscriptionSuccess = this.subscribeToSpotMarketAccount(marketIndex);
|
|
289
|
-
this.setSpotOracleMap();
|
|
289
|
+
await this.setSpotOracleMap();
|
|
290
290
|
return subscriptionSuccess;
|
|
291
291
|
}
|
|
292
292
|
|
|
@@ -295,7 +295,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
295
295
|
return true;
|
|
296
296
|
}
|
|
297
297
|
const subscriptionSuccess = this.subscribeToPerpMarketAccount(marketIndex);
|
|
298
|
-
this.setPerpOracleMap();
|
|
298
|
+
await this.setPerpOracleMap();
|
|
299
299
|
return subscriptionSuccess;
|
|
300
300
|
}
|
|
301
301
|
|
|
@@ -311,7 +311,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
311
311
|
return this.subscribeToOracle(oracleInfo);
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
-
private setPerpOracleMap() {
|
|
314
|
+
private async setPerpOracleMap() {
|
|
315
315
|
const perpMarkets = this.getMarketAccountsAndSlots();
|
|
316
316
|
for (const perpMarket of perpMarkets) {
|
|
317
317
|
if (!perpMarket) {
|
|
@@ -320,11 +320,17 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
320
320
|
const perpMarketAccount = perpMarket.data;
|
|
321
321
|
const perpMarketIndex = perpMarketAccount.marketIndex;
|
|
322
322
|
const oracle = perpMarketAccount.amm.oracle;
|
|
323
|
+
if (!this.oracleSubscribers.has(oracle.toBase58())) {
|
|
324
|
+
await this.addOracle({
|
|
325
|
+
publicKey: oracle,
|
|
326
|
+
source: perpMarket.data.amm.oracleSource,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
323
329
|
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
324
330
|
}
|
|
325
331
|
}
|
|
326
332
|
|
|
327
|
-
private setSpotOracleMap() {
|
|
333
|
+
private async setSpotOracleMap() {
|
|
328
334
|
const spotMarkets = this.getSpotMarketAccountsAndSlots();
|
|
329
335
|
for (const spotMarket of spotMarkets) {
|
|
330
336
|
if (!spotMarket) {
|
|
@@ -333,6 +339,12 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
333
339
|
const spotMarketAccount = spotMarket.data;
|
|
334
340
|
const spotMarketIndex = spotMarketAccount.marketIndex;
|
|
335
341
|
const oracle = spotMarketAccount.oracle;
|
|
342
|
+
if (!this.oracleSubscribers.has(oracle.toBase58())) {
|
|
343
|
+
await this.addOracle({
|
|
344
|
+
publicKey: oracle,
|
|
345
|
+
source: spotMarketAccount.oracleSource,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
336
348
|
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
337
349
|
}
|
|
338
350
|
}
|
|
@@ -400,12 +412,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
400
412
|
|
|
401
413
|
if (!perpMarketAccount.data.amm.oracle.equals(oracle)) {
|
|
402
414
|
// If the oracle has changed, we need to update the oracle map in background
|
|
403
|
-
this.
|
|
404
|
-
source: perpMarketAccount.data.amm.oracleSource,
|
|
405
|
-
publicKey: perpMarketAccount.data.amm.oracle,
|
|
406
|
-
}).then(() => {
|
|
407
|
-
this.setPerpOracleMap();
|
|
408
|
-
});
|
|
415
|
+
this.setPerpOracleMap();
|
|
409
416
|
}
|
|
410
417
|
|
|
411
418
|
return this.getOraclePriceDataAndSlot(oracle);
|
|
@@ -422,12 +429,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
422
429
|
|
|
423
430
|
if (!spotMarketAccount.data.oracle.equals(oracle)) {
|
|
424
431
|
// If the oracle has changed, we need to update the oracle map in background
|
|
425
|
-
this.
|
|
426
|
-
source: spotMarketAccount.data.oracleSource,
|
|
427
|
-
publicKey: spotMarketAccount.data.oracle,
|
|
428
|
-
}).then(() => {
|
|
429
|
-
this.setSpotOracleMap();
|
|
430
|
-
});
|
|
432
|
+
this.setSpotOracleMap();
|
|
431
433
|
}
|
|
432
434
|
|
|
433
435
|
return this.getOraclePriceDataAndSlot(oracle);
|
package/src/driftClient.ts
CHANGED
|
@@ -6183,9 +6183,13 @@ export class DriftClient {
|
|
|
6183
6183
|
}
|
|
6184
6184
|
}
|
|
6185
6185
|
|
|
6186
|
+
const userAccountExists =
|
|
6187
|
+
!!this.getUser()?.accountSubscriber?.isSubscribed &&
|
|
6188
|
+
(await this.checkIfAccountExists(this.getUser().userAccountPublicKey));
|
|
6189
|
+
|
|
6186
6190
|
const remainingAccounts = this.getRemainingAccounts({
|
|
6187
|
-
userAccounts: [this.getUserAccount()],
|
|
6188
|
-
useMarketLastSlotCache:
|
|
6191
|
+
userAccounts: userAccountExists ? [this.getUserAccount()] : [],
|
|
6192
|
+
useMarketLastSlotCache: false,
|
|
6189
6193
|
writableSpotMarketIndexes: [marketIndex],
|
|
6190
6194
|
});
|
|
6191
6195
|
|
|
@@ -5,6 +5,7 @@ import { PythClient } from '../oracles/pythClient';
|
|
|
5
5
|
// import { SwitchboardClient } from '../oracles/switchboardClient';
|
|
6
6
|
import { QuoteAssetOracleClient } from '../oracles/quoteAssetOracleClient';
|
|
7
7
|
import { BN } from '@coral-xyz/anchor';
|
|
8
|
+
import { SwitchboardClient } from '../oracles/switchboardClient';
|
|
8
9
|
|
|
9
10
|
export function getOracleClient(
|
|
10
11
|
oracleSource: OracleSource,
|
|
@@ -26,9 +27,9 @@ export function getOracleClient(
|
|
|
26
27
|
return new PythClient(connection, undefined, true);
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
if (isVariant(oracleSource, 'switchboard')) {
|
|
31
|
+
return new SwitchboardClient(connection);
|
|
32
|
+
}
|
|
32
33
|
|
|
33
34
|
if (isVariant(oracleSource, 'quoteAsset')) {
|
|
34
35
|
return new QuoteAssetOracleClient();
|