@carrot-protocol/clend-rpc 0.1.6 → 0.1.7-fe-math-dev-ce2629b
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/dist/index.d.ts +1 -1
- package/dist/index.js +25 -2
- package/dist/index.js.map +1 -1
- package/dist/rpc.js +57 -57
- package/dist/rpc.js.map +1 -1
- package/dist/state.js +11 -11
- package/dist/state.js.map +1 -1
- package/package.json +9 -10
- package/dist/math.d.ts +0 -322
- package/dist/math.js +0 -737
- package/dist/math.js.map +0 -1
package/dist/math.js
DELETED
|
@@ -1,737 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.uiToAmount = uiToAmount;
|
|
4
|
-
exports.amountToUi = amountToUi;
|
|
5
|
-
exports.calculateUtilizationRate = calculateUtilizationRate;
|
|
6
|
-
exports.calculateAssetQuantity = calculateAssetQuantity;
|
|
7
|
-
exports.calculateLiabilityQuantity = calculateLiabilityQuantity;
|
|
8
|
-
exports.calculateTotalAssetQuantity = calculateTotalAssetQuantity;
|
|
9
|
-
exports.calculateTotalLiabilityQuantity = calculateTotalLiabilityQuantity;
|
|
10
|
-
exports.calculateBankUtilizationRate = calculateBankUtilizationRate;
|
|
11
|
-
exports.calculateBaseInterestRate = calculateBaseInterestRate;
|
|
12
|
-
exports.calculateSupplyApy = calculateSupplyApy;
|
|
13
|
-
exports.calculateBorrowApy = calculateBorrowApy;
|
|
14
|
-
exports.computeAdjustLeverageAmounts = computeAdjustLeverageAmounts;
|
|
15
|
-
exports.computeMaxLeverage = computeMaxLeverage;
|
|
16
|
-
exports.computeLoopingAmounts = computeLoopingAmounts;
|
|
17
|
-
exports.calculateWeightedValue = calculateWeightedValue;
|
|
18
|
-
exports.calculateWeightedAmount = calculateWeightedAmount;
|
|
19
|
-
exports.calculateWeightedLeverage = calculateWeightedLeverage;
|
|
20
|
-
exports.computeWithdrawLeverageAmounts = computeWithdrawLeverageAmounts;
|
|
21
|
-
exports.calculateHealthFactorAndLeverage = calculateHealthFactorAndLeverage;
|
|
22
|
-
exports.calculateAccruedInterest = calculateAccruedInterest;
|
|
23
|
-
exports.adjustBorrowForOriginationFee = adjustBorrowForOriginationFee;
|
|
24
|
-
exports.adjustAmountForSlippage = adjustAmountForSlippage;
|
|
25
|
-
exports.calculateLiquidationPrice = calculateLiquidationPrice;
|
|
26
|
-
exports.calculateLtv = calculateLtv;
|
|
27
|
-
exports.calculateLiquidationPriceChangePercentage = calculateLiquidationPriceChangePercentage;
|
|
28
|
-
exports.calculateLiabilityInterest = calculateLiabilityInterest;
|
|
29
|
-
exports.addInterestAccrualBuffer = addInterestAccrualBuffer;
|
|
30
|
-
const anchor_1 = require("@coral-xyz/anchor");
|
|
31
|
-
const decimal_js_1 = require("decimal.js");
|
|
32
|
-
/**
|
|
33
|
-
* Convert a UI number to a token amount BN
|
|
34
|
-
* @param uiAmount Amount in UI format (e.g., 1.5 USDC)
|
|
35
|
-
* @param decimals Token decimals
|
|
36
|
-
* @returns BN representing the token amount in smallest units (lamports)
|
|
37
|
-
*/
|
|
38
|
-
function uiToAmount(uiAmount, decimals) {
|
|
39
|
-
return new anchor_1.BN(Math.floor(uiAmount * 10 ** decimals));
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Convert a token amount BN to a UI number
|
|
43
|
-
* @param tokenAmount BN representing the token amount in smallest units (lamports)
|
|
44
|
-
* @param decimals Token decimals
|
|
45
|
-
* @returns Number in UI format (e.g., 1.5 USDC)
|
|
46
|
-
*/
|
|
47
|
-
function amountToUi(amount, decimals) {
|
|
48
|
-
if (typeof amount === "number") {
|
|
49
|
-
return amount / 10 ** decimals;
|
|
50
|
-
}
|
|
51
|
-
return amount.toNumber() / 10 ** decimals;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Calculate the utilization rate of a bank
|
|
55
|
-
* @param totalSupply Total supply of tokens
|
|
56
|
-
* @param totalBorrow Total borrowed tokens
|
|
57
|
-
* @returns Utilization rate as a decimal (0-1)
|
|
58
|
-
*/
|
|
59
|
-
function calculateUtilizationRate(totalSupply, totalBorrow) {
|
|
60
|
-
if (totalSupply === 0 || totalBorrow === 0)
|
|
61
|
-
return 0;
|
|
62
|
-
return Math.min(totalBorrow / totalSupply, 1);
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Calculate asset quantity from asset shares
|
|
66
|
-
* @param assetShares Asset shares amount
|
|
67
|
-
* @param assetShareValue Value of each asset share
|
|
68
|
-
* @returns Asset quantity
|
|
69
|
-
*/
|
|
70
|
-
function calculateAssetQuantity(assetShares, assetShareValue) {
|
|
71
|
-
const shares = typeof assetShares === "number"
|
|
72
|
-
? assetShares
|
|
73
|
-
: Number(assetShares.toString());
|
|
74
|
-
return shares * assetShareValue;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Calculate liability quantity from liability shares
|
|
78
|
-
* @param liabilityShares Liability shares amount
|
|
79
|
-
* @param liabilityShareValue Value of each liability share
|
|
80
|
-
* @returns Liability quantity
|
|
81
|
-
*/
|
|
82
|
-
function calculateLiabilityQuantity(liabilityShares, liabilityShareValue) {
|
|
83
|
-
const shares = typeof liabilityShares === "number"
|
|
84
|
-
? liabilityShares
|
|
85
|
-
: Number(liabilityShares.toString());
|
|
86
|
-
return shares * liabilityShareValue;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Calculate total asset quantity
|
|
90
|
-
* @param totalAssetShares Total asset shares in the bank
|
|
91
|
-
* @param assetShareValue Value of each asset share
|
|
92
|
-
* @returns Total asset quantity
|
|
93
|
-
*
|
|
94
|
-
* Note: You can get these values from a Bank object:
|
|
95
|
-
* - totalAssetShares = bank.totalAssetShares
|
|
96
|
-
* - assetShareValue = bank.assetShareValue
|
|
97
|
-
*/
|
|
98
|
-
function calculateTotalAssetQuantity(totalAssetShares, assetShareValue) {
|
|
99
|
-
return calculateAssetQuantity(totalAssetShares, assetShareValue);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Calculate total liability quantity
|
|
103
|
-
* @param totalLiabilityShares Total liability shares in the bank
|
|
104
|
-
* @param liabilityShareValue Value of each liability share
|
|
105
|
-
* @returns Total liability quantity
|
|
106
|
-
*
|
|
107
|
-
* Note: You can get these values from a Bank object:
|
|
108
|
-
* - totalLiabilityShares = bank.totalLiabilityShares
|
|
109
|
-
* - liabilityShareValue = bank.liabilityShareValue
|
|
110
|
-
*/
|
|
111
|
-
function calculateTotalLiabilityQuantity(totalLiabilityShares, liabilityShareValue) {
|
|
112
|
-
return calculateLiabilityQuantity(totalLiabilityShares, liabilityShareValue);
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Calculate the bank's utilization rate
|
|
116
|
-
* @param totalAssetShares Total asset shares in the bank
|
|
117
|
-
* @param assetShareValue Value of each asset share
|
|
118
|
-
* @param totalLiabilityShares Total liability shares in the bank
|
|
119
|
-
* @param liabilityShareValue Value of each liability share
|
|
120
|
-
* @returns Utilization rate as a decimal (0-1)
|
|
121
|
-
*
|
|
122
|
-
* Note: You can get these values from a Bank object:
|
|
123
|
-
* - totalAssetShares = bank.totalAssetShares
|
|
124
|
-
* - assetShareValue = bank.assetShareValue
|
|
125
|
-
* - totalLiabilityShares = bank.totalLiabilityShares
|
|
126
|
-
* - liabilityShareValue = bank.liabilityShareValue
|
|
127
|
-
*/
|
|
128
|
-
function calculateBankUtilizationRate(totalAssetShares, assetShareValue, totalLiabilityShares, liabilityShareValue) {
|
|
129
|
-
const totalAssets = calculateTotalAssetQuantity(totalAssetShares, assetShareValue);
|
|
130
|
-
const totalLiabilities = calculateTotalLiabilityQuantity(totalLiabilityShares, liabilityShareValue);
|
|
131
|
-
return calculateUtilizationRate(totalAssets, totalLiabilities);
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Calculate the base interest rate based on utilization rate
|
|
135
|
-
* @param utilizationRate Current utilization rate (0-1)
|
|
136
|
-
* @param optimalUtilizationRate Optimal utilization rate target
|
|
137
|
-
* @param plateauInterestRate Interest rate at optimal utilization
|
|
138
|
-
* @param maxInterestRate Maximum interest rate at 100% utilization
|
|
139
|
-
* @returns Base interest rate as a decimal
|
|
140
|
-
*
|
|
141
|
-
* Note: You can get these values from a Bank object:
|
|
142
|
-
* - optimalUtilizationRate = bank.config.interestRateConfig.optimalUtilizationRate
|
|
143
|
-
* - plateauInterestRate = bank.config.interestRateConfig.plateauInterestRate
|
|
144
|
-
* - maxInterestRate = bank.config.interestRateConfig.maxInterestRate
|
|
145
|
-
*/
|
|
146
|
-
function calculateBaseInterestRate(utilizationRate, optimalUtilizationRate, plateauInterestRate, maxInterestRate) {
|
|
147
|
-
if (utilizationRate <= optimalUtilizationRate) {
|
|
148
|
-
// Below optimal: linear increase from 0 to plateau rate
|
|
149
|
-
return (utilizationRate / optimalUtilizationRate) * plateauInterestRate;
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
// Above optimal: linear increase from plateau to max rate
|
|
153
|
-
const excessUtilization = utilizationRate - optimalUtilizationRate;
|
|
154
|
-
const remainingUtilization = 1 - optimalUtilizationRate;
|
|
155
|
-
const excessRate = maxInterestRate - plateauInterestRate;
|
|
156
|
-
return (plateauInterestRate +
|
|
157
|
-
(excessUtilization / remainingUtilization) * excessRate);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Calculate the supply APY
|
|
162
|
-
* @param utilizationRate Current utilization rate (0-1)
|
|
163
|
-
* @param baseInterestRate Base interest rate calculated from utilization
|
|
164
|
-
* @param protocolIrFee Protocol interest rate fee
|
|
165
|
-
* @param insuranceIrFee Insurance interest rate fee
|
|
166
|
-
* @returns Supply APY as a decimal (e.g., 0.05 for 5%)
|
|
167
|
-
*
|
|
168
|
-
* Note: You can get these values from a Bank object:
|
|
169
|
-
* - utilizationRate = calculateBankUtilizationRate(...)
|
|
170
|
-
* - baseInterestRate = calculateBaseInterestRate(...)
|
|
171
|
-
* - protocolIrFee = bank.config.interestRateConfig.protocolIrFee
|
|
172
|
-
* - insuranceIrFee = bank.config.interestRateConfig.insuranceIrFee
|
|
173
|
-
*/
|
|
174
|
-
function calculateSupplyApy(utilizationRate, baseInterestRate, protocolIrFee, insuranceIrFee) {
|
|
175
|
-
// Supply rate = base rate * utilization rate * (1 - protocol fees)
|
|
176
|
-
const totalFeeRate = protocolIrFee + insuranceIrFee;
|
|
177
|
-
return baseInterestRate * utilizationRate * (1 - totalFeeRate);
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Calculate the borrow APY
|
|
181
|
-
* @param baseInterestRate Base interest rate calculated from utilization
|
|
182
|
-
* @param protocolFixedFeeApr Protocol fixed fee APR
|
|
183
|
-
* @param insuranceFeeFixedApr Insurance fixed fee APR
|
|
184
|
-
* @returns Borrow APY as a decimal (e.g., 0.08 for 8%)
|
|
185
|
-
*
|
|
186
|
-
* Note: You can get these values from a Bank object:
|
|
187
|
-
* - baseInterestRate = calculateBaseInterestRate(...)
|
|
188
|
-
* - protocolFixedFeeApr = bank.config.interestRateConfig.protocolFixedFeeApr
|
|
189
|
-
* - insuranceFeeFixedApr = bank.config.interestRateConfig.insuranceFeeFixedApr
|
|
190
|
-
*/
|
|
191
|
-
function calculateBorrowApy(baseInterestRate, protocolFixedFeeApr, insuranceFeeFixedApr) {
|
|
192
|
-
// Borrow rate = base rate + fixed protocol fee + fixed insurance fee
|
|
193
|
-
const totalFeeRate = protocolFixedFeeApr + insuranceFeeFixedApr;
|
|
194
|
-
return baseInterestRate + totalFeeRate;
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Computes amounts needed to adjust leverage
|
|
198
|
-
* @param currentCollateral - Current collateral amount (e.g., JLP)
|
|
199
|
-
* @param currentDebt - Current debt amount (e.g., USDC)
|
|
200
|
-
* @param collateralPrice - Current collateral price in USD
|
|
201
|
-
* @param debtPrice - Current debt token price in USD
|
|
202
|
-
* @param currentLeverage - Current leverage ratio
|
|
203
|
-
* @param targetLeverage - Desired leverage ratio
|
|
204
|
-
* @param collateralWeight - Weight of collateral for maintenance (0-1)
|
|
205
|
-
* @param debtWeight - Weight of debt for maintenance (1+)
|
|
206
|
-
*/
|
|
207
|
-
function computeAdjustLeverageAmounts(currentCollateral, currentDebt, collateralPrice, debtPrice, currentLeverage, targetLeverage, collateralWeight, debtWeight) {
|
|
208
|
-
// Convert everything to weighted USD value
|
|
209
|
-
const weightedCollateralValue = calculateWeightedValue(currentCollateral, collateralPrice, collateralWeight);
|
|
210
|
-
const weightedDebtValue = calculateWeightedValue(currentDebt, debtPrice, debtWeight);
|
|
211
|
-
const weightedEquity = weightedCollateralValue - weightedDebtValue;
|
|
212
|
-
if (weightedEquity <= 0) {
|
|
213
|
-
throw new Error("Weighted equity must be positive");
|
|
214
|
-
}
|
|
215
|
-
// Target weighted position size based on desired leverage
|
|
216
|
-
const targetWeightedPositionValue = weightedEquity * targetLeverage;
|
|
217
|
-
const targetWeightedDebtValue = targetWeightedPositionValue - weightedEquity;
|
|
218
|
-
// Convert back to raw token amounts
|
|
219
|
-
const targetCollateral = targetWeightedPositionValue / (collateralPrice * collateralWeight);
|
|
220
|
-
const targetDebt = targetWeightedDebtValue / (debtPrice * debtWeight);
|
|
221
|
-
// Calculate changes needed
|
|
222
|
-
const collateralDelta = targetCollateral - currentCollateral;
|
|
223
|
-
const debtDelta = targetDebt - currentDebt;
|
|
224
|
-
return {
|
|
225
|
-
isIncrease: targetLeverage > currentLeverage,
|
|
226
|
-
collateralDelta: Math.abs(collateralDelta),
|
|
227
|
-
debtDelta: Math.abs(debtDelta),
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Computes the maximum leverage possible given deposit and borrow asset weights
|
|
232
|
-
* @param depositAssetWeight - Initial risk weight of deposit asset (0-1). Higher value = more trusted as collateral
|
|
233
|
-
* @param borrowLiabilityWeight - Initial risk weight of borrow asset (0-2). Higher value = more conservative borrowing
|
|
234
|
-
* @returns Object containing:
|
|
235
|
-
* - maxLeverage: Maximum leverage possible through recursive borrow-deposit
|
|
236
|
-
* - ltv: Loan-to-Value ratio, representing what portion of collateral can be borrowed
|
|
237
|
-
*/
|
|
238
|
-
function computeMaxLeverage(depositAssetWeight, borrowLiabilityWeight) {
|
|
239
|
-
// Handle edge cases
|
|
240
|
-
if (borrowLiabilityWeight <= 0) {
|
|
241
|
-
return { maxLeverage: -1, ltv: -1 };
|
|
242
|
-
}
|
|
243
|
-
// LTV represents what portion of collateral value can be borrowed
|
|
244
|
-
const ltv = depositAssetWeight / borrowLiabilityWeight;
|
|
245
|
-
// Maximum leverage possible through recursive borrow-deposit cycles
|
|
246
|
-
// If LTV > 1, leverage is infinite
|
|
247
|
-
if (ltv > 1) {
|
|
248
|
-
return { maxLeverage: -1, ltv };
|
|
249
|
-
}
|
|
250
|
-
if (ltv === 1) {
|
|
251
|
-
return { maxLeverage: -1, ltv };
|
|
252
|
-
}
|
|
253
|
-
return {
|
|
254
|
-
maxLeverage: 1 / (1 - ltv),
|
|
255
|
-
ltv,
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Computes the borrow and deposit amounts needed to achieve target leverage, accounting for weights
|
|
260
|
-
* @param principal - Initial deposit amount
|
|
261
|
-
* @param targetLeverage - Desired leverage multiplier
|
|
262
|
-
* @param depositPrice - Price of deposit/collateral asset
|
|
263
|
-
* @param borrowPrice - Price of borrow/debt asset
|
|
264
|
-
* @param collateralWeight - Weight of collateral asset (0-1)
|
|
265
|
-
* @param debtWeight - Weight of debt asset (1+)
|
|
266
|
-
* @returns Object containing:
|
|
267
|
-
* - borrowAmount: Amount to borrow in borrow asset units
|
|
268
|
-
* - totalDepositAmount: Total final position size in deposit asset units
|
|
269
|
-
*/
|
|
270
|
-
function computeLoopingAmounts(principal, targetLeverage, depositPrice, borrowPrice, collateralWeight, debtWeight) {
|
|
271
|
-
// Validate inputs
|
|
272
|
-
if (principal <= 0)
|
|
273
|
-
throw new Error("Principal must be positive");
|
|
274
|
-
if (targetLeverage <= 1)
|
|
275
|
-
throw new Error("Target leverage must be greater than 1");
|
|
276
|
-
if (depositPrice <= 0 || borrowPrice <= 0)
|
|
277
|
-
throw new Error("Prices must be positive");
|
|
278
|
-
if (collateralWeight <= 0 || collateralWeight > 1)
|
|
279
|
-
throw new Error("Collateral weight must be between 0 and 1");
|
|
280
|
-
if (debtWeight < 1)
|
|
281
|
-
throw new Error("Debt weight must be greater than or equal to 1");
|
|
282
|
-
const numerator = principal * depositPrice * collateralWeight * (targetLeverage - 1);
|
|
283
|
-
const denominator = borrowPrice *
|
|
284
|
-
(collateralWeight - targetLeverage * (collateralWeight - debtWeight));
|
|
285
|
-
// If denominator is close to zero or negative, we need to cap the leverage
|
|
286
|
-
if (denominator <= 0.000001) {
|
|
287
|
-
throw new Error("Target leverage is too high for the given weights");
|
|
288
|
-
}
|
|
289
|
-
const borrowAmount = numerator / denominator;
|
|
290
|
-
// Calculate total deposit amount
|
|
291
|
-
const totalDepositAmount = principal + borrowAmount * (borrowPrice / depositPrice);
|
|
292
|
-
return {
|
|
293
|
-
borrowAmountUi: borrowAmount,
|
|
294
|
-
totalDepositAmountUi: totalDepositAmount,
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Calculates the weighted value of an amount based on its price and weight
|
|
299
|
-
* @param amount - Raw amount of the token
|
|
300
|
-
* @param price - Price of the token
|
|
301
|
-
* @param weight - Weight to apply (0-1 for assets, 1+ for liabilities)
|
|
302
|
-
* @returns Weighted value in USD terms
|
|
303
|
-
*/
|
|
304
|
-
function calculateWeightedValue(amount, price, weight) {
|
|
305
|
-
const weightedAmount = calculateWeightedAmount(amount, weight);
|
|
306
|
-
return weightedAmount * price;
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* Calculates the weighted value of an amount based on its price and weight
|
|
310
|
-
* @param amount - Raw amount of the token
|
|
311
|
-
* @param price - Price of the token
|
|
312
|
-
* @param weight - Weight to apply (0-1 for assets, 1+ for liabilities)
|
|
313
|
-
* @returns Weighted value in USD terms
|
|
314
|
-
*/
|
|
315
|
-
function calculateWeightedAmount(amount, weight) {
|
|
316
|
-
return amount * weight;
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* Calculates leverage using weighted values
|
|
320
|
-
* @param collateralAmount - Amount of collateral
|
|
321
|
-
* @param collateralPrice - Price of collateral
|
|
322
|
-
* @param collateralWeight - Weight of collateral (0-1)
|
|
323
|
-
* @param debtAmount - Amount of debt
|
|
324
|
-
* @param debtPrice - Price of debt
|
|
325
|
-
* @param debtWeight - Weight of debt (1+)
|
|
326
|
-
* @returns Leverage ratio
|
|
327
|
-
*/
|
|
328
|
-
function calculateWeightedLeverage(collateralAmount, collateralPrice, collateralWeight, debtAmount, debtPrice, debtWeight) {
|
|
329
|
-
const weightedCollateralValue = calculateWeightedValue(collateralAmount, collateralPrice, collateralWeight);
|
|
330
|
-
const weightedDebtValue = calculateWeightedValue(debtAmount, debtPrice, debtWeight);
|
|
331
|
-
const netValue = weightedCollateralValue - weightedDebtValue;
|
|
332
|
-
if (netValue <= 0) {
|
|
333
|
-
throw new Error("Net value must be positive");
|
|
334
|
-
}
|
|
335
|
-
return weightedCollateralValue / netValue;
|
|
336
|
-
}
|
|
337
|
-
/**
|
|
338
|
-
* Calculates the debt to repay when withdrawing collateral to maintain the same leverage ratio
|
|
339
|
-
* @param currentCollateral - Current collateral amount
|
|
340
|
-
* @param currentDebt - Current debt amount
|
|
341
|
-
* @param withdrawAmount - Amount of collateral to withdraw
|
|
342
|
-
* @param collateralPrice - Price of collateral token
|
|
343
|
-
* @param debtPrice - Price of debt token
|
|
344
|
-
* @param collateralWeight - Weight of collateral (0-1)
|
|
345
|
-
* @param debtWeight - Weight of debt (1+)
|
|
346
|
-
* @returns Object containing the debt to repay and new leverage values
|
|
347
|
-
*/
|
|
348
|
-
function computeWithdrawLeverageAmounts(currentCollateral, currentDebt, withdrawAmount, collateralPrice, debtPrice, collateralWeight, debtWeight) {
|
|
349
|
-
// Calculate current leverage
|
|
350
|
-
const currentLeverage = calculateWeightedLeverage(currentCollateral, collateralPrice, collateralWeight, currentDebt, debtPrice, debtWeight);
|
|
351
|
-
// Ensure we don't withdraw more than available
|
|
352
|
-
if (withdrawAmount > currentCollateral) {
|
|
353
|
-
throw new Error("Withdrawal amount exceeds available collateral");
|
|
354
|
-
}
|
|
355
|
-
// Calculate new collateral amount
|
|
356
|
-
const newCollateral = currentCollateral - withdrawAmount;
|
|
357
|
-
// Calculate weighted collateral after withdrawal
|
|
358
|
-
const newWeightedCollateral = newCollateral * collateralPrice * collateralWeight;
|
|
359
|
-
// To maintain the same leverage, we need:
|
|
360
|
-
// currentLeverage = newWeightedCollateral / (newWeightedCollateral - newWeightedDebt)
|
|
361
|
-
//
|
|
362
|
-
// Solving for newWeightedDebt:
|
|
363
|
-
// currentLeverage * (newWeightedCollateral - newWeightedDebt) = newWeightedCollateral
|
|
364
|
-
// currentLeverage * newWeightedCollateral - currentLeverage * newWeightedDebt = newWeightedCollateral
|
|
365
|
-
// -currentLeverage * newWeightedDebt = newWeightedCollateral - currentLeverage * newWeightedCollateral
|
|
366
|
-
// -currentLeverage * newWeightedDebt = newWeightedCollateral * (1 - currentLeverage)
|
|
367
|
-
const newWeightedDebt = newWeightedCollateral * (1 - 1 / currentLeverage);
|
|
368
|
-
// Convert weighted debt to actual debt amount
|
|
369
|
-
const newDebt = newWeightedDebt / (debtPrice * debtWeight);
|
|
370
|
-
// Calculate debt to repay
|
|
371
|
-
const debtToRepay = currentDebt - newDebt;
|
|
372
|
-
// Calculate what the new leverage will be (should be very close to currentLeverage)
|
|
373
|
-
const newLeverage = calculateWeightedLeverage(newCollateral, collateralPrice, collateralWeight, newDebt, debtPrice, debtWeight);
|
|
374
|
-
return {
|
|
375
|
-
debtToRepayUi: debtToRepay,
|
|
376
|
-
newCollateralUi: newCollateral,
|
|
377
|
-
newDebtUi: newDebt,
|
|
378
|
-
currentLeverage,
|
|
379
|
-
newLeverage,
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
/**
|
|
383
|
-
* Calculates the health factor and leverage of a Clend account using weighted maintenance values.
|
|
384
|
-
*
|
|
385
|
-
* Standard Health Factor = Total Weighted Assets (Maintenance) / Total Weighted Liabilities (Maintenance)
|
|
386
|
-
* Interpretation:
|
|
387
|
-
* - HF > 1: Position is overcollateralized (safe).
|
|
388
|
-
* - HF = 1: Position is at the liquidation threshold.
|
|
389
|
-
* - HF < 1: Position is undercollateralized and liquidatable.
|
|
390
|
-
* - HF = Infinity: Position has no debt (healthiest).
|
|
391
|
-
*
|
|
392
|
-
* Leverage = Total Weighted Assets (Maintenance) / (Total Weighted Assets (Maintenance) - Total Weighted Liabilities (Maintenance))
|
|
393
|
-
*
|
|
394
|
-
* @param weightedAssetValues - An array of the user's weighted asset values (maintenance).
|
|
395
|
-
* @param weightedLiabilityValues - An array of the user's weighted liability values (maintenance).
|
|
396
|
-
* @returns An object containing the healthFactor and leverage.
|
|
397
|
-
*/
|
|
398
|
-
function calculateHealthFactorAndLeverage(weightedAssetValues, weightedLiabilityValues) {
|
|
399
|
-
let totalWeightedAssets = 0;
|
|
400
|
-
for (const weightedAssetValue of weightedAssetValues) {
|
|
401
|
-
totalWeightedAssets += weightedAssetValue;
|
|
402
|
-
}
|
|
403
|
-
let totalWeightedLiabilities = 0;
|
|
404
|
-
for (const weightedLiabilityValue of weightedLiabilityValues) {
|
|
405
|
-
totalWeightedLiabilities += weightedLiabilityValue;
|
|
406
|
-
}
|
|
407
|
-
// Calculate health factor using standard convention (Assets / Liabilities)
|
|
408
|
-
let healthFactor;
|
|
409
|
-
if (totalWeightedLiabilities === 0) {
|
|
410
|
-
// Handle division by zero: No liabilities means infinite health
|
|
411
|
-
healthFactor = Infinity;
|
|
412
|
-
}
|
|
413
|
-
else if (totalWeightedAssets === 0) {
|
|
414
|
-
// Handle edge case where assets are zero but liabilities are not (should imply HF=0)
|
|
415
|
-
healthFactor = 0;
|
|
416
|
-
}
|
|
417
|
-
else {
|
|
418
|
-
// Standard calculation
|
|
419
|
-
healthFactor = totalWeightedAssets / totalWeightedLiabilities;
|
|
420
|
-
}
|
|
421
|
-
// Calculate leverage (same formula as before, using weighted values)
|
|
422
|
-
let leverage = 0; // Default to 0 if equity is zero or negative
|
|
423
|
-
const equity = totalWeightedAssets - totalWeightedLiabilities;
|
|
424
|
-
if (equity > 0 && totalWeightedAssets > 0) {
|
|
425
|
-
// Ensure equity is positive and avoid division by zero if assets are zero
|
|
426
|
-
leverage = totalWeightedAssets / equity;
|
|
427
|
-
}
|
|
428
|
-
else if (totalWeightedAssets > 0 && totalWeightedLiabilities === 0) {
|
|
429
|
-
// If only assets exist, leverage is 1x
|
|
430
|
-
leverage = 1;
|
|
431
|
-
}
|
|
432
|
-
return { healthFactor, leverage };
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* Calculates the interest that has accrued but not yet been applied to a bank
|
|
436
|
-
* @param lastUpdate The timestamp of the last update
|
|
437
|
-
* @param assetAmountUi The total asset amount in UI format
|
|
438
|
-
* @param liabilityAmountUi The total liability amount in UI format
|
|
439
|
-
* @param utilizationRate The current utilization rate
|
|
440
|
-
* @param interestRateConfig The interest rate configuration
|
|
441
|
-
* @param currentTimestamp Optional current timestamp (in seconds). Defaults to Math.floor(Date.now() / 1000)
|
|
442
|
-
* @returns Object containing:
|
|
443
|
-
* - assetInterestAccrued: Interest accrued for lenders (in token units)
|
|
444
|
-
* - liabilityInterestAccrued: Interest accrued for borrowers (in token units)
|
|
445
|
-
* - insuranceFeesAccrued: Insurance fees accrued (in token units)
|
|
446
|
-
* - groupFeesAccrued: Group fees accrued (in token units)
|
|
447
|
-
* - protocolFeesAccrued: Protocol fees accrued (in token units)
|
|
448
|
-
*/
|
|
449
|
-
function calculateAccruedInterest(lastUpdate, assetAmountUi, liabilityAmountUi, utilizationRate, interestRateConfig, currentTimestamp) {
|
|
450
|
-
const timeDelta = currentTimestamp - lastUpdate.toNumber();
|
|
451
|
-
// If no time has passed, return zero values
|
|
452
|
-
if (timeDelta <= 0) {
|
|
453
|
-
return {
|
|
454
|
-
assetInterestAccrued: 0,
|
|
455
|
-
liabilityInterestAccrued: 0,
|
|
456
|
-
insuranceFeesAccrued: 0,
|
|
457
|
-
groupFeesAccrued: 0,
|
|
458
|
-
protocolFeesAccrued: 0,
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
// Get total assets and liabilities
|
|
462
|
-
const totalAssets = assetAmountUi;
|
|
463
|
-
const totalLiabilities = liabilityAmountUi;
|
|
464
|
-
// If either total assets or liabilities are zero, return zero values
|
|
465
|
-
if (totalAssets === 0 || totalLiabilities === 0) {
|
|
466
|
-
return {
|
|
467
|
-
assetInterestAccrued: 0,
|
|
468
|
-
liabilityInterestAccrued: 0,
|
|
469
|
-
insuranceFeesAccrued: 0,
|
|
470
|
-
groupFeesAccrued: 0,
|
|
471
|
-
protocolFeesAccrued: 0,
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
// Get interest rate configuration
|
|
475
|
-
const { optimalUtilizationRate, plateauInterestRate, maxInterestRate, insuranceFeeFixedApr, insuranceIrFee, protocolFixedFeeApr, protocolIrFee, } = interestRateConfig;
|
|
476
|
-
// Calculate base interest rate
|
|
477
|
-
const baseInterestRate = calculateBaseInterestRate(utilizationRate, optimalUtilizationRate, plateauInterestRate, maxInterestRate);
|
|
478
|
-
// Calculate lending rate (supply rate)
|
|
479
|
-
const lendingRate = baseInterestRate * utilizationRate * (1 - (protocolIrFee + insuranceIrFee));
|
|
480
|
-
// Calculate borrowing rate
|
|
481
|
-
const borrowingRate = baseInterestRate * (1 + protocolIrFee) +
|
|
482
|
-
protocolFixedFeeApr +
|
|
483
|
-
insuranceFeeFixedApr;
|
|
484
|
-
// Calculate fee rates
|
|
485
|
-
const insuranceFeeRate = baseInterestRate * insuranceIrFee + insuranceFeeFixedApr;
|
|
486
|
-
const groupFeeRate = baseInterestRate * protocolIrFee + protocolFixedFeeApr;
|
|
487
|
-
const protocolFeeRate = baseInterestRate * protocolIrFee + protocolFixedFeeApr;
|
|
488
|
-
// Calculate interest accrued for the time period
|
|
489
|
-
const secondsPerYear = 365 * 24 * 60 * 60;
|
|
490
|
-
const timeDeltaFraction = timeDelta / secondsPerYear;
|
|
491
|
-
// Calculate asset interest accrued (for lenders)
|
|
492
|
-
const assetInterestAccrued = totalAssets * lendingRate * timeDeltaFraction;
|
|
493
|
-
// Calculate liability interest accrued (for borrowers)
|
|
494
|
-
const liabilityInterestAccrued = totalLiabilities * borrowingRate * timeDeltaFraction;
|
|
495
|
-
// Calculate fees accrued
|
|
496
|
-
const insuranceFeesAccrued = totalLiabilities * insuranceFeeRate * timeDeltaFraction;
|
|
497
|
-
const groupFeesAccrued = totalLiabilities * groupFeeRate * timeDeltaFraction;
|
|
498
|
-
const protocolFeesAccrued = totalLiabilities * protocolFeeRate * timeDeltaFraction;
|
|
499
|
-
return {
|
|
500
|
-
assetInterestAccrued,
|
|
501
|
-
liabilityInterestAccrued,
|
|
502
|
-
insuranceFeesAccrued,
|
|
503
|
-
groupFeesAccrued,
|
|
504
|
-
protocolFeesAccrued,
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
* Adjusts an ideal borrow amount downwards solely to compensate for the
|
|
509
|
-
* protocol's origination fee. This calculates the principal amount to borrow
|
|
510
|
-
* such that after the fee is added, the liability matches the ideal amount.
|
|
511
|
-
*
|
|
512
|
-
* @param idealBorrowAmount - The target borrow amount before considering the fee (native units, BN).
|
|
513
|
-
* @param originationFeeRate - The protocol origination fee rate (e.g., 0.001 for 0.1%).
|
|
514
|
-
* @returns Adjusted borrow amount (native units, BN), slightly less than or equal to ideal.
|
|
515
|
-
*/
|
|
516
|
-
function adjustBorrowForOriginationFee(idealBorrowAmount, originationFeeRate) {
|
|
517
|
-
// Ensure the fee rate is valid
|
|
518
|
-
if (originationFeeRate < 0) {
|
|
519
|
-
return idealBorrowAmount;
|
|
520
|
-
}
|
|
521
|
-
const feeRateDecimal = new decimal_js_1.Decimal(originationFeeRate);
|
|
522
|
-
// If there's no fee, no adjustment is needed
|
|
523
|
-
if (feeRateDecimal.isZero()) {
|
|
524
|
-
return idealBorrowAmount;
|
|
525
|
-
}
|
|
526
|
-
// Formula: B_actual ≈ B_ideal / (1 + FeeRate)
|
|
527
|
-
// We borrow slightly less, anticipating the fee being added to the liability.
|
|
528
|
-
const denominator = new decimal_js_1.Decimal(1).add(feeRateDecimal);
|
|
529
|
-
// Safety check for the denominator (should not happen with non-negative fee)
|
|
530
|
-
if (denominator.isZero() ||
|
|
531
|
-
denominator.isNaN() ||
|
|
532
|
-
!denominator.isFinite() ||
|
|
533
|
-
denominator.isNegative()) {
|
|
534
|
-
return idealBorrowAmount;
|
|
535
|
-
}
|
|
536
|
-
const idealBorrowDecimal = new decimal_js_1.Decimal(idealBorrowAmount.toString());
|
|
537
|
-
const adjustedBorrowDecimal = idealBorrowDecimal.div(denominator);
|
|
538
|
-
// Round down when reducing the borrow amount due to the fee cost.
|
|
539
|
-
const adjustedBorrowAmount = new anchor_1.BN(adjustedBorrowDecimal.floor().toFixed());
|
|
540
|
-
// Ensure we don't adjust below zero
|
|
541
|
-
return anchor_1.BN.max(adjustedBorrowAmount, new anchor_1.BN(0));
|
|
542
|
-
}
|
|
543
|
-
/**
|
|
544
|
-
* Adjusts an amount upwards to compensate for potential swap slippage,
|
|
545
|
-
* assuming worst-case based on slippageBps.
|
|
546
|
-
*
|
|
547
|
-
* @param amountToAdjust - The amount to adjust (native units, BN), typically after cost adjustments.
|
|
548
|
-
* @param slippageBps - The maximum slippage tolerance in basis points (e.g., 100 for 1%).
|
|
549
|
-
* @returns Adjusted amount (native units, BN), slightly more than the input amount. Returns input amount if slippageBps is zero or invalid.
|
|
550
|
-
*/
|
|
551
|
-
function adjustAmountForSlippage(amountToAdjust, slippageBps) {
|
|
552
|
-
if (slippageBps <= 0) {
|
|
553
|
-
return amountToAdjust; // No adjustment if no slippage tolerance
|
|
554
|
-
}
|
|
555
|
-
const S = new decimal_js_1.Decimal(slippageBps).div(10000); // Slippage factor S as decimal
|
|
556
|
-
// Ensure S is less than 1 (100% slippage)
|
|
557
|
-
if (S.gte(1)) {
|
|
558
|
-
return amountToAdjust;
|
|
559
|
-
}
|
|
560
|
-
// Formula: B_actual ≈ B_ideal / (1 - S)
|
|
561
|
-
// We borrow slightly more, anticipating the swap output will be worth less by factor S.
|
|
562
|
-
const denominator = new decimal_js_1.Decimal(1).sub(S);
|
|
563
|
-
// Should not happen with S < 1, but safety check
|
|
564
|
-
if (denominator.isZero() ||
|
|
565
|
-
denominator.isNaN() ||
|
|
566
|
-
!denominator.isFinite() ||
|
|
567
|
-
denominator.isNegative()) {
|
|
568
|
-
return amountToAdjust;
|
|
569
|
-
}
|
|
570
|
-
const amountToAdjustDecimal = new decimal_js_1.Decimal(amountToAdjust.toString());
|
|
571
|
-
const adjustedAmountDecimal = amountToAdjustDecimal.div(denominator);
|
|
572
|
-
// Round up when increasing amount due to needing more input for slippage
|
|
573
|
-
const adjustedAmount = new anchor_1.BN(adjustedAmountDecimal.ceil().toFixed());
|
|
574
|
-
return adjustedAmount;
|
|
575
|
-
}
|
|
576
|
-
/**
|
|
577
|
-
* Calculates the estimated liquidation price for a collateral asset.
|
|
578
|
-
*
|
|
579
|
-
* Liquidation is possible when the risk-adjusted value of debt meets or exceeds
|
|
580
|
-
* the risk-adjusted value of the collateral, based on maintenance requirements.
|
|
581
|
-
*
|
|
582
|
-
* Formula:
|
|
583
|
-
* CollateralLiquidationPrice = (DebtAmount * DebtPrice * DebtMaintenanceLiabilityWeight) / (CollateralAmount * CollateralMaintenanceAssetWeight)
|
|
584
|
-
*
|
|
585
|
-
* @param collateralAmount The amount of the collateral asset deposited (e.g., number of JLP tokens).
|
|
586
|
-
* @param collateralMaintenanceAssetWeight The maintenance asset weight for the collateral asset (e.g., 0.85 for 85%). Found in Marginfi protocol config/UI.
|
|
587
|
-
* @param debtAmount The amount of the debt asset borrowed (e.g., number of USDC tokens).
|
|
588
|
-
* @param debtMaintenanceLiabilityWeight The maintenance liability weight for the debt asset (e.g., 1.1 for 110%). Found in Marginfi protocol config/UI.
|
|
589
|
-
* @param debtPrice The current price of the debt asset.
|
|
590
|
-
* @returns The estimated price of the collateral asset at which liquidation may occur, or Infinity if collateral amount/weight is zero.
|
|
591
|
-
*/
|
|
592
|
-
function calculateLiquidationPrice(collateralAmountUi, collateralMaintenanceAssetWeight, debtAmountUi, debtMaintenanceLiabilityWeight, debtPrice) {
|
|
593
|
-
// Ensure inputs are valid numbers
|
|
594
|
-
if (isNaN(collateralAmountUi) ||
|
|
595
|
-
isNaN(collateralMaintenanceAssetWeight) ||
|
|
596
|
-
isNaN(debtAmountUi) ||
|
|
597
|
-
isNaN(debtMaintenanceLiabilityWeight) ||
|
|
598
|
-
isNaN(debtPrice)) {
|
|
599
|
-
throw new Error("All input parameters must be valid numbers.");
|
|
600
|
-
}
|
|
601
|
-
// if 0 values just return 0
|
|
602
|
-
if (collateralAmountUi === 0 ||
|
|
603
|
-
debtAmountUi === 0 ||
|
|
604
|
-
debtPrice === 0 ||
|
|
605
|
-
collateralMaintenanceAssetWeight === 0 ||
|
|
606
|
-
debtMaintenanceLiabilityWeight === 0) {
|
|
607
|
-
return 0;
|
|
608
|
-
}
|
|
609
|
-
// Calculate the weighted value of the collateral side (denominator)
|
|
610
|
-
const weightedCollateralValueFactor = collateralAmountUi * collateralMaintenanceAssetWeight;
|
|
611
|
-
// Avoid division by zero if collateral amount or weight is zero
|
|
612
|
-
if (weightedCollateralValueFactor <= 0) {
|
|
613
|
-
throw new Error(`collateral amount is 0 or less`);
|
|
614
|
-
}
|
|
615
|
-
// Calculate the weighted value of the debt side (numerator)
|
|
616
|
-
const weightedDebtValue = debtAmountUi * debtPrice * debtMaintenanceLiabilityWeight;
|
|
617
|
-
// Calculate the liquidation price
|
|
618
|
-
const liquidationPrice = weightedDebtValue / weightedCollateralValueFactor;
|
|
619
|
-
return liquidationPrice;
|
|
620
|
-
}
|
|
621
|
-
/**
|
|
622
|
-
* Calculates the Loan-to-Value (LTV) ratio.
|
|
623
|
-
* LTV = Total Value of Liabilities / Total Value of Assets
|
|
624
|
-
*
|
|
625
|
-
* Note: The input values can be either weighted (initial or maintenance) or unweighted USD values,
|
|
626
|
-
* as long as the same type of value is used consistently for both assets and liabilities.
|
|
627
|
-
* The interpretation of the LTV depends on the type of values used.
|
|
628
|
-
*
|
|
629
|
-
* @param {number[]} assetValues - An array of the user's asset values (e.g., USD value, weighted or unweighted).
|
|
630
|
-
* @param {number[]} liabilityValues - An array of the user's liability values (e.g., USD value, weighted or unweighted).
|
|
631
|
-
* @returns {number} The LTV ratio. Returns 0 if there are no liabilities. Returns `NaN` if total asset value is zero or negative.
|
|
632
|
-
*/
|
|
633
|
-
function calculateLtv(assetValues, liabilityValues) {
|
|
634
|
-
let totalAssetValue = 0;
|
|
635
|
-
for (const value of assetValues) {
|
|
636
|
-
totalAssetValue += value;
|
|
637
|
-
}
|
|
638
|
-
let totalLiabilityValue = 0;
|
|
639
|
-
for (const value of liabilityValues) {
|
|
640
|
-
totalLiabilityValue += value;
|
|
641
|
-
}
|
|
642
|
-
// If there are no assets (or negative total value), LTV is undefined.
|
|
643
|
-
if (totalAssetValue <= 0) {
|
|
644
|
-
// Return NaN if liabilities exist but assets don't, or if assets have zero/negative value.
|
|
645
|
-
// Return 0 if both are zero (as technically liabilities are 0).
|
|
646
|
-
return totalLiabilityValue === 0 ? 0 : NaN;
|
|
647
|
-
}
|
|
648
|
-
// If there are no liabilities, LTV is 0.
|
|
649
|
-
if (totalLiabilityValue === 0) {
|
|
650
|
-
return 0;
|
|
651
|
-
}
|
|
652
|
-
// Standard LTV calculation
|
|
653
|
-
const ltv = totalLiabilityValue / totalAssetValue;
|
|
654
|
-
return ltv;
|
|
655
|
-
}
|
|
656
|
-
/**
|
|
657
|
-
* Calculates the percentage change required for the current price to reach the liquidation price.
|
|
658
|
-
*
|
|
659
|
-
* @param currentPrice The current price of the asset.
|
|
660
|
-
* @param liquidationPrice The price at which the asset would be liquidated.
|
|
661
|
-
* @returns The percentage change needed to reach the liquidation price (e.g., -10.5 for a 10.5% drop). Returns Infinity if currentPrice is 0.
|
|
662
|
-
*/
|
|
663
|
-
function calculateLiquidationPriceChangePercentage(currentPrice, liquidationPrice) {
|
|
664
|
-
if (currentPrice <= 0) {
|
|
665
|
-
return 0;
|
|
666
|
-
}
|
|
667
|
-
const priceChange = liquidationPrice - currentPrice;
|
|
668
|
-
const percentageChange = (priceChange / currentPrice) * 100;
|
|
669
|
-
return percentageChange;
|
|
670
|
-
}
|
|
671
|
-
/**
|
|
672
|
-
* Calculates the current liability interest for a specific liability position,
|
|
673
|
-
* accounting for interest accrued since the bank's last update.
|
|
674
|
-
*
|
|
675
|
-
* @param userLiabilitySharesBN - The user's liability shares for the debt asset (native units, BN).
|
|
676
|
-
* @param bankLiabilityShareValue - The bank's liability share value as of last update (number).
|
|
677
|
-
* @param bankBorrowApy - The current estimated borrow APY of the debt asset (e.g., 0.025 for 2.5%).
|
|
678
|
-
* @param bankLastUpdateSeconds - The Unix timestamp (seconds) when the bank's interest was last updated on-chain.
|
|
679
|
-
* @param currentTimeSeconds - The current Unix timestamp (seconds).
|
|
680
|
-
* @returns The estimated current debt amount for the user (native units, BN).
|
|
681
|
-
*/
|
|
682
|
-
function calculateLiabilityInterest(userLiabilityShares, bankLiabilityShareValue, bankBorrowApy, bankLastUpdateSeconds, currentTimeSeconds) {
|
|
683
|
-
// If user has no liability shares for this bank, debt is zero.
|
|
684
|
-
if (userLiabilityShares <= 0) {
|
|
685
|
-
return new anchor_1.BN(0);
|
|
686
|
-
}
|
|
687
|
-
// Calculate time delta
|
|
688
|
-
const secondsSinceLastUpdate = currentTimeSeconds - bankLastUpdateSeconds;
|
|
689
|
-
let currentLiabilityShareValue;
|
|
690
|
-
// hardcode for now
|
|
691
|
-
const secondsPerYear = 31536000;
|
|
692
|
-
// Calculate the current share value if time has passed and interest rate is positive
|
|
693
|
-
if (secondsSinceLastUpdate > 0) {
|
|
694
|
-
const interestRatePerSecond = bankBorrowApy / secondsPerYear;
|
|
695
|
-
const growthFactor = interestRatePerSecond * secondsSinceLastUpdate + 1;
|
|
696
|
-
currentLiabilityShareValue = bankLiabilityShareValue * growthFactor;
|
|
697
|
-
}
|
|
698
|
-
else {
|
|
699
|
-
// Otherwise, use the share value as of the last update
|
|
700
|
-
currentLiabilityShareValue = bankLiabilityShareValue;
|
|
701
|
-
}
|
|
702
|
-
// Calculate estimated debt = user_shares * current_share_value
|
|
703
|
-
const debt = new anchor_1.BN(userLiabilityShares * currentLiabilityShareValue);
|
|
704
|
-
return debt;
|
|
705
|
-
}
|
|
706
|
-
/**
|
|
707
|
-
* Calculates the final debt repayment target amount by adding buffers
|
|
708
|
-
* for future interest accrual and minor discrepancies to an estimated current debt.
|
|
709
|
-
* this is used to calculate the final debt to repay amount taking into account tx execution time from when its calculated
|
|
710
|
-
*
|
|
711
|
-
* @param currentDebt - The current debt amount including interest accrued up to the present moment
|
|
712
|
-
* @param borrowApy - The current estimated borrow APY of the debt asset (e.g., 0.025 for 2.5%).
|
|
713
|
-
* @param futureInterestBufferSec - The estimated number of seconds of future interest to buffer for transaction execution time. As in, if it takes
|
|
714
|
-
* 10 seconds to execute the tx from when this is called, we will add 10 seconds of interest to the debt
|
|
715
|
-
* @returns The final debt repayment target amount (native units, BN).
|
|
716
|
-
*/
|
|
717
|
-
function addInterestAccrualBuffer(currentDebt, borrowApy, futureInterestBufferSec) {
|
|
718
|
-
// A small fixed buffer amount (in lamports/native units) to add for minor rounding or timing variations (default: 100).
|
|
719
|
-
const fixedBufferLamports = new anchor_1.BN(1000);
|
|
720
|
-
const SECONDS_PER_YEAR = 31536000;
|
|
721
|
-
let finalDebtToRepay = currentDebt;
|
|
722
|
-
// Add buffer for future interest during execution, if applicable
|
|
723
|
-
if (borrowApy > 0 && futureInterestBufferSec > 0 && !currentDebt.isZero()) {
|
|
724
|
-
const interestRatePerSecond = new decimal_js_1.Decimal(borrowApy).div(SECONDS_PER_YEAR);
|
|
725
|
-
// Calculate buffer based on the estimated current debt amount
|
|
726
|
-
const futureInterestDecimal = new decimal_js_1.Decimal(currentDebt.toString())
|
|
727
|
-
.mul(interestRatePerSecond)
|
|
728
|
-
.mul(futureInterestBufferSec);
|
|
729
|
-
// Round UP the future interest amount to be conservative
|
|
730
|
-
const futureInterestBN = new anchor_1.BN(futureInterestDecimal.ceil().toFixed());
|
|
731
|
-
finalDebtToRepay = finalDebtToRepay.add(futureInterestBN);
|
|
732
|
-
}
|
|
733
|
-
// Add the small fixed buffer
|
|
734
|
-
finalDebtToRepay = finalDebtToRepay.add(fixedBufferLamports);
|
|
735
|
-
return finalDebtToRepay;
|
|
736
|
-
}
|
|
737
|
-
//# sourceMappingURL=math.js.map
|