@drift-labs/sdk 0.2.0-master.11 → 0.2.0-master.14
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/lib/accounts/fetch.d.ts +2 -1
- package/lib/accounts/fetch.js +9 -1
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +14 -1
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
- package/lib/addresses/pda.d.ts +1 -0
- package/lib/addresses/pda.js +8 -1
- package/lib/admin.d.ts +2 -0
- package/lib/admin.js +18 -0
- package/lib/clearingHouse.d.ts +24 -3
- package/lib/clearingHouse.js +352 -51
- package/lib/clearingHouseConfig.d.ts +1 -0
- package/lib/clearingHouseUser.d.ts +15 -15
- package/lib/clearingHouseUser.js +185 -73
- package/lib/clearingHouseUserStats.d.ts +17 -0
- package/lib/clearingHouseUserStats.js +36 -0
- package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
- package/lib/clearingHouseUserStatsConfig.js +2 -0
- package/lib/config.js +1 -1
- package/lib/constants/banks.d.ts +2 -2
- package/lib/constants/banks.js +4 -3
- package/lib/constants/numericConstants.d.ts +2 -0
- package/lib/constants/numericConstants.js +3 -1
- package/lib/events/eventList.js +3 -0
- package/lib/events/types.d.ts +2 -1
- package/lib/factory/bigNum.d.ts +1 -0
- package/lib/factory/bigNum.js +37 -11
- package/lib/idl/clearing_house.json +692 -58
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/amm.js +2 -2
- package/lib/math/bankBalance.d.ts +7 -1
- package/lib/math/bankBalance.js +76 -1
- package/lib/math/margin.d.ts +11 -0
- package/lib/math/margin.js +72 -0
- package/lib/math/market.d.ts +4 -1
- package/lib/math/market.js +35 -1
- package/lib/math/oracles.d.ts +3 -0
- package/lib/math/oracles.js +25 -5
- package/lib/math/position.d.ts +8 -0
- package/lib/math/position.js +43 -12
- package/lib/math/trade.js +2 -2
- package/lib/orders.d.ts +1 -2
- package/lib/orders.js +2 -77
- package/lib/tokenFaucet.d.ts +1 -0
- package/lib/tokenFaucet.js +23 -12
- package/lib/tx/retryTxSender.js +9 -2
- package/lib/types.d.ts +78 -10
- package/lib/types.js +12 -0
- package/lib/util/getTokenAddress.d.ts +2 -0
- package/lib/util/getTokenAddress.js +9 -0
- package/package.json +1 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +18 -0
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/pda.ts +13 -0
- package/src/admin.ts +29 -1
- package/src/clearingHouse.ts +619 -62
- package/src/clearingHouseConfig.ts +1 -0
- package/src/clearingHouseUser.ts +317 -105
- package/src/clearingHouseUserStats.ts +53 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +1 -1
- package/src/constants/banks.js +42 -0
- package/src/constants/banks.ts +6 -3
- package/src/constants/markets.js +42 -0
- package/src/constants/numericConstants.js +41 -0
- package/src/constants/numericConstants.ts +3 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/types.ts +2 -0
- package/src/factory/bigNum.js +37 -11
- package/src/factory/bigNum.ts +43 -13
- package/src/idl/clearing_house.json +692 -58
- package/src/index.ts +1 -0
- package/src/math/amm.ts +8 -5
- package/src/math/bankBalance.ts +147 -1
- package/src/math/margin.ts +124 -0
- package/src/math/market.ts +66 -1
- package/src/math/oracles.ts +42 -5
- package/src/math/position.ts +60 -9
- package/src/math/trade.ts +2 -2
- package/src/orders.ts +4 -157
- package/src/tokenFaucet.js +189 -0
- package/src/tokenFaucet.ts +38 -15
- package/src/tx/retryTxSender.ts +11 -3
- package/src/types.js +12 -1
- package/src/types.ts +83 -10
- package/src/{accounts/fetch.js → util/computeUnits.js} +11 -13
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/getTokenAddress.ts +18 -0
- package/tests/bn/test.ts +2 -0
- package/src/accounts/bulkAccountLoader.js +0 -197
- package/src/accounts/bulkUserSubscription.js +0 -33
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -311
- package/src/accounts/pollingOracleSubscriber.js +0 -93
- package/src/accounts/pollingTokenAccountSubscriber.js +0 -90
- package/src/accounts/pollingUserAccountSubscriber.js +0 -132
- package/src/accounts/types.js +0 -10
- package/src/accounts/utils.js +0 -7
- package/src/accounts/webSocketAccountSubscriber.js +0 -93
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -233
- package/src/accounts/webSocketUserAccountSubscriber.js +0 -62
- package/src/addresses/pda.js +0 -104
- package/src/index.js +0 -100
- package/src/math/bankBalance.js +0 -75
- package/src/math/market.js +0 -57
- package/src/math/orders.js +0 -110
- package/src/math/position.js +0 -140
- package/src/mockUSDCFaucet.js +0 -280
- package/src/orders.js +0 -134
- package/src/tx/retryTxSender.js +0 -188
package/src/index.ts
CHANGED
|
@@ -35,6 +35,7 @@ export * from './math/amm';
|
|
|
35
35
|
export * from './math/trade';
|
|
36
36
|
export * from './math/orders';
|
|
37
37
|
export * from './math/repeg';
|
|
38
|
+
export * from './math/margin';
|
|
38
39
|
export * from './orders';
|
|
39
40
|
export * from './orderParams';
|
|
40
41
|
export * from './slot/SlotSubscriber';
|
package/src/math/amm.ts
CHANGED
|
@@ -33,11 +33,14 @@ export function calculatePegFromTargetPrice(
|
|
|
33
33
|
baseAssetReserve: BN,
|
|
34
34
|
quoteAssetReserve: BN
|
|
35
35
|
): BN {
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
return BN.max(
|
|
37
|
+
targetPrice
|
|
38
|
+
.mul(baseAssetReserve)
|
|
39
|
+
.div(quoteAssetReserve)
|
|
40
|
+
.add(PRICE_DIV_PEG.div(new BN(2)))
|
|
41
|
+
.div(PRICE_DIV_PEG),
|
|
42
|
+
ONE
|
|
43
|
+
);
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
export function calculateOptimalPegAndBudget(
|
package/src/math/bankBalance.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BankAccount,
|
|
3
|
+
BankBalanceType,
|
|
4
|
+
isVariant,
|
|
5
|
+
MarginCategory,
|
|
6
|
+
} from '../types';
|
|
2
7
|
import { BN } from '@project-serum/anchor';
|
|
3
8
|
import {
|
|
4
9
|
BANK_UTILIZATION_PRECISION,
|
|
@@ -6,8 +11,14 @@ import {
|
|
|
6
11
|
TEN,
|
|
7
12
|
ZERO,
|
|
8
13
|
BANK_INTEREST_PRECISION,
|
|
14
|
+
BANK_WEIGHT_PRECISION,
|
|
9
15
|
ONE_YEAR,
|
|
16
|
+
AMM_RESERVE_PRECISION,
|
|
10
17
|
} from '../constants/numericConstants';
|
|
18
|
+
import {
|
|
19
|
+
calculateSizeDiscountAssetWeight,
|
|
20
|
+
calculateSizePremiumLiabilityWeight,
|
|
21
|
+
} from './margin';
|
|
11
22
|
|
|
12
23
|
export function getBalance(
|
|
13
24
|
tokenAmount: BN,
|
|
@@ -43,6 +54,92 @@ export function getTokenAmount(
|
|
|
43
54
|
return balanceAmount.mul(cumulativeInterest).div(precisionDecrease);
|
|
44
55
|
}
|
|
45
56
|
|
|
57
|
+
export function calculateAssetWeight(
|
|
58
|
+
balanceAmount: BN,
|
|
59
|
+
bank: BankAccount,
|
|
60
|
+
marginCategory: MarginCategory
|
|
61
|
+
): BN {
|
|
62
|
+
const sizePrecision = TEN.pow(new BN(bank.decimals));
|
|
63
|
+
let sizeInAmmReservePrecision;
|
|
64
|
+
if (sizePrecision.gt(AMM_RESERVE_PRECISION)) {
|
|
65
|
+
sizeInAmmReservePrecision = balanceAmount.div(
|
|
66
|
+
sizePrecision.div(AMM_RESERVE_PRECISION)
|
|
67
|
+
);
|
|
68
|
+
} else {
|
|
69
|
+
sizeInAmmReservePrecision = balanceAmount
|
|
70
|
+
.mul(AMM_RESERVE_PRECISION)
|
|
71
|
+
.div(sizePrecision);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let assetWeight;
|
|
75
|
+
|
|
76
|
+
switch (marginCategory) {
|
|
77
|
+
case 'Initial':
|
|
78
|
+
assetWeight = calculateSizeDiscountAssetWeight(
|
|
79
|
+
sizeInAmmReservePrecision,
|
|
80
|
+
bank.imfFactor,
|
|
81
|
+
bank.initialAssetWeight
|
|
82
|
+
);
|
|
83
|
+
break;
|
|
84
|
+
case 'Maintenance':
|
|
85
|
+
assetWeight = calculateSizeDiscountAssetWeight(
|
|
86
|
+
sizeInAmmReservePrecision,
|
|
87
|
+
bank.imfFactor,
|
|
88
|
+
bank.maintenanceAssetWeight
|
|
89
|
+
);
|
|
90
|
+
break;
|
|
91
|
+
default:
|
|
92
|
+
assetWeight = bank.initialAssetWeight;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return assetWeight;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function calculateLiabilityWeight(
|
|
100
|
+
balanceAmount: BN,
|
|
101
|
+
bank: BankAccount,
|
|
102
|
+
marginCategory: MarginCategory
|
|
103
|
+
): BN {
|
|
104
|
+
const sizePrecision = TEN.pow(new BN(bank.decimals));
|
|
105
|
+
let sizeInAmmReservePrecision;
|
|
106
|
+
if (sizePrecision.gt(AMM_RESERVE_PRECISION)) {
|
|
107
|
+
sizeInAmmReservePrecision = balanceAmount.div(
|
|
108
|
+
sizePrecision.div(AMM_RESERVE_PRECISION)
|
|
109
|
+
);
|
|
110
|
+
} else {
|
|
111
|
+
sizeInAmmReservePrecision = balanceAmount
|
|
112
|
+
.mul(AMM_RESERVE_PRECISION)
|
|
113
|
+
.div(sizePrecision);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let assetWeight;
|
|
117
|
+
|
|
118
|
+
switch (marginCategory) {
|
|
119
|
+
case 'Initial':
|
|
120
|
+
assetWeight = calculateSizePremiumLiabilityWeight(
|
|
121
|
+
sizeInAmmReservePrecision,
|
|
122
|
+
bank.imfFactor,
|
|
123
|
+
bank.initialLiabilityWeight,
|
|
124
|
+
BANK_WEIGHT_PRECISION
|
|
125
|
+
);
|
|
126
|
+
break;
|
|
127
|
+
case 'Maintenance':
|
|
128
|
+
assetWeight = calculateSizePremiumLiabilityWeight(
|
|
129
|
+
sizeInAmmReservePrecision,
|
|
130
|
+
bank.imfFactor,
|
|
131
|
+
bank.maintenanceLiabilityWeight,
|
|
132
|
+
BANK_WEIGHT_PRECISION
|
|
133
|
+
);
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
assetWeight = bank.initialLiabilityWeight;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return assetWeight;
|
|
141
|
+
}
|
|
142
|
+
|
|
46
143
|
export function calculateInterestAccumulated(
|
|
47
144
|
bank: BankAccount,
|
|
48
145
|
now: BN
|
|
@@ -110,3 +207,52 @@ export function calculateInterestAccumulated(
|
|
|
110
207
|
|
|
111
208
|
return { borrowInterest, depositInterest };
|
|
112
209
|
}
|
|
210
|
+
|
|
211
|
+
export function calculateWithdrawLimit(
|
|
212
|
+
bank: BankAccount,
|
|
213
|
+
now: BN
|
|
214
|
+
): { borrowLimit: BN; withdrawLimit: BN } {
|
|
215
|
+
const bankDepositTokenAmount = getTokenAmount(
|
|
216
|
+
bank.depositBalance,
|
|
217
|
+
bank,
|
|
218
|
+
BankBalanceType.DEPOSIT
|
|
219
|
+
);
|
|
220
|
+
const bankBorrowTokenAmount = getTokenAmount(
|
|
221
|
+
bank.borrowBalance,
|
|
222
|
+
bank,
|
|
223
|
+
BankBalanceType.BORROW
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
const twentyFourHours = new BN(60 * 60 * 24);
|
|
227
|
+
const sinceLast = now.sub(bank.lastUpdated);
|
|
228
|
+
const sinceStart = BN.max(ZERO, twentyFourHours.sub(sinceLast));
|
|
229
|
+
const borrowTokenTwapLive = bank.borrowTokenTwap
|
|
230
|
+
.mul(sinceStart)
|
|
231
|
+
.add(bankBorrowTokenAmount.mul(sinceLast))
|
|
232
|
+
.div(sinceLast.add(sinceLast));
|
|
233
|
+
|
|
234
|
+
const depositTokenTwapLive = bank.depositTokenTwap
|
|
235
|
+
.mul(sinceStart)
|
|
236
|
+
.add(bankDepositTokenAmount.mul(sinceLast))
|
|
237
|
+
.div(sinceLast.add(sinceLast));
|
|
238
|
+
|
|
239
|
+
const maxBorrowTokens = BN.min(
|
|
240
|
+
BN.max(
|
|
241
|
+
bankDepositTokenAmount.div(new BN(6)),
|
|
242
|
+
borrowTokenTwapLive.add(borrowTokenTwapLive.div(new BN(5)))
|
|
243
|
+
),
|
|
244
|
+
bankDepositTokenAmount.sub(bankDepositTokenAmount.div(new BN(10)))
|
|
245
|
+
); // between ~15-90% utilization with friction on twap
|
|
246
|
+
|
|
247
|
+
const minDepositTokens = depositTokenTwapLive.sub(
|
|
248
|
+
BN.min(
|
|
249
|
+
BN.max(depositTokenTwapLive.div(new BN(5)), bank.withdrawGuardThreshold),
|
|
250
|
+
depositTokenTwapLive
|
|
251
|
+
)
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
borrowLimit: maxBorrowTokens.sub(bankBorrowTokenAmount),
|
|
256
|
+
withdrawLimit: bankDepositTokenAmount.sub(minDepositTokens),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { squareRootBN } from './utils';
|
|
2
|
+
import {
|
|
3
|
+
BANK_WEIGHT_PRECISION,
|
|
4
|
+
BANK_IMF_PRECISION,
|
|
5
|
+
ZERO,
|
|
6
|
+
BID_ASK_SPREAD_PRECISION,
|
|
7
|
+
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
8
|
+
MARK_PRICE_PRECISION,
|
|
9
|
+
} from '../constants/numericConstants';
|
|
10
|
+
import { BN } from '@project-serum/anchor';
|
|
11
|
+
import { OraclePriceData } from '../oracles/types';
|
|
12
|
+
import { MarketAccount, UserPosition } from '..';
|
|
13
|
+
|
|
14
|
+
export function calculateSizePremiumLiabilityWeight(
|
|
15
|
+
size: BN, // AMM_RESERVE_PRECISION
|
|
16
|
+
imfFactor: BN,
|
|
17
|
+
liabilityWeight: BN,
|
|
18
|
+
precision: BN
|
|
19
|
+
): BN {
|
|
20
|
+
if (imfFactor.eq(ZERO)) {
|
|
21
|
+
return liabilityWeight;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const sizeSqrt = squareRootBN(size.div(new BN(1000)).add(new BN(1))); //1e13 -> 1e10 -> 1e5
|
|
25
|
+
const liabilityWeightNumerator = liabilityWeight.sub(
|
|
26
|
+
liabilityWeight.div(BN.max(new BN(1), BANK_IMF_PRECISION.div(imfFactor)))
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const sizePremiumLiabilityWeight = liabilityWeightNumerator.add(
|
|
30
|
+
sizeSqrt // 1e5
|
|
31
|
+
.mul(imfFactor)
|
|
32
|
+
.div(new BN(100_000).mul(BANK_IMF_PRECISION).div(precision)) // 1e5
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const maxLiabilityWeight = BN.max(
|
|
36
|
+
liabilityWeight,
|
|
37
|
+
sizePremiumLiabilityWeight
|
|
38
|
+
);
|
|
39
|
+
return maxLiabilityWeight;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function calculateSizeDiscountAssetWeight(
|
|
43
|
+
size: BN, // AMM_RESERVE_PRECISION
|
|
44
|
+
imfFactor: BN,
|
|
45
|
+
assetWeight: BN
|
|
46
|
+
): BN {
|
|
47
|
+
if (imfFactor.eq(ZERO)) {
|
|
48
|
+
return assetWeight;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const sizeSqrt = squareRootBN(size.div(new BN(1000)).add(new BN(1))); //1e13 -> 1e10 -> 1e5
|
|
52
|
+
const imfNumerator = BANK_IMF_PRECISION.add(
|
|
53
|
+
BANK_IMF_PRECISION.div(new BN(10))
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const sizeDiscountAssetWeight = imfNumerator.mul(BANK_WEIGHT_PRECISION).div(
|
|
57
|
+
BANK_IMF_PRECISION.add(
|
|
58
|
+
sizeSqrt // 1e5
|
|
59
|
+
.mul(imfFactor)
|
|
60
|
+
.div(new BN(100_000)) // 1e5
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const minAssetWeight = BN.min(assetWeight, sizeDiscountAssetWeight);
|
|
65
|
+
|
|
66
|
+
return minAssetWeight;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function calculateOraclePriceForPerpMargin(
|
|
70
|
+
marketPosition: UserPosition,
|
|
71
|
+
market: MarketAccount,
|
|
72
|
+
oraclePriceData: OraclePriceData
|
|
73
|
+
): BN {
|
|
74
|
+
const oraclePriceOffset = BN.min(
|
|
75
|
+
new BN(market.amm.maxSpread)
|
|
76
|
+
.mul(oraclePriceData.price)
|
|
77
|
+
.div(BID_ASK_SPREAD_PRECISION),
|
|
78
|
+
oraclePriceData.confidence.add(
|
|
79
|
+
new BN(market.amm.baseSpread)
|
|
80
|
+
.mul(oraclePriceData.price)
|
|
81
|
+
.div(BID_ASK_SPREAD_PRECISION)
|
|
82
|
+
)
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
let marginPrice: BN;
|
|
86
|
+
if (marketPosition.baseAssetAmount.gt(ZERO)) {
|
|
87
|
+
marginPrice = oraclePriceData.price.sub(oraclePriceOffset);
|
|
88
|
+
} else {
|
|
89
|
+
marginPrice = oraclePriceData.price.add(oraclePriceOffset);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return marginPrice;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function calculateMarginBaseAssetValue(
|
|
96
|
+
market: MarketAccount,
|
|
97
|
+
marketPosition: UserPosition,
|
|
98
|
+
oraclePriceData: OraclePriceData
|
|
99
|
+
): BN {
|
|
100
|
+
const marginPrice = calculateOraclePriceForPerpMargin(
|
|
101
|
+
marketPosition,
|
|
102
|
+
market,
|
|
103
|
+
oraclePriceData
|
|
104
|
+
);
|
|
105
|
+
const baseAssetValue = marketPosition.baseAssetAmount
|
|
106
|
+
.abs()
|
|
107
|
+
.mul(marginPrice)
|
|
108
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
|
|
109
|
+
|
|
110
|
+
return baseAssetValue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function calculateWorstCaseBaseAssetAmount(
|
|
114
|
+
marketPosition: UserPosition
|
|
115
|
+
): BN {
|
|
116
|
+
const allBids = marketPosition.baseAssetAmount.add(marketPosition.openBids);
|
|
117
|
+
const allAsks = marketPosition.baseAssetAmount.add(marketPosition.openAsks);
|
|
118
|
+
|
|
119
|
+
if (allBids.abs().gt(allAsks.abs())) {
|
|
120
|
+
return allBids;
|
|
121
|
+
} else {
|
|
122
|
+
return allAsks;
|
|
123
|
+
}
|
|
124
|
+
}
|
package/src/math/market.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { BN } from '@project-serum/anchor';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
MarketAccount,
|
|
4
|
+
PositionDirection,
|
|
5
|
+
MarginCategory,
|
|
6
|
+
BankAccount,
|
|
7
|
+
BankBalanceType,
|
|
8
|
+
} from '../types';
|
|
3
9
|
import {
|
|
4
10
|
calculateAmmReservesAfterSwap,
|
|
5
11
|
calculatePrice,
|
|
@@ -7,7 +13,13 @@ import {
|
|
|
7
13
|
getSwapDirection,
|
|
8
14
|
calculateUpdatedAMM,
|
|
9
15
|
} from './amm';
|
|
16
|
+
import {
|
|
17
|
+
calculateSizeDiscountAssetWeight,
|
|
18
|
+
calculateSizePremiumLiabilityWeight,
|
|
19
|
+
} from './margin';
|
|
10
20
|
import { OraclePriceData } from '../oracles/types';
|
|
21
|
+
import { MARGIN_PRECISION } from '../constants/numericConstants';
|
|
22
|
+
import { getTokenAmount } from './bankBalance';
|
|
11
23
|
|
|
12
24
|
/**
|
|
13
25
|
* Calculates market mark price
|
|
@@ -103,3 +115,56 @@ export function calculateOracleSpread(
|
|
|
103
115
|
): BN {
|
|
104
116
|
return price.sub(oraclePriceData.price);
|
|
105
117
|
}
|
|
118
|
+
|
|
119
|
+
export function calculateMarketMarginRatio(
|
|
120
|
+
market: MarketAccount,
|
|
121
|
+
size: BN,
|
|
122
|
+
marginCategory: MarginCategory
|
|
123
|
+
): number {
|
|
124
|
+
let marginRatio;
|
|
125
|
+
switch (marginCategory) {
|
|
126
|
+
case 'Initial':
|
|
127
|
+
marginRatio = calculateSizePremiumLiabilityWeight(
|
|
128
|
+
size,
|
|
129
|
+
market.imfFactor,
|
|
130
|
+
new BN(market.marginRatioInitial),
|
|
131
|
+
MARGIN_PRECISION
|
|
132
|
+
).toNumber();
|
|
133
|
+
break;
|
|
134
|
+
case 'Maintenance':
|
|
135
|
+
marginRatio = market.marginRatioMaintenance;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return marginRatio;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function calculateUnsettledAssetWeight(
|
|
143
|
+
market: MarketAccount,
|
|
144
|
+
unsettledPnl: BN,
|
|
145
|
+
marginCategory: MarginCategory
|
|
146
|
+
): BN {
|
|
147
|
+
let assetWeight: BN;
|
|
148
|
+
|
|
149
|
+
switch (marginCategory) {
|
|
150
|
+
case 'Initial':
|
|
151
|
+
assetWeight = calculateSizeDiscountAssetWeight(
|
|
152
|
+
unsettledPnl,
|
|
153
|
+
market.unsettledImfFactor,
|
|
154
|
+
new BN(market.unsettledInitialAssetWeight)
|
|
155
|
+
);
|
|
156
|
+
break;
|
|
157
|
+
case 'Maintenance':
|
|
158
|
+
assetWeight = new BN(market.unsettledMaintenanceAssetWeight);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return assetWeight;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function calculateMarketAvailablePNL(
|
|
166
|
+
market: MarketAccount,
|
|
167
|
+
bank: BankAccount
|
|
168
|
+
): BN {
|
|
169
|
+
return getTokenAmount(market.pnlPool.balance, bank, BankBalanceType.DEPOSIT);
|
|
170
|
+
}
|
package/src/math/oracles.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { AMM, OracleGuardRails } from '../types';
|
|
2
2
|
import { OraclePriceData } from '../oracles/types';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
BID_ASK_SPREAD_PRECISION,
|
|
5
|
+
MARK_PRICE_PRECISION,
|
|
6
|
+
ONE,
|
|
7
|
+
ZERO,
|
|
8
|
+
} from '../constants/numericConstants';
|
|
4
9
|
import { BN } from '../index';
|
|
5
10
|
|
|
6
11
|
export function isOracleValid(
|
|
@@ -9,7 +14,7 @@ export function isOracleValid(
|
|
|
9
14
|
oracleGuardRails: OracleGuardRails,
|
|
10
15
|
slot: number
|
|
11
16
|
): boolean {
|
|
12
|
-
const isOraclePriceNonPositive = oraclePriceData.price.
|
|
17
|
+
const isOraclePriceNonPositive = oraclePriceData.price.lte(ZERO);
|
|
13
18
|
const isOraclePriceTooVolatile =
|
|
14
19
|
oraclePriceData.price
|
|
15
20
|
.div(BN.max(ONE, amm.lastOraclePriceTwap))
|
|
@@ -18,9 +23,11 @@ export function isOracleValid(
|
|
|
18
23
|
.div(BN.max(ONE, oraclePriceData.price))
|
|
19
24
|
.gt(oracleGuardRails.validity.tooVolatileRatio);
|
|
20
25
|
|
|
21
|
-
const isConfidenceTooLarge =
|
|
22
|
-
.
|
|
23
|
-
.
|
|
26
|
+
const isConfidenceTooLarge = new BN(amm.baseSpread)
|
|
27
|
+
.add(BN.max(ONE, oraclePriceData.confidence))
|
|
28
|
+
.mul(BID_ASK_SPREAD_PRECISION)
|
|
29
|
+
.div(oraclePriceData.price)
|
|
30
|
+
.gt(new BN(amm.maxSpread));
|
|
24
31
|
|
|
25
32
|
const oracleIsStale = oraclePriceData.slot
|
|
26
33
|
.sub(new BN(slot))
|
|
@@ -34,3 +41,33 @@ export function isOracleValid(
|
|
|
34
41
|
isConfidenceTooLarge
|
|
35
42
|
);
|
|
36
43
|
}
|
|
44
|
+
|
|
45
|
+
export function isOracleTooDivergent(
|
|
46
|
+
amm: AMM,
|
|
47
|
+
oraclePriceData: OraclePriceData,
|
|
48
|
+
oracleGuardRails: OracleGuardRails,
|
|
49
|
+
now: BN
|
|
50
|
+
): boolean {
|
|
51
|
+
const sinceLastUpdate = now.sub(amm.lastOraclePriceTwapTs);
|
|
52
|
+
const sinceStart = BN.max(ZERO, new BN(60 * 5).sub(sinceLastUpdate));
|
|
53
|
+
const oracleTwap5min = amm.lastOraclePriceTwap5min
|
|
54
|
+
.mul(sinceStart)
|
|
55
|
+
.add(oraclePriceData.price)
|
|
56
|
+
.mul(sinceLastUpdate)
|
|
57
|
+
.div(sinceStart.add(sinceLastUpdate));
|
|
58
|
+
|
|
59
|
+
const oracleSpread = oracleTwap5min.sub(oraclePriceData.price);
|
|
60
|
+
const oracleSpreadPct = oracleSpread
|
|
61
|
+
.mul(MARK_PRICE_PRECISION)
|
|
62
|
+
.div(oracleTwap5min);
|
|
63
|
+
|
|
64
|
+
const tooDivergent = oracleSpreadPct
|
|
65
|
+
.abs()
|
|
66
|
+
.gte(
|
|
67
|
+
BID_ASK_SPREAD_PRECISION.mul(
|
|
68
|
+
oracleGuardRails.priceDivergence.markOracleDivergenceNumerator
|
|
69
|
+
).div(oracleGuardRails.priceDivergence.markOracleDivergenceDenominator)
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return tooDivergent;
|
|
73
|
+
}
|
package/src/math/position.ts
CHANGED
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
getSwapDirection,
|
|
19
19
|
} from './amm';
|
|
20
20
|
|
|
21
|
+
import { calculateMarginBaseAssetValue } from './margin';
|
|
22
|
+
|
|
21
23
|
/**
|
|
22
24
|
* calculateBaseAssetValue
|
|
23
25
|
* = market value of closing entire position
|
|
@@ -84,6 +86,7 @@ export function calculateBaseAssetValue(
|
|
|
84
86
|
* @param market
|
|
85
87
|
* @param marketPosition
|
|
86
88
|
* @param withFunding (adds unrealized funding payment pnl to result)
|
|
89
|
+
* @param oraclePriceData
|
|
87
90
|
* @returns BaseAssetAmount : Precision QUOTE_PRECISION
|
|
88
91
|
*/
|
|
89
92
|
export function calculatePositionPNL(
|
|
@@ -93,21 +96,21 @@ export function calculatePositionPNL(
|
|
|
93
96
|
oraclePriceData: OraclePriceData
|
|
94
97
|
): BN {
|
|
95
98
|
if (marketPosition.baseAssetAmount.eq(ZERO)) {
|
|
96
|
-
return
|
|
99
|
+
return marketPosition.quoteAssetAmount;
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
const baseAssetValue =
|
|
102
|
+
const baseAssetValue = calculateMarginBaseAssetValue(
|
|
100
103
|
market,
|
|
101
104
|
marketPosition,
|
|
102
105
|
oraclePriceData
|
|
103
106
|
);
|
|
104
107
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
const baseAssetValueSign = marketPosition.baseAssetAmount.isNeg()
|
|
109
|
+
? new BN(-1)
|
|
110
|
+
: new BN(1);
|
|
111
|
+
let pnl = baseAssetValue
|
|
112
|
+
.mul(baseAssetValueSign)
|
|
113
|
+
.add(marketPosition.quoteAssetAmount);
|
|
111
114
|
|
|
112
115
|
if (withFunding) {
|
|
113
116
|
const fundingRatePnL = calculatePositionFundingPNL(
|
|
@@ -121,6 +124,36 @@ export function calculatePositionPNL(
|
|
|
121
124
|
return pnl;
|
|
122
125
|
}
|
|
123
126
|
|
|
127
|
+
export function calculateUnsettledPnl(
|
|
128
|
+
market: MarketAccount,
|
|
129
|
+
marketPosition: UserPosition,
|
|
130
|
+
oraclePriceData: OraclePriceData
|
|
131
|
+
): BN {
|
|
132
|
+
const unrealizedPnl = calculatePositionPNL(
|
|
133
|
+
market,
|
|
134
|
+
marketPosition,
|
|
135
|
+
true,
|
|
136
|
+
oraclePriceData
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
let unsettledPnl = unrealizedPnl;
|
|
140
|
+
if (unrealizedPnl.gt(ZERO)) {
|
|
141
|
+
const fundingPnL = calculatePositionFundingPNL(market, marketPosition).div(
|
|
142
|
+
PRICE_TO_QUOTE_PRECISION
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
const maxPositivePnl = BN.max(
|
|
146
|
+
marketPosition.quoteAssetAmount
|
|
147
|
+
.add(marketPosition.quoteEntryAmount)
|
|
148
|
+
.add(fundingPnL),
|
|
149
|
+
ZERO
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
unsettledPnl = BN.min(maxPositivePnl, unrealizedPnl);
|
|
153
|
+
}
|
|
154
|
+
return unsettledPnl;
|
|
155
|
+
}
|
|
156
|
+
|
|
124
157
|
/**
|
|
125
158
|
*
|
|
126
159
|
* @param market
|
|
@@ -156,7 +189,8 @@ export function positionIsAvailable(position: UserPosition): boolean {
|
|
|
156
189
|
return (
|
|
157
190
|
position.baseAssetAmount.eq(ZERO) &&
|
|
158
191
|
position.openOrders.eq(ZERO) &&
|
|
159
|
-
position.
|
|
192
|
+
position.quoteAssetAmount.eq(ZERO) &&
|
|
193
|
+
position.lpShares.eq(ZERO)
|
|
160
194
|
);
|
|
161
195
|
}
|
|
162
196
|
|
|
@@ -170,6 +204,23 @@ export function calculateEntryPrice(userPosition: UserPosition): BN {
|
|
|
170
204
|
return ZERO;
|
|
171
205
|
}
|
|
172
206
|
|
|
207
|
+
return userPosition.quoteEntryAmount
|
|
208
|
+
.mul(MARK_PRICE_PRECISION)
|
|
209
|
+
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
210
|
+
.div(userPosition.baseAssetAmount)
|
|
211
|
+
.abs();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
*
|
|
216
|
+
* @param userPosition
|
|
217
|
+
* @returns Precision: MARK_PRICE_PRECISION (10^10)
|
|
218
|
+
*/
|
|
219
|
+
export function calculateCostBasis(userPosition: UserPosition): BN {
|
|
220
|
+
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
221
|
+
return ZERO;
|
|
222
|
+
}
|
|
223
|
+
|
|
173
224
|
return userPosition.quoteAssetAmount
|
|
174
225
|
.mul(MARK_PRICE_PRECISION)
|
|
175
226
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
package/src/math/trade.ts
CHANGED
|
@@ -177,13 +177,13 @@ export function calculateTradeAcquiredAmounts(
|
|
|
177
177
|
|
|
178
178
|
const acquiredBase = amm.baseAssetReserve.sub(newBaseAssetReserve);
|
|
179
179
|
const acquiredQuote = amm.quoteAssetReserve.sub(newQuoteAssetReserve);
|
|
180
|
-
const
|
|
180
|
+
const acquiredQuoteAssetAmount = calculateQuoteAssetAmountSwapped(
|
|
181
181
|
acquiredQuote.abs(),
|
|
182
182
|
amm.pegMultiplier,
|
|
183
183
|
swapDirection
|
|
184
184
|
);
|
|
185
185
|
|
|
186
|
-
return [acquiredBase, acquiredQuote,
|
|
186
|
+
return [acquiredBase, acquiredQuote, acquiredQuoteAssetAmount];
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
/**
|