@drift-labs/sdk 2.95.0-beta.2 → 2.95.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/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 +66 -6
- 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 +125 -12
- 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,81 @@ 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
|
|
214
|
+
.filter((_, i) => !!oracleAccountInfos[i])
|
|
215
|
+
.map((oracleInfo, i) => {
|
|
216
|
+
const oracleClient = this.oracleClientCache.get(
|
|
217
|
+
oracleInfo.source,
|
|
218
|
+
connection,
|
|
219
|
+
this.program
|
|
220
|
+
);
|
|
221
|
+
const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(
|
|
222
|
+
oracleAccountInfos[i].data
|
|
223
|
+
);
|
|
224
|
+
return [oracleInfo.publicKey.toString(), oraclePriceData];
|
|
225
|
+
})
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
removeInitialData() {
|
|
230
|
+
this.initialPerpMarketAccountData = new Map();
|
|
231
|
+
this.initialSpotMarketAccountData = new Map();
|
|
232
|
+
this.initialOraclePriceData = new Map();
|
|
233
|
+
}
|
|
234
|
+
|
|
138
235
|
async subscribeToPerpMarketAccounts(): Promise<boolean> {
|
|
139
236
|
await Promise.all(
|
|
140
237
|
this.perpMarketIndexes.map((marketIndex) =>
|
|
@@ -157,6 +254,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
157
254
|
this.resubOpts,
|
|
158
255
|
this.commitment
|
|
159
256
|
);
|
|
257
|
+
accountSubscriber.setData(
|
|
258
|
+
this.initialPerpMarketAccountData.get(marketIndex)
|
|
259
|
+
);
|
|
160
260
|
await accountSubscriber.subscribe((data: PerpMarketAccount) => {
|
|
161
261
|
this.eventEmitter.emit('perpMarketAccountUpdate', data);
|
|
162
262
|
this.eventEmitter.emit('update');
|
|
@@ -187,6 +287,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
187
287
|
this.resubOpts,
|
|
188
288
|
this.commitment
|
|
189
289
|
);
|
|
290
|
+
accountSubscriber.setData(
|
|
291
|
+
this.initialSpotMarketAccountData.get(marketIndex)
|
|
292
|
+
);
|
|
190
293
|
await accountSubscriber.subscribe((data: SpotMarketAccount) => {
|
|
191
294
|
this.eventEmitter.emit('spotMarketAccountUpdate', data);
|
|
192
295
|
this.eventEmitter.emit('update');
|
|
@@ -206,6 +309,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
206
309
|
}
|
|
207
310
|
|
|
208
311
|
async subscribeToOracle(oracleInfo: OracleInfo): Promise<boolean> {
|
|
312
|
+
const oracleString = oracleInfo.publicKey.toString();
|
|
209
313
|
const client = this.oracleClientCache.get(
|
|
210
314
|
oracleInfo.source,
|
|
211
315
|
this.program.provider.connection,
|
|
@@ -221,16 +325,17 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
221
325
|
this.resubOpts,
|
|
222
326
|
this.commitment
|
|
223
327
|
);
|
|
224
|
-
|
|
328
|
+
const initialOraclePriceData =
|
|
329
|
+
this.initialOraclePriceData.get(oracleString);
|
|
330
|
+
if (initialOraclePriceData) {
|
|
331
|
+
accountSubscriber.setData(initialOraclePriceData);
|
|
332
|
+
}
|
|
225
333
|
await accountSubscriber.subscribe((data: OraclePriceData) => {
|
|
226
334
|
this.eventEmitter.emit('oraclePriceUpdate', oracleInfo.publicKey, data);
|
|
227
335
|
this.eventEmitter.emit('update');
|
|
228
336
|
});
|
|
229
337
|
|
|
230
|
-
this.oracleSubscribers.set(
|
|
231
|
-
oracleInfo.publicKey.toString(),
|
|
232
|
-
accountSubscriber
|
|
233
|
-
);
|
|
338
|
+
this.oracleSubscribers.set(oracleString, accountSubscriber);
|
|
234
339
|
return true;
|
|
235
340
|
}
|
|
236
341
|
|
|
@@ -341,6 +446,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
341
446
|
);
|
|
342
447
|
}
|
|
343
448
|
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
449
|
+
this.perpOracleStringMap.set(perpMarketIndex, oracle.toBase58());
|
|
344
450
|
}
|
|
345
451
|
await Promise.all(addOraclePromises);
|
|
346
452
|
}
|
|
@@ -364,6 +470,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
364
470
|
);
|
|
365
471
|
}
|
|
366
472
|
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
473
|
+
this.spotOracleStringMap.set(spotMarketIndex, oracle.toBase58());
|
|
367
474
|
}
|
|
368
475
|
await Promise.all(addOraclePromises);
|
|
369
476
|
}
|
|
@@ -408,16 +515,20 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
408
515
|
}
|
|
409
516
|
|
|
410
517
|
public getOraclePriceDataAndSlot(
|
|
411
|
-
oraclePublicKey: PublicKey
|
|
518
|
+
oraclePublicKey: PublicKey | string
|
|
412
519
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
413
520
|
this.assertIsSubscribed();
|
|
414
|
-
|
|
521
|
+
const oracleString =
|
|
522
|
+
typeof oraclePublicKey === 'string'
|
|
523
|
+
? oraclePublicKey
|
|
524
|
+
: oraclePublicKey.toBase58();
|
|
525
|
+
if (oracleString === ORACLE_DEFAULT_KEY) {
|
|
415
526
|
return {
|
|
416
527
|
data: QUOTE_ORACLE_PRICE_DATA,
|
|
417
528
|
slot: 0,
|
|
418
529
|
};
|
|
419
530
|
}
|
|
420
|
-
return this.oracleSubscribers.get(
|
|
531
|
+
return this.oracleSubscribers.get(oracleString).dataAndSlot;
|
|
421
532
|
}
|
|
422
533
|
|
|
423
534
|
public getOraclePriceDataAndSlotForPerpMarket(
|
|
@@ -425,6 +536,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
425
536
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
426
537
|
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
427
538
|
const oracle = this.perpOracleMap.get(marketIndex);
|
|
539
|
+
const oracleString = this.perpOracleStringMap.get(marketIndex);
|
|
428
540
|
if (!perpMarketAccount || !oracle) {
|
|
429
541
|
return undefined;
|
|
430
542
|
}
|
|
@@ -434,7 +546,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
434
546
|
this.setPerpOracleMap();
|
|
435
547
|
}
|
|
436
548
|
|
|
437
|
-
return this.getOraclePriceDataAndSlot(
|
|
549
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
438
550
|
}
|
|
439
551
|
|
|
440
552
|
public getOraclePriceDataAndSlotForSpotMarket(
|
|
@@ -442,6 +554,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
442
554
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
443
555
|
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
444
556
|
const oracle = this.spotOracleMap.get(marketIndex);
|
|
557
|
+
const oracleString = this.spotOracleStringMap.get(marketIndex);
|
|
445
558
|
if (!spotMarketAccount || !oracle) {
|
|
446
559
|
return undefined;
|
|
447
560
|
}
|
|
@@ -451,6 +564,6 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
451
564
|
this.setSpotOracleMap();
|
|
452
565
|
}
|
|
453
566
|
|
|
454
|
-
return this.getOraclePriceDataAndSlot(
|
|
567
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
455
568
|
}
|
|
456
569
|
}
|
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
|
});
|
package/src/events/parse.ts
CHANGED
|
@@ -11,7 +11,17 @@ export function parseLogs(
|
|
|
11
11
|
logs: string[],
|
|
12
12
|
programId = driftProgramId
|
|
13
13
|
): Event[] {
|
|
14
|
+
const { events } = parseLogsWithRaw(program, logs, programId);
|
|
15
|
+
return events;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function parseLogsWithRaw(
|
|
19
|
+
program: Program,
|
|
20
|
+
logs: string[],
|
|
21
|
+
programId = driftProgramId
|
|
22
|
+
): { events: Event[]; rawLogs: string[] } {
|
|
14
23
|
const events = [];
|
|
24
|
+
const rawLogs = [];
|
|
15
25
|
const execution = new ExecutionContext();
|
|
16
26
|
for (const log of logs) {
|
|
17
27
|
if (log.startsWith('Log truncated')) {
|
|
@@ -26,6 +36,7 @@ export function parseLogs(
|
|
|
26
36
|
);
|
|
27
37
|
if (event) {
|
|
28
38
|
events.push(event);
|
|
39
|
+
rawLogs.push(log);
|
|
29
40
|
}
|
|
30
41
|
if (newProgram) {
|
|
31
42
|
execution.push(newProgram);
|
|
@@ -34,7 +45,7 @@ export function parseLogs(
|
|
|
34
45
|
execution.pop();
|
|
35
46
|
}
|
|
36
47
|
}
|
|
37
|
-
return events;
|
|
48
|
+
return { events, rawLogs };
|
|
38
49
|
}
|
|
39
50
|
|
|
40
51
|
function handleLog(
|