@drift-labs/sdk 2.54.0-beta.1 → 2.54.0-beta.10
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/pollingInsuranceFundStakeAccountSubscriber.js +0 -1
- package/lib/constants/perpMarkets.js +20 -0
- package/lib/driftClient.d.ts +8 -2
- package/lib/driftClient.js +95 -20
- package/lib/events/webSocketLogProvider.js +3 -0
- package/lib/idl/drift.json +7 -1
- package/lib/jupiter/jupiterClient.d.ts +6 -0
- package/lib/jupiter/jupiterClient.js +2 -2
- package/lib/math/funding.js +24 -1
- package/lib/math/oracles.js +2 -2
- package/lib/math/superStake.d.ts +51 -0
- package/lib/math/superStake.js +10 -2
- package/lib/priorityFee/averageOverSlotsStrategy.d.ts +0 -5
- package/lib/priorityFee/averageOverSlotsStrategy.js +1 -13
- package/lib/priorityFee/maxOverSlotsStrategy.d.ts +0 -5
- package/lib/priorityFee/maxOverSlotsStrategy.js +1 -13
- package/lib/priorityFee/priorityFeeSubscriber.d.ts +5 -4
- package/lib/priorityFee/priorityFeeSubscriber.js +15 -21
- package/lib/tx/baseTxSender.js +2 -2
- package/lib/tx/retryTxSender.js +4 -21
- package/lib/tx/utils.d.ts +5 -1
- package/lib/tx/utils.js +20 -1
- package/lib/userMap/userMap.js +4 -0
- package/package.json +1 -1
- package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +0 -1
- package/src/constants/perpMarkets.ts +20 -0
- package/src/driftClient.ts +197 -39
- package/src/events/webSocketLogProvider.ts +11 -2
- package/src/idl/drift.json +7 -1
- package/src/jupiter/jupiterClient.ts +8 -2
- package/src/math/funding.ts +28 -1
- package/src/math/oracles.ts +2 -2
- package/src/math/superStake.ts +60 -1
- package/src/priorityFee/averageOverSlotsStrategy.ts +1 -16
- package/src/priorityFee/maxOverSlotsStrategy.ts +1 -16
- package/src/priorityFee/priorityFeeSubscriber.ts +22 -26
- package/src/tx/baseTxSender.ts +3 -2
- package/src/tx/retryTxSender.ts +5 -23
- package/src/tx/utils.ts +32 -0
- package/src/userMap/userMap.ts +3 -0
- package/tests/amm/test.ts +275 -2
- package/tests/dlob/test.ts +2 -2
- package/tests/tx/priorityFeeStrategy.ts +2 -2
package/src/math/superStake.ts
CHANGED
|
@@ -333,6 +333,63 @@ export async function fetchJitoSolMetrics() {
|
|
|
333
333
|
return data;
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
+
export type MSOL_METRICS_ENDPOINT_RESPONSE = {
|
|
337
|
+
total_active_balance: number;
|
|
338
|
+
available_reserve_balance: number;
|
|
339
|
+
emergency_cooling_down: number;
|
|
340
|
+
tvl_sol: number;
|
|
341
|
+
msol_directed_stake_sol: number;
|
|
342
|
+
msol_directed_stake_msol: number;
|
|
343
|
+
mnde_total_supply: number;
|
|
344
|
+
mnde_circulating_supply: number;
|
|
345
|
+
validators_count: number;
|
|
346
|
+
stake_accounts: number;
|
|
347
|
+
staking_sol_cap: number;
|
|
348
|
+
m_sol_price: number;
|
|
349
|
+
avg_staking_apy: number;
|
|
350
|
+
msol_price_apy_14d: number;
|
|
351
|
+
msol_price_apy_30d: number;
|
|
352
|
+
msol_price_apy_90d: number;
|
|
353
|
+
msol_price_apy_365d: number;
|
|
354
|
+
reserve_pda: number;
|
|
355
|
+
treasury_m_sol_amount: number;
|
|
356
|
+
m_sol_mint_supply: number;
|
|
357
|
+
m_sol_supply_state: number;
|
|
358
|
+
liq_pool_sol: number;
|
|
359
|
+
liq_pool_m_sol: number;
|
|
360
|
+
liq_pool_value: number;
|
|
361
|
+
liq_pool_token_supply: number;
|
|
362
|
+
liq_pool_token_price: number;
|
|
363
|
+
liq_pool_target: number;
|
|
364
|
+
liq_pool_min_fee: number;
|
|
365
|
+
liq_pool_max_fee: number;
|
|
366
|
+
liq_pool_current_fee: number;
|
|
367
|
+
liq_pool_treasury_cut: number;
|
|
368
|
+
liq_pool_cap: number;
|
|
369
|
+
total_cooling_down: number;
|
|
370
|
+
last_stake_delta_epoch: number;
|
|
371
|
+
circulating_ticket_count: number;
|
|
372
|
+
circulating_ticket_balance: number;
|
|
373
|
+
reward_fee_bp: number;
|
|
374
|
+
lido_staking: number;
|
|
375
|
+
lido_st_sol_price: number;
|
|
376
|
+
lido_stsol_price_apy_14d: number;
|
|
377
|
+
lido_stsol_price_apy_30d: number;
|
|
378
|
+
lido_stsol_price_apy_90d: number;
|
|
379
|
+
lido_stsol_price_apy_365d: number;
|
|
380
|
+
stake_delta: number;
|
|
381
|
+
bot_balance: number;
|
|
382
|
+
treasury_farm_claim_mnde_balance: number;
|
|
383
|
+
last_3_epochs_avg_duration_hs: number;
|
|
384
|
+
mnde_votes_validators: number;
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
export const fetchMSolMetrics = async () => {
|
|
388
|
+
const res = await fetch('https://api2.marinade.finance/metrics_json');
|
|
389
|
+
const data: MSOL_METRICS_ENDPOINT_RESPONSE = await res.json();
|
|
390
|
+
return data;
|
|
391
|
+
};
|
|
392
|
+
|
|
336
393
|
const getJitoSolHistoricalPriceMap = async (timestamps: number[]) => {
|
|
337
394
|
try {
|
|
338
395
|
const data = await fetchJitoSolMetrics();
|
|
@@ -382,7 +439,9 @@ export async function calculateSolEarned({
|
|
|
382
439
|
const now = Date.now() / 1000;
|
|
383
440
|
const timestamps: number[] = [
|
|
384
441
|
now,
|
|
385
|
-
...depositRecords
|
|
442
|
+
...depositRecords
|
|
443
|
+
.filter((r) => r.marketIndex === marketIndex)
|
|
444
|
+
.map((r) => r.ts.toNumber()),
|
|
386
445
|
];
|
|
387
446
|
|
|
388
447
|
let lstRatios = new Map<number, number>();
|
|
@@ -1,30 +1,15 @@
|
|
|
1
1
|
import { PriorityFeeStrategy } from './types';
|
|
2
2
|
|
|
3
3
|
export class AverageOverSlotsStrategy implements PriorityFeeStrategy {
|
|
4
|
-
private lookbackSlots: number;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @param lookbackSlots The number of slots to look back from the max slot in the sample
|
|
8
|
-
*/
|
|
9
|
-
constructor(lookbackSlots = 10) {
|
|
10
|
-
this.lookbackSlots = lookbackSlots;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
4
|
calculate(samples: { slot: number; prioritizationFee: number }[]): number {
|
|
14
5
|
if (samples.length === 0) {
|
|
15
6
|
return 0;
|
|
16
7
|
}
|
|
17
|
-
const stopSlot = samples[0].slot - this.lookbackSlots;
|
|
18
8
|
let runningSumFees = 0;
|
|
19
|
-
let countFees = 0;
|
|
20
9
|
|
|
21
10
|
for (let i = 0; i < samples.length; i++) {
|
|
22
|
-
if (samples[i].slot <= stopSlot) {
|
|
23
|
-
return runningSumFees / countFees;
|
|
24
|
-
}
|
|
25
11
|
runningSumFees += samples[i].prioritizationFee;
|
|
26
|
-
countFees++;
|
|
27
12
|
}
|
|
28
|
-
return runningSumFees /
|
|
13
|
+
return runningSumFees / samples.length;
|
|
29
14
|
}
|
|
30
15
|
}
|
|
@@ -1,30 +1,15 @@
|
|
|
1
1
|
import { PriorityFeeStrategy } from './types';
|
|
2
2
|
|
|
3
3
|
export class MaxOverSlotsStrategy implements PriorityFeeStrategy {
|
|
4
|
-
private lookbackSlots: number;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @param lookbackSlots The number of slots to look back from the max slot in the sample
|
|
8
|
-
*/
|
|
9
|
-
constructor(lookbackSlots = 10) {
|
|
10
|
-
this.lookbackSlots = lookbackSlots;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
4
|
calculate(samples: { slot: number; prioritizationFee: number }[]): number {
|
|
14
5
|
if (samples.length === 0) {
|
|
15
6
|
return 0;
|
|
16
7
|
}
|
|
17
8
|
// Assuming samples are sorted in descending order of slot.
|
|
18
|
-
const stopSlot = samples[0].slot - this.lookbackSlots;
|
|
19
9
|
let currMaxFee = samples[0].prioritizationFee;
|
|
20
10
|
|
|
21
11
|
for (let i = 0; i < samples.length; i++) {
|
|
22
|
-
|
|
23
|
-
return currMaxFee;
|
|
24
|
-
}
|
|
25
|
-
if (samples[i].prioritizationFee > currMaxFee) {
|
|
26
|
-
currMaxFee = samples[i].prioritizationFee;
|
|
27
|
-
}
|
|
12
|
+
currMaxFee = Math.max(samples[i].prioritizationFee, currMaxFee);
|
|
28
13
|
}
|
|
29
14
|
return currMaxFee;
|
|
30
15
|
}
|
|
@@ -10,16 +10,20 @@ export class PriorityFeeSubscriber {
|
|
|
10
10
|
customStrategy?: PriorityFeeStrategy;
|
|
11
11
|
averageStrategy = new AverageOverSlotsStrategy();
|
|
12
12
|
maxStrategy = new MaxOverSlotsStrategy();
|
|
13
|
+
lookbackDistance: number;
|
|
13
14
|
|
|
14
15
|
intervalId?: ReturnType<typeof setTimeout>;
|
|
15
16
|
|
|
16
17
|
latestPriorityFee = 0;
|
|
17
|
-
lastStrategyResult = 0;
|
|
18
18
|
lastCustomStrategyResult = 0;
|
|
19
19
|
lastAvgStrategyResult = 0;
|
|
20
20
|
lastMaxStrategyResult = 0;
|
|
21
21
|
lastSlotSeen = 0;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @param props
|
|
25
|
+
* customStrategy : strategy to return the priority fee to use based on recent samples. defaults to AVERAGE.
|
|
26
|
+
*/
|
|
23
27
|
public constructor({
|
|
24
28
|
connection,
|
|
25
29
|
frequencyMs,
|
|
@@ -36,28 +40,12 @@ export class PriorityFeeSubscriber {
|
|
|
36
40
|
this.connection = connection;
|
|
37
41
|
this.frequencyMs = frequencyMs;
|
|
38
42
|
this.addresses = addresses;
|
|
39
|
-
if (
|
|
40
|
-
this.
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
if (customStrategy) {
|
|
43
|
+
if (!customStrategy) {
|
|
44
|
+
this.customStrategy = new AverageOverSlotsStrategy();
|
|
45
|
+
} else {
|
|
44
46
|
this.customStrategy = customStrategy;
|
|
45
47
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
public get avgPriorityFee(): number {
|
|
49
|
-
return Math.floor(this.lastAvgStrategyResult);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
public get maxPriorityFee(): number {
|
|
53
|
-
return Math.floor(this.lastMaxStrategyResult);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public get customPriorityFee(): number {
|
|
57
|
-
if (!this.customStrategy) {
|
|
58
|
-
console.error('Custom strategy not set');
|
|
59
|
-
}
|
|
60
|
-
return Math.floor(this.lastCustomStrategyResult);
|
|
48
|
+
this.lookbackDistance = slotsToCheck;
|
|
61
49
|
}
|
|
62
50
|
|
|
63
51
|
public async subscribe(): Promise<void> {
|
|
@@ -75,21 +63,29 @@ export class PriorityFeeSubscriber {
|
|
|
75
63
|
[this.addresses]
|
|
76
64
|
);
|
|
77
65
|
|
|
78
|
-
// getRecentPrioritizationFees returns results unsorted
|
|
79
66
|
const results: { slot: number; prioritizationFee: number }[] =
|
|
80
67
|
rpcJSONResponse?.result;
|
|
68
|
+
|
|
81
69
|
if (!results.length) return;
|
|
82
|
-
const descResults = results.sort((a, b) => b.slot - a.slot);
|
|
83
70
|
|
|
71
|
+
// # Sort and filter results based on the slot lookback setting
|
|
72
|
+
const descResults = results.sort((a, b) => b.slot - a.slot);
|
|
84
73
|
const mostRecentResult = descResults[0];
|
|
74
|
+
const cutoffSlot = mostRecentResult.slot - this.lookbackDistance;
|
|
75
|
+
|
|
76
|
+
const resultsToUse = descResults.filter(
|
|
77
|
+
(result) => result.slot >= cutoffSlot
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// # Handle results
|
|
85
81
|
this.latestPriorityFee = mostRecentResult.prioritizationFee;
|
|
86
82
|
this.lastSlotSeen = mostRecentResult.slot;
|
|
87
83
|
|
|
88
|
-
this.lastAvgStrategyResult = this.averageStrategy.calculate(
|
|
89
|
-
this.lastMaxStrategyResult = this.maxStrategy.calculate(
|
|
84
|
+
this.lastAvgStrategyResult = this.averageStrategy.calculate(resultsToUse);
|
|
85
|
+
this.lastMaxStrategyResult = this.maxStrategy.calculate(resultsToUse);
|
|
90
86
|
if (this.customStrategy) {
|
|
91
87
|
this.lastCustomStrategyResult =
|
|
92
|
-
this.customStrategy.calculate(
|
|
88
|
+
this.customStrategy.calculate(resultsToUse);
|
|
93
89
|
}
|
|
94
90
|
}
|
|
95
91
|
|
package/src/tx/baseTxSender.ts
CHANGED
|
@@ -247,9 +247,11 @@ export abstract class BaseTxSender implements TxSender {
|
|
|
247
247
|
commitment: Commitment = 'finalized'
|
|
248
248
|
): Promise<RpcResponseAndContext<SignatureResult> | undefined> {
|
|
249
249
|
let totalTime = 0;
|
|
250
|
-
let backoffTime =
|
|
250
|
+
let backoffTime = 400; // approx block time
|
|
251
251
|
|
|
252
252
|
while (totalTime < this.timeout) {
|
|
253
|
+
await new Promise((resolve) => setTimeout(resolve, backoffTime));
|
|
254
|
+
|
|
253
255
|
const response = await this.connection.getSignatureStatus(signature);
|
|
254
256
|
const result = response && response.value?.[0];
|
|
255
257
|
|
|
@@ -257,7 +259,6 @@ export abstract class BaseTxSender implements TxSender {
|
|
|
257
259
|
return { context: result.context, value: { err: null } };
|
|
258
260
|
}
|
|
259
261
|
|
|
260
|
-
await new Promise((resolve) => setTimeout(resolve, backoffTime));
|
|
261
262
|
totalTime += backoffTime;
|
|
262
263
|
backoffTime = Math.min(backoffTime * 2, 5000);
|
|
263
264
|
}
|
package/src/tx/retryTxSender.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { ConfirmationStrategy, TxSigAndSlot } from './types';
|
|
2
|
-
import {
|
|
3
|
-
ConfirmOptions,
|
|
4
|
-
TransactionSignature,
|
|
5
|
-
Connection,
|
|
6
|
-
} from '@solana/web3.js';
|
|
2
|
+
import { ConfirmOptions, Connection } from '@solana/web3.js';
|
|
7
3
|
import { AnchorProvider } from '@coral-xyz/anchor';
|
|
8
4
|
import { IWallet } from '../types';
|
|
9
5
|
import { BaseTxSender } from './baseTxSender';
|
|
@@ -70,14 +66,8 @@ export class RetryTxSender extends BaseTxSender {
|
|
|
70
66
|
): Promise<TxSigAndSlot> {
|
|
71
67
|
const startTime = this.getTimestamp();
|
|
72
68
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
txid = await this.connection.sendRawTransaction(rawTransaction, opts);
|
|
76
|
-
this.sendToAdditionalConnections(rawTransaction, opts);
|
|
77
|
-
} catch (e) {
|
|
78
|
-
console.error(e);
|
|
79
|
-
throw e;
|
|
80
|
-
}
|
|
69
|
+
const txid = await this.connection.sendRawTransaction(rawTransaction, opts);
|
|
70
|
+
this.sendToAdditionalConnections(rawTransaction, opts);
|
|
81
71
|
|
|
82
72
|
let done = false;
|
|
83
73
|
const resolveReference: ResolveReference = {
|
|
@@ -105,16 +95,8 @@ export class RetryTxSender extends BaseTxSender {
|
|
|
105
95
|
}
|
|
106
96
|
})();
|
|
107
97
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const result = await this.confirmTransaction(txid, opts.commitment);
|
|
111
|
-
slot = result.context.slot;
|
|
112
|
-
} catch (e) {
|
|
113
|
-
console.error(e);
|
|
114
|
-
throw e;
|
|
115
|
-
} finally {
|
|
116
|
-
stopWaiting();
|
|
117
|
-
}
|
|
98
|
+
const result = await this.confirmTransaction(txid, opts.commitment);
|
|
99
|
+
const slot = result.context.slot;
|
|
118
100
|
|
|
119
101
|
return { txSig: txid, slot };
|
|
120
102
|
}
|
package/src/tx/utils.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { Wallet } from '@coral-xyz/anchor';
|
|
1
2
|
import {
|
|
2
3
|
Transaction,
|
|
3
4
|
TransactionInstruction,
|
|
4
5
|
ComputeBudgetProgram,
|
|
6
|
+
VersionedTransaction,
|
|
5
7
|
} from '@solana/web3.js';
|
|
6
8
|
|
|
7
9
|
const COMPUTE_UNITS_DEFAULT = 200_000;
|
|
@@ -30,3 +32,33 @@ export function wrapInTx(
|
|
|
30
32
|
|
|
31
33
|
return tx.add(instruction);
|
|
32
34
|
}
|
|
35
|
+
|
|
36
|
+
/* Helper function for signing multiple transactions where some may be undefined and mapping the output */
|
|
37
|
+
export async function getSignedTransactionMap(
|
|
38
|
+
wallet: Wallet,
|
|
39
|
+
txsToSign: (Transaction | VersionedTransaction | undefined)[],
|
|
40
|
+
keys: string[]
|
|
41
|
+
): Promise<{ [key: string]: Transaction | VersionedTransaction | undefined }> {
|
|
42
|
+
const signedTxMap: {
|
|
43
|
+
[key: string]: Transaction | VersionedTransaction | undefined;
|
|
44
|
+
} = {};
|
|
45
|
+
|
|
46
|
+
const keysWithTx = [];
|
|
47
|
+
txsToSign.forEach((tx, index) => {
|
|
48
|
+
if (tx == undefined) {
|
|
49
|
+
signedTxMap[keys[index]] = undefined;
|
|
50
|
+
} else {
|
|
51
|
+
keysWithTx.push(keys[index]);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const signedTxs = await wallet.signAllTransactions(
|
|
56
|
+
txsToSign.filter((tx) => tx !== undefined)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
signedTxs.forEach((signedTx, index) => {
|
|
60
|
+
signedTxMap[keysWithTx[index]] = signedTx;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return signedTxMap;
|
|
64
|
+
}
|
package/src/userMap/userMap.ts
CHANGED
|
@@ -337,6 +337,9 @@ export class UserMap implements UserMapInterface {
|
|
|
337
337
|
const userAccount = this.decode('User', buffer);
|
|
338
338
|
await this.addPubkey(new PublicKey(key), userAccount);
|
|
339
339
|
this.userMap.get(key).accountSubscriber.updateData(userAccount, slot);
|
|
340
|
+
} else {
|
|
341
|
+
const userAccount = this.decode('User', buffer);
|
|
342
|
+
this.userMap.get(key).accountSubscriber.updateData(userAccount, slot);
|
|
340
343
|
}
|
|
341
344
|
// give event loop a chance to breathe
|
|
342
345
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
package/tests/amm/test.ts
CHANGED
|
@@ -28,6 +28,9 @@ import {
|
|
|
28
28
|
squareRootBN,
|
|
29
29
|
calculateReferencePriceOffset,
|
|
30
30
|
calculateInventoryLiquidityRatio,
|
|
31
|
+
ContractTier,
|
|
32
|
+
isOracleValid,
|
|
33
|
+
OracleGuardRails,
|
|
31
34
|
} from '../../src';
|
|
32
35
|
import { mockPerpMarkets } from '../dlob/helpers';
|
|
33
36
|
|
|
@@ -875,11 +878,12 @@ describe('AMM Tests', () => {
|
|
|
875
878
|
const mockMarket1 = myMockPerpMarkets[0];
|
|
876
879
|
const mockAmm = mockMarket1.amm;
|
|
877
880
|
const now = new BN(new Date().getTime() / 1000); //todo
|
|
881
|
+
const slot = 999999999;
|
|
878
882
|
|
|
879
883
|
const oraclePriceData = {
|
|
880
884
|
price: new BN(13.553 * PRICE_PRECISION.toNumber()),
|
|
881
|
-
slot: new BN(
|
|
882
|
-
confidence: new BN(
|
|
885
|
+
slot: new BN(slot),
|
|
886
|
+
confidence: new BN(1000),
|
|
883
887
|
hasSufficientNumberOfDataPoints: true,
|
|
884
888
|
};
|
|
885
889
|
mockAmm.oracleStd = new BN(0.18 * PRICE_PRECISION.toNumber());
|
|
@@ -901,6 +905,127 @@ describe('AMM Tests', () => {
|
|
|
901
905
|
const liveOracleStd = calculateLiveOracleStd(mockAmm, oraclePriceData, now);
|
|
902
906
|
console.log('liveOracleStd:', liveOracleStd.toNumber());
|
|
903
907
|
assert(liveOracleStd.eq(new BN(192962)));
|
|
908
|
+
|
|
909
|
+
const oracleGuardRails: OracleGuardRails = {
|
|
910
|
+
priceDivergence: {
|
|
911
|
+
markOraclePercentDivergence: PERCENTAGE_PRECISION.divn(10),
|
|
912
|
+
oracleTwap5MinPercentDivergence: PERCENTAGE_PRECISION.divn(10),
|
|
913
|
+
},
|
|
914
|
+
validity: {
|
|
915
|
+
slotsBeforeStaleForAmm: new BN(10),
|
|
916
|
+
slotsBeforeStaleForMargin: new BN(60),
|
|
917
|
+
confidenceIntervalMaxSize: new BN(20000),
|
|
918
|
+
tooVolatileRatio: new BN(5),
|
|
919
|
+
},
|
|
920
|
+
};
|
|
921
|
+
|
|
922
|
+
// good oracle
|
|
923
|
+
assert(isOracleValid(mockAmm, oraclePriceData, oracleGuardRails, slot + 5));
|
|
924
|
+
|
|
925
|
+
// conf too high
|
|
926
|
+
assert(
|
|
927
|
+
!isOracleValid(
|
|
928
|
+
mockAmm,
|
|
929
|
+
{
|
|
930
|
+
price: new BN(13.553 * PRICE_PRECISION.toNumber()),
|
|
931
|
+
slot: new BN(slot),
|
|
932
|
+
confidence: new BN(13.553 * PRICE_PRECISION.toNumber() * 0.021),
|
|
933
|
+
hasSufficientNumberOfDataPoints: true,
|
|
934
|
+
},
|
|
935
|
+
oracleGuardRails,
|
|
936
|
+
slot
|
|
937
|
+
)
|
|
938
|
+
);
|
|
939
|
+
|
|
940
|
+
// not hasSufficientNumberOfDataPoints
|
|
941
|
+
assert(
|
|
942
|
+
!isOracleValid(
|
|
943
|
+
mockAmm,
|
|
944
|
+
{
|
|
945
|
+
price: new BN(13.553 * PRICE_PRECISION.toNumber()),
|
|
946
|
+
slot: new BN(slot),
|
|
947
|
+
confidence: new BN(1),
|
|
948
|
+
hasSufficientNumberOfDataPoints: false,
|
|
949
|
+
},
|
|
950
|
+
oracleGuardRails,
|
|
951
|
+
slot
|
|
952
|
+
)
|
|
953
|
+
);
|
|
954
|
+
|
|
955
|
+
// negative oracle price
|
|
956
|
+
assert(
|
|
957
|
+
!isOracleValid(
|
|
958
|
+
mockAmm,
|
|
959
|
+
{
|
|
960
|
+
price: new BN(-1 * PRICE_PRECISION.toNumber()),
|
|
961
|
+
slot: new BN(slot),
|
|
962
|
+
confidence: new BN(1),
|
|
963
|
+
hasSufficientNumberOfDataPoints: true,
|
|
964
|
+
},
|
|
965
|
+
oracleGuardRails,
|
|
966
|
+
slot
|
|
967
|
+
)
|
|
968
|
+
);
|
|
969
|
+
|
|
970
|
+
// too delayed for amm
|
|
971
|
+
assert(
|
|
972
|
+
!isOracleValid(
|
|
973
|
+
mockAmm,
|
|
974
|
+
{
|
|
975
|
+
price: new BN(13.553 * PRICE_PRECISION.toNumber()),
|
|
976
|
+
slot: new BN(slot),
|
|
977
|
+
confidence: new BN(1),
|
|
978
|
+
hasSufficientNumberOfDataPoints: true,
|
|
979
|
+
},
|
|
980
|
+
oracleGuardRails,
|
|
981
|
+
slot + 100
|
|
982
|
+
)
|
|
983
|
+
);
|
|
984
|
+
|
|
985
|
+
// im passing stale slot (should not call oracle invalid)
|
|
986
|
+
assert(
|
|
987
|
+
isOracleValid(
|
|
988
|
+
mockAmm,
|
|
989
|
+
{
|
|
990
|
+
price: new BN(13.553 * PRICE_PRECISION.toNumber()),
|
|
991
|
+
slot: new BN(slot + 100),
|
|
992
|
+
confidence: new BN(1),
|
|
993
|
+
hasSufficientNumberOfDataPoints: true,
|
|
994
|
+
},
|
|
995
|
+
oracleGuardRails,
|
|
996
|
+
slot
|
|
997
|
+
)
|
|
998
|
+
);
|
|
999
|
+
|
|
1000
|
+
// too volatile (more than 5x higher)
|
|
1001
|
+
assert(
|
|
1002
|
+
!isOracleValid(
|
|
1003
|
+
mockAmm,
|
|
1004
|
+
{
|
|
1005
|
+
price: new BN(113.553 * PRICE_PRECISION.toNumber()),
|
|
1006
|
+
slot: new BN(slot + 5),
|
|
1007
|
+
confidence: new BN(1),
|
|
1008
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1009
|
+
},
|
|
1010
|
+
oracleGuardRails,
|
|
1011
|
+
slot
|
|
1012
|
+
)
|
|
1013
|
+
);
|
|
1014
|
+
|
|
1015
|
+
// too volatile (more than 1/5 lower)
|
|
1016
|
+
assert(
|
|
1017
|
+
!isOracleValid(
|
|
1018
|
+
mockAmm,
|
|
1019
|
+
{
|
|
1020
|
+
price: new BN(0.553 * PRICE_PRECISION.toNumber()),
|
|
1021
|
+
slot: new BN(slot + 5),
|
|
1022
|
+
confidence: new BN(1),
|
|
1023
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1024
|
+
},
|
|
1025
|
+
oracleGuardRails,
|
|
1026
|
+
slot
|
|
1027
|
+
)
|
|
1028
|
+
);
|
|
904
1029
|
});
|
|
905
1030
|
|
|
906
1031
|
it('predicted funding rate mock1', async () => {
|
|
@@ -1065,6 +1190,154 @@ describe('AMM Tests', () => {
|
|
|
1065
1190
|
assert(est2.eq(new BN('-719')));
|
|
1066
1191
|
});
|
|
1067
1192
|
|
|
1193
|
+
it('predicted funding rate mock clamp', async () => {
|
|
1194
|
+
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
1195
|
+
const mockMarket1 = myMockPerpMarkets[0];
|
|
1196
|
+
|
|
1197
|
+
// make it like OP
|
|
1198
|
+
const now = new BN(1688881915);
|
|
1199
|
+
|
|
1200
|
+
mockMarket1.amm.fundingPeriod = new BN(3600);
|
|
1201
|
+
mockMarket1.amm.lastFundingRateTs = new BN(1688864415);
|
|
1202
|
+
|
|
1203
|
+
const currentMarkPrice = new BN(1.2242 * PRICE_PRECISION.toNumber()); // trading at a premium
|
|
1204
|
+
const oraclePriceData: OraclePriceData = {
|
|
1205
|
+
price: new BN(1.924 * PRICE_PRECISION.toNumber()),
|
|
1206
|
+
slot: new BN(0),
|
|
1207
|
+
confidence: new BN(1),
|
|
1208
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1209
|
+
};
|
|
1210
|
+
mockMarket1.amm.historicalOracleData.lastOraclePrice = new BN(
|
|
1211
|
+
1.9535 * PRICE_PRECISION.toNumber()
|
|
1212
|
+
);
|
|
1213
|
+
|
|
1214
|
+
// mockMarket1.amm.pegMultiplier = new BN(1.897573 * 1e3);
|
|
1215
|
+
|
|
1216
|
+
mockMarket1.amm.lastMarkPriceTwap = new BN(
|
|
1217
|
+
1.218363 * PRICE_PRECISION.toNumber()
|
|
1218
|
+
);
|
|
1219
|
+
mockMarket1.amm.lastBidPriceTwap = new BN(
|
|
1220
|
+
1.218363 * PRICE_PRECISION.toNumber()
|
|
1221
|
+
);
|
|
1222
|
+
mockMarket1.amm.lastAskPriceTwap = new BN(
|
|
1223
|
+
1.218364 * PRICE_PRECISION.toNumber()
|
|
1224
|
+
);
|
|
1225
|
+
mockMarket1.amm.lastMarkPriceTwapTs = new BN(1688878815);
|
|
1226
|
+
|
|
1227
|
+
mockMarket1.amm.historicalOracleData.lastOraclePriceTwap = new BN(
|
|
1228
|
+
1.820964 * PRICE_PRECISION.toNumber()
|
|
1229
|
+
);
|
|
1230
|
+
mockMarket1.amm.historicalOracleData.lastOraclePriceTwapTs = new BN(
|
|
1231
|
+
1688879991
|
|
1232
|
+
);
|
|
1233
|
+
mockMarket1.contractTier = ContractTier.A;
|
|
1234
|
+
|
|
1235
|
+
const [
|
|
1236
|
+
_markTwapLive,
|
|
1237
|
+
_oracleTwapLive,
|
|
1238
|
+
_lowerboundEst,
|
|
1239
|
+
_cappedAltEst,
|
|
1240
|
+
_interpEst,
|
|
1241
|
+
] = await calculateAllEstimatedFundingRate(
|
|
1242
|
+
mockMarket1,
|
|
1243
|
+
oraclePriceData,
|
|
1244
|
+
currentMarkPrice,
|
|
1245
|
+
now
|
|
1246
|
+
);
|
|
1247
|
+
|
|
1248
|
+
// console.log(_markTwapLive.toString());
|
|
1249
|
+
// console.log(_oracleTwapLive.toString());
|
|
1250
|
+
// console.log(_lowerboundEst.toString());
|
|
1251
|
+
// console.log(_cappedAltEst.toString());
|
|
1252
|
+
// console.log(_interpEst.toString());
|
|
1253
|
+
// console.log('-----');
|
|
1254
|
+
|
|
1255
|
+
let [markTwapLive, oracleTwapLive, est1, est2] =
|
|
1256
|
+
await calculateLongShortFundingRateAndLiveTwaps(
|
|
1257
|
+
mockMarket1,
|
|
1258
|
+
oraclePriceData,
|
|
1259
|
+
currentMarkPrice,
|
|
1260
|
+
now
|
|
1261
|
+
);
|
|
1262
|
+
|
|
1263
|
+
console.log(
|
|
1264
|
+
'markTwapLive:',
|
|
1265
|
+
mockMarket1.amm.lastMarkPriceTwap.toString(),
|
|
1266
|
+
'->',
|
|
1267
|
+
markTwapLive.toString()
|
|
1268
|
+
);
|
|
1269
|
+
console.log(
|
|
1270
|
+
'oracTwapLive:',
|
|
1271
|
+
mockMarket1.amm.historicalOracleData.lastOraclePriceTwap.toString(),
|
|
1272
|
+
'->',
|
|
1273
|
+
oracleTwapLive.toString()
|
|
1274
|
+
);
|
|
1275
|
+
console.log('pred funding:', est1.toString(), est2.toString());
|
|
1276
|
+
|
|
1277
|
+
assert(markTwapLive.eq(new BN('1680634')));
|
|
1278
|
+
assert(oracleTwapLive.eq(new BN('1876031')));
|
|
1279
|
+
assert(est1.eq(est2));
|
|
1280
|
+
assert(est2.eq(new BN('-126261')));
|
|
1281
|
+
|
|
1282
|
+
mockMarket1.contractTier = ContractTier.C;
|
|
1283
|
+
|
|
1284
|
+
[markTwapLive, oracleTwapLive, est1, est2] =
|
|
1285
|
+
await calculateLongShortFundingRateAndLiveTwaps(
|
|
1286
|
+
mockMarket1,
|
|
1287
|
+
oraclePriceData,
|
|
1288
|
+
currentMarkPrice,
|
|
1289
|
+
now
|
|
1290
|
+
);
|
|
1291
|
+
|
|
1292
|
+
console.log(
|
|
1293
|
+
'markTwapLive:',
|
|
1294
|
+
mockMarket1.amm.lastMarkPriceTwap.toString(),
|
|
1295
|
+
'->',
|
|
1296
|
+
markTwapLive.toString()
|
|
1297
|
+
);
|
|
1298
|
+
console.log(
|
|
1299
|
+
'oracTwapLive:',
|
|
1300
|
+
mockMarket1.amm.historicalOracleData.lastOraclePriceTwap.toString(),
|
|
1301
|
+
'->',
|
|
1302
|
+
oracleTwapLive.toString()
|
|
1303
|
+
);
|
|
1304
|
+
console.log('pred funding:', est1.toString(), est2.toString());
|
|
1305
|
+
|
|
1306
|
+
assert(markTwapLive.eq(new BN('1680634')));
|
|
1307
|
+
assert(oracleTwapLive.eq(new BN('1876031')));
|
|
1308
|
+
assert(est1.eq(est2));
|
|
1309
|
+
assert(est2.eq(new BN('-208332')));
|
|
1310
|
+
|
|
1311
|
+
mockMarket1.contractTier = ContractTier.SPECULATIVE;
|
|
1312
|
+
|
|
1313
|
+
[markTwapLive, oracleTwapLive, est1, est2] =
|
|
1314
|
+
await calculateLongShortFundingRateAndLiveTwaps(
|
|
1315
|
+
mockMarket1,
|
|
1316
|
+
oraclePriceData,
|
|
1317
|
+
currentMarkPrice,
|
|
1318
|
+
now
|
|
1319
|
+
);
|
|
1320
|
+
|
|
1321
|
+
console.log(
|
|
1322
|
+
'markTwapLive:',
|
|
1323
|
+
mockMarket1.amm.lastMarkPriceTwap.toString(),
|
|
1324
|
+
'->',
|
|
1325
|
+
markTwapLive.toString()
|
|
1326
|
+
);
|
|
1327
|
+
console.log(
|
|
1328
|
+
'oracTwapLive:',
|
|
1329
|
+
mockMarket1.amm.historicalOracleData.lastOraclePriceTwap.toString(),
|
|
1330
|
+
'->',
|
|
1331
|
+
oracleTwapLive.toString()
|
|
1332
|
+
);
|
|
1333
|
+
console.log('pred funding:', est1.toString(), est2.toString());
|
|
1334
|
+
|
|
1335
|
+
assert(markTwapLive.eq(new BN('1680634')));
|
|
1336
|
+
assert(oracleTwapLive.eq(new BN('1876031')));
|
|
1337
|
+
assert(est1.eq(est2));
|
|
1338
|
+
assert(est2.eq(new BN('-416666')));
|
|
1339
|
+
});
|
|
1340
|
+
|
|
1068
1341
|
it('orderbook L2 gen (no topOfBookQuoteAmounts, 10 numOrders, low liquidity)', async () => {
|
|
1069
1342
|
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
1070
1343
|
|
package/tests/dlob/test.ts
CHANGED
|
@@ -76,7 +76,7 @@ function insertOrderToDLOB(
|
|
|
76
76
|
auctionEndPrice,
|
|
77
77
|
maxTs,
|
|
78
78
|
},
|
|
79
|
-
userAccount,
|
|
79
|
+
userAccount.toString(),
|
|
80
80
|
slot.toNumber()
|
|
81
81
|
);
|
|
82
82
|
}
|
|
@@ -127,7 +127,7 @@ function insertTriggerOrderToDLOB(
|
|
|
127
127
|
auctionEndPrice,
|
|
128
128
|
maxTs,
|
|
129
129
|
},
|
|
130
|
-
userAccount,
|
|
130
|
+
userAccount.toString(),
|
|
131
131
|
slot.toNumber()
|
|
132
132
|
);
|
|
133
133
|
}
|
|
@@ -66,7 +66,7 @@ describe('PriorityFeeStrategy', () => {
|
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
it('MaxOverSlotsStrategy should calculate the max prioritization fee over slots', () => {
|
|
69
|
-
const maxOverSlotsStrategy = new MaxOverSlotsStrategy(
|
|
69
|
+
const maxOverSlotsStrategy = new MaxOverSlotsStrategy();
|
|
70
70
|
const samples = [
|
|
71
71
|
{ slot: 6, prioritizationFee: 432 },
|
|
72
72
|
{ slot: 3, prioritizationFee: 543 },
|
|
@@ -80,7 +80,7 @@ describe('PriorityFeeStrategy', () => {
|
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
it('AverageOverSlotsStrategy should calculate the average prioritization fee over slots', () => {
|
|
83
|
-
const averageOverSlotsStrategy = new AverageOverSlotsStrategy(
|
|
83
|
+
const averageOverSlotsStrategy = new AverageOverSlotsStrategy();
|
|
84
84
|
const samples = [
|
|
85
85
|
{ slot: 6, prioritizationFee: 432 },
|
|
86
86
|
{ slot: 3, prioritizationFee: 543 },
|