@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,432 @@
1
+ import {
2
+ BaseAdapter,
3
+ DepositParams,
4
+ WithdrawParams,
5
+ BaseAdapterConfig,
6
+ } from "./baseAdapter";
7
+ import { toBigInt } from "./adapter-utils";
8
+ import { Protocols } from "@/interfaces";
9
+ import { MAX_DELAY } from "../vesu-extended-strategy/utils/constants";
10
+ import { SupportedPosition } from "./baseAdapter";
11
+ import { PositionAPY, APYType, PositionAmount } from "./baseAdapter";
12
+ import { Web3Number } from "@/dataTypes";
13
+ import { PositionInfo } from "./baseAdapter";
14
+ import { ManageCall } from "./baseAdapter";
15
+ import { ContractAddr } from "@/dataTypes";
16
+ import { AVNU_EXCHANGE } from "./adapter-utils";
17
+ import { MAX_RETRIES } from "../vesu-extended-strategy/utils/constants";
18
+ import { Quote } from "@avnu/avnu-sdk";
19
+ import { hash, uint256 } from "starknet";
20
+ import { AvnuWrapper } from "@/modules/avnu";
21
+ import axios from "axios";
22
+ import {SIMPLE_SANITIZER } from "./adapter-utils";
23
+ import { returnFormattedAmount } from "../vesu-extended-strategy/utils/helper";
24
+ import { logger } from "@/utils";
25
+ export interface AvnuAdapterConfig extends BaseAdapterConfig {
26
+ baseUrl: string;
27
+ avnuContract: ContractAddr; //0x04270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f
28
+ slippage: number;
29
+ minimumExtendedPriceDifferenceForSwapOpen: number;
30
+ maximumExtendedPriceDifferenceForSwapClosing: number;
31
+ }
32
+
33
+ export class AvnuAdapter extends BaseAdapter<DepositParams, WithdrawParams> {
34
+ readonly config: AvnuAdapterConfig;
35
+ protected avnuWrapper: AvnuWrapper;
36
+
37
+ constructor(config: AvnuAdapterConfig) {
38
+ super(config, AvnuAdapter.name, Protocols.AVNU);
39
+ this.config = config as AvnuAdapterConfig;
40
+ this.avnuWrapper = new AvnuWrapper();
41
+ }
42
+ //abstract means the method has no implementation in this class; instead, child classes must implement it.
43
+ protected async getAPY(
44
+ supportedPosition: SupportedPosition
45
+ ): Promise<PositionAPY> {
46
+ return Promise.resolve({ apy: 0, type: APYType.BASE });
47
+ }
48
+
49
+ protected async getPosition(
50
+ supportedPosition: SupportedPosition
51
+ ): Promise<PositionAmount> {
52
+ return Promise.resolve({ amount: new Web3Number(0, 0), remarks: "" });
53
+ }
54
+
55
+ async maxDeposit(amount?: Web3Number): Promise<PositionInfo> {
56
+ return Promise.resolve({
57
+ tokenInfo: this.config.baseToken,
58
+ amount: new Web3Number(0, 0),
59
+ usdValue: 0,
60
+ apy: { apy: 0, type: APYType.BASE },
61
+ protocol: Protocols.AVNU,
62
+ remarks: "",
63
+ });
64
+ }
65
+
66
+ async maxWithdraw(): Promise<PositionInfo> {
67
+ return Promise.resolve({
68
+ tokenInfo: this.config.baseToken,
69
+ amount: new Web3Number(0, 0),
70
+ usdValue: 0,
71
+ apy: { apy: 0, type: APYType.BASE },
72
+ protocol: Protocols.AVNU,
73
+ remarks: "",
74
+ });
75
+ }
76
+
77
+ protected _getDepositLeaf(): {
78
+ // considering deposit is converting usdc to wbtc
79
+ target: ContractAddr;
80
+ method: string;
81
+ packedArguments: bigint[];
82
+ sanitizer: ContractAddr;
83
+ id: string;
84
+ }[] {
85
+ const vaultAllocator = ContractAddr.from(
86
+ this.config.vaultAllocator.address
87
+ );
88
+ return [
89
+ {
90
+ target: this.config.supportedPositions[0].asset.address,
91
+ method: "approve",
92
+ packedArguments: [
93
+ AVNU_EXCHANGE.toBigInt(),
94
+ ],
95
+ sanitizer: SIMPLE_SANITIZER,
96
+ id: `approve_${this.config.supportedPositions[0].asset.symbol}`,
97
+ },
98
+ {
99
+ target: AVNU_EXCHANGE,
100
+ method: "multi_route_swap",
101
+ packedArguments: [
102
+ this.config.supportedPositions[0].asset.address.toBigInt(), //usdc
103
+ this.config.supportedPositions[1].asset.address.toBigInt(), //wbtc
104
+ vaultAllocator.toBigInt(),
105
+ ],
106
+ sanitizer: SIMPLE_SANITIZER,
107
+ id: `asutb_${this.config.supportedPositions[0].asset.symbol}_${this.config.supportedPositions[1].asset.symbol}`,
108
+ },
109
+ ];
110
+ }
111
+
112
+ protected _getWithdrawLeaf(): {
113
+ target: ContractAddr;
114
+ method: string;
115
+ packedArguments: bigint[];
116
+ sanitizer: ContractAddr;
117
+ id: string;
118
+ }[] {
119
+ const vaultAllocator = ContractAddr.from(
120
+ this.config.vaultAllocator.address
121
+ );
122
+ const toToken = this.config.supportedPositions[0].asset;
123
+ const fromToken = this.config.supportedPositions[1].asset;
124
+ return [
125
+ {
126
+ target: fromToken.address,
127
+ method: "approve",
128
+ packedArguments: [
129
+ AVNU_EXCHANGE.toBigInt(),
130
+ ],
131
+ sanitizer: SIMPLE_SANITIZER,
132
+ id: `approve_${fromToken.symbol}`,
133
+ },
134
+ {
135
+ target: AVNU_EXCHANGE,
136
+ method: "multi_route_swap",
137
+ packedArguments: [
138
+ fromToken.address.toBigInt(), //wbtc
139
+ toToken.address.toBigInt(), //usdc
140
+ vaultAllocator.toBigInt(),
141
+ ],
142
+ sanitizer: SIMPLE_SANITIZER,
143
+ id: `asbtu_${fromToken.symbol}_${fromToken.symbol}`,
144
+ },
145
+ ];
146
+ }
147
+
148
+ protected _getLegacySwapLeaf(): {
149
+ target: ContractAddr;
150
+ method: string;
151
+ packedArguments: bigint[];
152
+ sanitizer: ContractAddr;
153
+ id: string;
154
+ }[] {
155
+ return [];
156
+ }
157
+
158
+ async getDepositCall(params: DepositParams): Promise<ManageCall[]> {
159
+ try {
160
+ const fromToken = this.config.supportedPositions[0].asset; //usdc
161
+ const toToken = this.config.supportedPositions[1].asset; //wbtc
162
+ const vaultAllocator = ContractAddr.from(
163
+ this.config.vaultAllocator.address
164
+ );
165
+ const quote = await this.getQuotesAvnu(
166
+ fromToken.address.toString(),
167
+ toToken.address.toString(),
168
+ params.amount.toNumber(),
169
+ vaultAllocator.address.toString(),
170
+ toToken.decimals,
171
+ true
172
+ )
173
+ //console.log(`${AvnuAdapter.name}::getDepositCall quote: ${JSON.stringify(quote)}`);
174
+ if (!quote) {
175
+ logger.error("error getting quote from avnu");
176
+ return [];
177
+ }
178
+ logger.info(`${this.name}::getDepositCall quote: ${quote.sellAmountInUsd}`);
179
+ const getCalldata = await this.avnuWrapper.getSwapCallData(
180
+ quote,
181
+ vaultAllocator.address
182
+ );
183
+ const swapCallData = getCalldata[0];
184
+
185
+ // const approveCallData = getCalldata[0];
186
+ const amount = uint256.bnToUint256(quote.sellAmountInUsd*10**7)
187
+ return [
188
+ {
189
+ sanitizer: SIMPLE_SANITIZER,
190
+ call: {
191
+ contractAddress: fromToken.address,
192
+ selector: hash.getSelectorFromName("approve"),
193
+ calldata:[
194
+ AVNU_EXCHANGE.toBigInt(),
195
+ toBigInt(amount.low.toString()), // amount low
196
+ toBigInt(amount.high.toString()), // amount high
197
+ ] ,
198
+ },
199
+ },
200
+ {
201
+ sanitizer: SIMPLE_SANITIZER,
202
+ call: {
203
+ contractAddress: AVNU_EXCHANGE,
204
+ selector: hash.getSelectorFromName("multi_route_swap"),
205
+ calldata: swapCallData,
206
+ },
207
+ },
208
+ ];
209
+ } catch (error) {
210
+ logger.error(`Error getting Avnu quote: ${error}`);
211
+ return [];
212
+ }
213
+ }
214
+
215
+ //Swap wbtc to usdc
216
+ async getWithdrawCall(params: WithdrawParams): Promise<ManageCall[]> {
217
+ try {
218
+ const toToken = this.config.supportedPositions[0].asset;
219
+ const fromToken = this.config.supportedPositions[1].asset;
220
+ const vaultAllocator = ContractAddr.from(
221
+ this.config.vaultAllocator.address
222
+ );
223
+ const quote = await this.getQuotesAvnu(
224
+ fromToken.address.toString(),
225
+ toToken.address.toString(),
226
+ params.amount.toNumber(),
227
+ vaultAllocator.address.toString(),
228
+ fromToken.decimals,
229
+ false
230
+ );
231
+ if (!quote) {
232
+ logger.error("No quotes available for this swap, error in quotes avnu");
233
+ return [];
234
+ }
235
+ const getCalldata = await this.avnuWrapper.getSwapCallData(
236
+ quote,
237
+ vaultAllocator.address
238
+ );
239
+ const swapCallData = getCalldata[0];
240
+ const amount = uint256.bnToUint256(params.amount.toWei())
241
+ return [
242
+ {
243
+ sanitizer: SIMPLE_SANITIZER,
244
+ call: {
245
+ contractAddress:fromToken.address,
246
+ selector: hash.getSelectorFromName("approve"),
247
+ calldata: [
248
+ AVNU_EXCHANGE.toBigInt(),
249
+ toBigInt(amount.low.toString()), // amount low
250
+ toBigInt(amount.high.toString()), // amount high
251
+ ],
252
+ },
253
+ },
254
+ {
255
+ sanitizer: SIMPLE_SANITIZER,
256
+ call: {
257
+ contractAddress: AVNU_EXCHANGE,
258
+ selector: hash.getSelectorFromName("multi_route_swap"),
259
+ calldata: swapCallData,
260
+ },
261
+ },
262
+ ];
263
+ } catch (error) {
264
+ logger.error(`Error getting Avnu quote: ${error}`);
265
+ return [];
266
+ }
267
+ }
268
+
269
+ async getSwapCallData(quote: Quote): Promise<bigint[][]> {
270
+ return await this.avnuWrapper.getSwapCallData(quote, this.config.vaultAllocator.address);
271
+ }
272
+
273
+ async getHealthFactor(): Promise<number> {
274
+ return Promise.resolve(1);
275
+ }
276
+
277
+ async fetchQuoteWithRetry(
278
+ params: Record<string, any>,
279
+ retries: number = 5
280
+ ): Promise<any> {
281
+ for (let attempt = 0; attempt < retries; attempt++) {
282
+ try {
283
+ const response = await axios.get(this.config.baseUrl, { params });
284
+ if (response.data && response.data.length > 0) {
285
+ return response;
286
+ }
287
+ throw new Error("Empty response data");
288
+ } catch (err) {
289
+ logger.error(`Error fetching quote with retry: ${err}`);
290
+ if (attempt === retries - 1) {
291
+ throw err;
292
+ }
293
+ await new Promise((resolve) => setTimeout(resolve, attempt * MAX_DELAY));
294
+ }
295
+ }
296
+ throw new Error("Failed to fetch quote after retries");
297
+ }
298
+
299
+ async getQuotesAvnu (
300
+ from_token_address: string,
301
+ to_token_address: string,
302
+ amount: number, //amount in btc units
303
+ takerAddress: string,
304
+ toTokenDecimals: number,
305
+ usdcToBtc: boolean,
306
+ maxIterations: number = 5,
307
+ tolerance: number = 5000
308
+ ): Promise<Quote | null>{
309
+ try {
310
+ const fromToken = this.config.supportedPositions[0].asset;
311
+ const toToken = this.config.supportedPositions[1].asset;
312
+ if(!usdcToBtc) {
313
+ const sellAmount = returnFormattedAmount(amount, toTokenDecimals);
314
+ const params: Record<string, any> = {
315
+ sellTokenAddress: from_token_address,
316
+ buyTokenAddress: to_token_address,
317
+ takerAddress,
318
+ sellAmount:sellAmount,
319
+ };
320
+ const finalQuote = await this.fetchQuoteWithRetry(params);
321
+ if (!finalQuote.data.length) {
322
+ logger.error("No quotes available for this swap, error in quotes avnu");
323
+ return null;
324
+ }
325
+ const dataObject: Quote = finalQuote.data[0];
326
+ return dataObject;
327
+ }
328
+ const btcPrice = await this.getPriceOfToken(toToken.address.toString());
329
+ if (!btcPrice) {
330
+ logger.error(`error getting btc price: ${btcPrice}`);
331
+ return null;
332
+ }
333
+ const estimatedUsdcAmount = Math.floor(amount * btcPrice);
334
+ const targetBtcBig = BigInt(returnFormattedAmount(amount, toTokenDecimals));
335
+
336
+ // Check if the amount is too small - if estimated USDC amount is 0 or target BTC is 0, skip
337
+ if (estimatedUsdcAmount === 0 || targetBtcBig === 0n) {
338
+ logger.warn(`${AvnuAdapter.name}::getQuotesAvnu Amount too small: estimatedUsdcAmount=${estimatedUsdcAmount}, targetBtcBig=${targetBtcBig.toString()}, amount=${amount}`);
339
+ return null;
340
+ }
341
+ let low = BigInt(
342
+ Math.floor(
343
+ (estimatedUsdcAmount * 10 ** fromToken.decimals) * 0.9
344
+ )
345
+ );
346
+ let high = BigInt(
347
+ Math.floor(
348
+ (estimatedUsdcAmount * 10 ** fromToken.decimals) * 1.1
349
+ )
350
+ );
351
+ let mid = 0n;
352
+ for (let i = 0; i < maxIterations; i++) {
353
+ mid = (low + high) / 2n;
354
+ // Skip if mid is 0 to avoid fetching quotes with 0 amount
355
+ if (mid === 0n) {
356
+ logger.warn(`${AvnuAdapter.name}::getQuotesAvnu Binary search resulted in 0 amount, stopping search`);
357
+ break;
358
+ }
359
+ const sellAmount = returnFormattedAmount(Number(mid), 0);
360
+ const quote = await this.fetchQuoteWithRetry({
361
+ sellTokenAddress: from_token_address,
362
+ buyTokenAddress: to_token_address,
363
+ takerAddress,
364
+ sellAmount,
365
+ });
366
+
367
+ const gotBtc = BigInt(quote.data[0].buyAmount);
368
+ if (gotBtc === targetBtcBig) return quote.data[0];
369
+
370
+ if (gotBtc > targetBtcBig) {
371
+ high = mid;
372
+ } else {
373
+ low = mid;
374
+ }
375
+
376
+ if (
377
+ gotBtc >= targetBtcBig &&
378
+ gotBtc <= targetBtcBig + BigInt(tolerance)
379
+ ) {
380
+ return quote.data[0];
381
+ }
382
+ }
383
+ // Check if mid is still 0 before final quote fetch
384
+ if (mid === 0n) {
385
+ logger.warn(`${AvnuAdapter.name}::getQuotesAvnu Final mid value is 0, cannot fetch quote`);
386
+ return null;
387
+ }
388
+
389
+ let sellAmount = returnFormattedAmount(
390
+ Number(mid),
391
+ 0
392
+ );
393
+ const params: Record<string, any> = {
394
+ sellTokenAddress: from_token_address,
395
+ buyTokenAddress: to_token_address,
396
+ takerAddress,
397
+ sellAmount: sellAmount,
398
+ };
399
+ const finalQuote = await this.fetchQuoteWithRetry(params);
400
+ if (!finalQuote.data.length) {
401
+ logger.error("No quotes available for this swap, error in quotes avnu");
402
+ return null;
403
+ }
404
+ const dataObject: Quote = finalQuote.data[0];
405
+ return dataObject;
406
+ } catch (err) {
407
+ logger.error(`No quotes available for this swap: ${err}`);
408
+ return null;
409
+ }
410
+ };
411
+
412
+ async getPriceOfToken (
413
+ tokenAddress: string,
414
+ retries: number = MAX_RETRIES
415
+ ): Promise<number | null> {
416
+ try {
417
+ const url = `https://starknet.impulse.avnu.fi/v1/tokens/${tokenAddress}/prices/line`;
418
+ const response = await axios.get(url);
419
+ const length = response.data.length;
420
+ return response.data[length - 1].value;
421
+ } catch (err) {
422
+ if (retries > 0) {
423
+ await new Promise((resolve) => setTimeout(resolve, MAX_DELAY));
424
+ return this.getPriceOfToken(tokenAddress, retries - 1);
425
+ } else {
426
+ logger.error(`Failed to fetch price for ${tokenAddress} after ${MAX_RETRIES} attempts`);
427
+ return null;
428
+ }
429
+ }
430
+ };
431
+
432
+ }