@strkfarm/sdk 1.2.0 → 2.0.0-dev-strategy2.1

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.
Files changed (60) hide show
  1. package/dist/index.browser.global.js +76556 -66640
  2. package/dist/index.browser.mjs +34235 -24392
  3. package/dist/index.d.ts +2372 -793
  4. package/dist/index.js +31967 -22084
  5. package/dist/index.mjs +25545 -15719
  6. package/package.json +86 -76
  7. package/readme.md +56 -1
  8. package/src/data/extended-deposit.abi.json +3613 -0
  9. package/src/data/universal-vault.abi.json +135 -20
  10. package/src/dataTypes/_bignumber.ts +11 -0
  11. package/src/dataTypes/address.ts +7 -0
  12. package/src/global.ts +240 -193
  13. package/src/interfaces/common.tsx +26 -2
  14. package/src/modules/ExtendedWrapperSDk/index.ts +62 -0
  15. package/src/modules/ExtendedWrapperSDk/types.ts +311 -0
  16. package/src/modules/ExtendedWrapperSDk/wrapper.ts +448 -0
  17. package/src/modules/avnu.ts +17 -4
  18. package/src/modules/ekubo-quoter.ts +89 -10
  19. package/src/modules/erc20.ts +67 -21
  20. package/src/modules/harvests.ts +29 -43
  21. package/src/modules/index.ts +5 -1
  22. package/src/modules/lst-apr.ts +36 -0
  23. package/src/modules/midas.ts +159 -0
  24. package/src/modules/pricer-from-api.ts +2 -2
  25. package/src/modules/pricer-lst.ts +1 -1
  26. package/src/modules/pricer.ts +3 -38
  27. package/src/modules/token-market-data.ts +202 -0
  28. package/src/node/deployer.ts +1 -36
  29. package/src/strategies/autoCompounderStrk.ts +1 -1
  30. package/src/strategies/base-strategy.ts +20 -3
  31. package/src/strategies/btc-vesu-extended-strategy/core-strategy.tsx +1486 -0
  32. package/src/strategies/btc-vesu-extended-strategy/services/operationService.ts +32 -0
  33. package/src/strategies/btc-vesu-extended-strategy/utils/constants.ts +3 -0
  34. package/src/strategies/btc-vesu-extended-strategy/utils/helper.ts +396 -0
  35. package/src/strategies/btc-vesu-extended-strategy/utils/types.ts +5 -0
  36. package/src/strategies/ekubo-cl-vault.tsx +123 -306
  37. package/src/strategies/index.ts +7 -1
  38. package/src/strategies/svk-strategy.ts +247 -0
  39. package/src/strategies/universal-adapters/adapter-optimizer.ts +65 -0
  40. package/src/strategies/universal-adapters/adapter-utils.ts +5 -1
  41. package/src/strategies/universal-adapters/avnu-adapter.ts +432 -0
  42. package/src/strategies/universal-adapters/baseAdapter.ts +181 -153
  43. package/src/strategies/universal-adapters/common-adapter.ts +98 -77
  44. package/src/strategies/universal-adapters/extended-adapter.ts +976 -0
  45. package/src/strategies/universal-adapters/index.ts +7 -1
  46. package/src/strategies/universal-adapters/unused-balance-adapter.ts +109 -0
  47. package/src/strategies/universal-adapters/vesu-adapter.ts +230 -230
  48. package/src/strategies/universal-adapters/vesu-borrow-adapter.ts +1247 -0
  49. package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +1306 -0
  50. package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +58 -51
  51. package/src/strategies/universal-lst-muliplier-strategy.tsx +716 -844
  52. package/src/strategies/universal-strategy.tsx +1103 -1181
  53. package/src/strategies/vesu-extended-strategy/services/operationService.ts +34 -0
  54. package/src/strategies/vesu-extended-strategy/types/transaction-metadata.ts +25 -0
  55. package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +77 -0
  56. package/src/strategies/vesu-extended-strategy/utils/constants.ts +50 -0
  57. package/src/strategies/vesu-extended-strategy/utils/helper.ts +367 -0
  58. package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +1420 -0
  59. package/src/strategies/vesu-rebalance.tsx +16 -20
  60. package/src/utils/health-factor-math.ts +11 -5
