@drift-labs/sdk 2.74.0-beta.1 → 2.74.0-beta.11
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/adminClient.d.ts +12 -3
- package/lib/adminClient.js +60 -32
- package/lib/blockhashSubscriber/BlockhashSubscriber.d.ts +21 -0
- package/lib/blockhashSubscriber/BlockhashSubscriber.js +73 -0
- package/lib/blockhashSubscriber/index.d.ts +1 -0
- package/lib/blockhashSubscriber/index.js +17 -0
- package/lib/blockhashSubscriber/types.d.ts +7 -0
- package/lib/blockhashSubscriber/types.js +2 -0
- package/lib/dlob/orderBookLevels.js +47 -12
- package/lib/driftClient.d.ts +5 -0
- package/lib/driftClient.js +17 -0
- package/lib/events/parse.d.ts +1 -1
- package/lib/events/parse.js +12 -12
- package/lib/idl/drift.json +85 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/funding.js +0 -6
- package/lib/math/oracles.js +1 -1
- package/lib/math/tiers.js +1 -1
- package/lib/oracles/prelaunchOracleClient.js +1 -0
- package/lib/oracles/types.d.ts +1 -0
- package/lib/tx/baseTxSender.d.ts +1 -1
- package/lib/tx/baseTxSender.js +9 -2
- package/lib/tx/fastSingleTxSender.d.ts +1 -1
- package/lib/tx/fastSingleTxSender.js +11 -3
- package/lib/tx/types.d.ts +1 -1
- package/lib/types.d.ts +3 -0
- package/lib/types.js +1 -0
- package/lib/user.d.ts +6 -4
- package/lib/user.js +24 -21
- package/package.json +1 -1
- package/src/adminClient.ts +297 -87
- package/src/blockhashSubscriber/BlockhashSubscriber.ts +108 -0
- package/src/blockhashSubscriber/index.ts +1 -0
- package/src/blockhashSubscriber/types.ts +8 -0
- package/src/dlob/orderBookLevels.ts +51 -15
- package/src/driftClient.ts +37 -0
- package/src/events/parse.ts +26 -12
- package/src/idl/drift.json +85 -0
- package/src/index.ts +1 -0
- package/src/math/funding.ts +0 -4
- package/src/math/oracles.ts +1 -1
- package/src/math/tiers.ts +1 -1
- package/src/oracles/prelaunchOracleClient.ts +1 -0
- package/src/oracles/types.ts +1 -0
- package/src/tx/baseTxSender.ts +12 -4
- package/src/tx/fastSingleTxSender.ts +13 -5
- package/src/tx/types.ts +2 -1
- package/src/types.ts +1 -0
- package/src/user.ts +32 -30
- package/tests/amm/test.ts +3 -1
- package/tests/dlob/test.ts +57 -0
package/src/driftClient.ts
CHANGED
|
@@ -1074,6 +1074,43 @@ export class DriftClient {
|
|
|
1074
1074
|
return ix;
|
|
1075
1075
|
}
|
|
1076
1076
|
|
|
1077
|
+
public async updateUserReduceOnly(
|
|
1078
|
+
updates: { reduceOnly: boolean; subAccountId: number }[]
|
|
1079
|
+
): Promise<TransactionSignature> {
|
|
1080
|
+
const ixs = await Promise.all(
|
|
1081
|
+
updates.map(async ({ reduceOnly, subAccountId }) => {
|
|
1082
|
+
return await this.getUpdateUserReduceOnlyIx(reduceOnly, subAccountId);
|
|
1083
|
+
})
|
|
1084
|
+
);
|
|
1085
|
+
|
|
1086
|
+
const tx = await this.buildTransaction(ixs, this.txParams);
|
|
1087
|
+
|
|
1088
|
+
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
1089
|
+
return txSig;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
public async getUpdateUserReduceOnlyIx(
|
|
1093
|
+
reduceOnly: boolean,
|
|
1094
|
+
subAccountId: number
|
|
1095
|
+
) {
|
|
1096
|
+
const ix = await this.program.instruction.updateUserReduceOnly(
|
|
1097
|
+
subAccountId,
|
|
1098
|
+
reduceOnly,
|
|
1099
|
+
{
|
|
1100
|
+
accounts: {
|
|
1101
|
+
user: getUserAccountPublicKeySync(
|
|
1102
|
+
this.program.programId,
|
|
1103
|
+
this.wallet.publicKey,
|
|
1104
|
+
subAccountId
|
|
1105
|
+
),
|
|
1106
|
+
authority: this.wallet.publicKey,
|
|
1107
|
+
},
|
|
1108
|
+
}
|
|
1109
|
+
);
|
|
1110
|
+
|
|
1111
|
+
return ix;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1077
1114
|
public async fetchAllUserAccounts(
|
|
1078
1115
|
includeIdle = true
|
|
1079
1116
|
): Promise<ProgramAccount<UserAccount>[]> {
|
package/src/events/parse.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { Program, Event } from '@coral-xyz/anchor';
|
|
2
2
|
|
|
3
3
|
const driftProgramId = 'dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH';
|
|
4
|
-
const driftProgramStart = `Program ${driftProgramId} invoke`;
|
|
5
4
|
const PROGRAM_LOG = 'Program log: ';
|
|
6
5
|
const PROGRAM_DATA = 'Program data: ';
|
|
7
6
|
const PROGRAM_LOG_START_INDEX = PROGRAM_LOG.length;
|
|
8
7
|
const PROGRAM_DATA_START_INDEX = PROGRAM_DATA.length;
|
|
9
8
|
|
|
10
|
-
export function parseLogs(
|
|
9
|
+
export function parseLogs(
|
|
10
|
+
program: Program,
|
|
11
|
+
logs: string[],
|
|
12
|
+
programId = driftProgramId
|
|
13
|
+
): Event[] {
|
|
11
14
|
const events = [];
|
|
12
15
|
const execution = new ExecutionContext();
|
|
13
16
|
for (const log of logs) {
|
|
@@ -15,7 +18,12 @@ export function parseLogs(program: Program, logs: string[]): Event[] {
|
|
|
15
18
|
break;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
const [event, newProgram, didPop] = handleLog(
|
|
21
|
+
const [event, newProgram, didPop] = handleLog(
|
|
22
|
+
execution,
|
|
23
|
+
log,
|
|
24
|
+
program,
|
|
25
|
+
programId
|
|
26
|
+
);
|
|
19
27
|
if (event) {
|
|
20
28
|
events.push(event);
|
|
21
29
|
}
|
|
@@ -32,22 +40,24 @@ export function parseLogs(program: Program, logs: string[]): Event[] {
|
|
|
32
40
|
function handleLog(
|
|
33
41
|
execution: ExecutionContext,
|
|
34
42
|
log: string,
|
|
35
|
-
program: Program
|
|
43
|
+
program: Program,
|
|
44
|
+
programId = driftProgramId
|
|
36
45
|
): [Event | null, string | null, boolean] {
|
|
37
46
|
// Executing program is drift program.
|
|
38
|
-
if (execution.stack.length > 0 && execution.program() ===
|
|
39
|
-
return handleProgramLog(log, program);
|
|
47
|
+
if (execution.stack.length > 0 && execution.program() === programId) {
|
|
48
|
+
return handleProgramLog(log, program, programId);
|
|
40
49
|
}
|
|
41
50
|
// Executing program is not drift program.
|
|
42
51
|
else {
|
|
43
|
-
return [null, ...handleSystemLog(log)];
|
|
52
|
+
return [null, ...handleSystemLog(log, programId)];
|
|
44
53
|
}
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
// Handles logs from *drift* program.
|
|
48
57
|
function handleProgramLog(
|
|
49
58
|
log: string,
|
|
50
|
-
program: Program
|
|
59
|
+
program: Program,
|
|
60
|
+
programId = driftProgramId
|
|
51
61
|
): [Event | null, string | null, boolean] {
|
|
52
62
|
// This is a `msg!` log or a `sol_log_data` log.
|
|
53
63
|
if (log.startsWith(PROGRAM_LOG)) {
|
|
@@ -59,21 +69,25 @@ function handleProgramLog(
|
|
|
59
69
|
const event = program.coder.events.decode(logStr);
|
|
60
70
|
return [event, null, false];
|
|
61
71
|
} else {
|
|
62
|
-
return [null, ...handleSystemLog(log)];
|
|
72
|
+
return [null, ...handleSystemLog(log, programId)];
|
|
63
73
|
}
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
// Handles logs when the current program being executing is *not* drift.
|
|
67
|
-
function handleSystemLog(
|
|
77
|
+
function handleSystemLog(
|
|
78
|
+
log: string,
|
|
79
|
+
programId = driftProgramId
|
|
80
|
+
): [string | null, boolean] {
|
|
68
81
|
// System component.
|
|
69
82
|
const logStart = log.split(':')[0];
|
|
83
|
+
const programStart = `Program ${programId} invoke`;
|
|
70
84
|
|
|
71
85
|
// Did the program finish executing?
|
|
72
86
|
if (logStart.match(/^Program (.*) success/g) !== null) {
|
|
73
87
|
return [null, true];
|
|
74
88
|
// Recursive call.
|
|
75
|
-
} else if (logStart.startsWith(
|
|
76
|
-
return [
|
|
89
|
+
} else if (logStart.startsWith(programStart)) {
|
|
90
|
+
return [programId, false];
|
|
77
91
|
}
|
|
78
92
|
// CPI call.
|
|
79
93
|
else if (logStart.includes('invoke')) {
|
package/src/idl/drift.json
CHANGED
|
@@ -2651,10 +2651,40 @@
|
|
|
2651
2651
|
"name": "liquidatorFee",
|
|
2652
2652
|
"type": "u32"
|
|
2653
2653
|
},
|
|
2654
|
+
{
|
|
2655
|
+
"name": "ifLiquidationFee",
|
|
2656
|
+
"type": "u32"
|
|
2657
|
+
},
|
|
2654
2658
|
{
|
|
2655
2659
|
"name": "activeStatus",
|
|
2656
2660
|
"type": "bool"
|
|
2657
2661
|
},
|
|
2662
|
+
{
|
|
2663
|
+
"name": "assetTier",
|
|
2664
|
+
"type": {
|
|
2665
|
+
"defined": "AssetTier"
|
|
2666
|
+
}
|
|
2667
|
+
},
|
|
2668
|
+
{
|
|
2669
|
+
"name": "scaleInitialAssetWeightStart",
|
|
2670
|
+
"type": "u64"
|
|
2671
|
+
},
|
|
2672
|
+
{
|
|
2673
|
+
"name": "withdrawGuardThreshold",
|
|
2674
|
+
"type": "u64"
|
|
2675
|
+
},
|
|
2676
|
+
{
|
|
2677
|
+
"name": "orderTickSize",
|
|
2678
|
+
"type": "u64"
|
|
2679
|
+
},
|
|
2680
|
+
{
|
|
2681
|
+
"name": "orderStepSize",
|
|
2682
|
+
"type": "u64"
|
|
2683
|
+
},
|
|
2684
|
+
{
|
|
2685
|
+
"name": "ifTotalFactor",
|
|
2686
|
+
"type": "u32"
|
|
2687
|
+
},
|
|
2658
2688
|
{
|
|
2659
2689
|
"name": "name",
|
|
2660
2690
|
"type": {
|
|
@@ -2943,10 +2973,62 @@
|
|
|
2943
2973
|
"name": "liquidatorFee",
|
|
2944
2974
|
"type": "u32"
|
|
2945
2975
|
},
|
|
2976
|
+
{
|
|
2977
|
+
"name": "ifLiquidationFee",
|
|
2978
|
+
"type": "u32"
|
|
2979
|
+
},
|
|
2980
|
+
{
|
|
2981
|
+
"name": "imfFactor",
|
|
2982
|
+
"type": "u32"
|
|
2983
|
+
},
|
|
2946
2984
|
{
|
|
2947
2985
|
"name": "activeStatus",
|
|
2948
2986
|
"type": "bool"
|
|
2949
2987
|
},
|
|
2988
|
+
{
|
|
2989
|
+
"name": "baseSpread",
|
|
2990
|
+
"type": "u32"
|
|
2991
|
+
},
|
|
2992
|
+
{
|
|
2993
|
+
"name": "maxSpread",
|
|
2994
|
+
"type": "u32"
|
|
2995
|
+
},
|
|
2996
|
+
{
|
|
2997
|
+
"name": "maxOpenInterest",
|
|
2998
|
+
"type": "u128"
|
|
2999
|
+
},
|
|
3000
|
+
{
|
|
3001
|
+
"name": "maxRevenueWithdrawPerPeriod",
|
|
3002
|
+
"type": "u64"
|
|
3003
|
+
},
|
|
3004
|
+
{
|
|
3005
|
+
"name": "quoteMaxInsurance",
|
|
3006
|
+
"type": "u64"
|
|
3007
|
+
},
|
|
3008
|
+
{
|
|
3009
|
+
"name": "orderStepSize",
|
|
3010
|
+
"type": "u64"
|
|
3011
|
+
},
|
|
3012
|
+
{
|
|
3013
|
+
"name": "orderTickSize",
|
|
3014
|
+
"type": "u64"
|
|
3015
|
+
},
|
|
3016
|
+
{
|
|
3017
|
+
"name": "minOrderSize",
|
|
3018
|
+
"type": "u64"
|
|
3019
|
+
},
|
|
3020
|
+
{
|
|
3021
|
+
"name": "concentrationCoefScale",
|
|
3022
|
+
"type": "u128"
|
|
3023
|
+
},
|
|
3024
|
+
{
|
|
3025
|
+
"name": "curveUpdateIntensity",
|
|
3026
|
+
"type": "u8"
|
|
3027
|
+
},
|
|
3028
|
+
{
|
|
3029
|
+
"name": "ammJitIntensity",
|
|
3030
|
+
"type": "u8"
|
|
3031
|
+
},
|
|
2950
3032
|
{
|
|
2951
3033
|
"name": "name",
|
|
2952
3034
|
"type": {
|
|
@@ -9119,6 +9201,9 @@
|
|
|
9119
9201
|
{
|
|
9120
9202
|
"name": "Speculative"
|
|
9121
9203
|
},
|
|
9204
|
+
{
|
|
9205
|
+
"name": "HighlySpeculative"
|
|
9206
|
+
},
|
|
9122
9207
|
{
|
|
9123
9208
|
"name": "Isolated"
|
|
9124
9209
|
}
|
package/src/index.ts
CHANGED
package/src/math/funding.ts
CHANGED
|
@@ -252,10 +252,6 @@ function getMaxPriceDivergenceForFundingRate(
|
|
|
252
252
|
return oracleTwap.divn(33);
|
|
253
253
|
} else if (isVariant(market.contractTier, 'c')) {
|
|
254
254
|
return oracleTwap.divn(20);
|
|
255
|
-
} else if (isVariant(market.contractTier, 'speculative')) {
|
|
256
|
-
return oracleTwap.divn(10);
|
|
257
|
-
} else if (isVariant(market.contractTier, 'isolated')) {
|
|
258
|
-
return oracleTwap.divn(10);
|
|
259
255
|
} else {
|
|
260
256
|
return oracleTwap.divn(10);
|
|
261
257
|
}
|
package/src/math/oracles.ts
CHANGED
|
@@ -39,7 +39,7 @@ export function getMaxConfidenceIntervalMultiplier(
|
|
|
39
39
|
maxConfidenceIntervalMultiplier = new BN(2);
|
|
40
40
|
} else if (isVariant(market.contractTier, 'speculative')) {
|
|
41
41
|
maxConfidenceIntervalMultiplier = new BN(10);
|
|
42
|
-
} else
|
|
42
|
+
} else {
|
|
43
43
|
maxConfidenceIntervalMultiplier = new BN(50);
|
|
44
44
|
}
|
|
45
45
|
return maxConfidenceIntervalMultiplier;
|
package/src/math/tiers.ts
CHANGED
|
@@ -9,7 +9,7 @@ export function getPerpMarketTierNumber(perpMarket: PerpMarketAccount): number {
|
|
|
9
9
|
return 2;
|
|
10
10
|
} else if (isVariant(perpMarket.contractTier, 'speculative')) {
|
|
11
11
|
return 3;
|
|
12
|
-
} else if (isVariant(perpMarket.contractTier, '
|
|
12
|
+
} else if (isVariant(perpMarket.contractTier, 'highlySpeculative')) {
|
|
13
13
|
return 4;
|
|
14
14
|
} else {
|
|
15
15
|
return 5;
|
package/src/oracles/types.ts
CHANGED
package/src/tx/baseTxSender.ts
CHANGED
|
@@ -112,7 +112,8 @@ export abstract class BaseTxSender implements TxSender {
|
|
|
112
112
|
ixs: TransactionInstruction[],
|
|
113
113
|
lookupTableAccounts: AddressLookupTableAccount[],
|
|
114
114
|
additionalSigners?: Array<Signer>,
|
|
115
|
-
opts?: ConfirmOptions
|
|
115
|
+
opts?: ConfirmOptions,
|
|
116
|
+
blockhash?: string
|
|
116
117
|
): Promise<VersionedTransaction> {
|
|
117
118
|
if (additionalSigners === undefined) {
|
|
118
119
|
additionalSigners = [];
|
|
@@ -121,11 +122,18 @@ export abstract class BaseTxSender implements TxSender {
|
|
|
121
122
|
opts = this.opts;
|
|
122
123
|
}
|
|
123
124
|
|
|
125
|
+
let recentBlockhash = '';
|
|
126
|
+
if (blockhash) {
|
|
127
|
+
recentBlockhash = blockhash;
|
|
128
|
+
} else {
|
|
129
|
+
recentBlockhash = (
|
|
130
|
+
await this.connection.getLatestBlockhash(opts.preflightCommitment)
|
|
131
|
+
).blockhash;
|
|
132
|
+
}
|
|
133
|
+
|
|
124
134
|
const message = new TransactionMessage({
|
|
125
135
|
payerKey: this.wallet.publicKey,
|
|
126
|
-
recentBlockhash
|
|
127
|
-
await this.connection.getLatestBlockhash(opts.preflightCommitment)
|
|
128
|
-
).blockhash,
|
|
136
|
+
recentBlockhash,
|
|
129
137
|
instructions: ixs,
|
|
130
138
|
}).compileToV0Message(lookupTableAccounts);
|
|
131
139
|
|
|
@@ -109,7 +109,8 @@ export class FastSingleTxSender extends BaseTxSender {
|
|
|
109
109
|
ixs: TransactionInstruction[],
|
|
110
110
|
lookupTableAccounts: AddressLookupTableAccount[],
|
|
111
111
|
additionalSigners?: Array<Signer>,
|
|
112
|
-
opts?: ConfirmOptions
|
|
112
|
+
opts?: ConfirmOptions,
|
|
113
|
+
blockhash?: string
|
|
113
114
|
): Promise<VersionedTransaction> {
|
|
114
115
|
if (additionalSigners === undefined) {
|
|
115
116
|
additionalSigners = [];
|
|
@@ -118,12 +119,19 @@ export class FastSingleTxSender extends BaseTxSender {
|
|
|
118
119
|
opts = this.opts;
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
recentBlockhash
|
|
122
|
+
let recentBlockhash = '';
|
|
123
|
+
if (blockhash) {
|
|
124
|
+
recentBlockhash = blockhash;
|
|
125
|
+
} else {
|
|
126
|
+
recentBlockhash =
|
|
124
127
|
this.recentBlockhash ??
|
|
125
128
|
(await this.connection.getLatestBlockhash(opts.preflightCommitment))
|
|
126
|
-
.blockhash
|
|
129
|
+
.blockhash;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const message = new TransactionMessage({
|
|
133
|
+
payerKey: this.wallet.publicKey,
|
|
134
|
+
recentBlockhash,
|
|
127
135
|
instructions: ixs,
|
|
128
136
|
}).compileToV0Message(lookupTableAccounts);
|
|
129
137
|
|
package/src/tx/types.ts
CHANGED
|
@@ -47,7 +47,8 @@ export interface TxSender {
|
|
|
47
47
|
ixs: TransactionInstruction[],
|
|
48
48
|
lookupTableAccounts: AddressLookupTableAccount[],
|
|
49
49
|
additionalSigners?: Array<Signer>,
|
|
50
|
-
opts?: ConfirmOptions
|
|
50
|
+
opts?: ConfirmOptions,
|
|
51
|
+
blockhash?: string
|
|
51
52
|
): Promise<VersionedTransaction>;
|
|
52
53
|
|
|
53
54
|
sendRawTransaction(
|
package/src/types.ts
CHANGED
|
@@ -58,6 +58,7 @@ export class ContractTier {
|
|
|
58
58
|
static readonly B = { b: {} };
|
|
59
59
|
static readonly C = { c: {} };
|
|
60
60
|
static readonly SPECULATIVE = { speculative: {} };
|
|
61
|
+
static readonly HIGHLY_SPECULATIVE = { highlySpeculative: {} };
|
|
61
62
|
static readonly ISOLATED = { isolated: {} };
|
|
62
63
|
}
|
|
63
64
|
|
package/src/user.ts
CHANGED
|
@@ -1975,21 +1975,25 @@ export class User {
|
|
|
1975
1975
|
/**
|
|
1976
1976
|
* Calculate the liquidation price of a perp position, with optional parameter to calculate the liquidation price after a trade
|
|
1977
1977
|
* @param marketIndex
|
|
1978
|
-
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^
|
|
1978
|
+
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^9
|
|
1979
|
+
* @param estimatedEntryPrice
|
|
1979
1980
|
* @param marginCategory // allow Initial to be passed in if we are trying to calculate price for DLP de-risking
|
|
1981
|
+
* @param includeOpenOrders
|
|
1980
1982
|
* @returns Precision : PRICE_PRECISION
|
|
1981
1983
|
*/
|
|
1982
1984
|
public liquidationPrice(
|
|
1983
1985
|
marketIndex: number,
|
|
1984
1986
|
positionBaseSizeChange: BN = ZERO,
|
|
1985
1987
|
estimatedEntryPrice: BN = ZERO,
|
|
1986
|
-
marginCategory: MarginCategory = 'Maintenance'
|
|
1988
|
+
marginCategory: MarginCategory = 'Maintenance',
|
|
1989
|
+
includeOpenOrders = false
|
|
1987
1990
|
): BN {
|
|
1988
1991
|
const totalCollateral = this.getTotalCollateral(marginCategory);
|
|
1989
1992
|
const marginRequirement = this.getMarginRequirement(
|
|
1990
1993
|
marginCategory,
|
|
1991
1994
|
undefined,
|
|
1992
|
-
false
|
|
1995
|
+
false,
|
|
1996
|
+
includeOpenOrders
|
|
1993
1997
|
);
|
|
1994
1998
|
let freeCollateral = BN.max(ZERO, totalCollateral.sub(marginRequirement));
|
|
1995
1999
|
|
|
@@ -2015,7 +2019,8 @@ export class User {
|
|
|
2015
2019
|
oraclePrice,
|
|
2016
2020
|
currentPerpPosition,
|
|
2017
2021
|
positionBaseSizeChange,
|
|
2018
|
-
estimatedEntryPrice
|
|
2022
|
+
estimatedEntryPrice,
|
|
2023
|
+
includeOpenOrders
|
|
2019
2024
|
);
|
|
2020
2025
|
|
|
2021
2026
|
freeCollateral = freeCollateral.add(freeCollateralChangeFromNewPosition);
|
|
@@ -2024,7 +2029,8 @@ export class User {
|
|
|
2024
2029
|
market,
|
|
2025
2030
|
currentPerpPosition,
|
|
2026
2031
|
positionBaseSizeChange,
|
|
2027
|
-
marginCategory
|
|
2032
|
+
marginCategory,
|
|
2033
|
+
includeOpenOrders
|
|
2028
2034
|
);
|
|
2029
2035
|
|
|
2030
2036
|
if (!freeCollateralDelta) {
|
|
@@ -2082,7 +2088,8 @@ export class User {
|
|
|
2082
2088
|
oraclePrice: BN,
|
|
2083
2089
|
perpPosition: PerpPosition,
|
|
2084
2090
|
positionBaseSizeChange: BN,
|
|
2085
|
-
estimatedEntryPrice: BN
|
|
2091
|
+
estimatedEntryPrice: BN,
|
|
2092
|
+
includeOpenOrders: boolean
|
|
2086
2093
|
): BN {
|
|
2087
2094
|
let freeCollateralChange = ZERO;
|
|
2088
2095
|
|
|
@@ -2097,8 +2104,6 @@ export class User {
|
|
|
2097
2104
|
if (positionBaseSizeChange.gt(ZERO)) {
|
|
2098
2105
|
freeCollateralChange = costBasis.sub(newPositionValue);
|
|
2099
2106
|
} else {
|
|
2100
|
-
console.log('newPositionValue', newPositionValue.toString());
|
|
2101
|
-
console.log('costBasis', costBasis.toString());
|
|
2102
2107
|
freeCollateralChange = newPositionValue.sub(costBasis);
|
|
2103
2108
|
}
|
|
2104
2109
|
|
|
@@ -2111,24 +2116,23 @@ export class User {
|
|
|
2111
2116
|
freeCollateralChange = freeCollateralChange.sub(takerFee);
|
|
2112
2117
|
}
|
|
2113
2118
|
|
|
2114
|
-
const
|
|
2115
|
-
calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
2119
|
+
const baseAssetAmount = includeOpenOrders
|
|
2120
|
+
? calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
2121
|
+
: perpPosition.baseAssetAmount;
|
|
2116
2122
|
|
|
2117
|
-
const
|
|
2118
|
-
positionBaseSizeChange
|
|
2119
|
-
);
|
|
2123
|
+
const newBaseAssetAmount = baseAssetAmount.add(positionBaseSizeChange);
|
|
2120
2124
|
|
|
2121
2125
|
const newMarginRatio = calculateMarketMarginRatio(
|
|
2122
2126
|
market,
|
|
2123
|
-
|
|
2127
|
+
newBaseAssetAmount.abs(),
|
|
2124
2128
|
'Maintenance'
|
|
2125
2129
|
);
|
|
2126
2130
|
|
|
2127
2131
|
// update free collateral to account for new margin requirement from position change
|
|
2128
2132
|
freeCollateralChange = freeCollateralChange.sub(
|
|
2129
|
-
|
|
2133
|
+
newBaseAssetAmount
|
|
2130
2134
|
.abs()
|
|
2131
|
-
.sub(
|
|
2135
|
+
.sub(baseAssetAmount.abs())
|
|
2132
2136
|
.mul(oraclePrice)
|
|
2133
2137
|
.div(BASE_PRECISION)
|
|
2134
2138
|
.mul(new BN(newMarginRatio))
|
|
@@ -2142,25 +2146,23 @@ export class User {
|
|
|
2142
2146
|
market: PerpMarketAccount,
|
|
2143
2147
|
perpPosition: PerpPosition,
|
|
2144
2148
|
positionBaseSizeChange: BN,
|
|
2145
|
-
marginCategory: MarginCategory = 'Maintenance'
|
|
2149
|
+
marginCategory: MarginCategory = 'Maintenance',
|
|
2150
|
+
includeOpenOrders = false
|
|
2146
2151
|
): BN | undefined {
|
|
2147
|
-
const
|
|
2152
|
+
const baseAssetAmount = includeOpenOrders
|
|
2153
|
+
? calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
2154
|
+
: perpPosition.baseAssetAmount;
|
|
2148
2155
|
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
currentBaseAssetAmount
|
|
2153
|
-
);
|
|
2154
|
-
const proposedBaseAssetAmount = currentBaseAssetAmount.add(
|
|
2155
|
-
positionBaseSizeChange
|
|
2156
|
-
);
|
|
2157
|
-
const proposedWorstCaseBaseAssetAmount = worstCaseBaseAssetAmount.add(
|
|
2158
|
-
positionBaseSizeChange
|
|
2156
|
+
// zero if include orders == false
|
|
2157
|
+
const orderBaseAssetAmount = baseAssetAmount.sub(
|
|
2158
|
+
perpPosition.baseAssetAmount
|
|
2159
2159
|
);
|
|
2160
2160
|
|
|
2161
|
+
const proposedBaseAssetAmount = baseAssetAmount.add(positionBaseSizeChange);
|
|
2162
|
+
|
|
2161
2163
|
const marginRatio = calculateMarketMarginRatio(
|
|
2162
2164
|
market,
|
|
2163
|
-
|
|
2165
|
+
proposedBaseAssetAmount.abs(),
|
|
2164
2166
|
marginCategory,
|
|
2165
2167
|
this.getUserAccount().maxMarginRatio
|
|
2166
2168
|
);
|
|
@@ -2168,7 +2170,7 @@ export class User {
|
|
|
2168
2170
|
.mul(QUOTE_PRECISION)
|
|
2169
2171
|
.div(MARGIN_PRECISION);
|
|
2170
2172
|
|
|
2171
|
-
if (
|
|
2173
|
+
if (proposedBaseAssetAmount.eq(ZERO)) {
|
|
2172
2174
|
return undefined;
|
|
2173
2175
|
}
|
|
2174
2176
|
|
package/tests/amm/test.ts
CHANGED
|
@@ -1193,7 +1193,9 @@ describe('AMM Tests', () => {
|
|
|
1193
1193
|
};
|
|
1194
1194
|
|
|
1195
1195
|
// good oracle
|
|
1196
|
-
assert(
|
|
1196
|
+
assert(
|
|
1197
|
+
isOracleValid(mockMarket1, oraclePriceData, oracleGuardRails, slot + 5)
|
|
1198
|
+
);
|
|
1197
1199
|
|
|
1198
1200
|
// conf too high
|
|
1199
1201
|
assert(
|
package/tests/dlob/test.ts
CHANGED
|
@@ -6614,6 +6614,63 @@ describe('Uncross L2', () => {
|
|
|
6614
6614
|
);
|
|
6615
6615
|
});
|
|
6616
6616
|
|
|
6617
|
+
it('Handles user crossing bid in second level', () => {
|
|
6618
|
+
const oraclePrice = new BN(190.3843 * PRICE_PRECISION.toNumber());
|
|
6619
|
+
const bids = [
|
|
6620
|
+
[190.59, 2],
|
|
6621
|
+
[190.588, 58.3],
|
|
6622
|
+
[190.5557, 5],
|
|
6623
|
+
[190.5547, 5],
|
|
6624
|
+
[190.5508, 5],
|
|
6625
|
+
[190.541, 2],
|
|
6626
|
+
[190.5099, 49.1],
|
|
6627
|
+
[190.5, 60],
|
|
6628
|
+
].map(([price, size]) => ({
|
|
6629
|
+
price: new BN(price * PRICE_PRECISION.toNumber()),
|
|
6630
|
+
size: new BN(size * BASE_PRECISION.toNumber()),
|
|
6631
|
+
sources: { vamm: new BN(size * BASE_PRECISION.toNumber()) },
|
|
6632
|
+
}));
|
|
6633
|
+
|
|
6634
|
+
const asks = [
|
|
6635
|
+
[190.5, 86.5],
|
|
6636
|
+
[190.6159, 1],
|
|
6637
|
+
[190.656, 10.5],
|
|
6638
|
+
[190.6561, 1],
|
|
6639
|
+
[190.6585, 5],
|
|
6640
|
+
[190.6595, 5],
|
|
6641
|
+
[190.6596, 5],
|
|
6642
|
+
].map(([price, size]) => ({
|
|
6643
|
+
price: new BN(price * PRICE_PRECISION.toNumber()),
|
|
6644
|
+
size: new BN(size * BASE_PRECISION.toNumber()),
|
|
6645
|
+
sources: { vamm: new BN(size * BASE_PRECISION.toNumber()) },
|
|
6646
|
+
}));
|
|
6647
|
+
|
|
6648
|
+
expect(asksAreSortedAsc(asks), 'Input asks are ascending').to.be.true;
|
|
6649
|
+
expect(bidsAreSortedDesc(bids), 'Input bids are descending').to.be.true;
|
|
6650
|
+
|
|
6651
|
+
const groupingSize = new BN('100');
|
|
6652
|
+
|
|
6653
|
+
const userBidPrice = new BN(190.588 * PRICE_PRECISION.toNumber());
|
|
6654
|
+
const userBids = new Set<string>([userBidPrice.toString()]);
|
|
6655
|
+
|
|
6656
|
+
const { bids: newBids, asks: newAsks } = uncrossL2(
|
|
6657
|
+
bids,
|
|
6658
|
+
asks,
|
|
6659
|
+
oraclePrice,
|
|
6660
|
+
oraclePrice,
|
|
6661
|
+
oraclePrice,
|
|
6662
|
+
groupingSize,
|
|
6663
|
+
userBids,
|
|
6664
|
+
new Set<string>()
|
|
6665
|
+
);
|
|
6666
|
+
|
|
6667
|
+
expect(asksAreSortedAsc(newAsks), 'Uncrossed asks are ascending').to.be
|
|
6668
|
+
.true;
|
|
6669
|
+
expect(bidsAreSortedDesc(newBids), 'Uncrossed bids are descending').to.be
|
|
6670
|
+
.true;
|
|
6671
|
+
expect(newBids[0].price.toString()).to.equal(userBidPrice.toString());
|
|
6672
|
+
});
|
|
6673
|
+
|
|
6617
6674
|
it('Handles edge case bide and asks with large cross and an overlapping level', () => {
|
|
6618
6675
|
const bids = [
|
|
6619
6676
|
'104411000',
|