@strkfarm/sdk 2.0.0-dev.4 → 2.0.0-dev.40

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 (77) hide show
  1. package/dist/cli.js +190 -36
  2. package/dist/cli.mjs +188 -34
  3. package/dist/index.browser.global.js +116018 -90768
  4. package/dist/index.browser.mjs +12769 -10876
  5. package/dist/index.d.ts +2222 -1947
  6. package/dist/index.js +13171 -11077
  7. package/dist/index.mjs +13076 -11004
  8. package/package.json +3 -3
  9. package/src/data/avnu.abi.json +840 -0
  10. package/src/data/ekubo-price-fethcer.abi.json +265 -0
  11. package/src/data/redeem-request-nft.abi.json +752 -0
  12. package/src/data/universal-vault.abi.json +8 -7
  13. package/src/dataTypes/_bignumber.ts +13 -4
  14. package/src/dataTypes/bignumber.browser.ts +10 -1
  15. package/src/dataTypes/bignumber.node.ts +10 -1
  16. package/src/dataTypes/index.ts +3 -2
  17. package/src/dataTypes/mynumber.ts +141 -0
  18. package/src/global.ts +96 -41
  19. package/src/index.browser.ts +2 -1
  20. package/src/interfaces/common.tsx +212 -5
  21. package/src/modules/apollo-client-config.ts +28 -0
  22. package/src/modules/avnu.ts +21 -12
  23. package/src/modules/ekubo-pricer.ts +79 -0
  24. package/src/modules/ekubo-quoter.ts +48 -30
  25. package/src/modules/erc20.ts +17 -0
  26. package/src/modules/harvests.ts +43 -29
  27. package/src/modules/index.ts +1 -1
  28. package/src/modules/pragma.ts +23 -8
  29. package/src/modules/pricer-from-api.ts +156 -15
  30. package/src/modules/pricer-lst.ts +1 -1
  31. package/src/modules/pricer.ts +40 -4
  32. package/src/modules/pricerBase.ts +2 -1
  33. package/src/node/deployer.ts +36 -1
  34. package/src/node/pricer-redis.ts +2 -1
  35. package/src/strategies/base-strategy.ts +168 -16
  36. package/src/strategies/constants.ts +8 -3
  37. package/src/strategies/ekubo-cl-vault.tsx +1044 -351
  38. package/src/strategies/factory.ts +199 -0
  39. package/src/strategies/index.ts +5 -3
  40. package/src/strategies/registry.ts +262 -0
  41. package/src/strategies/sensei.ts +353 -9
  42. package/src/strategies/svk-strategy.ts +125 -30
  43. package/src/strategies/token-boosted-xstrk-carry-strategy.tsx +1225 -0
  44. package/src/strategies/types.ts +4 -0
  45. package/src/strategies/universal-adapters/adapter-utils.ts +4 -1
  46. package/src/strategies/universal-adapters/avnu-adapter.ts +196 -272
  47. package/src/strategies/universal-adapters/baseAdapter.ts +263 -251
  48. package/src/strategies/universal-adapters/common-adapter.ts +206 -203
  49. package/src/strategies/universal-adapters/index.ts +10 -8
  50. package/src/strategies/universal-adapters/svk-troves-adapter.ts +511 -0
  51. package/src/strategies/universal-adapters/token-transfer-adapter.ts +200 -0
  52. package/src/strategies/universal-adapters/vesu-adapter.ts +120 -82
  53. package/src/strategies/universal-adapters/vesu-modify-position-adapter.ts +525 -0
  54. package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +1098 -712
  55. package/src/strategies/universal-adapters/vesu-position-common.ts +258 -0
  56. package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +18 -3
  57. package/src/strategies/universal-lst-muliplier-strategy.tsx +551 -405
  58. package/src/strategies/universal-strategy.tsx +1487 -1173
  59. package/src/strategies/vesu-rebalance.tsx +252 -152
  60. package/src/strategies/yoloVault.ts +1084 -0
  61. package/src/utils/cacheClass.ts +11 -2
  62. package/src/utils/health-factor-math.ts +33 -1
  63. package/src/utils/index.ts +3 -1
  64. package/src/utils/logger.browser.ts +22 -4
  65. package/src/utils/logger.node.ts +259 -24
  66. package/src/utils/starknet-call-parser.ts +1036 -0
  67. package/src/utils/strategy-utils.ts +61 -0
  68. package/src/modules/ExtendedWrapperSDk/index.ts +0 -62
  69. package/src/modules/ExtendedWrapperSDk/types.ts +0 -311
  70. package/src/modules/ExtendedWrapperSDk/wrapper.ts +0 -395
  71. package/src/strategies/universal-adapters/extended-adapter.ts +0 -661
  72. package/src/strategies/universal-adapters/unused-balance-adapter.ts +0 -109
  73. package/src/strategies/vesu-extended-strategy/services/operationService.ts +0 -34
  74. package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +0 -77
  75. package/src/strategies/vesu-extended-strategy/utils/constants.ts +0 -49
  76. package/src/strategies/vesu-extended-strategy/utils/helper.ts +0 -372
  77. package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +0 -1140
