@drift-labs/sdk 2.37.1-beta.8 → 2.38.0
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/bulkAccountLoader.js +12 -1
- package/lib/adminClient.d.ts +1 -0
- package/lib/adminClient.js +10 -0
- package/lib/events/eventSubscriber.js +1 -1
- package/lib/events/fetchLogs.d.ts +1 -1
- package/lib/events/fetchLogs.js +2 -2
- package/lib/events/pollingLogProvider.d.ts +2 -1
- package/lib/events/pollingLogProvider.js +3 -2
- package/lib/events/types.d.ts +1 -0
- package/lib/idl/drift.json +41 -9
- package/lib/types.d.ts +2 -0
- package/lib/user.d.ts +2 -2
- package/lib/user.js +53 -25
- package/package.json +1 -1
- package/src/accounts/bulkAccountLoader.ts +11 -1
- package/src/adminClient.ts +18 -0
- package/src/events/eventSubscriber.ts +2 -1
- package/src/events/fetchLogs.ts +3 -2
- package/src/events/pollingLogProvider.ts +4 -2
- package/src/events/types.ts +1 -0
- package/src/idl/drift.json +41 -9
- package/src/types.ts +3 -0
- package/src/user.ts +74 -35
- package/tests/dlob/helpers.ts +2 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.37.1-beta.
|
|
1
|
+
2.37.1-beta.13
|
|
@@ -168,7 +168,18 @@ class BulkAccountLoader {
|
|
|
168
168
|
}
|
|
169
169
|
handleAccountCallbacks(accountToLoad, buffer, slot) {
|
|
170
170
|
for (const [_, callback] of accountToLoad.callbacks) {
|
|
171
|
-
|
|
171
|
+
try {
|
|
172
|
+
callback(buffer, slot);
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
console.log('Bulk account load: error in account callback');
|
|
176
|
+
console.log('accounto to load', accountToLoad.publicKey.toString());
|
|
177
|
+
console.log('buffer', buffer.toString('base64'));
|
|
178
|
+
for (const callback of accountToLoad.callbacks.values()) {
|
|
179
|
+
console.log('account to load cb', callback);
|
|
180
|
+
}
|
|
181
|
+
throw e;
|
|
182
|
+
}
|
|
172
183
|
}
|
|
173
184
|
}
|
|
174
185
|
getBufferAndSlot(publicKey) {
|
package/lib/adminClient.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export declare class AdminClient extends DriftClient {
|
|
|
26
26
|
updateAmmJitIntensity(perpMarketIndex: number, ammJitIntensity: number): Promise<TransactionSignature>;
|
|
27
27
|
updatePerpMarketName(perpMarketIndex: number, name: string): Promise<TransactionSignature>;
|
|
28
28
|
updateSpotMarketName(spotMarketIndex: number, name: string): Promise<TransactionSignature>;
|
|
29
|
+
updatePerpMarketPerLpBase(perpMarketIndex: number, perLpBase: number): Promise<TransactionSignature>;
|
|
29
30
|
updatePerpMarketMaxSpread(perpMarketIndex: number, maxSpread: number): Promise<TransactionSignature>;
|
|
30
31
|
updatePerpFeeStructure(feeStructure: FeeStructure): Promise<TransactionSignature>;
|
|
31
32
|
updateSpotFeeStructure(feeStructure: FeeStructure): Promise<TransactionSignature>;
|
package/lib/adminClient.js
CHANGED
|
@@ -365,6 +365,16 @@ class AdminClient extends driftClient_1.DriftClient {
|
|
|
365
365
|
},
|
|
366
366
|
});
|
|
367
367
|
}
|
|
368
|
+
async updatePerpMarketPerLpBase(perpMarketIndex, perLpBase) {
|
|
369
|
+
const perpMarketPublicKey = await (0, pda_1.getPerpMarketPublicKey)(this.program.programId, perpMarketIndex);
|
|
370
|
+
return await this.program.rpc.updatePerpMarketPerLpBase(perLpBase, {
|
|
371
|
+
accounts: {
|
|
372
|
+
admin: this.wallet.publicKey,
|
|
373
|
+
state: await this.getStatePublicKey(),
|
|
374
|
+
perpMarket: perpMarketPublicKey,
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
}
|
|
368
378
|
async updatePerpMarketMaxSpread(perpMarketIndex, maxSpread) {
|
|
369
379
|
const perpMarketPublicKey = await (0, pda_1.getPerpMarketPublicKey)(this.program.programId, perpMarketIndex);
|
|
370
380
|
return await this.program.rpc.updatePerpMarketMaxSpread(maxSpread, {
|
|
@@ -30,7 +30,7 @@ class EventSubscriber {
|
|
|
30
30
|
this.logProvider = new webSocketLogProvider_1.WebSocketLogProvider(this.connection, this.address, this.options.commitment);
|
|
31
31
|
}
|
|
32
32
|
else {
|
|
33
|
-
this.logProvider = new pollingLogProvider_1.PollingLogProvider(this.connection, this.address, options.commitment, this.options.logProviderConfig.frequency);
|
|
33
|
+
this.logProvider = new pollingLogProvider_1.PollingLogProvider(this.connection, this.address, options.commitment, this.options.logProviderConfig.frequency, this.options.logProviderConfig.batchSize);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
async subscribe() {
|
|
@@ -14,7 +14,7 @@ type FetchLogsResponse = {
|
|
|
14
14
|
transactionLogs: Log[];
|
|
15
15
|
mostRecentBlockTime: number | undefined;
|
|
16
16
|
};
|
|
17
|
-
export declare function fetchLogs(connection: Connection, address: PublicKey, finality: Finality, beforeTx?: TransactionSignature, untilTx?: TransactionSignature, limit?: number): Promise<FetchLogsResponse>;
|
|
17
|
+
export declare function fetchLogs(connection: Connection, address: PublicKey, finality: Finality, beforeTx?: TransactionSignature, untilTx?: TransactionSignature, limit?: number, batchSize?: number): Promise<FetchLogsResponse>;
|
|
18
18
|
export declare function fetchTransactionLogs(connection: Connection, signatures: TransactionSignature[], finality: Finality): Promise<Log[]>;
|
|
19
19
|
export declare class LogParser {
|
|
20
20
|
private program;
|
package/lib/events/fetchLogs.js
CHANGED
|
@@ -9,7 +9,7 @@ function mapTransactionResponseToLog(transaction) {
|
|
|
9
9
|
logs: transaction.meta.logMessages,
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
|
-
async function fetchLogs(connection, address, finality, beforeTx, untilTx, limit) {
|
|
12
|
+
async function fetchLogs(connection, address, finality, beforeTx, untilTx, limit, batchSize = 25) {
|
|
13
13
|
const signatures = await connection.getSignaturesForAddress(address, {
|
|
14
14
|
before: beforeTx,
|
|
15
15
|
until: untilTx,
|
|
@@ -20,7 +20,7 @@ async function fetchLogs(connection, address, finality, beforeTx, untilTx, limit
|
|
|
20
20
|
if (filteredSignatures.length === 0) {
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
|
-
const chunkedSignatures = chunk(filteredSignatures,
|
|
23
|
+
const chunkedSignatures = chunk(filteredSignatures, batchSize);
|
|
24
24
|
const transactionLogs = (await Promise.all(chunkedSignatures.map(async (chunk) => {
|
|
25
25
|
return await fetchTransactionLogs(connection, chunk.map((confirmedSignature) => confirmedSignature.signature), finality);
|
|
26
26
|
}))).flat();
|
|
@@ -4,12 +4,13 @@ export declare class PollingLogProvider implements LogProvider {
|
|
|
4
4
|
private connection;
|
|
5
5
|
private address;
|
|
6
6
|
private frequency;
|
|
7
|
+
private batchSize?;
|
|
7
8
|
private finality;
|
|
8
9
|
private intervalId;
|
|
9
10
|
private mostRecentSeenTx?;
|
|
10
11
|
private mutex;
|
|
11
12
|
private firstFetch;
|
|
12
|
-
constructor(connection: Connection, address: PublicKey, commitment: Commitment, frequency?: number);
|
|
13
|
+
constructor(connection: Connection, address: PublicKey, commitment: Commitment, frequency?: number, batchSize?: number);
|
|
13
14
|
subscribe(callback: logProviderCallback, skipHistory?: boolean): boolean;
|
|
14
15
|
isSubscribed(): boolean;
|
|
15
16
|
unsubscribe(): Promise<boolean>;
|
|
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PollingLogProvider = void 0;
|
|
4
4
|
const fetchLogs_1 = require("./fetchLogs");
|
|
5
5
|
class PollingLogProvider {
|
|
6
|
-
constructor(connection, address, commitment, frequency = 15 * 1000) {
|
|
6
|
+
constructor(connection, address, commitment, frequency = 15 * 1000, batchSize) {
|
|
7
7
|
this.connection = connection;
|
|
8
8
|
this.address = address;
|
|
9
9
|
this.frequency = frequency;
|
|
10
|
+
this.batchSize = batchSize;
|
|
10
11
|
this.firstFetch = true;
|
|
11
12
|
this.finality = commitment === 'finalized' ? 'finalized' : 'confirmed';
|
|
12
13
|
}
|
|
@@ -22,7 +23,7 @@ class PollingLogProvider {
|
|
|
22
23
|
try {
|
|
23
24
|
const response = await (0, fetchLogs_1.fetchLogs)(this.connection, this.address, this.finality, undefined, this.mostRecentSeenTx,
|
|
24
25
|
// If skipping history, only fetch one log back, not the maximum amount available
|
|
25
|
-
skipHistory && this.firstFetch ? 1 : undefined);
|
|
26
|
+
skipHistory && this.firstFetch ? 1 : undefined, this.batchSize);
|
|
26
27
|
if (response === undefined) {
|
|
27
28
|
return;
|
|
28
29
|
}
|
package/lib/events/types.d.ts
CHANGED
package/lib/idl/drift.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.38.0",
|
|
3
3
|
"name": "drift",
|
|
4
4
|
"instructions": [
|
|
5
5
|
{
|
|
@@ -3882,6 +3882,32 @@
|
|
|
3882
3882
|
}
|
|
3883
3883
|
]
|
|
3884
3884
|
},
|
|
3885
|
+
{
|
|
3886
|
+
"name": "updatePerpMarketPerLpBase",
|
|
3887
|
+
"accounts": [
|
|
3888
|
+
{
|
|
3889
|
+
"name": "admin",
|
|
3890
|
+
"isMut": false,
|
|
3891
|
+
"isSigner": true
|
|
3892
|
+
},
|
|
3893
|
+
{
|
|
3894
|
+
"name": "state",
|
|
3895
|
+
"isMut": false,
|
|
3896
|
+
"isSigner": false
|
|
3897
|
+
},
|
|
3898
|
+
{
|
|
3899
|
+
"name": "perpMarket",
|
|
3900
|
+
"isMut": true,
|
|
3901
|
+
"isSigner": false
|
|
3902
|
+
}
|
|
3903
|
+
],
|
|
3904
|
+
"args": [
|
|
3905
|
+
{
|
|
3906
|
+
"name": "perLpBase",
|
|
3907
|
+
"type": "i8"
|
|
3908
|
+
}
|
|
3909
|
+
]
|
|
3910
|
+
},
|
|
3885
3911
|
{
|
|
3886
3912
|
"name": "updateLpCooldownTime",
|
|
3887
3913
|
"accounts": [
|
|
@@ -6978,9 +7004,20 @@
|
|
|
6978
7004
|
],
|
|
6979
7005
|
"type": "i32"
|
|
6980
7006
|
},
|
|
7007
|
+
{
|
|
7008
|
+
"name": "perLpBase",
|
|
7009
|
+
"docs": [
|
|
7010
|
+
"expo for unit of per_lp, base 10 (if per_lp_base=X, then per_lp unit is 10^X)"
|
|
7011
|
+
],
|
|
7012
|
+
"type": "i8"
|
|
7013
|
+
},
|
|
6981
7014
|
{
|
|
6982
7015
|
"name": "padding1",
|
|
6983
|
-
"type": "
|
|
7016
|
+
"type": "u8"
|
|
7017
|
+
},
|
|
7018
|
+
{
|
|
7019
|
+
"name": "padding2",
|
|
7020
|
+
"type": "u16"
|
|
6984
7021
|
},
|
|
6985
7022
|
{
|
|
6986
7023
|
"name": "totalFeeEarnedPerLp",
|
|
@@ -7447,13 +7484,8 @@
|
|
|
7447
7484
|
"type": "u8"
|
|
7448
7485
|
},
|
|
7449
7486
|
{
|
|
7450
|
-
"name": "
|
|
7451
|
-
"type":
|
|
7452
|
-
"array": [
|
|
7453
|
-
"u8",
|
|
7454
|
-
1
|
|
7455
|
-
]
|
|
7456
|
-
}
|
|
7487
|
+
"name": "perLpBase",
|
|
7488
|
+
"type": "i8"
|
|
7457
7489
|
}
|
|
7458
7490
|
]
|
|
7459
7491
|
}
|
package/lib/types.d.ts
CHANGED
|
@@ -821,6 +821,7 @@ export type AMM = {
|
|
|
821
821
|
bidQuoteAssetReserve: BN;
|
|
822
822
|
askBaseAssetReserve: BN;
|
|
823
823
|
askQuoteAssetReserve: BN;
|
|
824
|
+
perLpBase: number;
|
|
824
825
|
};
|
|
825
826
|
export type PerpPosition = {
|
|
826
827
|
baseAssetAmount: BN;
|
|
@@ -837,6 +838,7 @@ export type PerpPosition = {
|
|
|
837
838
|
remainderBaseAssetAmount: number;
|
|
838
839
|
lastBaseAssetAmountPerLp: BN;
|
|
839
840
|
lastQuoteAssetAmountPerLp: BN;
|
|
841
|
+
perLpBase: number;
|
|
840
842
|
};
|
|
841
843
|
export type UserStatsAccount = {
|
|
842
844
|
numberOfSubAccounts: number;
|
package/lib/user.d.ts
CHANGED
|
@@ -101,10 +101,10 @@ export declare class User {
|
|
|
101
101
|
getPerpBuyingPower(marketIndex: number, collateralBuffer?: any): BN;
|
|
102
102
|
getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex: number, freeCollateral: BN, baseAssetAmount: BN): BN;
|
|
103
103
|
/**
|
|
104
|
-
* calculates Free Collateral = Total collateral -
|
|
104
|
+
* calculates Free Collateral = Total collateral - margin requirement
|
|
105
105
|
* @returns : Precision QUOTE_PRECISION
|
|
106
106
|
*/
|
|
107
|
-
getFreeCollateral(): BN;
|
|
107
|
+
getFreeCollateral(marginCategory?: MarginCategory): BN;
|
|
108
108
|
/**
|
|
109
109
|
* @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
|
|
110
110
|
*/
|
package/lib/user.js
CHANGED
|
@@ -145,6 +145,7 @@ class User {
|
|
|
145
145
|
lpShares: numericConstants_1.ZERO,
|
|
146
146
|
lastBaseAssetAmountPerLp: numericConstants_1.ZERO,
|
|
147
147
|
lastQuoteAssetAmountPerLp: numericConstants_1.ZERO,
|
|
148
|
+
perLpBase: 0,
|
|
148
149
|
};
|
|
149
150
|
}
|
|
150
151
|
getClonedPosition(position) {
|
|
@@ -258,17 +259,54 @@ class User {
|
|
|
258
259
|
}
|
|
259
260
|
const position = this.getClonedPosition(originalPosition);
|
|
260
261
|
const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
|
|
262
|
+
if (market.amm.perLpBase != position.perLpBase) {
|
|
263
|
+
// perLpBase = 1 => per 10 LP shares, perLpBase = -1 => per 0.1 LP shares
|
|
264
|
+
const expoDiff = market.amm.perLpBase - position.perLpBase;
|
|
265
|
+
const marketPerLpRebaseScalar = new _1.BN(10 ** Math.abs(expoDiff));
|
|
266
|
+
if (expoDiff > 0) {
|
|
267
|
+
position.lastBaseAssetAmountPerLp =
|
|
268
|
+
position.lastBaseAssetAmountPerLp.mul(marketPerLpRebaseScalar);
|
|
269
|
+
position.lastQuoteAssetAmountPerLp =
|
|
270
|
+
position.lastQuoteAssetAmountPerLp.mul(marketPerLpRebaseScalar);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
position.lastBaseAssetAmountPerLp =
|
|
274
|
+
position.lastBaseAssetAmountPerLp.div(marketPerLpRebaseScalar);
|
|
275
|
+
position.lastQuoteAssetAmountPerLp =
|
|
276
|
+
position.lastQuoteAssetAmountPerLp.div(marketPerLpRebaseScalar);
|
|
277
|
+
}
|
|
278
|
+
position.perLpBase = position.perLpBase + expoDiff;
|
|
279
|
+
}
|
|
261
280
|
const nShares = position.lpShares;
|
|
262
281
|
// incorp unsettled funding on pre settled position
|
|
263
282
|
const quoteFundingPnl = (0, _1.calculatePositionFundingPNL)(market, position);
|
|
283
|
+
let baseUnit = numericConstants_1.AMM_RESERVE_PRECISION;
|
|
284
|
+
if (market.amm.perLpBase == position.perLpBase) {
|
|
285
|
+
if (position.perLpBase >= 0 &&
|
|
286
|
+
position.perLpBase <= numericConstants_1.AMM_RESERVE_PRECISION_EXP.toNumber()) {
|
|
287
|
+
const marketPerLpRebase = new _1.BN(10 ** market.amm.perLpBase);
|
|
288
|
+
baseUnit = baseUnit.mul(marketPerLpRebase);
|
|
289
|
+
}
|
|
290
|
+
else if (position.perLpBase < 0 &&
|
|
291
|
+
position.perLpBase >= -numericConstants_1.AMM_RESERVE_PRECISION_EXP.toNumber()) {
|
|
292
|
+
const marketPerLpRebase = new _1.BN(10 ** Math.abs(market.amm.perLpBase));
|
|
293
|
+
baseUnit = baseUnit.div(marketPerLpRebase);
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
throw 'cannot calc';
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
throw 'market.amm.perLpBase != position.perLpBase';
|
|
301
|
+
}
|
|
264
302
|
const deltaBaa = market.amm.baseAssetAmountPerLp
|
|
265
303
|
.sub(position.lastBaseAssetAmountPerLp)
|
|
266
304
|
.mul(nShares)
|
|
267
|
-
.div(
|
|
305
|
+
.div(baseUnit);
|
|
268
306
|
const deltaQaa = market.amm.quoteAssetAmountPerLp
|
|
269
307
|
.sub(position.lastQuoteAssetAmountPerLp)
|
|
270
308
|
.mul(nShares)
|
|
271
|
-
.div(
|
|
309
|
+
.div(baseUnit);
|
|
272
310
|
function sign(v) {
|
|
273
311
|
return v.isNeg() ? new _1.BN(-1) : new _1.BN(1);
|
|
274
312
|
}
|
|
@@ -376,13 +414,15 @@ class User {
|
|
|
376
414
|
return freeCollateral.mul(numericConstants_1.MARGIN_PRECISION).div(new _1.BN(marginRatio));
|
|
377
415
|
}
|
|
378
416
|
/**
|
|
379
|
-
* calculates Free Collateral = Total collateral -
|
|
417
|
+
* calculates Free Collateral = Total collateral - margin requirement
|
|
380
418
|
* @returns : Precision QUOTE_PRECISION
|
|
381
419
|
*/
|
|
382
|
-
getFreeCollateral() {
|
|
383
|
-
const totalCollateral = this.getTotalCollateral(
|
|
384
|
-
const
|
|
385
|
-
|
|
420
|
+
getFreeCollateral(marginCategory = 'Initial') {
|
|
421
|
+
const totalCollateral = this.getTotalCollateral(marginCategory, true);
|
|
422
|
+
const marginRequirement = marginCategory === 'Initial'
|
|
423
|
+
? this.getInitialMarginRequirement()
|
|
424
|
+
: this.getMaintenanceMarginRequirement();
|
|
425
|
+
const freeCollateral = totalCollateral.sub(marginRequirement);
|
|
386
426
|
return freeCollateral.gte(numericConstants_1.ZERO) ? freeCollateral : numericConstants_1.ZERO;
|
|
387
427
|
}
|
|
388
428
|
/**
|
|
@@ -648,15 +688,8 @@ class User {
|
|
|
648
688
|
health = 0;
|
|
649
689
|
}
|
|
650
690
|
else {
|
|
651
|
-
|
|
652
|
-
100)
|
|
653
|
-
health = Math.min(1, Math.log(healthP1) / Math.log(100)) * 100;
|
|
654
|
-
if (health > 1) {
|
|
655
|
-
health = Math.round(health);
|
|
656
|
-
}
|
|
657
|
-
else {
|
|
658
|
-
health = Math.round(health * 100) / 100;
|
|
659
|
-
}
|
|
691
|
+
health = Math.round(Math.min(100, Math.max(0, (1 - maintenanceMarginReq.toNumber() / totalCollateral.toNumber()) *
|
|
692
|
+
100)));
|
|
660
693
|
}
|
|
661
694
|
return health;
|
|
662
695
|
}
|
|
@@ -721,12 +754,7 @@ class User {
|
|
|
721
754
|
*/
|
|
722
755
|
getPerpMarketLiabilityValue(marketIndex, marginCategory, liquidationBuffer, includeOpenOrders, strict = false) {
|
|
723
756
|
const perpPosition = this.getPerpPosition(marketIndex);
|
|
724
|
-
|
|
725
|
-
return numericConstants_1.ZERO;
|
|
726
|
-
}
|
|
727
|
-
else {
|
|
728
|
-
return this.calculateWeightedPerpPositionValue(perpPosition, marginCategory, liquidationBuffer, includeOpenOrders, strict);
|
|
729
|
-
}
|
|
757
|
+
return this.calculateWeightedPerpPositionValue(perpPosition, marginCategory, liquidationBuffer, includeOpenOrders, strict);
|
|
730
758
|
}
|
|
731
759
|
/**
|
|
732
760
|
* calculates sum of position value across all positions in margin system
|
|
@@ -1779,7 +1807,7 @@ class User {
|
|
|
1779
1807
|
healthComponents.perpPnl.push({
|
|
1780
1808
|
marketIndex: perpMarket.marketIndex,
|
|
1781
1809
|
size: positionUnrealizedPnl,
|
|
1782
|
-
value:
|
|
1810
|
+
value: pnlValue,
|
|
1783
1811
|
weight: pnlWeight,
|
|
1784
1812
|
weightedValue: wegithedPnlValue,
|
|
1785
1813
|
});
|
|
@@ -1820,7 +1848,7 @@ class User {
|
|
|
1820
1848
|
healthComponents.deposits.push({
|
|
1821
1849
|
marketIndex: spotMarketAccount.marketIndex,
|
|
1822
1850
|
size: worstCaseTokenAmount,
|
|
1823
|
-
value:
|
|
1851
|
+
value: baseAssetValue,
|
|
1824
1852
|
weight: weight,
|
|
1825
1853
|
weightedValue: weightedValue,
|
|
1826
1854
|
});
|
|
@@ -1854,7 +1882,7 @@ class User {
|
|
|
1854
1882
|
healthComponents.deposits.push({
|
|
1855
1883
|
marketIndex: spotMarketAccount.marketIndex,
|
|
1856
1884
|
size: netQuoteValue,
|
|
1857
|
-
value:
|
|
1885
|
+
value: baseAssetValue,
|
|
1858
1886
|
weight: weight,
|
|
1859
1887
|
weightedValue: weightedValue,
|
|
1860
1888
|
});
|
package/package.json
CHANGED
|
@@ -229,7 +229,17 @@ export class BulkAccountLoader {
|
|
|
229
229
|
slot: number
|
|
230
230
|
): void {
|
|
231
231
|
for (const [_, callback] of accountToLoad.callbacks) {
|
|
232
|
-
|
|
232
|
+
try {
|
|
233
|
+
callback(buffer, slot);
|
|
234
|
+
} catch (e) {
|
|
235
|
+
console.log('Bulk account load: error in account callback');
|
|
236
|
+
console.log('accounto to load', accountToLoad.publicKey.toString());
|
|
237
|
+
console.log('buffer', buffer.toString('base64'));
|
|
238
|
+
for (const callback of accountToLoad.callbacks.values()) {
|
|
239
|
+
console.log('account to load cb', callback);
|
|
240
|
+
}
|
|
241
|
+
throw e;
|
|
242
|
+
}
|
|
233
243
|
}
|
|
234
244
|
}
|
|
235
245
|
|
package/src/adminClient.ts
CHANGED
|
@@ -691,6 +691,24 @@ export class AdminClient extends DriftClient {
|
|
|
691
691
|
});
|
|
692
692
|
}
|
|
693
693
|
|
|
694
|
+
public async updatePerpMarketPerLpBase(
|
|
695
|
+
perpMarketIndex: number,
|
|
696
|
+
perLpBase: number
|
|
697
|
+
): Promise<TransactionSignature> {
|
|
698
|
+
const perpMarketPublicKey = await getPerpMarketPublicKey(
|
|
699
|
+
this.program.programId,
|
|
700
|
+
perpMarketIndex
|
|
701
|
+
);
|
|
702
|
+
|
|
703
|
+
return await this.program.rpc.updatePerpMarketPerLpBase(perLpBase, {
|
|
704
|
+
accounts: {
|
|
705
|
+
admin: this.wallet.publicKey,
|
|
706
|
+
state: await this.getStatePublicKey(),
|
|
707
|
+
perpMarket: perpMarketPublicKey,
|
|
708
|
+
},
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
|
|
694
712
|
public async updatePerpMarketMaxSpread(
|
|
695
713
|
perpMarketIndex: number,
|
|
696
714
|
maxSpread: number
|
package/src/events/fetchLogs.ts
CHANGED
|
@@ -36,7 +36,8 @@ export async function fetchLogs(
|
|
|
36
36
|
finality: Finality,
|
|
37
37
|
beforeTx?: TransactionSignature,
|
|
38
38
|
untilTx?: TransactionSignature,
|
|
39
|
-
limit?: number
|
|
39
|
+
limit?: number,
|
|
40
|
+
batchSize = 25
|
|
40
41
|
): Promise<FetchLogsResponse> {
|
|
41
42
|
const signatures = await connection.getSignaturesForAddress(
|
|
42
43
|
address,
|
|
@@ -60,7 +61,7 @@ export async function fetchLogs(
|
|
|
60
61
|
return undefined;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
const chunkedSignatures = chunk(filteredSignatures,
|
|
64
|
+
const chunkedSignatures = chunk(filteredSignatures, batchSize);
|
|
64
65
|
|
|
65
66
|
const transactionLogs = (
|
|
66
67
|
await Promise.all(
|
|
@@ -19,7 +19,8 @@ export class PollingLogProvider implements LogProvider {
|
|
|
19
19
|
private connection: Connection,
|
|
20
20
|
private address: PublicKey,
|
|
21
21
|
commitment: Commitment,
|
|
22
|
-
private frequency = 15 * 1000
|
|
22
|
+
private frequency = 15 * 1000,
|
|
23
|
+
private batchSize?: number
|
|
23
24
|
) {
|
|
24
25
|
this.finality = commitment === 'finalized' ? 'finalized' : 'confirmed';
|
|
25
26
|
}
|
|
@@ -46,7 +47,8 @@ export class PollingLogProvider implements LogProvider {
|
|
|
46
47
|
undefined,
|
|
47
48
|
this.mostRecentSeenTx,
|
|
48
49
|
// If skipping history, only fetch one log back, not the maximum amount available
|
|
49
|
-
skipHistory && this.firstFetch ? 1 : undefined
|
|
50
|
+
skipHistory && this.firstFetch ? 1 : undefined,
|
|
51
|
+
this.batchSize
|
|
50
52
|
);
|
|
51
53
|
|
|
52
54
|
if (response === undefined) {
|
package/src/events/types.ts
CHANGED
package/src/idl/drift.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.38.0",
|
|
3
3
|
"name": "drift",
|
|
4
4
|
"instructions": [
|
|
5
5
|
{
|
|
@@ -3882,6 +3882,32 @@
|
|
|
3882
3882
|
}
|
|
3883
3883
|
]
|
|
3884
3884
|
},
|
|
3885
|
+
{
|
|
3886
|
+
"name": "updatePerpMarketPerLpBase",
|
|
3887
|
+
"accounts": [
|
|
3888
|
+
{
|
|
3889
|
+
"name": "admin",
|
|
3890
|
+
"isMut": false,
|
|
3891
|
+
"isSigner": true
|
|
3892
|
+
},
|
|
3893
|
+
{
|
|
3894
|
+
"name": "state",
|
|
3895
|
+
"isMut": false,
|
|
3896
|
+
"isSigner": false
|
|
3897
|
+
},
|
|
3898
|
+
{
|
|
3899
|
+
"name": "perpMarket",
|
|
3900
|
+
"isMut": true,
|
|
3901
|
+
"isSigner": false
|
|
3902
|
+
}
|
|
3903
|
+
],
|
|
3904
|
+
"args": [
|
|
3905
|
+
{
|
|
3906
|
+
"name": "perLpBase",
|
|
3907
|
+
"type": "i8"
|
|
3908
|
+
}
|
|
3909
|
+
]
|
|
3910
|
+
},
|
|
3885
3911
|
{
|
|
3886
3912
|
"name": "updateLpCooldownTime",
|
|
3887
3913
|
"accounts": [
|
|
@@ -6978,9 +7004,20 @@
|
|
|
6978
7004
|
],
|
|
6979
7005
|
"type": "i32"
|
|
6980
7006
|
},
|
|
7007
|
+
{
|
|
7008
|
+
"name": "perLpBase",
|
|
7009
|
+
"docs": [
|
|
7010
|
+
"expo for unit of per_lp, base 10 (if per_lp_base=X, then per_lp unit is 10^X)"
|
|
7011
|
+
],
|
|
7012
|
+
"type": "i8"
|
|
7013
|
+
},
|
|
6981
7014
|
{
|
|
6982
7015
|
"name": "padding1",
|
|
6983
|
-
"type": "
|
|
7016
|
+
"type": "u8"
|
|
7017
|
+
},
|
|
7018
|
+
{
|
|
7019
|
+
"name": "padding2",
|
|
7020
|
+
"type": "u16"
|
|
6984
7021
|
},
|
|
6985
7022
|
{
|
|
6986
7023
|
"name": "totalFeeEarnedPerLp",
|
|
@@ -7447,13 +7484,8 @@
|
|
|
7447
7484
|
"type": "u8"
|
|
7448
7485
|
},
|
|
7449
7486
|
{
|
|
7450
|
-
"name": "
|
|
7451
|
-
"type":
|
|
7452
|
-
"array": [
|
|
7453
|
-
"u8",
|
|
7454
|
-
1
|
|
7455
|
-
]
|
|
7456
|
-
}
|
|
7487
|
+
"name": "perLpBase",
|
|
7488
|
+
"type": "i8"
|
|
7457
7489
|
}
|
|
7458
7490
|
]
|
|
7459
7491
|
}
|
package/src/types.ts
CHANGED
|
@@ -767,6 +767,8 @@ export type AMM = {
|
|
|
767
767
|
bidQuoteAssetReserve: BN;
|
|
768
768
|
askBaseAssetReserve: BN;
|
|
769
769
|
askQuoteAssetReserve: BN;
|
|
770
|
+
|
|
771
|
+
perLpBase: number; // i8
|
|
770
772
|
};
|
|
771
773
|
|
|
772
774
|
// # User Account Types
|
|
@@ -785,6 +787,7 @@ export type PerpPosition = {
|
|
|
785
787
|
remainderBaseAssetAmount: number;
|
|
786
788
|
lastBaseAssetAmountPerLp: BN;
|
|
787
789
|
lastQuoteAssetAmountPerLp: BN;
|
|
790
|
+
perLpBase: number;
|
|
788
791
|
};
|
|
789
792
|
|
|
790
793
|
export type UserStatsAccount = {
|
package/src/user.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
BASE_PRECISION,
|
|
32
32
|
ONE,
|
|
33
33
|
TWO,
|
|
34
|
+
AMM_RESERVE_PRECISION_EXP,
|
|
34
35
|
} from './constants/numericConstants';
|
|
35
36
|
import {
|
|
36
37
|
UserAccountSubscriber,
|
|
@@ -264,6 +265,7 @@ export class User {
|
|
|
264
265
|
lpShares: ZERO,
|
|
265
266
|
lastBaseAssetAmountPerLp: ZERO,
|
|
266
267
|
lastQuoteAssetAmountPerLp: ZERO,
|
|
268
|
+
perLpBase: 0,
|
|
267
269
|
};
|
|
268
270
|
}
|
|
269
271
|
|
|
@@ -427,21 +429,62 @@ export class User {
|
|
|
427
429
|
}
|
|
428
430
|
|
|
429
431
|
const position = this.getClonedPosition(originalPosition);
|
|
430
|
-
|
|
431
432
|
const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
|
|
433
|
+
|
|
434
|
+
if (market.amm.perLpBase != position.perLpBase) {
|
|
435
|
+
// perLpBase = 1 => per 10 LP shares, perLpBase = -1 => per 0.1 LP shares
|
|
436
|
+
const expoDiff = market.amm.perLpBase - position.perLpBase;
|
|
437
|
+
const marketPerLpRebaseScalar = new BN(10 ** Math.abs(expoDiff));
|
|
438
|
+
|
|
439
|
+
if (expoDiff > 0) {
|
|
440
|
+
position.lastBaseAssetAmountPerLp =
|
|
441
|
+
position.lastBaseAssetAmountPerLp.mul(marketPerLpRebaseScalar);
|
|
442
|
+
position.lastQuoteAssetAmountPerLp =
|
|
443
|
+
position.lastQuoteAssetAmountPerLp.mul(marketPerLpRebaseScalar);
|
|
444
|
+
} else {
|
|
445
|
+
position.lastBaseAssetAmountPerLp =
|
|
446
|
+
position.lastBaseAssetAmountPerLp.div(marketPerLpRebaseScalar);
|
|
447
|
+
position.lastQuoteAssetAmountPerLp =
|
|
448
|
+
position.lastQuoteAssetAmountPerLp.div(marketPerLpRebaseScalar);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
position.perLpBase = position.perLpBase + expoDiff;
|
|
452
|
+
}
|
|
453
|
+
|
|
432
454
|
const nShares = position.lpShares;
|
|
433
455
|
|
|
434
456
|
// incorp unsettled funding on pre settled position
|
|
435
457
|
const quoteFundingPnl = calculatePositionFundingPNL(market, position);
|
|
436
458
|
|
|
459
|
+
let baseUnit = AMM_RESERVE_PRECISION;
|
|
460
|
+
if (market.amm.perLpBase == position.perLpBase) {
|
|
461
|
+
if (
|
|
462
|
+
position.perLpBase >= 0 &&
|
|
463
|
+
position.perLpBase <= AMM_RESERVE_PRECISION_EXP.toNumber()
|
|
464
|
+
) {
|
|
465
|
+
const marketPerLpRebase = new BN(10 ** market.amm.perLpBase);
|
|
466
|
+
baseUnit = baseUnit.mul(marketPerLpRebase);
|
|
467
|
+
} else if (
|
|
468
|
+
position.perLpBase < 0 &&
|
|
469
|
+
position.perLpBase >= -AMM_RESERVE_PRECISION_EXP.toNumber()
|
|
470
|
+
) {
|
|
471
|
+
const marketPerLpRebase = new BN(10 ** Math.abs(market.amm.perLpBase));
|
|
472
|
+
baseUnit = baseUnit.div(marketPerLpRebase);
|
|
473
|
+
} else {
|
|
474
|
+
throw 'cannot calc';
|
|
475
|
+
}
|
|
476
|
+
} else {
|
|
477
|
+
throw 'market.amm.perLpBase != position.perLpBase';
|
|
478
|
+
}
|
|
479
|
+
|
|
437
480
|
const deltaBaa = market.amm.baseAssetAmountPerLp
|
|
438
481
|
.sub(position.lastBaseAssetAmountPerLp)
|
|
439
482
|
.mul(nShares)
|
|
440
|
-
.div(
|
|
483
|
+
.div(baseUnit);
|
|
441
484
|
const deltaQaa = market.amm.quoteAssetAmountPerLp
|
|
442
485
|
.sub(position.lastQuoteAssetAmountPerLp)
|
|
443
486
|
.mul(nShares)
|
|
444
|
-
.div(
|
|
487
|
+
.div(baseUnit);
|
|
445
488
|
|
|
446
489
|
function sign(v: BN) {
|
|
447
490
|
return v.isNeg() ? new BN(-1) : new BN(1);
|
|
@@ -593,13 +636,16 @@ export class User {
|
|
|
593
636
|
}
|
|
594
637
|
|
|
595
638
|
/**
|
|
596
|
-
* calculates Free Collateral = Total collateral -
|
|
639
|
+
* calculates Free Collateral = Total collateral - margin requirement
|
|
597
640
|
* @returns : Precision QUOTE_PRECISION
|
|
598
641
|
*/
|
|
599
|
-
public getFreeCollateral(): BN {
|
|
600
|
-
const totalCollateral = this.getTotalCollateral(
|
|
601
|
-
const
|
|
602
|
-
|
|
642
|
+
public getFreeCollateral(marginCategory: MarginCategory = 'Initial'): BN {
|
|
643
|
+
const totalCollateral = this.getTotalCollateral(marginCategory, true);
|
|
644
|
+
const marginRequirement =
|
|
645
|
+
marginCategory === 'Initial'
|
|
646
|
+
? this.getInitialMarginRequirement()
|
|
647
|
+
: this.getMaintenanceMarginRequirement();
|
|
648
|
+
const freeCollateral = totalCollateral.sub(marginRequirement);
|
|
603
649
|
return freeCollateral.gte(ZERO) ? freeCollateral : ZERO;
|
|
604
650
|
}
|
|
605
651
|
|
|
@@ -1179,19 +1225,16 @@ export class User {
|
|
|
1179
1225
|
} else if (totalCollateral.lte(ZERO)) {
|
|
1180
1226
|
health = 0;
|
|
1181
1227
|
} else {
|
|
1182
|
-
|
|
1183
|
-
Math.
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
} else {
|
|
1193
|
-
health = Math.round(health * 100) / 100;
|
|
1194
|
-
}
|
|
1228
|
+
health = Math.round(
|
|
1229
|
+
Math.min(
|
|
1230
|
+
100,
|
|
1231
|
+
Math.max(
|
|
1232
|
+
0,
|
|
1233
|
+
(1 - maintenanceMarginReq.toNumber() / totalCollateral.toNumber()) *
|
|
1234
|
+
100
|
|
1235
|
+
)
|
|
1236
|
+
)
|
|
1237
|
+
);
|
|
1195
1238
|
}
|
|
1196
1239
|
|
|
1197
1240
|
return health;
|
|
@@ -1316,17 +1359,13 @@ export class User {
|
|
|
1316
1359
|
strict = false
|
|
1317
1360
|
): BN {
|
|
1318
1361
|
const perpPosition = this.getPerpPosition(marketIndex);
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
includeOpenOrders,
|
|
1327
|
-
strict
|
|
1328
|
-
);
|
|
1329
|
-
}
|
|
1362
|
+
return this.calculateWeightedPerpPositionValue(
|
|
1363
|
+
perpPosition,
|
|
1364
|
+
marginCategory,
|
|
1365
|
+
liquidationBuffer,
|
|
1366
|
+
includeOpenOrders,
|
|
1367
|
+
strict
|
|
1368
|
+
);
|
|
1330
1369
|
}
|
|
1331
1370
|
|
|
1332
1371
|
/**
|
|
@@ -3228,7 +3267,7 @@ export class User {
|
|
|
3228
3267
|
healthComponents.perpPnl.push({
|
|
3229
3268
|
marketIndex: perpMarket.marketIndex,
|
|
3230
3269
|
size: positionUnrealizedPnl,
|
|
3231
|
-
value:
|
|
3270
|
+
value: pnlValue,
|
|
3232
3271
|
weight: pnlWeight,
|
|
3233
3272
|
weightedValue: wegithedPnlValue,
|
|
3234
3273
|
});
|
|
@@ -3304,7 +3343,7 @@ export class User {
|
|
|
3304
3343
|
healthComponents.deposits.push({
|
|
3305
3344
|
marketIndex: spotMarketAccount.marketIndex,
|
|
3306
3345
|
size: worstCaseTokenAmount,
|
|
3307
|
-
value:
|
|
3346
|
+
value: baseAssetValue,
|
|
3308
3347
|
weight: weight,
|
|
3309
3348
|
weightedValue: weightedValue,
|
|
3310
3349
|
});
|
|
@@ -3355,7 +3394,7 @@ export class User {
|
|
|
3355
3394
|
healthComponents.deposits.push({
|
|
3356
3395
|
marketIndex: spotMarketAccount.marketIndex,
|
|
3357
3396
|
size: netQuoteValue,
|
|
3358
|
-
value:
|
|
3397
|
+
value: baseAssetValue,
|
|
3359
3398
|
weight: weight,
|
|
3360
3399
|
weightedValue: weightedValue,
|
|
3361
3400
|
});
|
package/tests/dlob/helpers.ts
CHANGED
|
@@ -39,9 +39,11 @@ export const mockPerpPosition: PerpPosition = {
|
|
|
39
39
|
remainderBaseAssetAmount: 0,
|
|
40
40
|
lastBaseAssetAmountPerLp: new BN(0),
|
|
41
41
|
lastQuoteAssetAmountPerLp: new BN(0),
|
|
42
|
+
perLpBase: 0,
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
export const mockAMM: AMM = {
|
|
46
|
+
perLpBase: 0,
|
|
45
47
|
/* these values create a bid/ask price of 12 */
|
|
46
48
|
baseAssetReserve: new BN(1).mul(BASE_PRECISION),
|
|
47
49
|
quoteAssetReserve: new BN(12)
|