@drift-labs/sdk 2.38.1-beta.0 → 2.38.1-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/fetch.js +2 -2
- package/lib/accounts/pollingDriftClientAccountSubscriber.js +2 -2
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +2 -2
- package/lib/adminClient.d.ts +1 -0
- package/lib/adminClient.js +11 -0
- package/lib/config.d.ts +1 -0
- package/lib/config.js +2 -0
- package/lib/driftClient.d.ts +22 -2
- package/lib/driftClient.js +101 -15
- package/lib/examples/loadDlob.js +3 -1
- package/lib/examples/makeTradeExample.js +3 -1
- package/lib/idl/drift.json +36 -1
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/jupiter/jupiterClient.d.ts +197 -0
- package/lib/jupiter/jupiterClient.js +48 -3
- package/lib/math/spotBalance.d.ts +6 -5
- package/lib/math/spotBalance.js +28 -11
- package/lib/math/spotMarket.d.ts +1 -1
- package/lib/math/spotMarket.js +2 -2
- package/lib/math/spotPosition.d.ts +16 -3
- package/lib/math/spotPosition.js +53 -9
- package/lib/oracles/strictOraclePrice.d.ts +8 -0
- package/lib/oracles/strictOraclePrice.js +17 -0
- package/lib/priorityFee/priorityFeeSubscriber.d.ts +22 -0
- package/lib/priorityFee/priorityFeeSubscriber.js +46 -0
- package/lib/tokenFaucet.js +1 -0
- package/lib/types.d.ts +4 -0
- package/lib/types.js +3 -0
- package/lib/user.d.ts +5 -4
- package/lib/user.js +71 -105
- package/package.json +2 -2
- package/src/accounts/fetch.ts +2 -2
- package/src/accounts/pollingDriftClientAccountSubscriber.ts +2 -2
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +10 -8
- package/src/adminClient.ts +23 -0
- package/src/config.ts +3 -0
- package/src/driftClient.ts +173 -13
- package/src/examples/loadDlob.ts +1 -0
- package/src/examples/makeTradeExample.ts +1 -0
- package/src/idl/drift.json +36 -1
- package/src/index.ts +3 -0
- package/src/jupiter/jupiterClient.ts +246 -3
- package/src/math/spotBalance.ts +37 -11
- package/src/math/spotMarket.ts +7 -1
- package/src/math/spotPosition.ts +133 -18
- package/src/oracles/strictOraclePrice.ts +19 -0
- package/src/priorityFee/priorityFeeSubscriber.ts +75 -0
- package/src/tokenFaucet.ts +1 -0
- package/src/types.ts +4 -0
- package/src/user.ts +171 -228
- package/tests/dlob/helpers.ts +10 -7
- package/tests/user/test.ts +77 -4
package/src/math/spotMarket.ts
CHANGED
|
@@ -21,12 +21,18 @@ export function castNumberToSpotPrecision(
|
|
|
21
21
|
|
|
22
22
|
export function calculateSpotMarketMarginRatio(
|
|
23
23
|
market: SpotMarketAccount,
|
|
24
|
+
oraclePrice: BN,
|
|
24
25
|
marginCategory: MarginCategory,
|
|
25
26
|
size: BN,
|
|
26
27
|
balanceType: SpotBalanceType
|
|
27
28
|
): number {
|
|
28
29
|
if (isVariant(balanceType, 'deposit')) {
|
|
29
|
-
const assetWeight = calculateAssetWeight(
|
|
30
|
+
const assetWeight = calculateAssetWeight(
|
|
31
|
+
size,
|
|
32
|
+
oraclePrice,
|
|
33
|
+
market,
|
|
34
|
+
marginCategory
|
|
35
|
+
);
|
|
30
36
|
return MARGIN_PRECISION.sub(assetWeight).toNumber();
|
|
31
37
|
} else {
|
|
32
38
|
const liabilityWeight = calculateLiabilityWeight(
|
package/src/math/spotPosition.ts
CHANGED
|
@@ -1,22 +1,38 @@
|
|
|
1
|
-
import { SpotMarketAccount, SpotPosition } from '../types';
|
|
2
|
-
import {
|
|
1
|
+
import { MarginCategory, SpotMarketAccount, SpotPosition } from '../types';
|
|
2
|
+
import {
|
|
3
|
+
SPOT_MARKET_WEIGHT_PRECISION,
|
|
4
|
+
ZERO,
|
|
5
|
+
} from '../constants/numericConstants';
|
|
3
6
|
import { BN } from '@coral-xyz/anchor';
|
|
4
7
|
import {
|
|
8
|
+
calculateAssetWeight,
|
|
9
|
+
calculateLiabilityWeight,
|
|
5
10
|
getSignedTokenAmount,
|
|
11
|
+
getStrictTokenValue,
|
|
6
12
|
getTokenAmount,
|
|
7
13
|
getTokenValue,
|
|
8
14
|
} from './spotBalance';
|
|
9
|
-
import {
|
|
15
|
+
import { StrictOraclePrice } from '../oracles/strictOraclePrice';
|
|
10
16
|
|
|
11
17
|
export function isSpotPositionAvailable(position: SpotPosition): boolean {
|
|
12
18
|
return position.scaledBalance.eq(ZERO) && position.openOrders === 0;
|
|
13
19
|
}
|
|
14
20
|
|
|
21
|
+
export type OrderFillSimulation = {
|
|
22
|
+
tokenAmount: BN;
|
|
23
|
+
ordersValue: BN;
|
|
24
|
+
tokenValue: BN;
|
|
25
|
+
weight: BN;
|
|
26
|
+
weightedTokenValue: BN;
|
|
27
|
+
freeCollateralContribution;
|
|
28
|
+
};
|
|
29
|
+
|
|
15
30
|
export function getWorstCaseTokenAmounts(
|
|
16
31
|
spotPosition: SpotPosition,
|
|
17
32
|
spotMarketAccount: SpotMarketAccount,
|
|
18
|
-
|
|
19
|
-
|
|
33
|
+
strictOraclePrice: StrictOraclePrice,
|
|
34
|
+
marginCategory: MarginCategory
|
|
35
|
+
): OrderFillSimulation {
|
|
20
36
|
const tokenAmount = getSignedTokenAmount(
|
|
21
37
|
getTokenAmount(
|
|
22
38
|
spotPosition.scaledBalance,
|
|
@@ -26,22 +42,121 @@ export function getWorstCaseTokenAmounts(
|
|
|
26
42
|
spotPosition.balanceType
|
|
27
43
|
);
|
|
28
44
|
|
|
29
|
-
const
|
|
30
|
-
|
|
45
|
+
const tokenValue = getStrictTokenValue(
|
|
46
|
+
tokenAmount,
|
|
47
|
+
spotMarketAccount.decimals,
|
|
48
|
+
strictOraclePrice
|
|
49
|
+
);
|
|
31
50
|
|
|
32
|
-
if (
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
51
|
+
if (spotPosition.openBids.eq(ZERO) && spotPosition.openAsks.eq(ZERO)) {
|
|
52
|
+
const { weight, weightedTokenValue } = calculateWeightedTokenValue(
|
|
53
|
+
tokenAmount,
|
|
54
|
+
tokenValue,
|
|
55
|
+
strictOraclePrice.current,
|
|
56
|
+
spotMarketAccount,
|
|
57
|
+
marginCategory
|
|
37
58
|
);
|
|
38
|
-
return
|
|
59
|
+
return {
|
|
60
|
+
tokenAmount,
|
|
61
|
+
ordersValue: ZERO,
|
|
62
|
+
tokenValue,
|
|
63
|
+
weight,
|
|
64
|
+
weightedTokenValue,
|
|
65
|
+
freeCollateralContribution: weightedTokenValue,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const bidsSimulation = simulateOrderFill(
|
|
70
|
+
tokenAmount,
|
|
71
|
+
tokenValue,
|
|
72
|
+
spotPosition.openBids,
|
|
73
|
+
strictOraclePrice,
|
|
74
|
+
spotMarketAccount,
|
|
75
|
+
marginCategory
|
|
76
|
+
);
|
|
77
|
+
const asksSimulation = simulateOrderFill(
|
|
78
|
+
tokenAmount,
|
|
79
|
+
tokenValue,
|
|
80
|
+
spotPosition.openAsks,
|
|
81
|
+
strictOraclePrice,
|
|
82
|
+
spotMarketAccount,
|
|
83
|
+
marginCategory
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
if (
|
|
87
|
+
asksSimulation.freeCollateralContribution.lt(
|
|
88
|
+
bidsSimulation.freeCollateralContribution
|
|
89
|
+
)
|
|
90
|
+
) {
|
|
91
|
+
return asksSimulation;
|
|
39
92
|
} else {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
93
|
+
return bidsSimulation;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function calculateWeightedTokenValue(
|
|
98
|
+
tokenAmount: BN,
|
|
99
|
+
tokenValue: BN,
|
|
100
|
+
oraclePrice: BN,
|
|
101
|
+
spotMarket: SpotMarketAccount,
|
|
102
|
+
marginCategory: MarginCategory
|
|
103
|
+
): { weight: BN; weightedTokenValue: BN } {
|
|
104
|
+
let weight: BN;
|
|
105
|
+
if (tokenValue.gte(ZERO)) {
|
|
106
|
+
weight = calculateAssetWeight(
|
|
107
|
+
tokenAmount,
|
|
108
|
+
oraclePrice,
|
|
109
|
+
spotMarket,
|
|
110
|
+
marginCategory
|
|
111
|
+
);
|
|
112
|
+
} else {
|
|
113
|
+
weight = calculateLiabilityWeight(
|
|
114
|
+
tokenAmount.abs(),
|
|
115
|
+
spotMarket,
|
|
116
|
+
marginCategory
|
|
44
117
|
);
|
|
45
|
-
return [tokenAmountAllAsksFill, worstCaseQuoteTokenAmount];
|
|
46
118
|
}
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
weight: weight,
|
|
122
|
+
weightedTokenValue: tokenValue
|
|
123
|
+
.mul(weight)
|
|
124
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function simulateOrderFill(
|
|
129
|
+
tokenAmount: BN,
|
|
130
|
+
tokenValue: BN,
|
|
131
|
+
openOrders: BN,
|
|
132
|
+
strictOraclePrice: StrictOraclePrice,
|
|
133
|
+
spotMarket: SpotMarketAccount,
|
|
134
|
+
marginCategory: MarginCategory
|
|
135
|
+
): OrderFillSimulation {
|
|
136
|
+
const ordersValue = getTokenValue(openOrders.neg(), spotMarket.decimals, {
|
|
137
|
+
price: strictOraclePrice.max(),
|
|
138
|
+
});
|
|
139
|
+
const tokenAmountAfterFill = tokenAmount.add(openOrders);
|
|
140
|
+
const tokenValueAfterFill = tokenValue.add(ordersValue.neg());
|
|
141
|
+
|
|
142
|
+
const { weight, weightedTokenValue: weightedTokenValueAfterFill } =
|
|
143
|
+
calculateWeightedTokenValue(
|
|
144
|
+
tokenAmountAfterFill,
|
|
145
|
+
tokenValueAfterFill,
|
|
146
|
+
strictOraclePrice.current,
|
|
147
|
+
spotMarket,
|
|
148
|
+
marginCategory
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const freeCollateralContribution =
|
|
152
|
+
weightedTokenValueAfterFill.add(ordersValue);
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
tokenAmount: tokenAmountAfterFill,
|
|
156
|
+
ordersValue: ordersValue,
|
|
157
|
+
tokenValue: tokenValueAfterFill,
|
|
158
|
+
weight,
|
|
159
|
+
weightedTokenValue: weightedTokenValueAfterFill,
|
|
160
|
+
freeCollateralContribution,
|
|
161
|
+
};
|
|
47
162
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BN } from '@coral-xyz/anchor';
|
|
2
|
+
|
|
3
|
+
export class StrictOraclePrice {
|
|
4
|
+
current: BN;
|
|
5
|
+
twap?: BN;
|
|
6
|
+
|
|
7
|
+
constructor(current: BN, twap?: BN) {
|
|
8
|
+
this.current = current;
|
|
9
|
+
this.twap = twap;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public max(): BN {
|
|
13
|
+
return this.twap ? BN.max(this.twap, this.current) : this.current;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public min(): BN {
|
|
17
|
+
return this.twap ? BN.min(this.twap, this.current) : this.current;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Connection, PublicKey } from '@solana/web3.js';
|
|
2
|
+
|
|
3
|
+
export class PriorityFeeSubscriber {
|
|
4
|
+
connection: Connection;
|
|
5
|
+
frequencyMs: number;
|
|
6
|
+
addresses: PublicKey[];
|
|
7
|
+
slotsToCheck: number;
|
|
8
|
+
|
|
9
|
+
intervalId?: NodeJS.Timer;
|
|
10
|
+
|
|
11
|
+
latestPriorityFee = 0;
|
|
12
|
+
// avg of last {slotsToCheck} slots
|
|
13
|
+
avgPriorityFee = 0;
|
|
14
|
+
// max of last {slotsToCheck} slots
|
|
15
|
+
maxPriorityFee = 0;
|
|
16
|
+
lastSlotSeen = 0;
|
|
17
|
+
|
|
18
|
+
public constructor({
|
|
19
|
+
connection,
|
|
20
|
+
frequencyMs,
|
|
21
|
+
addresses,
|
|
22
|
+
slotsToCheck = 10,
|
|
23
|
+
}: {
|
|
24
|
+
connection: Connection;
|
|
25
|
+
frequencyMs: number;
|
|
26
|
+
addresses: PublicKey[];
|
|
27
|
+
slotsToCheck?: number;
|
|
28
|
+
}) {
|
|
29
|
+
this.connection = connection;
|
|
30
|
+
this.frequencyMs = frequencyMs;
|
|
31
|
+
this.addresses = addresses;
|
|
32
|
+
this.slotsToCheck = slotsToCheck;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public async subscribe(): Promise<void> {
|
|
36
|
+
if (this.intervalId) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.intervalId = setInterval(this.load.bind(this), this.frequencyMs);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public async load(): Promise<void> {
|
|
44
|
+
// @ts-ignore
|
|
45
|
+
const rpcJSONResponse: any = await this.connection._rpcRequest(
|
|
46
|
+
'getRecentPrioritizationFees',
|
|
47
|
+
[this.addresses]
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const descResults: { slot: number; prioritizationFee: number }[] =
|
|
51
|
+
rpcJSONResponse?.result
|
|
52
|
+
?.sort((a, b) => b.slot - a.slot)
|
|
53
|
+
?.slice(0, this.slotsToCheck) ?? [];
|
|
54
|
+
|
|
55
|
+
if (!descResults?.length) return;
|
|
56
|
+
|
|
57
|
+
const mostRecentResult = descResults[0];
|
|
58
|
+
this.latestPriorityFee = mostRecentResult.prioritizationFee;
|
|
59
|
+
this.lastSlotSeen = mostRecentResult.slot;
|
|
60
|
+
this.avgPriorityFee =
|
|
61
|
+
descResults.reduce((a, b) => {
|
|
62
|
+
return a + b.prioritizationFee;
|
|
63
|
+
}, 0) / descResults.length;
|
|
64
|
+
this.maxPriorityFee = Math.max(
|
|
65
|
+
...descResults.map((result) => result.prioritizationFee)
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public async unsubscribe(): Promise<void> {
|
|
70
|
+
if (this.intervalId) {
|
|
71
|
+
clearInterval(this.intervalId);
|
|
72
|
+
this.intervalId = undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/tokenFaucet.ts
CHANGED
|
@@ -38,6 +38,7 @@ export class TokenFaucet {
|
|
|
38
38
|
this.connection = connection;
|
|
39
39
|
this.wallet = wallet;
|
|
40
40
|
this.opts = opts || AnchorProvider.defaultOptions();
|
|
41
|
+
// @ts-ignore
|
|
41
42
|
const provider = new AnchorProvider(connection, wallet, this.opts);
|
|
42
43
|
this.provider = provider;
|
|
43
44
|
this.program = new Program(tokenFaucet as Idl, programId, provider);
|
package/src/types.ts
CHANGED
|
@@ -155,6 +155,9 @@ export class OrderActionExplanation {
|
|
|
155
155
|
static readonly ORDER_FILLED_WITH_SERUM = {
|
|
156
156
|
orderFillWithSerum: {},
|
|
157
157
|
};
|
|
158
|
+
static readonly ORDER_FILLED_WITH_PHOENIX = {
|
|
159
|
+
orderFillWithPhoenix: {},
|
|
160
|
+
};
|
|
158
161
|
static readonly REDUCE_ONLY_ORDER_INCREASED_POSITION = {
|
|
159
162
|
reduceOnlyOrderIncreasedPosition: {},
|
|
160
163
|
};
|
|
@@ -652,6 +655,7 @@ export type SpotMarketAccount = {
|
|
|
652
655
|
maintenanceLiabilityWeight: number;
|
|
653
656
|
liquidatorFee: number;
|
|
654
657
|
imfFactor: number;
|
|
658
|
+
scaleInitialAssetWeightStart: BN;
|
|
655
659
|
|
|
656
660
|
withdrawGuardThreshold: BN;
|
|
657
661
|
depositTokenTwap: BN;
|