@@ -0,0 +1,258 @@
1
+ import { ContractAddr, Web3Number } from "@/dataTypes";
2
+ import { IConfig, IProtocol, TokenInfo } from "@/interfaces";
3
+ import { TokenMarketData } from "@/modules";
4
+ import { logger } from "@/utils";
5
+ import { HealthFactorMath } from "@/utils/health-factor-math";
6
+ import { num } from "starknet";
7
+ import {
8
+ APYType,
9
+ PositionAPY,
10
+ PositionAmount,
11
+ PositionInfo,
12
+ SupportedPosition,
13
+ } from "./baseAdapter";
14
+ import { VesuAdapter } from "./vesu-adapter";
15
+
16
+ export type VesuPositionCommonContext = {
17
+ adapterName: string;
18
+ protocol: IProtocol;
19
+ poolId: ContractAddr;
20
+ collateral: TokenInfo;
21
+ debt: TokenInfo;
22
+ networkConfig: IConfig;
23
+ pricer: {
24
+ getPrice: (symbol: string) => Promise<{ price: number }>;
25
+ };
26
+ vesuAdapter: VesuAdapter;
27
+ tokenMarketData: TokenMarketData;
28
+ targetHealthFactor: number;
29
+ getCache: <T>(key: string) => T | null | undefined;
30
+ setCache: <T>(key: string, value: T, ttlMs: number) => void;
31
+ getUSDValue: (asset: TokenInfo, amount: Web3Number) => Promise<number>;
32
+ };
33
+
34
+ export async function getVesuCommonAPY(
35
+ ctx: VesuPositionCommonContext,
36
+ supportedPosition: SupportedPosition,
37
+ ): Promise<PositionAPY> {
38
+ const cacheKey = `apy_${ctx.poolId.address}_${supportedPosition.asset.symbol}`;
39
+ const cacheData = ctx.getCache<PositionAPY>(cacheKey);
40
+ if (cacheData) {
41
+ return cacheData;
42
+ }
43
+
44
+ try {
45
+ const allVesuPools = await VesuAdapter.getVesuPools();
46
+ const asset = supportedPosition.asset;
47
+ const pool = allVesuPools.pools.find((p) =>
48
+ ctx.poolId.eqString(num.getHexString(p.id)),
49
+ );
50
+ if (!pool) {
51
+ logger.warn(`${ctx.adapterName}: Pool not found for token ${asset.symbol}`);
52
+ return { apy: 0, type: APYType.BASE };
53
+ }
54
+
55
+ const assetStats = pool.assets.find(
56
+ (a: any) => a.symbol.toLowerCase() === asset.symbol.toLowerCase(),
57
+ )?.stats;
58
+ if (!assetStats) {
59
+ logger.warn(`${ctx.adapterName}: Asset stats not found for token ${asset.symbol}`);
60
+ return { apy: 0, type: APYType.BASE };
61
+ }
62
+
63
+ let apy = 0;
64
+ if (supportedPosition.isDebt) {
65
+ apy = Number(assetStats.borrowApr?.value || 0) / 1e18;
66
+ } else {
67
+ const isAssetBTC = asset.symbol.toLowerCase().includes("btc");
68
+ const baseAPY =
69
+ Number(
70
+ isAssetBTC
71
+ ? assetStats.btcFiSupplyApr?.value + assetStats.supplyApy?.value
72
+ : assetStats.supplyApy?.value || 0,
73
+ ) / 1e18;
74
+ const rewardAPY = Number(assetStats.defiSpringSupplyApr?.value || "0") / 1e18;
75
+ apy = baseAPY + rewardAPY;
76
+ if (ctx.tokenMarketData.isAPYSupported(asset)) {
77
+ apy += await ctx.tokenMarketData.getAPY(asset);
78
+ }
79
+ }
80
+
81
+ const result = { apy, type: APYType.BASE };
82
+ ctx.setCache(cacheKey, result, 300000);
83
+ return result;
84
+ } catch (error) {
85
+ logger.error(`${ctx.adapterName}: Error getting APY for ${supportedPosition.asset.symbol}:`, error);
86
+ throw error;
87
+ }
88
+ }
89
+
90
+ export async function getVesuCommonPosition(
91
+ ctx: VesuPositionCommonContext,
92
+ supportedPosition: SupportedPosition,
93
+ ): Promise<PositionAmount> {
94
+ const cacheKey = `position_${ctx.poolId.address}_${supportedPosition.asset.symbol}`;
95
+ const cacheData = ctx.getCache<PositionAmount>(cacheKey);
96
+ if (cacheData) {
97
+ return cacheData;
98
+ }
99
+
100
+ try {
101
+ ctx.vesuAdapter.networkConfig = ctx.networkConfig;
102
+ ctx.vesuAdapter.pricer = ctx.pricer as any;
103
+ const positions = await ctx.vesuAdapter.getPositions(ctx.networkConfig);
104
+ let position = positions.find((p) => p.token.address.eq(supportedPosition.asset.address));
105
+ if (!position) {
106
+ logger.warn(`${ctx.adapterName}: Position not found for token ${supportedPosition.asset.symbol}`);
107
+ return {
108
+ amount: new Web3Number("0", supportedPosition.asset.decimals),
109
+ remarks: "Position not found",
110
+ };
111
+ }
112
+ if (supportedPosition.isDebt) {
113
+ position.amount = position.amount.multipliedBy(-1);
114
+ position.usdValue = position.usdValue * -1;
115
+ }
116
+ const result = { amount: position.amount, remarks: position.remarks };
117
+ ctx.setCache(cacheKey, result, 60000);
118
+ return result;
119
+ } catch (error) {
120
+ logger.error(`${ctx.adapterName}: Error getting position for ${supportedPosition.asset.symbol}:`, error);
121
+ throw error;
122
+ }
123
+ }
124
+
125
+ export async function getVesuCommonMaxBorrowableAPY(
126
+ ctx: VesuPositionCommonContext,
127
+ ): Promise<number> {
128
+ const collateralAPY = await getVesuCommonAPY(ctx, {
129
+ asset: ctx.collateral,
130
+ isDebt: false,
131
+ });
132
+ return collateralAPY.apy * 0.8;
133
+ }
134
+
135
+ /// @dev this function is used to calculate the max deposit amount based on the available debt capacity
136
+ export async function getVesuCommonMaxDeposit(
137
+ ctx: VesuPositionCommonContext,
138
+ amount?: Web3Number,
139
+ ): Promise<{collateralPosition: PositionInfo, debtPosition: PositionInfo}> {
140
+ const collateral = ctx.collateral;
141
+ const debt = ctx.debt;
142
+ try {
143
+ ctx.vesuAdapter.networkConfig = ctx.networkConfig;
144
+ ctx.vesuAdapter.pricer = ctx.pricer as any;
145
+
146
+ const positions = await ctx.vesuAdapter.getPositions(ctx.networkConfig);
147
+ const collateralPosition = positions.find((p) => p.token.address.eq(collateral.address));
148
+ const debtPosition = positions.find((p) => p.token.address.eq(debt.address));
149
+ if (!collateralPosition || !debtPosition) {
150
+ throw new Error("Could not find current positions");
151
+ }
152
+
153
+ const maxBorrowableAPY = await getVesuCommonMaxBorrowableAPY(ctx);
154
+ const maxBorrowableResult = await ctx.vesuAdapter.getMaxBorrowableByInterestRate(
155
+ ctx.networkConfig,
156
+ debt,
157
+ maxBorrowableAPY,
158
+ );
159
+ const maxBorrowable = maxBorrowableResult.maxDebtToHave;
160
+ const debtCap = await ctx.vesuAdapter.getDebtCap(ctx.networkConfig);
161
+ const actualMaxBorrowable = maxBorrowable.minimum(debtCap);
162
+ const maxLTV = await ctx.vesuAdapter.getLTVConfig(ctx.networkConfig);
163
+
164
+ const collateralPrice = await ctx.pricer.getPrice(collateral.symbol);
165
+ if (collateralPrice.price === 0) {
166
+ throw new Error("Collateral price is 0");
167
+ }
168
+ const debtPrice = await ctx.pricer.getPrice(debt.symbol);
169
+ if (debtPrice.price === 0) {
170
+ throw new Error("Debt price is 0");
171
+ }
172
+
173
+ /**
174
+ * We use existing collateral and debt also in the calculations.
175
+ * This will ensure any new collateral requirement also considers low ltv possibilities + new debt being created.
176
+ */
177
+ const maxCollateralFromDebt = HealthFactorMath.getCollateralRequired(
178
+ actualMaxBorrowable.plus(debtPosition.amount), // net new debt
179
+ debtPrice.price,
180
+ ctx.targetHealthFactor,
181
+ maxLTV,
182
+ collateralPrice.price,
183
+ collateral,
184
+ );
185
+ const maxNewCollateral = maxCollateralFromDebt.minus(collateralPosition.amount).minimum(0); // net new collateral
186
+ const maxDepositAmount = amount ? amount.minimum(maxNewCollateral) : maxNewCollateral;
187
+ const usdValue = await ctx.getUSDValue(collateral, maxDepositAmount);
188
+ const apys = await Promise.all([
189
+ getVesuCommonAPY(ctx, { asset: collateral, isDebt: false }),
190
+ getVesuCommonAPY(ctx, { asset: debt, isDebt: true }),
191
+ ]);
192
+
193
+ const borrowAmountUSD = actualMaxBorrowable.multipliedBy(debtPrice.price);
194
+
195
+ return {collateralPosition: {
196
+ tokenInfo: collateral,
197
+ amount: maxDepositAmount,
198
+ usdValue,
199
+ remarks: "Max deposit based on available debt capacity",
200
+ apy: { apy: apys[0].apy, type: APYType.BASE },
201
+ protocol: ctx.protocol,
202
+ }, debtPosition: {
203
+ tokenInfo: debt,
204
+ amount: actualMaxBorrowable,
205
+ usdValue: borrowAmountUSD.toNumber(),
206
+ remarks: "Max borrow based on available debt capacity",
207
+ apy: { apy: apys[1].apy, type: APYType.BASE },
208
+ protocol: ctx.protocol,
209
+ }};
210
+ } catch (error) {
211
+ logger.error(`${ctx.adapterName}: Error calculating max deposit:`, error);
212
+ throw error;
213
+ }
214
+ }
215
+
216
+ export async function getVesuCommonMaxWithdraw(
217
+ ctx: VesuPositionCommonContext,
218
+ ): Promise<{collateralPosition: PositionInfo, debtPosition: PositionInfo}> {
219
+ const collateral = ctx.collateral;
220
+ const debt = ctx.debt;
221
+ try {
222
+ ctx.vesuAdapter.networkConfig = ctx.networkConfig;
223
+ ctx.vesuAdapter.pricer = ctx.pricer as any;
224
+ const positions = await ctx.vesuAdapter.getPositions(ctx.networkConfig);
225
+ const collateralPosition = positions.find((p) => p.token.address.eq(collateral.address));
226
+ const debtPosition = positions.find((p) => p.token.address.eq(debt.address));
227
+ if (!collateralPosition || !debtPosition) {
228
+ throw new Error("Could not find current positions");
229
+ }
230
+
231
+ const apys = await Promise.all([
232
+ getVesuCommonAPY(ctx, { asset: collateral, isDebt: false }),
233
+ getVesuCommonAPY(ctx, { asset: debt, isDebt: true }),
234
+ ]);
235
+
236
+ return {
237
+ collateralPosition: {
238
+ tokenInfo: collateral,
239
+ amount: collateralPosition.amount,
240
+ usdValue: collateralPosition.usdValue,
241
+ remarks: "Max withdraw based on health factor",
242
+ apy: { apy: apys[0].apy, type: APYType.BASE },
243
+ protocol: ctx.protocol,
244
+ },
245
+ debtPosition: {
246
+ tokenInfo: debt,
247
+ amount: debtPosition.amount,
248
+ usdValue: debtPosition.usdValue,
249
+ remarks: "Max withdraw based on health factor",
250
+ apy: { apy: apys[1].apy, type: APYType.BASE },
251
+ protocol: ctx.protocol,
252
+ },
253
+ };
254
+ } catch (error) {
255
+ logger.error(`${ctx.adapterName}: Error calculating max withdraw:`, error);
256
+ throw error;
257
+ }
258
+ }
@@ -24,6 +24,18 @@ export class VesuSupplyOnlyAdapter extends BaseAdapter<DepositParams, WithdrawPa
24
24
  this.tokenMarketData = new TokenMarketData(this.config.pricer, this.config.networkConfig);
