@drift-labs/sdk 2.95.0-beta.2 → 2.95.0-beta.21
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 +3 -1
- package/lib/accounts/pollingDriftClientAccountSubscriber.js +14 -4
- package/lib/accounts/types.d.ts +1 -1
- package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +8 -1
- package/lib/accounts/webSocketDriftClientAccountSubscriber.js +70 -8
- package/lib/addresses/pda.d.ts +2 -0
- package/lib/addresses/pda.js +15 -1
- package/lib/config.d.ts +3 -0
- package/lib/config.js +2 -0
- package/lib/constants/perpMarkets.js +25 -4
- package/lib/constants/spotMarkets.js +10 -0
- package/lib/driftClient.js +6 -2
- package/lib/events/parse.d.ts +4 -0
- package/lib/events/parse.js +10 -3
- package/lib/idl/drift.json +8 -3
- package/lib/math/auction.d.ts +5 -1
- package/lib/math/auction.js +5 -1
- package/lib/math/insurance.d.ts +3 -1
- package/lib/math/insurance.js +31 -1
- package/lib/math/spotBalance.d.ts +3 -3
- package/lib/math/spotBalance.js +7 -7
- package/package.json +1 -1
- package/src/accounts/pollingDriftClientAccountSubscriber.ts +17 -5
- package/src/accounts/types.ts +1 -1
- package/src/accounts/webSocketDriftClientAccountSubscriber.ts +132 -14
- package/src/addresses/pda.ts +26 -0
- package/src/config.ts +8 -0
- package/src/constants/perpMarkets.ts +26 -4
- package/src/constants/spotMarkets.ts +11 -0
- package/src/driftClient.ts +11 -2
- package/src/events/parse.ts +12 -1
- package/src/idl/drift.json +8 -3
- package/src/math/auction.ts +16 -0
- package/src/math/insurance.ts +48 -2
- package/src/math/spotBalance.ts +13 -7
package/lib/math/insurance.js
CHANGED
|
@@ -1,8 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.unstakeSharesToAmountWithOpenRequest = exports.unstakeSharesToAmount = exports.stakeAmountToShares = void 0;
|
|
3
|
+
exports.unstakeSharesToAmountWithOpenRequest = exports.unstakeSharesToAmount = exports.stakeAmountToShares = exports.nextRevenuePoolSettleApr = void 0;
|
|
4
4
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
5
5
|
const index_1 = require("../index");
|
|
6
|
+
const spotBalance_1 = require("../math/spotBalance");
|
|
7
|
+
function nextRevenuePoolSettleApr(spotMarket, vaultBalance, // vault token amount
|
|
8
|
+
amount // delta token amount
|
|
9
|
+
) {
|
|
10
|
+
const MAX_APR = new index_1.BN(10).mul(numericConstants_1.PERCENTAGE_PRECISION); // 1000% APR
|
|
11
|
+
// Conmputing the APR:
|
|
12
|
+
const revenuePoolBN = (0, spotBalance_1.getTokenAmount)(spotMarket.revenuePool.scaledBalance, spotMarket, index_1.SpotBalanceType.DEPOSIT);
|
|
13
|
+
const payoutRatio = 0.1;
|
|
14
|
+
const ratioForStakers = spotMarket.insuranceFund.totalFactor > 0 &&
|
|
15
|
+
spotMarket.insuranceFund.userFactor > 0 &&
|
|
16
|
+
spotMarket.insuranceFund.revenueSettlePeriod.gt(numericConstants_1.ZERO)
|
|
17
|
+
? spotMarket.insuranceFund.userFactor /
|
|
18
|
+
spotMarket.insuranceFund.totalFactor
|
|
19
|
+
: 0;
|
|
20
|
+
// Settle periods from on-chain data:
|
|
21
|
+
const revSettlePeriod = spotMarket.insuranceFund.revenueSettlePeriod.toNumber() * 1000;
|
|
22
|
+
const settlesPerYear = 31536000000 / revSettlePeriod;
|
|
23
|
+
const projectedAnnualRev = revenuePoolBN
|
|
24
|
+
.muln(settlesPerYear)
|
|
25
|
+
.muln(payoutRatio);
|
|
26
|
+
const uncappedApr = vaultBalance.add(amount).eq(numericConstants_1.ZERO)
|
|
27
|
+
? 0
|
|
28
|
+
: projectedAnnualRev.muln(1000).div(vaultBalance.add(amount)).toNumber() *
|
|
29
|
+
100 *
|
|
30
|
+
1000;
|
|
31
|
+
const cappedApr = Math.min(uncappedApr, MAX_APR.toNumber());
|
|
32
|
+
const nextApr = cappedApr * ratioForStakers;
|
|
33
|
+
return nextApr;
|
|
34
|
+
}
|
|
35
|
+
exports.nextRevenuePoolSettleApr = nextRevenuePoolSettleApr;
|
|
6
36
|
function stakeAmountToShares(amount, totalIfShares, insuranceFundVaultBalance) {
|
|
7
37
|
let nShares;
|
|
8
38
|
if (insuranceFundVaultBalance.gt(numericConstants_1.ZERO)) {
|
|
@@ -62,9 +62,9 @@ export declare function calculateSpotMarketBorrowCapacity(spotMarketAccount: Spo
|
|
|
62
62
|
totalCapacity: BN;
|
|
63
63
|
remainingCapacity: BN;
|
|
64
64
|
};
|
|
65
|
-
export declare function calculateInterestRate(bank: SpotMarketAccount, delta?: BN): BN;
|
|
66
|
-
export declare function calculateDepositRate(bank: SpotMarketAccount, delta?: BN): BN;
|
|
67
|
-
export declare function calculateBorrowRate(bank: SpotMarketAccount, delta?: BN): BN;
|
|
65
|
+
export declare function calculateInterestRate(bank: SpotMarketAccount, delta?: BN, currentUtilization?: BN): BN;
|
|
66
|
+
export declare function calculateDepositRate(bank: SpotMarketAccount, delta?: BN, currentUtilization?: BN): BN;
|
|
67
|
+
export declare function calculateBorrowRate(bank: SpotMarketAccount, delta?: BN, currentUtilization?: BN): BN;
|
|
68
68
|
export declare function calculateInterestAccumulated(bank: SpotMarketAccount, now: BN): {
|
|
69
69
|
borrowInterest: BN;
|
|
70
70
|
depositInterest: BN;
|
package/lib/math/spotBalance.js
CHANGED
|
@@ -246,8 +246,8 @@ function calculateSpotMarketBorrowCapacity(spotMarketAccount, targetBorrowRate)
|
|
|
246
246
|
return { totalCapacity, remainingCapacity };
|
|
247
247
|
}
|
|
248
248
|
exports.calculateSpotMarketBorrowCapacity = calculateSpotMarketBorrowCapacity;
|
|
249
|
-
function calculateInterestRate(bank, delta = numericConstants_1.ZERO) {
|
|
250
|
-
const utilization = calculateUtilization(bank, delta);
|
|
249
|
+
function calculateInterestRate(bank, delta = numericConstants_1.ZERO, currentUtilization = null) {
|
|
250
|
+
const utilization = currentUtilization || calculateUtilization(bank, delta);
|
|
251
251
|
let interestRate;
|
|
252
252
|
if (utilization.gt(new anchor_1.BN(bank.optimalUtilization))) {
|
|
253
253
|
const surplusUtilization = utilization.sub(new anchor_1.BN(bank.optimalUtilization));
|
|
@@ -269,11 +269,11 @@ function calculateInterestRate(bank, delta = numericConstants_1.ZERO) {
|
|
|
269
269
|
return anchor_1.BN.max(interestRate, new anchor_1.BN(bank.minBorrowRate).mul(numericConstants_2.PERCENTAGE_PRECISION.divn(200)));
|
|
270
270
|
}
|
|
271
271
|
exports.calculateInterestRate = calculateInterestRate;
|
|
272
|
-
function calculateDepositRate(bank, delta = numericConstants_1.ZERO) {
|
|
272
|
+
function calculateDepositRate(bank, delta = numericConstants_1.ZERO, currentUtilization = null) {
|
|
273
273
|
// positive delta => adding to deposit
|
|
274
274
|
// negative delta => adding to borrow
|
|
275
|
-
const utilization = calculateUtilization(bank, delta);
|
|
276
|
-
const borrowRate = calculateBorrowRate(bank, delta);
|
|
275
|
+
const utilization = currentUtilization || calculateUtilization(bank, delta);
|
|
276
|
+
const borrowRate = calculateBorrowRate(bank, delta, utilization);
|
|
277
277
|
const depositRate = borrowRate
|
|
278
278
|
.mul(numericConstants_2.PERCENTAGE_PRECISION.sub(new anchor_1.BN(bank.insuranceFund.totalFactor)))
|
|
279
279
|
.mul(utilization)
|
|
@@ -282,8 +282,8 @@ function calculateDepositRate(bank, delta = numericConstants_1.ZERO) {
|
|
|
282
282
|
return depositRate;
|
|
283
283
|
}
|
|
284
284
|
exports.calculateDepositRate = calculateDepositRate;
|
|
285
|
-
function calculateBorrowRate(bank, delta = numericConstants_1.ZERO) {
|
|
286
|
-
return calculateInterestRate(bank, delta);
|
|
285
|
+
function calculateBorrowRate(bank, delta = numericConstants_1.ZERO, currentUtilization = null) {
|
|
286
|
+
return calculateInterestRate(bank, delta, currentUtilization);
|
|
287
287
|
}
|
|
288
288
|
exports.calculateBorrowRate = calculateBorrowRate;
|
|
289
289
|
function calculateInterestAccumulated(bank, now) {
|
package/package.json
CHANGED
|
@@ -28,6 +28,8 @@ import { OracleClientCache } from '../oracles/oracleClientCache';
|
|
|
28
28
|
import { QUOTE_ORACLE_PRICE_DATA } from '../oracles/quoteAssetOracleClient';
|
|
29
29
|
import { findAllMarketAndOracles } from '../config';
|
|
30
30
|
|
|
31
|
+
const ORACLE_DEFAULT_KEY = PublicKey.default.toBase58();
|
|
32
|
+
|
|
31
33
|
export class PollingDriftClientAccountSubscriber
|
|
32
34
|
implements DriftClientAccountSubscriber
|
|
33
35
|
{
|
|
@@ -50,8 +52,10 @@ export class PollingDriftClientAccountSubscriber
|
|
|
50
52
|
state?: DataAndSlot<StateAccount>;
|
|
51
53
|
perpMarket = new Map<number, DataAndSlot<PerpMarketAccount>>();
|
|
52
54
|
perpOracleMap = new Map<number, PublicKey>();
|
|
55
|
+
perpOracleStringMap = new Map<number, string>();
|
|
53
56
|
spotMarket = new Map<number, DataAndSlot<SpotMarketAccount>>();
|
|
54
57
|
spotOracleMap = new Map<number, PublicKey>();
|
|
58
|
+
spotOracleStringMap = new Map<number, string>();
|
|
55
59
|
oracles = new Map<string, DataAndSlot<OraclePriceData>>();
|
|
56
60
|
user?: DataAndSlot<UserAccount>;
|
|
57
61
|
|
|
@@ -470,6 +474,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
470
474
|
);
|
|
471
475
|
}
|
|
472
476
|
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
477
|
+
this.perpOracleStringMap.set(perpMarketIndex, oracle.toBase58());
|
|
473
478
|
}
|
|
474
479
|
await Promise.all(oraclePromises);
|
|
475
480
|
}
|
|
@@ -490,6 +495,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
490
495
|
);
|
|
491
496
|
}
|
|
492
497
|
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
498
|
+
this.spotOracleStringMap.set(spotMarketIndex, oracle.toBase58());
|
|
493
499
|
}
|
|
494
500
|
await Promise.all(oraclePromises);
|
|
495
501
|
}
|
|
@@ -528,17 +534,21 @@ export class PollingDriftClientAccountSubscriber
|
|
|
528
534
|
}
|
|
529
535
|
|
|
530
536
|
public getOraclePriceDataAndSlot(
|
|
531
|
-
oraclePublicKey: PublicKey
|
|
537
|
+
oraclePublicKey: PublicKey | string
|
|
532
538
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
533
539
|
this.assertIsSubscribed();
|
|
534
|
-
|
|
540
|
+
const oracleString =
|
|
541
|
+
typeof oraclePublicKey === 'string'
|
|
542
|
+
? oraclePublicKey
|
|
543
|
+
: oraclePublicKey.toBase58();
|
|
544
|
+
if (oracleString === ORACLE_DEFAULT_KEY) {
|
|
535
545
|
return {
|
|
536
546
|
data: QUOTE_ORACLE_PRICE_DATA,
|
|
537
547
|
slot: 0,
|
|
538
548
|
};
|
|
539
549
|
}
|
|
540
550
|
|
|
541
|
-
return this.oracles.get(
|
|
551
|
+
return this.oracles.get(oracleString);
|
|
542
552
|
}
|
|
543
553
|
|
|
544
554
|
public getOraclePriceDataAndSlotForPerpMarket(
|
|
@@ -546,6 +556,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
546
556
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
547
557
|
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
548
558
|
const oracle = this.perpOracleMap.get(marketIndex);
|
|
559
|
+
const oracleString = this.perpOracleStringMap.get(marketIndex);
|
|
549
560
|
|
|
550
561
|
if (!perpMarketAccount || !oracle) {
|
|
551
562
|
return undefined;
|
|
@@ -556,7 +567,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
556
567
|
this.setPerpOracleMap();
|
|
557
568
|
}
|
|
558
569
|
|
|
559
|
-
return this.getOraclePriceDataAndSlot(
|
|
570
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
560
571
|
}
|
|
561
572
|
|
|
562
573
|
public getOraclePriceDataAndSlotForSpotMarket(
|
|
@@ -564,6 +575,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
564
575
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
565
576
|
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
566
577
|
const oracle = this.spotOracleMap.get(marketIndex);
|
|
578
|
+
const oracleString = this.spotOracleStringMap.get(marketIndex);
|
|
567
579
|
if (!spotMarketAccount || !oracle) {
|
|
568
580
|
return undefined;
|
|
569
581
|
}
|
|
@@ -573,7 +585,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
573
585
|
this.setSpotOracleMap();
|
|
574
586
|
}
|
|
575
587
|
|
|
576
|
-
return this.getOraclePriceDataAndSlot(
|
|
588
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
577
589
|
}
|
|
578
590
|
|
|
579
591
|
public updateAccountLoaderPollingFrequency(pollingFrequency: number): void {
|
package/src/accounts/types.ts
CHANGED
|
@@ -72,7 +72,7 @@ export interface DriftClientAccountSubscriber {
|
|
|
72
72
|
): DataAndSlot<SpotMarketAccount> | undefined;
|
|
73
73
|
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
74
74
|
getOraclePriceDataAndSlot(
|
|
75
|
-
oraclePublicKey: PublicKey
|
|
75
|
+
oraclePublicKey: PublicKey | string
|
|
76
76
|
): DataAndSlot<OraclePriceData> | undefined;
|
|
77
77
|
getOraclePriceDataAndSlotForPerpMarket(
|
|
78
78
|
marketIndex: number
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
getDriftStateAccountPublicKey,
|
|
14
14
|
getSpotMarketPublicKey,
|
|
15
15
|
getPerpMarketPublicKey,
|
|
16
|
+
getPerpMarketPublicKeySync,
|
|
17
|
+
getSpotMarketPublicKeySync,
|
|
16
18
|
} from '../addresses/pda';
|
|
17
19
|
import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
|
|
18
20
|
import { Commitment, PublicKey } from '@solana/web3.js';
|
|
@@ -22,6 +24,8 @@ import * as Buffer from 'buffer';
|
|
|
22
24
|
import { QUOTE_ORACLE_PRICE_DATA } from '../oracles/quoteAssetOracleClient';
|
|
23
25
|
import { findAllMarketAndOracles } from '../config';
|
|
24
26
|
|
|
27
|
+
const ORACLE_DEFAULT_KEY = PublicKey.default.toBase58();
|
|
28
|
+
|
|
25
29
|
export class WebSocketDriftClientAccountSubscriber
|
|
26
30
|
implements DriftClientAccountSubscriber
|
|
27
31
|
{
|
|
@@ -43,13 +47,19 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
43
47
|
AccountSubscriber<PerpMarketAccount>
|
|
44
48
|
>();
|
|
45
49
|
perpOracleMap = new Map<number, PublicKey>();
|
|
50
|
+
perpOracleStringMap = new Map<number, string>();
|
|
46
51
|
spotMarketAccountSubscribers = new Map<
|
|
47
52
|
number,
|
|
48
53
|
AccountSubscriber<SpotMarketAccount>
|
|
49
54
|
>();
|
|
50
55
|
spotOracleMap = new Map<number, PublicKey>();
|
|
56
|
+
spotOracleStringMap = new Map<number, string>();
|
|
51
57
|
oracleSubscribers = new Map<string, AccountSubscriber<OraclePriceData>>();
|
|
52
58
|
|
|
59
|
+
initialPerpMarketAccountData: Map<number, PerpMarketAccount>;
|
|
60
|
+
initialSpotMarketAccountData: Map<number, SpotMarketAccount>;
|
|
61
|
+
initialOraclePriceData: Map<string, OraclePriceData>;
|
|
62
|
+
|
|
53
63
|
private isSubscribing = false;
|
|
54
64
|
private subscriptionPromise: Promise<boolean>;
|
|
55
65
|
private subscriptionPromiseResolver: (val: boolean) => void;
|
|
@@ -90,11 +100,23 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
90
100
|
});
|
|
91
101
|
|
|
92
102
|
if (this.shouldFindAllMarketsAndOracles) {
|
|
93
|
-
const {
|
|
94
|
-
|
|
103
|
+
const {
|
|
104
|
+
perpMarketIndexes,
|
|
105
|
+
perpMarketAccounts,
|
|
106
|
+
spotMarketIndexes,
|
|
107
|
+
spotMarketAccounts,
|
|
108
|
+
oracleInfos,
|
|
109
|
+
} = await findAllMarketAndOracles(this.program);
|
|
95
110
|
this.perpMarketIndexes = perpMarketIndexes;
|
|
96
111
|
this.spotMarketIndexes = spotMarketIndexes;
|
|
97
112
|
this.oracleInfos = oracleInfos;
|
|
113
|
+
// front run and set the initial data here to save extra gma call in set initial data
|
|
114
|
+
this.initialPerpMarketAccountData = new Map(
|
|
115
|
+
perpMarketAccounts.map((market) => [market.marketIndex, market])
|
|
116
|
+
);
|
|
117
|
+
this.initialSpotMarketAccountData = new Map(
|
|
118
|
+
spotMarketAccounts.map((market) => [market.marketIndex, market])
|
|
119
|
+
);
|
|
98
120
|
}
|
|
99
121
|
|
|
100
122
|
const statePublicKey = await getDriftStateAccountPublicKey(
|
|
@@ -115,6 +137,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
115
137
|
this.eventEmitter.emit('update');
|
|
116
138
|
});
|
|
117
139
|
|
|
140
|
+
// set initial data to avoid spamming getAccountInfo calls in webSocketAccountSubscriber
|
|
141
|
+
await this.setInitialData();
|
|
142
|
+
|
|
118
143
|
await Promise.all([
|
|
119
144
|
// subscribe to market accounts
|
|
120
145
|
this.subscribeToPerpMarketAccounts(),
|
|
@@ -132,9 +157,86 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
132
157
|
this.isSubscribed = true;
|
|
133
158
|
this.subscriptionPromiseResolver(true);
|
|
134
159
|
|
|
160
|
+
// delete initial data
|
|
161
|
+
this.removeInitialData();
|
|
162
|
+
|
|
135
163
|
return true;
|
|
136
164
|
}
|
|
137
165
|
|
|
166
|
+
async setInitialData(): Promise<void> {
|
|
167
|
+
const connection = this.program.provider.connection;
|
|
168
|
+
|
|
169
|
+
if (!this.initialPerpMarketAccountData) {
|
|
170
|
+
const perpMarketPublicKeys = this.perpMarketIndexes.map((marketIndex) =>
|
|
171
|
+
getPerpMarketPublicKeySync(this.program.programId, marketIndex)
|
|
172
|
+
);
|
|
173
|
+
const perpMarketAccountInfos = await connection.getMultipleAccountsInfo(
|
|
174
|
+
perpMarketPublicKeys
|
|
175
|
+
);
|
|
176
|
+
this.initialPerpMarketAccountData = new Map(
|
|
177
|
+
perpMarketAccountInfos
|
|
178
|
+
.filter((accountInfo) => !!accountInfo)
|
|
179
|
+
.map((accountInfo) => {
|
|
180
|
+
const perpMarket = this.program.coder.accounts.decode(
|
|
181
|
+
'PerpMarket',
|
|
182
|
+
accountInfo.data
|
|
183
|
+
);
|
|
184
|
+
return [perpMarket.marketIndex, perpMarket];
|
|
185
|
+
})
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!this.initialSpotMarketAccountData) {
|
|
190
|
+
const spotMarketPublicKeys = this.spotMarketIndexes.map((marketIndex) =>
|
|
191
|
+
getSpotMarketPublicKeySync(this.program.programId, marketIndex)
|
|
192
|
+
);
|
|
193
|
+
const spotMarketAccountInfos = await connection.getMultipleAccountsInfo(
|
|
194
|
+
spotMarketPublicKeys
|
|
195
|
+
);
|
|
196
|
+
this.initialSpotMarketAccountData = new Map(
|
|
197
|
+
spotMarketAccountInfos
|
|
198
|
+
.filter((accountInfo) => !!accountInfo)
|
|
199
|
+
.map((accountInfo) => {
|
|
200
|
+
const spotMarket = this.program.coder.accounts.decode(
|
|
201
|
+
'SpotMarket',
|
|
202
|
+
accountInfo.data
|
|
203
|
+
);
|
|
204
|
+
return [spotMarket.marketIndex, spotMarket];
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const oracleAccountInfos = await connection.getMultipleAccountsInfo(
|
|
210
|
+
this.oracleInfos.map((oracleInfo) => oracleInfo.publicKey)
|
|
211
|
+
);
|
|
212
|
+
this.initialOraclePriceData = new Map(
|
|
213
|
+
this.oracleInfos.reduce((result, oracleInfo, i) => {
|
|
214
|
+
if (!oracleAccountInfos[i]) {
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const oracleClient = this.oracleClientCache.get(
|
|
219
|
+
oracleInfo.source,
|
|
220
|
+
connection,
|
|
221
|
+
this.program
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(
|
|
225
|
+
oracleAccountInfos[i].data
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
result.push([oracleInfo.publicKey.toString(), oraclePriceData]);
|
|
229
|
+
return result;
|
|
230
|
+
}, [])
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
removeInitialData() {
|
|
235
|
+
this.initialPerpMarketAccountData = new Map();
|
|
236
|
+
this.initialSpotMarketAccountData = new Map();
|
|
237
|
+
this.initialOraclePriceData = new Map();
|
|
238
|
+
}
|
|
239
|
+
|
|
138
240
|
async subscribeToPerpMarketAccounts(): Promise<boolean> {
|
|
139
241
|
await Promise.all(
|
|
140
242
|
this.perpMarketIndexes.map((marketIndex) =>
|
|
@@ -157,6 +259,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
157
259
|
this.resubOpts,
|
|
158
260
|
this.commitment
|
|
159
261
|
);
|
|
262
|
+
accountSubscriber.setData(
|
|
263
|
+
this.initialPerpMarketAccountData.get(marketIndex)
|
|
264
|
+
);
|
|
160
265
|
await accountSubscriber.subscribe((data: PerpMarketAccount) => {
|
|
161
266
|
this.eventEmitter.emit('perpMarketAccountUpdate', data);
|
|
162
267
|
this.eventEmitter.emit('update');
|
|
@@ -187,6 +292,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
187
292
|
this.resubOpts,
|
|
188
293
|
this.commitment
|
|
189
294
|
);
|
|
295
|
+
accountSubscriber.setData(
|
|
296
|
+
this.initialSpotMarketAccountData.get(marketIndex)
|
|
297
|
+
);
|
|
190
298
|
await accountSubscriber.subscribe((data: SpotMarketAccount) => {
|
|
191
299
|
this.eventEmitter.emit('spotMarketAccountUpdate', data);
|
|
192
300
|
this.eventEmitter.emit('update');
|
|
@@ -206,6 +314,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
206
314
|
}
|
|
207
315
|
|
|
208
316
|
async subscribeToOracle(oracleInfo: OracleInfo): Promise<boolean> {
|
|
317
|
+
const oracleString = oracleInfo.publicKey.toString();
|
|
209
318
|
const client = this.oracleClientCache.get(
|
|
210
319
|
oracleInfo.source,
|
|
211
320
|
this.program.provider.connection,
|
|
@@ -221,16 +330,17 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
221
330
|
this.resubOpts,
|
|
222
331
|
this.commitment
|
|
223
332
|
);
|
|
224
|
-
|
|
333
|
+
const initialOraclePriceData =
|
|
334
|
+
this.initialOraclePriceData.get(oracleString);
|
|
335
|
+
if (initialOraclePriceData) {
|
|
336
|
+
accountSubscriber.setData(initialOraclePriceData);
|
|
337
|
+
}
|
|
225
338
|
await accountSubscriber.subscribe((data: OraclePriceData) => {
|
|
226
339
|
this.eventEmitter.emit('oraclePriceUpdate', oracleInfo.publicKey, data);
|
|
227
340
|
this.eventEmitter.emit('update');
|
|
228
341
|
});
|
|
229
342
|
|
|
230
|
-
this.oracleSubscribers.set(
|
|
231
|
-
oracleInfo.publicKey.toString(),
|
|
232
|
-
accountSubscriber
|
|
233
|
-
);
|
|
343
|
+
this.oracleSubscribers.set(oracleString, accountSubscriber);
|
|
234
344
|
return true;
|
|
235
345
|
}
|
|
236
346
|
|
|
@@ -326,7 +436,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
326
436
|
const perpMarkets = this.getMarketAccountsAndSlots();
|
|
327
437
|
const addOraclePromises = [];
|
|
328
438
|
for (const perpMarket of perpMarkets) {
|
|
329
|
-
if (!perpMarket) {
|
|
439
|
+
if (!perpMarket || !perpMarket.data) {
|
|
330
440
|
continue;
|
|
331
441
|
}
|
|
332
442
|
const perpMarketAccount = perpMarket.data;
|
|
@@ -341,6 +451,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
341
451
|
);
|
|
342
452
|
}
|
|
343
453
|
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
454
|
+
this.perpOracleStringMap.set(perpMarketIndex, oracle.toBase58());
|
|
344
455
|
}
|
|
345
456
|
await Promise.all(addOraclePromises);
|
|
346
457
|
}
|
|
@@ -349,7 +460,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
349
460
|
const spotMarkets = this.getSpotMarketAccountsAndSlots();
|
|
350
461
|
const addOraclePromises = [];
|
|
351
462
|
for (const spotMarket of spotMarkets) {
|
|
352
|
-
if (!spotMarket) {
|
|
463
|
+
if (!spotMarket || !spotMarket.data) {
|
|
353
464
|
continue;
|
|
354
465
|
}
|
|
355
466
|
const spotMarketAccount = spotMarket.data;
|
|
@@ -364,6 +475,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
364
475
|
);
|
|
365
476
|
}
|
|
366
477
|
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
478
|
+
this.spotOracleStringMap.set(spotMarketIndex, oracle.toBase58());
|
|
367
479
|
}
|
|
368
480
|
await Promise.all(addOraclePromises);
|
|
369
481
|
}
|
|
@@ -408,16 +520,20 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
408
520
|
}
|
|
409
521
|
|
|
410
522
|
public getOraclePriceDataAndSlot(
|
|
411
|
-
oraclePublicKey: PublicKey
|
|
523
|
+
oraclePublicKey: PublicKey | string
|
|
412
524
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
413
525
|
this.assertIsSubscribed();
|
|
414
|
-
|
|
526
|
+
const oracleString =
|
|
527
|
+
typeof oraclePublicKey === 'string'
|
|
528
|
+
? oraclePublicKey
|
|
529
|
+
: oraclePublicKey.toBase58();
|
|
530
|
+
if (oracleString === ORACLE_DEFAULT_KEY) {
|
|
415
531
|
return {
|
|
416
532
|
data: QUOTE_ORACLE_PRICE_DATA,
|
|
417
533
|
slot: 0,
|
|
418
534
|
};
|
|
419
535
|
}
|
|
420
|
-
return this.oracleSubscribers.get(
|
|
536
|
+
return this.oracleSubscribers.get(oracleString).dataAndSlot;
|
|
421
537
|
}
|
|
422
538
|
|
|
423
539
|
public getOraclePriceDataAndSlotForPerpMarket(
|
|
@@ -425,6 +541,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
425
541
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
426
542
|
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
427
543
|
const oracle = this.perpOracleMap.get(marketIndex);
|
|
544
|
+
const oracleString = this.perpOracleStringMap.get(marketIndex);
|
|
428
545
|
if (!perpMarketAccount || !oracle) {
|
|
429
546
|
return undefined;
|
|
430
547
|
}
|
|
@@ -434,7 +551,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
434
551
|
this.setPerpOracleMap();
|
|
435
552
|
}
|
|
436
553
|
|
|
437
|
-
return this.getOraclePriceDataAndSlot(
|
|
554
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
438
555
|
}
|
|
439
556
|
|
|
440
557
|
public getOraclePriceDataAndSlotForSpotMarket(
|
|
@@ -442,6 +559,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
442
559
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
443
560
|
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
444
561
|
const oracle = this.spotOracleMap.get(marketIndex);
|
|
562
|
+
const oracleString = this.spotOracleStringMap.get(marketIndex);
|
|
445
563
|
if (!spotMarketAccount || !oracle) {
|
|
446
564
|
return undefined;
|
|
447
565
|
}
|
|
@@ -451,6 +569,6 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
451
569
|
this.setSpotOracleMap();
|
|
452
570
|
}
|
|
453
571
|
|
|
454
|
-
return this.getOraclePriceDataAndSlot(
|
|
572
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
455
573
|
}
|
|
456
574
|
}
|
package/src/addresses/pda.ts
CHANGED
|
@@ -87,6 +87,19 @@ export async function getPerpMarketPublicKey(
|
|
|
87
87
|
)[0];
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
export function getPerpMarketPublicKeySync(
|
|
91
|
+
programId: PublicKey,
|
|
92
|
+
marketIndex: number
|
|
93
|
+
): PublicKey {
|
|
94
|
+
return PublicKey.findProgramAddressSync(
|
|
95
|
+
[
|
|
96
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('perp_market')),
|
|
97
|
+
new anchor.BN(marketIndex).toArrayLike(Buffer, 'le', 2),
|
|
98
|
+
],
|
|
99
|
+
programId
|
|
100
|
+
)[0];
|
|
101
|
+
}
|
|
102
|
+
|
|
90
103
|
export async function getSpotMarketPublicKey(
|
|
91
104
|
programId: PublicKey,
|
|
92
105
|
marketIndex: number
|
|
@@ -102,6 +115,19 @@ export async function getSpotMarketPublicKey(
|
|
|
102
115
|
)[0];
|
|
103
116
|
}
|
|
104
117
|
|
|
118
|
+
export function getSpotMarketPublicKeySync(
|
|
119
|
+
programId: PublicKey,
|
|
120
|
+
marketIndex: number
|
|
121
|
+
): PublicKey {
|
|
122
|
+
return PublicKey.findProgramAddressSync(
|
|
123
|
+
[
|
|
124
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('spot_market')),
|
|
125
|
+
new anchor.BN(marketIndex).toArrayLike(Buffer, 'le', 2),
|
|
126
|
+
],
|
|
127
|
+
programId
|
|
128
|
+
)[0];
|
|
129
|
+
}
|
|
130
|
+
|
|
105
131
|
export async function getSpotMarketVaultPublicKey(
|
|
106
132
|
programId: PublicKey,
|
|
107
133
|
marketIndex: number
|
package/src/config.ts
CHANGED
|
@@ -132,8 +132,10 @@ export function getMarketsAndOraclesForSubscription(env: DriftEnv): {
|
|
|
132
132
|
|
|
133
133
|
export async function findAllMarketAndOracles(program: Program): Promise<{
|
|
134
134
|
perpMarketIndexes: number[];
|
|
135
|
+
perpMarketAccounts: PerpMarketAccount[];
|
|
135
136
|
spotMarketIndexes: number[];
|
|
136
137
|
oracleInfos: OracleInfo[];
|
|
138
|
+
spotMarketAccounts: SpotMarketAccount[];
|
|
137
139
|
}> {
|
|
138
140
|
const perpMarketIndexes = [];
|
|
139
141
|
const spotMarketIndexes = [];
|
|
@@ -164,7 +166,13 @@ export async function findAllMarketAndOracles(program: Program): Promise<{
|
|
|
164
166
|
|
|
165
167
|
return {
|
|
166
168
|
perpMarketIndexes,
|
|
169
|
+
perpMarketAccounts: perpMarketProgramAccounts.map(
|
|
170
|
+
(account) => account.account
|
|
171
|
+
),
|
|
167
172
|
spotMarketIndexes,
|
|
173
|
+
spotMarketAccounts: spotMarketProgramAccounts.map(
|
|
174
|
+
(account) => account.account
|
|
175
|
+
),
|
|
168
176
|
oracleInfos: Array.from(oracleInfos.values()),
|
|
169
177
|
};
|
|
170
178
|
}
|
|
@@ -81,11 +81,11 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
81
81
|
symbol: 'MATIC-PERP',
|
|
82
82
|
baseAssetSymbol: 'MATIC',
|
|
83
83
|
marketIndex: 5,
|
|
84
|
-
oracle: new PublicKey('
|
|
84
|
+
oracle: new PublicKey('BrzyDgwELy4jjjsqLQpBeUxzrsueYyMhuWpYBaUYcXvi'),
|
|
85
85
|
launchTs: 1677690149000, //todo
|
|
86
86
|
oracleSource: OracleSource.PYTH_PULL,
|
|
87
87
|
pythFeedId:
|
|
88
|
-
'
|
|
88
|
+
'0xffd11c5a1cfd42f80afb2df4d9f264c15f956d68153335374ec10722edd70472',
|
|
89
89
|
},
|
|
90
90
|
{
|
|
91
91
|
fullName: 'Arbitrum',
|
|
@@ -416,11 +416,11 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
416
416
|
symbol: 'MATIC-PERP',
|
|
417
417
|
baseAssetSymbol: 'MATIC',
|
|
418
418
|
marketIndex: 5,
|
|
419
|
-
oracle: new PublicKey('
|
|
419
|
+
oracle: new PublicKey('BrzyDgwELy4jjjsqLQpBeUxzrsueYyMhuWpYBaUYcXvi'),
|
|
420
420
|
launchTs: 1677690149000, //todo
|
|
421
421
|
oracleSource: OracleSource.PYTH_PULL,
|
|
422
422
|
pythFeedId:
|
|
423
|
-
'
|
|
423
|
+
'0xffd11c5a1cfd42f80afb2df4d9f264c15f956d68153335374ec10722edd70472',
|
|
424
424
|
},
|
|
425
425
|
{
|
|
426
426
|
fullName: 'Arbitrum',
|
|
@@ -830,6 +830,28 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
830
830
|
launchTs: 1724250126000,
|
|
831
831
|
oracleSource: OracleSource.Prelaunch,
|
|
832
832
|
},
|
|
833
|
+
{
|
|
834
|
+
fullName: 'DEMOCRATS-WIN-MICHIGAN-BET',
|
|
835
|
+
category: ['Prediction', 'Election'],
|
|
836
|
+
symbol: 'DEMOCRATS-WIN-MICHIGAN-BET',
|
|
837
|
+
baseAssetSymbol: 'DEMOCRATS-WIN-MICHIGAN',
|
|
838
|
+
marketIndex: 41,
|
|
839
|
+
oracle: new PublicKey('8HTDLjhb2esGU5mu11v3pq3eWeFqmvKPkQNCnTTwKAyB'),
|
|
840
|
+
launchTs: 1725551484000,
|
|
841
|
+
oracleSource: OracleSource.Prelaunch,
|
|
842
|
+
},
|
|
843
|
+
{
|
|
844
|
+
fullName: 'TON',
|
|
845
|
+
category: ['L1'],
|
|
846
|
+
symbol: 'TON-PERP',
|
|
847
|
+
baseAssetSymbol: 'TON',
|
|
848
|
+
marketIndex: 42,
|
|
849
|
+
oracle: new PublicKey('BNjCXrpEqjdBnuRy2SAUgm5Pq8B73wGFwsf6RYFJiLPY'),
|
|
850
|
+
launchTs: 1725551484000,
|
|
851
|
+
oracleSource: OracleSource.PYTH_PULL,
|
|
852
|
+
pythFeedId:
|
|
853
|
+
'0x8963217838ab4cf5cadc172203c1f0b763fbaa45f346d8ee50ba994bbcac3026',
|
|
854
|
+
},
|
|
833
855
|
];
|
|
834
856
|
|
|
835
857
|
export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
|
|
@@ -412,6 +412,17 @@ export const MainnetSpotMarkets: SpotMarketConfig[] = [
|
|
|
412
412
|
pythFeedId:
|
|
413
413
|
'0xca3ba9a619a4b3755c10ac7d5e760275aa95e9823d38a84fedd416856cdba37c',
|
|
414
414
|
},
|
|
415
|
+
{
|
|
416
|
+
symbol: 'BNSOL',
|
|
417
|
+
marketIndex: 25,
|
|
418
|
+
oracle: new PublicKey('BAtFj4kQttZRVep3UZS2aZRDixkGYgWsbqTBVDbnSsPF'),
|
|
419
|
+
oracleSource: OracleSource.PYTH_PULL,
|
|
420
|
+
mint: new PublicKey('BNso1VUJnh4zcfpZa6986Ea66P6TCp59hvtNJ8b1X85'),
|
|
421
|
+
precision: LAMPORTS_PRECISION,
|
|
422
|
+
precisionExp: LAMPORTS_EXP,
|
|
423
|
+
pythFeedId:
|
|
424
|
+
'0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d',
|
|
425
|
+
},
|
|
415
426
|
];
|
|
416
427
|
|
|
417
428
|
export const SpotMarkets: { [key in DriftEnv]: SpotMarketConfig[] } = {
|
package/src/driftClient.ts
CHANGED
|
@@ -538,7 +538,9 @@ export class DriftClient {
|
|
|
538
538
|
public getOraclePriceDataAndSlot(
|
|
539
539
|
oraclePublicKey: PublicKey
|
|
540
540
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
541
|
-
return this.accountSubscriber.getOraclePriceDataAndSlot(
|
|
541
|
+
return this.accountSubscriber.getOraclePriceDataAndSlot(
|
|
542
|
+
oraclePublicKey.toBase58()
|
|
543
|
+
);
|
|
542
544
|
}
|
|
543
545
|
|
|
544
546
|
public async getSerumV3FulfillmentConfig(
|
|
@@ -3221,11 +3223,18 @@ export class DriftClient {
|
|
|
3221
3223
|
writablePerpMarketIndexes: [marketIndex],
|
|
3222
3224
|
writableSpotMarketIndexes: [QUOTE_SPOT_MARKET_INDEX],
|
|
3223
3225
|
});
|
|
3226
|
+
const perpMarketPublicKey = await getPerpMarketPublicKey(
|
|
3227
|
+
this.program.programId,
|
|
3228
|
+
marketIndex
|
|
3229
|
+
);
|
|
3224
3230
|
|
|
3225
3231
|
return await this.program.instruction.settleExpiredMarket(marketIndex, {
|
|
3226
3232
|
accounts: {
|
|
3227
3233
|
state: await this.getStatePublicKey(),
|
|
3228
|
-
|
|
3234
|
+
admin: this.isSubscribed
|
|
3235
|
+
? this.getStateAccount().admin
|
|
3236
|
+
: this.wallet.publicKey,
|
|
3237
|
+
perpMarket: perpMarketPublicKey,
|
|
3229
3238
|
},
|
|
3230
3239
|
remainingAccounts,
|
|
3231
3240
|
});
|