@@ -0,0 +1,34 @@
1
+ import { Web3Number } from "@/dataTypes";
2
+ import { TokenInfo } from "@/interfaces";
3
+ import { ExtendedAdapter } from "@/strategies/universal-adapters/extended-adapter";
4
+ import { VesuMultiplyAdapter } from "../../universal-adapters/vesu-multiply-adapter";
5
+ import { Call } from "starknet";
6
+ export abstract class Operations {
7
+ abstract shouldMoveAssets(
8
+ extendedAmount: Web3Number,
9
+ vesuAmount: Web3Number
10
+ ): Promise<Call[]>;
11
+ abstract shouldInvest(): Promise<{
12
+ shouldInvest: boolean;
13
+ vesuAmount: Web3Number;
14
+ extendedAmount: Web3Number;
15
+ extendedLeverage: number;
16
+ vesuLeverage: number;
17
+ }>;
18
+ abstract moveAssets(
19
+ params: { from: string; to: string; amount: Web3Number },
20
+ extendedAdapter: ExtendedAdapter,
21
+ vesuAdapter: VesuMultiplyAdapter
22
+ ): Promise<{
23
+ calls: Call[];
24
+ status: boolean;
25
+ }>;
26
+ abstract handleDeposit(): Promise<{
27
+ extendedAmountInBTC: Web3Number;
28
+ calls: Call[];
29
+ }>;
30
+ abstract handleWithdraw(amount: Web3Number): Promise<{
31
+ calls: Call[];
32
+ status: boolean;
33
+ }> ;
34
+ }
@@ -0,0 +1,25 @@
1
+ import { Protocols } from "@/interfaces";
2
+ import { Call } from "starknet";
3
+
4
+ /**
5
+ * Transaction metadata that SDK generates and risk engine stores in DB.
6
+ * This metadata is used to track transaction lifecycle without coupling SDK to DB.
7
+ */
8
+ export interface TransactionMetadata {
9
+ protocolFrom: typeof Protocols;
10
+ protocolTo: typeof Protocols;
11
+ transactionType: 'DEPOSIT' | 'WITHDRAWAL';
12
+ usdAmount: string;
13
+ }
14
+
15
+ /**
16
+ * Enhanced return type for operations that generate transactions.
17
+ * Includes both the calls (for execution) and metadata (for DB storage).
18
+ */
19
+ export interface TransactionResult<T = any> {
20
+ calls: Call[];
21
+ status: boolean;
22
+ transactionMetadata: TransactionMetadata;
23
+ }
24
+
25
+
@@ -0,0 +1,77 @@
1
+ import {
2
+ AVNU_API,
3
+ USDC_TOKEN_ADDRESS,
4
+ USDC_TOKEN_DECIMALS,
5
+ WBTC_TOKEN_ADDRESS,
6
+ WBTC_TOKEN_DECIMALS,
7
+ WALLET_ADDRESS,
8
+ EXTEND_CONTRACT_ADDRESS,
9
+ MULTIPLY_CONTRACT_ADDRESS,
10
+ EXTENDED_BASE_URL,
11
+ EXTEND_MARKET_NAME,
12
+ EXTENDED_QTY_PRECISION,
13
+ EXTENDED_FEES,
14
+ MAINTENANCE_MARGIN,
15
+ VESU_POOL_ID,
16
+ MAX_LTV_BTC_USDC,
17
+ MAX_LIQUIDATION_RATIO,
18
+ TARGET_HF,
19
+ EKUBO_ENDPOINT,
20
+ PRICE_MAX_SLIPPAGE_EKUBO,
21
+ MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING,
22
+ MINIMUM_EXTENDED_POSITION_SIZE
23
+ } from "./constants"
24
+ import VesuPoolV2Abi from '@/data/vesu-pool-v2.abi.json';
25
+ import ExtendedDepositAbi from '@/data/extended-deposit.abi.json';
26
+ import VesuMultiplyAbi from '@/data/vesu-multiple.abi.json';
27
+
28
+ // Grouped, readable configuration (no behavior change). Consumers can migrate gradually.
29
+
30
+ export const AddressesConfig = {
31
+ tokens: {
32
+ USDC: { address: USDC_TOKEN_ADDRESS, decimals: USDC_TOKEN_DECIMALS },
33
+ WBTC: { address: WBTC_TOKEN_ADDRESS, decimals: WBTC_TOKEN_DECIMALS },
34
+ },
35
+ contracts: {
36
+ EXTENDED: EXTEND_CONTRACT_ADDRESS,
37
+ MULTIPLY: MULTIPLY_CONTRACT_ADDRESS,
38
+ },
39
+ wallet: {
40
+ address: WALLET_ADDRESS,
41
+ },
42
+ } as const;
43
+
44
+ export const ExtendedConfig = {
45
+ baseUrl: EXTENDED_BASE_URL,
46
+ marketName: EXTEND_MARKET_NAME,
47
+ maintenanceMargin: MAINTENANCE_MARGIN,
48
+ precision: EXTENDED_QTY_PRECISION,
49
+ fees: EXTENDED_FEES,
50
+ minPositionSize: MINIMUM_EXTENDED_POSITION_SIZE,
51
+ } as const;
52
+
53
+ export const VesuConfig = {
54
+ poolId: VESU_POOL_ID,
55
+ maxLtv: MAX_LTV_BTC_USDC,
56
+ maxLiquidationRatio: MAX_LIQUIDATION_RATIO,
57
+ targetHealthFactor: TARGET_HF,
58
+ ekubo: {
59
+ endpoint: EKUBO_ENDPOINT,
60
+ priceMaxSlippage: PRICE_MAX_SLIPPAGE_EKUBO,
61
+ },
62
+ avnu: {
63
+ api: AVNU_API,
64
+ },
65
+ minDebtForVesuRebalacing:MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING
66
+ } as const;
67
+
68
+ export const AbisConfig = {
69
+ vesu: {
70
+ multiply: VesuMultiplyAbi,
71
+ pool: VesuPoolV2Abi,
72
+ },
73
+ extended: {
74
+ contract: ExtendedDepositAbi,
75
+ },
76
+ } as const;
77
+
@@ -0,0 +1,50 @@
1
+ export const AVNU_API = "https://starknet.api.avnu.fi/swap/v2/quotes";
2
+ export const SLIPPAGE = 0.01;
3
+ export const USDC_TOKEN_DECIMALS = 6;
4
+ export const USDC_TOKEN_ADDRESS =
5
+ "0x053C91253BC9682c04929cA02ED00b3E423f6710D2ee7e0D5EBB06F3eCF368A8";
6
+ export const BUFFER_USDC_IN_WITHDRAWAL=5;
7
+ export const WBTC_TOKEN_ADDRESS = "0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac";
8
+ export const WBTC_TOKEN_DECIMALS = 8;
9
+ export const MAINTENANCE_MARGIN = 0.01;
10
+ export const MAX_PRICE_DROP_PERCENTAGE = Number(process.env.MAX_PRICE_DROP_PERCENTAGE ?? 0.25);
11
+ export const MAX_LTV_BTC_USDC = 0.8428;
12
+ export const MAX_LIQUIDATION_RATIO = 0.86;
13
+ export const VAULT_ID_EXTENDED= process.env.VAULT_ID_EXTENDED ?? 220774;
14
+ export const WALLET_ADDRESS =
15
+ process.env.WALLET_ADDRESS ?? "0x07b84bb6E87588BdAde0bfe6173A615b3C220F9C3803456aE183C50EA1d15Ba1";
16
+ export const TESTNET_WALLET_ADDRESS =
17
+ process.env.TESTNET_WALLET_ADDRESS ?? "0x07b84bb6E87588BdAde0bfe6173A615b3C220F9C3803456aE183C50EA1d15Ba1";
18
+ export const TEST_WALLET_2 =
19
+ process.env.TEST_WALLET_2 ?? "0x004C1bdC61DAc7947F3C93d0163d660012E2aB0521567f7155fcf502848791A7";
20
+ export const STRK_API_TEST_RPC = process.env.STRK_API_TEST_RPC ?? "https://sepolia.starknet.a5a.ch";
21
+ export const STRK_API_RPC = process.env.STRK_API_RPC ?? "https://mainnet.starknet.a5a.ch";
22
+ export const MAX_RETRIES = Number(process.env.MAX_RETRIES ?? 3);
23
+ export const MAX_DELAY = Number(process.env.MAX_DELAY ?? 1500);
24
+ export const EXTEND_MARKET_NAME = "BTC-USD";
25
+ export const LIMIT_BALANCE = Number(process.env.LIMIT_BALANCE ?? 0.05);
26
+ export const LIMIT_BALANCE_VALUE=5;
27
+ export const REBALANCER_INTERVAL = Number(process.env.REBALANCER_INTERVAL ?? 180000); //3 mins
28
+ export const WITHDRAWAL_INTERVAL = Number(process.env.WITHDRAWAL_INTERVAL ?? 18000000); //5 hours
29
+ export const INVESTING_INTERVAL = Number(process.env.INVESTING_INTERVAL ?? 180000); //3 mins
30
+ export const MAXIMUM_DELTA = Number(process.env.MAXIMUM_DELTA ?? 5);
31
+ export const EXTENDED_BASE_URL = process.env.EXTENDED_BASE_URL ?? "https://api.starknet.extended.exchange";
32
+ export const VESU_POOL_ID = "0x02eef0c13b10b487ea5916b54c0a7f98ec43fb3048f60fdeedaf5b08f6f88aaf";
33
+ export const EKUBO_ENDPOINT = "https://quoter-mainnet-api.ekubo.org/{{AMOUNT}}/{{TOKEN_FROM_ADDRESS}}/{{TOKEN_TO_ADDRESS}}"; // e.g. ETH/USDC'
34
+ export const TARGET_HF = Number(process.env.TARGET_HF ?? 1.4);
35
+ export const MULTIPLY_CONTRACT_ADDRESS = "0x07964760e90baa28841ec94714151e03fbc13321797e68a874e88f27c9d58513";
36
+ export const EXTEND_CONTRACT_ADDRESS = "0x062da0780fae50d68cecaa5a051606dc21217ba290969b302db4dd99d2e9b470";
37
+ export const EXTENDED_QTY_PRECISION = 5;
38
+ export const EXTENDED_FEES= Number(process.env.EXTENDED_FEES ?? 0.006);
39
+ export const REBALANCE_PRICE_DROP_PERCENTAGE = Number(process.env.REBALANCE_PRICE_DROP_PERCENTAGE ?? 3);
40
+ export const PRICE_MAX_SLIPPAGE_EKUBO = Number(process.env.PRICE_MAX_SLIPPAGE_EKUBO ?? 0.005);
41
+ export const MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING = Number(process.env.MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING ?? 1);
42
+ export const MINIMUM_EXTENDED_POSITION_SIZE = 0.0001;
43
+ export const MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP = 0.00001;
44
+ export const MAX_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED = 700;
45
+ export const MIN_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED = -100;
46
+
47
+ //STATUS CODES
48
+ export const SUCCESS_STATUS_CODE = 200;
49
+ export const ERROR_STATUS_CODE = 500;
50
+ export const BAD_REQUEST_STATUS_CODE = 400;
@@ -0,0 +1,367 @@
1
+ import {
2
+ MAINTENANCE_MARGIN,
3
+ MAX_LTV_BTC_USDC,
4
+ MAX_PRICE_DROP_PERCENTAGE,
5
+ TARGET_HF,
6
+ WBTC_TOKEN_ADDRESS,
7
+ USDC_TOKEN_ADDRESS,
8
+ WBTC_TOKEN_DECIMALS,
9
+ USDC_TOKEN_DECIMALS,
10
+ MAX_LIQUIDATION_RATIO,
11
+ } from "./constants";
12
+ import { Web3Number } from "@/dataTypes";
13
+ import { Position } from "@/modules/ExtendedWrapperSDk";
14
+ // import { getAllOpenPositionsExtended } from "../services/extendedService";
15
+ import ExtendedWrapper from "@/modules/ExtendedWrapperSDk";
16
+ import { logger } from "@/utils";
17
+ // import {
18
+ // calculatePositionOnVesu,
19
+ // getAssetPrice,
20
+ // } from "../services/vesuService";
21
+ /**
22
+ * Function to return formatted amount to BigInt
23
+ * Converts a decimal amount to the proper format for blockchain transactions
24
+ * @param {number} amount - The decimal amount to convert
25
+ * @param {number} fromTokenDecimals - The decimal precision of the token
26
+ * @returns {string} The formatted amount as a hexadecimal string
27
+ */
28
+ export const returnFormattedAmount = (
29
+ amount: number,
30
+ toTokenDecimals: number
31
+ ) => {
32
+ const formattedAmount =
33
+ "0x" + BigInt(Math.floor(amount * 10 ** toTokenDecimals)).toString(16);
34
+ return formattedAmount;
35
+ };
36
+
37
+ /**
38
+ * calculates the amount to distribute to Extend and Vesu
39
+ * Determines how much to allocate to each platform based on leverage calculations
40
+ * @param {number} amount - The total amount to distribute
41
+ * @returns {object} Object containing avnu_amount, extended_amount, and extended_leverage
42
+ */
43
+ export const calculateAmountDistribution = async (
44
+ amount: number,
45
+ client: ExtendedWrapper,
46
+ marketName: string,
47
+ collateralPrice: number,
48
+ debtPrice: number,
49
+ collateralUnits: Web3Number,
50
+ extendedPosition: Position[] | null
51
+ ): Promise<{
52
+ vesu_amount: Web3Number;
53
+ extended_amount: Web3Number;
54
+ extended_leverage: number;
55
+ vesu_leverage: number;
56
+ }> => {
57
+ try {
58
+ const extended_leverage = calculateExtendedLevergae();
59
+ const vesu_leverage = calculateVesuLeverage();
60
+ if (extendedPosition === null) {
61
+ logger.error("error getting extended positions");
62
+ return {
63
+ vesu_amount: new Web3Number(0, 0),
64
+ extended_amount: new Web3Number(0, 0),
65
+ extended_leverage: 0,
66
+ vesu_leverage: 0,
67
+ };
68
+ }
69
+ const extendedExposureUSD =
70
+ extendedPosition.length > 0
71
+ ? new Web3Number(extendedPosition[0].value, WBTC_TOKEN_DECIMALS)
72
+ : new Web3Number(0, WBTC_TOKEN_DECIMALS);
73
+ const vesuBTCExposureUSD = collateralUnits.multipliedBy(collateralPrice);
74
+ const numerator1 = vesu_leverage * amount + vesuBTCExposureUSD.toNumber();
75
+ const numerator2 = extendedExposureUSD.toNumber();
76
+ const denominator = vesu_leverage + extended_leverage;
77
+ const ExtendedAmount = new Web3Number(
78
+ ((numerator1 - numerator2) / denominator).toFixed(2),
79
+ USDC_TOKEN_DECIMALS
80
+ );
81
+
82
+ const VesuAmount = new Web3Number(
83
+ amount.toFixed(2),
84
+ USDC_TOKEN_DECIMALS
85
+ ).minus(ExtendedAmount);
86
+
87
+ return {
88
+ vesu_amount: VesuAmount,
89
+ extended_amount: ExtendedAmount,
90
+ extended_leverage,
91
+ vesu_leverage,
92
+ };
93
+ } catch (err) {
94
+ return {
95
+ vesu_amount: new Web3Number(0, 0),
96
+ extended_amount: new Web3Number(0, 0),
97
+ extended_leverage: 0,
98
+ vesu_leverage: 0,
99
+ };
100
+ }
101
+ };
102
+
103
+ /**
104
+ * calculate the amount distribution for withdrawal
105
+ * @param amount - The amount to withdraw
106
+ * @param client - The client
107
+ * @param marketName - The market name
108
+ * @returns {object} Object containing avnu_amount and extended_amount
109
+ */
110
+ export const calculateAmountDistributionForWithdrawal = async (
111
+ amountInUsdc: Web3Number,
112
+ collateralPrice: number,
113
+ collateralUnits: Web3Number,
114
+ extendedPosition: Position[] | null
115
+ ): Promise<{
116
+ vesu_amount: Web3Number;
117
+ extended_amount: Web3Number;
118
+ extended_leverage: number;
119
+ vesu_leverage: number;
120
+ } | null> => {
121
+ try {
122
+ const extended_leverage = calculateExtendedLevergae();
123
+ const vesu_leverage = calculateVesuLeverage();
124
+ if (extendedPosition === null) {
125
+ logger.error("error getting extended positions");
126
+ return null;
127
+ }
128
+ const extendedExposureUSD =
129
+ extendedPosition.length > 0
130
+ ? new Web3Number(extendedPosition[0].value, USDC_TOKEN_DECIMALS)
131
+ : new Web3Number(0, USDC_TOKEN_DECIMALS);
132
+ const vesuExposureUSD = collateralUnits.multipliedBy(collateralPrice);
133
+ if (vesuExposureUSD.lessThan(0)) {
134
+ return {
135
+ vesu_amount: new Web3Number(0, USDC_TOKEN_DECIMALS),
136
+ extended_amount: amountInUsdc,
137
+ extended_leverage,
138
+ vesu_leverage,
139
+ };
140
+ }
141
+ if (extendedExposureUSD.lessThan(0)) {
142
+ return {
143
+ vesu_amount: amountInUsdc,
144
+ extended_amount: new Web3Number(0, USDC_TOKEN_DECIMALS),
145
+ extended_leverage,
146
+ vesu_leverage,
147
+ };
148
+ }
149
+ const numerator1 = amountInUsdc.multipliedBy(extended_leverage);
150
+ const numerator2 = vesuExposureUSD;
151
+ const numerator3 = extendedExposureUSD
152
+ .multipliedBy(-1);
153
+ const finalNumerator = numerator1.plus(numerator2).plus(numerator3);
154
+ const denominator = extended_leverage + vesu_leverage;
155
+ const vesuAmountInUSDC = finalNumerator.dividedBy(denominator);
156
+ console.log("the vesu amount in usdc is", vesuAmountInUSDC.toNumber());
157
+ const extendedAmountInUSDC = amountInUsdc.minus(vesuAmountInUSDC);
158
+ console.log(
159
+ "the extended amount in usdc is",
160
+ extendedAmountInUSDC.toNumber()
161
+ );
162
+ //console.log("the vesu amount in usdc is", vesuAmountInUSDC.toNumber());
163
+ //console.log("the extended amount in usdc is", extendedAmountInUSDC.toNumber());\
164
+ await new Promise((resolve) => setTimeout(resolve, 10000));
165
+ return {
166
+ vesu_amount: vesuAmountInUSDC,
167
+ extended_amount: extendedAmountInUSDC,
168
+ extended_leverage,
169
+ vesu_leverage,
170
+ };
171
+ } catch (err) {
172
+ logger.error(`error calculating amount distribution for withdrawal: ${err}`);
173
+ return null;
174
+ }
175
+ };
176
+ /**
177
+ * calculate the leverage required for Avnu
178
+ * calculates the optimal leverage for Avnu based on LTV ratios and price drop protection
179
+ * @returns {number} The calculated leverage value
180
+ */
181
+ export const calculateVesuLeverage = () => {
182
+ const max_ltv_ratio = (1 - MAX_PRICE_DROP_PERCENTAGE) * MAX_LIQUIDATION_RATIO; //0.75
183
+ const our_ltv_ratio = Math.floor(max_ltv_ratio * 100) - 5; //buffer of 5% to prevent liquidation
184
+ const leverage = 1 / (1 - our_ltv_ratio / 100);
185
+ return Math.ceil(leverage * 10) / 10;
186
+ };
187
+
188
+ /**
189
+ * calculate leverage for extended
190
+ * calculates the maximum safe leverage for Extended based on maintenance margin and price drop protection
191
+ * @returns {number} The calculated leverage value
192
+ */
193
+ export const calculateExtendedLevergae = () => {
194
+ const extended_leverage_max =
195
+ 1 / (MAINTENANCE_MARGIN + MAX_PRICE_DROP_PERCENTAGE);
196
+ return Math.floor(extended_leverage_max);
197
+ };
198
+
199
+ /**
200
+ * calculates the debt amount for leverage operations
201
+ * Determines how much debt to add or remove based on collateral changes and target health factor
202
+ * @param {Web3Number} collateralAmount - Current collateral amount
203
+ * @param {Web3Number} debtAmount - Current debt amount
204
+ * @param {number} debtPrice - Current price of the debt token
205
+ * @param {number} maxLtv - Maximum loan-to-value ratio (default: MAX_LTV_BTC_USDC)
206
+ * @param {number} addedAmount - Amount being added to collateral
207
+ * @param {number} collateralPrice - Current price of the collateral token
208
+ * @param {boolean} isDeposit - Whether this is a deposit (true) or withdrawal (false)
209
+ * @returns {object} Object containing deltadebtAmountUnits and isIncrease flag
210
+ */
211
+ // In case BTC_PRICE DROPS the added amount will be zero, and use this formula to calculated the debt that needs to be paid to maintain the ltv
212
+ export const calculateDebtAmount = (
213
+ collateralAmount: Web3Number,
214
+ debtAmount: Web3Number,
215
+ debtPrice: number,
216
+ maxLtv: number = MAX_LIQUIDATION_RATIO,
217
+ addedAmount: Web3Number, // this is in btc
218
+ collateralPrice: number,
219
+ isDeposit: boolean
220
+ ) => {
221
+ try {
222
+ // => X = (((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)) / (target hf - ltv)
223
+ const addedCollateral = addedAmount.multipliedBy(isDeposit ? 1 : -1);
224
+ const numerator1 = (collateralAmount
225
+ .plus(addedCollateral))
226
+ .multipliedBy(collateralPrice)
227
+ .multipliedBy(maxLtv);
228
+ const numerator2 = debtAmount
229
+ .multipliedBy(debtPrice)
230
+ .multipliedBy(TARGET_HF);
231
+ const denominator = TARGET_HF - maxLtv;
232
+ const x_debt_usd = numerator1.minus(numerator2).dividedBy(denominator);
233
+ let deltadebtAmountUnits = new Web3Number(
234
+ x_debt_usd.dividedBy(debtPrice).toFixed(2),
235
+ 2
236
+ );
237
+ let isIncrease = x_debt_usd.greaterThan(0);
238
+ return { deltadebtAmountUnits, isIncrease };
239
+ } catch (err) {
240
+ return { deltadebtAmountUnits: null, isIncrease: null };
241
+ }
242
+ };
243
+
244
+ /**
245
+ * calculate the debt amount to be repaid for withdrawal
246
+ * @param debtAmount in debt units
247
+ * @param collateralAmount in collateral units
248
+ * @param maxLtv in percentage
249
+ * @param withdrawalAmount in collateral units
250
+ * @param collateralPrice in usd
251
+ * @param debtPrice in usd
252
+ * @returns deltadebtAmountUnits in debt units
253
+ * isIncrease: true if the debt amount is increasing, false if it is decreasing
254
+ */
255
+ export const calculateDebtReductionAmountForWithdrawal = (
256
+ debtAmount: Web3Number,
257
+ collateralAmount: Web3Number,
258
+ maxLtv: number = MAX_LTV_BTC_USDC,
259
+ withdrawalAmount: Web3Number,
260
+ collateralPrice: number,
261
+ debtPrice: number,
262
+ usdcDecimals: number
263
+ ) => {
264
+ try {
265
+ const vesuLeverage = calculateVesuLeverage();
266
+ const numerator1 = collateralAmount
267
+ .multipliedBy(collateralPrice)
268
+ .multipliedBy(maxLtv)
269
+ .multipliedBy(-1);
270
+ withdrawalAmount = withdrawalAmount.multipliedBy(vesuLeverage);
271
+ const numerator2 = debtAmount
272
+ .multipliedBy(debtPrice)
273
+ .multipliedBy(TARGET_HF);
274
+ const numerator3 = withdrawalAmount
275
+ .multipliedBy(collateralPrice)
276
+ .multipliedBy(maxLtv);
277
+ const numeratorTotal = numerator1.plus(numerator2).plus(numerator3);
278
+ const denominator = debtPrice * TARGET_HF;
279
+ const x_debt_usdc = numeratorTotal.dividedBy(denominator);
280
+ let deltadebtAmountUnits = x_debt_usdc
281
+ .multipliedBy(-1)
282
+ .toFixed(usdcDecimals); // means we are paying debt
283
+ return { deltadebtAmountUnits };
284
+ } catch (err) {
285
+ return { deltadebtAmountUnits: null };
286
+ }
287
+ };
288
+
289
+ /**
290
+ * calculate the amount to deposit on extended when incurring losses
291
+ * @param client - The client
292
+ * @returns The amount to deposit on extended when incurring losses
293
+ */
294
+ export const calculateAmountDepositOnExtendedWhenIncurringLosses = async (
295
+ client: ExtendedWrapper
296
+ ) => {
297
+ try {
298
+ const extendedHoldings = await client.getHoldings();
299
+ const extended_leverage = calculateExtendedLevergae();
300
+ const latestPosition = (await client.getPositions()).data.pop();
301
+ if (!extendedHoldings || !latestPosition) {
302
+ logger.error(`error getting extended position: extendedHoldings=${extendedHoldings}, latestPosition=${latestPosition}`);
303
+ return null;
304
+ }
305
+ const positionValueInUSD = new Web3Number(latestPosition.value, USDC_TOKEN_DECIMALS);
306
+ const equity = extendedHoldings.data.equity;
307
+ const deposit = positionValueInUSD.dividedBy(extended_leverage).minus(equity).toFixed(2);
308
+ return new Web3Number(deposit, USDC_TOKEN_DECIMALS);
309
+ } catch (err) {
310
+ logger.error(`error calculating amount deposit on extended when incurring losses: ${err}`);
311
+ return null;
312
+ }
313
+ };
314
+
315
+ export const calculateExposureDelta = (
316
+ exposure_extended: number,
317
+ exposure_vesu: number
318
+ ) => {
319
+ const exposure_delta = new Web3Number(exposure_extended - exposure_vesu, 2);
320
+ return exposure_delta.absoluteValue().toNumber();
321
+ };
322
+
323
+ /// In case BTC PRICE DROPS
324
+ // 1. calculate the ltv on vesu
325
+ // 2. Find the debt that needs to be paid to maintain the ltv
326
+
327
+ /**
328
+ * calculate the delta percentage between the current btc price and the last btc price
329
+ * @param {number} btcPrice - The current btc price
330
+ * @param {number} lastBtcPrice - The last btc price
331
+ * @returns {number} The delta percentage
332
+ */
333
+ export const calculateBTCPriceDelta = (
334
+ btcPrice: number,
335
+ lastBtcPrice: number
336
+ ) => {
337
+ return ((btcPrice - lastBtcPrice) / lastBtcPrice) * 100;
338
+ };
339
+
340
+ export const calculateVesUPositionSizeGivenExtended = (
341
+ extendedPositonValue: number,
342
+ extendedHoldingAmount: Web3Number,
343
+ collateralAmount: Web3Number,
344
+ collateralPrice: number
345
+ ) => {
346
+ const extendedLeverage = calculateExtendedLevergae();
347
+ const vesuLeverage = calculateVesuLeverage();
348
+ const extendedAmount = extendedHoldingAmount;
349
+ const extendedAmountInBTC = extendedAmount
350
+ .dividedBy(collateralPrice).toFixed(WBTC_TOKEN_DECIMALS);
351
+ const numerator1 = extendedAmount.multipliedBy(extendedLeverage)
352
+ .plus(extendedPositonValue)
353
+ const numerator2 = collateralAmount
354
+ .multipliedBy(collateralPrice)
355
+ .multipliedBy(-1);
356
+ const vesuAmountInUsd = numerator1.plus(numerator2).dividedBy(vesuLeverage);
357
+ const vesuAmountInBTC = vesuAmountInUsd
358
+ .dividedBy(collateralPrice)
359
+ .toFixed(WBTC_TOKEN_DECIMALS);
360
+ return {
361
+ vesuAmountInUsd: vesuAmountInUsd.toFixed(2),
362
+ vesuAmountInBTC: new Web3Number(vesuAmountInBTC, WBTC_TOKEN_DECIMALS),
363
+ extendedAmountInBTC: extendedAmountInBTC,
364
+ };
365
+ };
366
+
367
+