25
25
  }
26
26
 
27
+ private _depositApproveProofReadableId(): string {
28
+ return `appr_dep_vtkn_${this.config.vTokenContract.shortString()}`;
29
+ }
30
+
31
+ private _depositCallProofReadableId(): string {
32
+ return `deposit_vtoken_${this.config.vTokenContract.shortString()}`;
33
+ }
34
+
35
+ private _withdrawCallProofReadableId(): string {
36
+ return `withdraw_vtoken_${this.config.vTokenContract.shortString()}`;
37
+ }
38
+
27
39
  protected async getAPY(supportedPosition: SupportedPosition): Promise<PositionAPY> {
28
40
  const CACHE_KEY = `apy_${this.config.vTokenContract.address}`;
29
41
  const cacheData = this.getCache<PositionAPY>(CACHE_KEY);
@@ -193,7 +205,7 @@ export class VesuSupplyOnlyAdapter extends BaseAdapter<DepositParams, WithdrawPa
193
205
  vTokenContract.toBigInt(), // spender
194
206
  ],
195
207
  sanitizer: SIMPLE_SANITIZER,
196
- id: `appr_dep_vtkn_${this.config.vTokenContract.shortString()}`
208
+ id: this._depositApproveProofReadableId()
197
209
  },
198
210
  // Deposit step
199
211
  {
@@ -203,7 +215,7 @@ export class VesuSupplyOnlyAdapter extends BaseAdapter<DepositParams, WithdrawPa
203
215
  this.config.vaultAllocator.toBigInt(),
204
216
  ],
205
217
  sanitizer: SIMPLE_SANITIZER,
206
- id: `deposit_vtoken_${this.config.vTokenContract.shortString()}`
218
+ id: this._depositCallProofReadableId()
207
219
  }
208
220
  ];
209
221
  }
@@ -227,7 +239,7 @@ export class VesuSupplyOnlyAdapter extends BaseAdapter<DepositParams, WithdrawPa
227
239
  this.config.vaultAllocator.toBigInt(),
228
240
  ],
229
241
  sanitizer: SIMPLE_SANITIZER,
230
- id: `withdraw_vtoken_${this.config.vTokenContract.shortString()}`
242
+ id: this._withdrawCallProofReadableId()
231
243
  }
232
244
  ];
233
245
  }
@@ -272,6 +284,7 @@ export class VesuSupplyOnlyAdapter extends BaseAdapter<DepositParams, WithdrawPa
272
284
  return [
273
285
  // Approval call
274
286
  {
287
+ proofReadableId: this._depositApproveProofReadableId(),
275
288
  sanitizer: SIMPLE_SANITIZER,
276
289
  call: {
277
290
  contractAddress: baseToken.address,
@@ -285,6 +298,7 @@ export class VesuSupplyOnlyAdapter extends BaseAdapter<DepositParams, WithdrawPa
285
298
  },
286
299
  // Deposit call
287
300
  {
301
+ proofReadableId: this._depositCallProofReadableId(),
288
302
  sanitizer: SIMPLE_SANITIZER,
289
303
  call: {
290
304
  contractAddress: vTokenContract,
@@ -308,6 +322,7 @@ export class VesuSupplyOnlyAdapter extends BaseAdapter<DepositParams, WithdrawPa
308
322
  return [
309
323
  // Withdraw call
310
324
  {
325
+ proofReadableId: this._withdrawCallProofReadableId(),
311
326
  sanitizer: SIMPLE_SANITIZER,
312
327
  call: {
313
328
  contractAddress: vTokenContract,