@strkfarm/sdk 2.0.0-dev.3 → 2.0.0-dev.31

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 (75) hide show
  1. package/dist/cli.js +190 -36
  2. package/dist/cli.mjs +188 -34
  3. package/dist/index.browser.global.js +78475 -45620
  4. package/dist/index.browser.mjs +19580 -9901
  5. package/dist/index.d.ts +3763 -1424
  6. package/dist/index.js +20977 -11063
  7. package/dist/index.mjs +20945 -11087
  8. package/package.json +1 -1
  9. package/src/data/avnu.abi.json +840 -0
  10. package/src/data/ekubo-price-fethcer.abi.json +265 -0
  11. package/src/dataTypes/_bignumber.ts +13 -4
  12. package/src/dataTypes/bignumber.browser.ts +6 -1
  13. package/src/dataTypes/bignumber.node.ts +5 -1
  14. package/src/dataTypes/index.ts +3 -2
  15. package/src/dataTypes/mynumber.ts +141 -0
  16. package/src/global.ts +76 -41
  17. package/src/index.browser.ts +2 -1
  18. package/src/interfaces/common.tsx +175 -3
  19. package/src/modules/ExtendedWrapperSDk/types.ts +28 -5
  20. package/src/modules/ExtendedWrapperSDk/wrapper.ts +275 -59
  21. package/src/modules/apollo-client-config.ts +28 -0
  22. package/src/modules/avnu.ts +4 -4
  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/pragma.ts +23 -8
  28. package/src/modules/pricer-from-api.ts +156 -15
  29. package/src/modules/pricer-lst.ts +1 -1
  30. package/src/modules/pricer.ts +40 -4
  31. package/src/modules/pricerBase.ts +2 -1
  32. package/src/node/deployer.ts +36 -1
  33. package/src/node/pricer-redis.ts +2 -1
  34. package/src/strategies/base-strategy.ts +78 -10
  35. package/src/strategies/ekubo-cl-vault.tsx +906 -347
  36. package/src/strategies/factory.ts +159 -0
  37. package/src/strategies/index.ts +7 -1
  38. package/src/strategies/registry.ts +239 -0
  39. package/src/strategies/sensei.ts +335 -7
  40. package/src/strategies/svk-strategy.ts +97 -27
  41. package/src/strategies/types.ts +4 -0
  42. package/src/strategies/universal-adapters/adapter-utils.ts +2 -1
  43. package/src/strategies/universal-adapters/avnu-adapter.ts +180 -265
  44. package/src/strategies/universal-adapters/baseAdapter.ts +263 -251
  45. package/src/strategies/universal-adapters/common-adapter.ts +206 -203
  46. package/src/strategies/universal-adapters/extended-adapter.ts +490 -316
  47. package/src/strategies/universal-adapters/index.ts +11 -8
  48. package/src/strategies/universal-adapters/svk-troves-adapter.ts +364 -0
  49. package/src/strategies/universal-adapters/token-transfer-adapter.ts +200 -0
  50. package/src/strategies/universal-adapters/usdc<>usdce-adapter.ts +200 -0
  51. package/src/strategies/universal-adapters/vesu-adapter.ts +120 -82
  52. package/src/strategies/universal-adapters/vesu-modify-position-adapter.ts +476 -0
  53. package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +1067 -704
  54. package/src/strategies/universal-adapters/vesu-position-common.ts +251 -0
  55. package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +18 -3
  56. package/src/strategies/universal-lst-muliplier-strategy.tsx +397 -204
  57. package/src/strategies/universal-strategy.tsx +1426 -1173
  58. package/src/strategies/vesu-extended-strategy/services/executionService.ts +2233 -0
  59. package/src/strategies/vesu-extended-strategy/services/extended-vesu-state-manager.ts +4087 -0
  60. package/src/strategies/vesu-extended-strategy/services/ltv-imbalance-rebalance-math.ts +783 -0
  61. package/src/strategies/vesu-extended-strategy/services/operationService.ts +38 -16
  62. package/src/strategies/vesu-extended-strategy/types/transaction-metadata.ts +88 -0
  63. package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +1 -0
  64. package/src/strategies/vesu-extended-strategy/utils/constants.ts +5 -6
  65. package/src/strategies/vesu-extended-strategy/utils/helper.ts +259 -103
  66. package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +688 -817
  67. package/src/strategies/vesu-rebalance.tsx +255 -152
  68. package/src/utils/cacheClass.ts +11 -2
  69. package/src/utils/health-factor-math.ts +4 -1
  70. package/src/utils/index.ts +3 -1
  71. package/src/utils/logger.browser.ts +22 -4
  72. package/src/utils/logger.node.ts +259 -24
  73. package/src/utils/starknet-call-parser.ts +1036 -0
  74. package/src/utils/strategy-utils.ts +61 -0
  75. package/src/strategies/universal-adapters/unused-balance-adapter.ts +0 -109
@@ -3,8 +3,9 @@ import {
3
3
  DepositParams,
4
4
  WithdrawParams,
5
5
  BaseAdapterConfig,
6
+ SwapPriceInfo,
6
7
  } from "./baseAdapter";
7
- import { SIMPLE_SANITIZER_V2, toBigInt } from "./adapter-utils";
8
+ import { toBigInt } from "./adapter-utils";
8
9
  import { Protocols } from "@/interfaces";
9
10
  import { MAX_DELAY } from "../vesu-extended-strategy/utils/constants";
10
11
  import { SupportedPosition } from "./baseAdapter";
@@ -13,42 +14,186 @@ import { Web3Number } from "@/dataTypes";
13
14
  import { PositionInfo } from "./baseAdapter";
14
15
  import { ManageCall } from "./baseAdapter";
15
16
  import { ContractAddr } from "@/dataTypes";
16
- import { TokenInfo } from "@/interfaces";
17
17
  import { AVNU_EXCHANGE } from "./adapter-utils";
18
18
  import { MAX_RETRIES } from "../vesu-extended-strategy/utils/constants";
19
19
  import { Quote } from "@avnu/avnu-sdk";
20
20
  import { hash, uint256 } from "starknet";
21
21
  import { AvnuWrapper } from "@/modules/avnu";
22
22
  import axios from "axios";
23
- import { AVNU_MIDDLEWARE, SIMPLE_SANITIZER } from "./adapter-utils";
23
+ import { SIMPLE_SANITIZER } from "./adapter-utils";
24
24
  import { returnFormattedAmount } from "../vesu-extended-strategy/utils/helper";
25
- import { logger } from "@/utils";
25
+ import { assert, logger } from "@/utils";
26
+ import { Global } from "@/global";
27
+ import { TokenInfo } from "@/interfaces";
28
+ import { ERC20 } from "@/modules";
26
29
  export interface AvnuAdapterConfig extends BaseAdapterConfig {
27
30
  baseUrl: string;
28
31
  avnuContract: ContractAddr; //0x04270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f
29
32
  slippage: number;
33
+ minimumExtendedPriceDifferenceForSwapOpen: number;
34
+ maximumExtendedPriceDifferenceForSwapClosing: number;
30
35
  }
31
36
 
32
37
  export class AvnuAdapter extends BaseAdapter<DepositParams, WithdrawParams> {
33
38
  readonly config: AvnuAdapterConfig;
34
39
  protected avnuWrapper: AvnuWrapper;
40
+ lastSwapPriceInfo: SwapPriceInfo | null = null;
41
+
42
+ private _depositApproveProofReadableId(): string {
43
+ return `approve_${this.config.supportedPositions[0].asset.symbol}`;
44
+ }
45
+
46
+ private _depositSwapProofReadableId(): string {
47
+ return `asutb_${this.config.supportedPositions[0].asset.symbol}_${this.config.supportedPositions[1].asset.symbol}`;
48
+ }
49
+
50
+ private _withdrawApproveProofReadableId(): string {
51
+ return `approve_${this.config.supportedPositions[1].asset.symbol}`;
52
+ }
53
+
54
+ private _withdrawSwapProofReadableId(): string {
55
+ const fromToken = this.config.supportedPositions[1].asset;
56
+ return `asbtu_${fromToken.symbol}_${fromToken.symbol}`;
57
+ }
58
+
59
+ private buildSwapLeafConfigs(
60
+ fromToken: TokenInfo,
61
+ toToken: TokenInfo,
62
+ swapId: string,
63
+ ): {
64
+ target: ContractAddr;
65
+ method: string;
66
+ packedArguments: bigint[];
67
+ sanitizer: ContractAddr;
68
+ id: string;
69
+ }[] {
70
+ const vaultAllocator = ContractAddr.from(this.config.vaultAllocator.address);
71
+ return [
72
+ {
73
+ target: fromToken.address,
74
+ method: "approve",
75
+ packedArguments: [AVNU_EXCHANGE.toBigInt()],
76
+ sanitizer: SIMPLE_SANITIZER,
77
+ id: `approve_${fromToken.symbol}`,
78
+ },
79
+ {
80
+ target: AVNU_EXCHANGE,
81
+ method: "multi_route_swap",
82
+ packedArguments: [
83
+ fromToken.address.toBigInt(),
84
+ toToken.address.toBigInt(),
85
+ vaultAllocator.toBigInt(),
86
+ ],
87
+ sanitizer: SIMPLE_SANITIZER,
88
+ id: swapId,
89
+ },
90
+ ];
91
+ }
92
+
93
+ private async buildSwapCalls(
94
+ params: DepositParams | WithdrawParams,
95
+ fromToken: TokenInfo,
96
+ toToken: TokenInfo,
97
+ usdcToBtc: boolean,
98
+ ): Promise<ManageCall[]> {
99
+ const vaultAllocator = ContractAddr.from(this.config.vaultAllocator.address);
100
+ const quote = await this.avnuWrapper.getQuotes(
101
+ fromToken.address.toString(),
102
+ toToken.address.toString(),
103
+ params.amount.toWei(),
104
+ vaultAllocator.address.toString(),
105
+ );
106
+
107
+ if (!quote) {
108
+ logger.error("No quotes available for this swap, error in quotes avnu");
109
+ return [];
110
+ }
111
+
112
+ const fromAmt = Web3Number.fromWei(quote.sellAmount.toString(), fromToken.decimals).toNumber();
113
+ const toAmt = Web3Number.fromWei(quote.buyAmount.toString(), toToken.decimals).toNumber();
114
+ this.lastSwapPriceInfo = {
115
+ source: 'avnu',
116
+ fromTokenSymbol: fromToken.symbol,
117
+ toTokenSymbol: toToken.symbol,
118
+ fromAmount: fromAmt,
119
+ toAmount: toAmt,
120
+ effectivePrice: toAmt !== 0 ? fromAmt / toAmt : 0,
121
+ };
122
+ logger.verbose(
123
+ `${AvnuAdapter.name}::buildSwapCalls stored price info: ` +
124
+ `${fromAmt} ${fromToken.symbol} → ${toAmt} ${toToken.symbol}, ` +
125
+ `effectivePrice=${this.lastSwapPriceInfo.effectivePrice}`,
126
+ );
127
+
128
+ const getCalldata = await this.avnuWrapper.getSwapCallData(
129
+ quote,
130
+ vaultAllocator.address,
131
+ );
132
+ const swapCallData = getCalldata[0];
133
+ const approveAmount = uint256.bnToUint256(params.amount.toWei());
134
+
135
+ return [
136
+ {
137
+ proofReadableId: usdcToBtc
138
+ ? this._depositApproveProofReadableId()
139
+ : this._withdrawApproveProofReadableId(),
140
+ sanitizer: SIMPLE_SANITIZER,
141
+ call: {
142
+ contractAddress: fromToken.address,
143
+ selector: hash.getSelectorFromName("approve"),
144
+ calldata: [
145
+ AVNU_EXCHANGE.toBigInt(),
146
+ toBigInt(approveAmount.low.toString()),
147
+ toBigInt(approveAmount.high.toString()),
148
+ ],
149
+ },
150
+ },
151
+ {
152
+ proofReadableId: usdcToBtc
153
+ ? this._depositSwapProofReadableId()
154
+ : this._withdrawSwapProofReadableId(),
155
+ sanitizer: SIMPLE_SANITIZER,
156
+ call: {
157
+ contractAddress: AVNU_EXCHANGE,
158
+ selector: hash.getSelectorFromName("multi_route_swap"),
159
+ calldata: swapCallData,
160
+ },
161
+ },
162
+ ];
163
+ }
35
164
 
36
165
  constructor(config: AvnuAdapterConfig) {
37
166
  super(config, AvnuAdapter.name, Protocols.AVNU);
38
167
  this.config = config as AvnuAdapterConfig;
39
168
  this.avnuWrapper = new AvnuWrapper();
169
+ assert(this.config.supportedPositions.length === 2, "AvnuAdapter must have 2 supported positions");
40
170
  }
41
171
  //abstract means the method has no implementation in this class; instead, child classes must implement it.
42
172
  protected async getAPY(
43
- supportedPosition: SupportedPosition
173
+ supportedPosition: SupportedPosition,
44
174
  ): Promise<PositionAPY> {
45
175
  return Promise.resolve({ apy: 0, type: APYType.BASE });
46
176
  }
47
177
 
48
178
  protected async getPosition(
49
- supportedPosition: SupportedPosition
50
- ): Promise<PositionAmount> {
51
- return Promise.resolve({ amount: new Web3Number(0, 0), remarks: "" });
179
+ supportedPosition: SupportedPosition,
180
+ ): Promise<PositionAmount | null> {
181
+ const toToken = this.config.supportedPositions[1].asset;
182
+ if (supportedPosition.asset.symbol != toToken.symbol) {
183
+ return null;
184
+ }
185
+ try {
186
+ // only measure balance of toToken, bcz from token usually gets trakced in unused balance or a previous avnu adapter
187
+ const balance = await new ERC20(this.config.networkConfig).balanceOf(
188
+ supportedPosition.asset.address,
189
+ this.config.vaultAllocator.address,
190
+ supportedPosition.asset.decimals,
191
+ );
192
+ return { amount: balance, remarks: `Swapped Unused balance (VA)` };
193
+ } catch (_e) {
194
+ logger.error(`${AvnuAdapter.name}::getPosition: failed for ${toToken.symbol}`);
195
+ throw new Error(`${AvnuAdapter.name}: failed to get balance for ${toToken.symbol}`);
196
+ }
52
197
  }
53
198
 
54
199
  async maxDeposit(amount?: Web3Number): Promise<PositionInfo> {
@@ -81,31 +226,11 @@ export class AvnuAdapter extends BaseAdapter<DepositParams, WithdrawParams> {
81
226
  sanitizer: ContractAddr;
82
227
  id: string;
83
228
  }[] {
84
- const vaultAllocator = ContractAddr.from(
85
- this.config.vaultAllocator.address
229
+ return this.buildSwapLeafConfigs(
230
+ this.config.supportedPositions[0].asset,
231
+ this.config.supportedPositions[1].asset,
232
+ this._depositSwapProofReadableId(),
86
233
  );
87
- return [
88
- {
89
- target: this.config.supportedPositions[0].asset.address,
90
- method: "approve",
91
- packedArguments: [
92
- AVNU_EXCHANGE.toBigInt(),
93
- ],
94
- sanitizer: SIMPLE_SANITIZER,
95
- id: `approve_${this.config.supportedPositions[0].asset.symbol}`,
96
- },
97
- {
98
- target: AVNU_EXCHANGE,
99
- method: "multi_route_swap",
100
- packedArguments: [
101
- this.config.supportedPositions[0].asset.address.toBigInt(), //usdc
102
- this.config.supportedPositions[1].asset.address.toBigInt(), //wbtc
103
- vaultAllocator.toBigInt(),
104
- ],
105
- sanitizer: SIMPLE_SANITIZER,
106
- id: `asutb_${this.config.supportedPositions[0].asset.symbol}_${this.config.supportedPositions[1].asset.symbol}`,
107
- },
108
- ];
109
234
  }
110
235
 
111
236
  protected _getWithdrawLeaf(): {
@@ -115,33 +240,13 @@ export class AvnuAdapter extends BaseAdapter<DepositParams, WithdrawParams> {
115
240
  sanitizer: ContractAddr;
116
241
  id: string;
117
242
  }[] {
118
- const vaultAllocator = ContractAddr.from(
119
- this.config.vaultAllocator.address
120
- );
121
243
  const toToken = this.config.supportedPositions[0].asset;
122
244
  const fromToken = this.config.supportedPositions[1].asset;
123
- return [
124
- {
125
- target: fromToken.address,
126
- method: "approve",
127
- packedArguments: [
128
- AVNU_EXCHANGE.toBigInt(),
129
- ],
130
- sanitizer: SIMPLE_SANITIZER,
131
- id: `approve_${fromToken.symbol}`,
132
- },
133
- {
134
- target: AVNU_EXCHANGE,
135
- method: "multi_route_swap",
136
- packedArguments: [
137
- fromToken.address.toBigInt(), //wbtc
138
- toToken.address.toBigInt(), //usdc
139
- vaultAllocator.toBigInt(),
140
- ],
141
- sanitizer: SIMPLE_SANITIZER,
142
- id: `asbtu_${fromToken.symbol}_${fromToken.symbol}`,
143
- },
144
- ];
245
+ return this.buildSwapLeafConfigs(
246
+ fromToken,
247
+ toToken,
248
+ this._withdrawSwapProofReadableId(),
249
+ );
145
250
  }
146
251
 
147
252
  protected _getLegacySwapLeaf(): {
@@ -158,53 +263,13 @@ export class AvnuAdapter extends BaseAdapter<DepositParams, WithdrawParams> {
158
263
  try {
159
264
  const fromToken = this.config.supportedPositions[0].asset; //usdc
160
265
  const toToken = this.config.supportedPositions[1].asset; //wbtc
161
- const vaultAllocator = ContractAddr.from(
162
- this.config.vaultAllocator.address
266
+ const calls = await this.buildSwapCalls(
267
+ params,
268
+ fromToken,
269
+ toToken,
270
+ true,
163
271
  );
164
- const quote = await this.getQuotesAvnu(
165
- fromToken.address.toString(),
166
- toToken.address.toString(),
167
- params.amount.toNumber(),
168
- vaultAllocator.address.toString(),
169
- toToken.decimals,
170
- true
171
- )
172
- //console.log(`${AvnuAdapter.name}::getDepositCall quote: ${JSON.stringify(quote)}`);
173
- if (!quote) {
174
- logger.error("error getting quote from avnu");
175
- return [];
176
- }
177
-
178
- const getCalldata = await this.avnuWrapper.getSwapCallData(
179
- quote,
180
- vaultAllocator.address
181
- );
182
- const swapCallData = getCalldata[0];
183
-
184
- // const approveCallData = getCalldata[0];
185
- const amount = uint256.bnToUint256(quote.sellAmountInUsd*10**7)
186
- return [
187
- {
188
- sanitizer: SIMPLE_SANITIZER,
189
- call: {
190
- contractAddress: fromToken.address,
191
- selector: hash.getSelectorFromName("approve"),
192
- calldata:[
193
- AVNU_EXCHANGE.toBigInt(),
194
- toBigInt(amount.low.toString()), // amount low
195
- toBigInt(amount.high.toString()), // amount high
196
- ] ,
197
- },
198
- },
199
- {
200
- sanitizer: SIMPLE_SANITIZER,
201
- call: {
202
- contractAddress: AVNU_EXCHANGE,
203
- selector: hash.getSelectorFromName("multi_route_swap"),
204
- calldata: swapCallData,
205
- },
206
- },
207
- ];
272
+ return calls;
208
273
  } catch (error) {
209
274
  logger.error(`Error getting Avnu quote: ${error}`);
210
275
  return [];
@@ -216,49 +281,13 @@ export class AvnuAdapter extends BaseAdapter<DepositParams, WithdrawParams> {
216
281
  try {
217
282
  const toToken = this.config.supportedPositions[0].asset;
218
283
  const fromToken = this.config.supportedPositions[1].asset;
219
- const vaultAllocator = ContractAddr.from(
220
- this.config.vaultAllocator.address
284
+ const calls = await this.buildSwapCalls(
285
+ params,
286
+ fromToken,
287
+ toToken,
288
+ false,
221
289
  );
222
- const quote = await this.getQuotesAvnu(
223
- fromToken.address.toString(),
224
- toToken.address.toString(),
225
- params.amount.toNumber(),
226
- vaultAllocator.address.toString(),
227
- fromToken.decimals,
228
- false
229
- );
230
- if (!quote) {
231
- logger.error("No quotes available for this swap, error in quotes avnu");
232
- return [];
233
- }
234
- const getCalldata = await this.avnuWrapper.getSwapCallData(
235
- quote,
236
- vaultAllocator.address
237
- );
238
- const swapCallData = getCalldata[0];
239
- const amount = uint256.bnToUint256(params.amount.toWei())
240
- return [
241
- {
242
- sanitizer: SIMPLE_SANITIZER,
243
- call: {
244
- contractAddress:fromToken.address,
245
- selector: hash.getSelectorFromName("approve"),
246
- calldata: [
247
- AVNU_EXCHANGE.toBigInt(),
248
- toBigInt(amount.low.toString()), // amount low
249
- toBigInt(amount.high.toString()), // amount high
250
- ],
251
- },
252
- },
253
- {
254
- sanitizer: SIMPLE_SANITIZER,
255
- call: {
256
- contractAddress: AVNU_EXCHANGE,
257
- selector: hash.getSelectorFromName("multi_route_swap"),
258
- calldata: swapCallData,
259
- },
260
- },
261
- ];
290
+ return calls;
262
291
  } catch (error) {
263
292
  logger.error(`Error getting Avnu quote: ${error}`);
264
293
  return [];
@@ -266,7 +295,10 @@ export class AvnuAdapter extends BaseAdapter<DepositParams, WithdrawParams> {
266
295
  }
267
296
 
268
297
  async getSwapCallData(quote: Quote): Promise<bigint[][]> {
269
- return await this.avnuWrapper.getSwapCallData(quote, this.config.vaultAllocator.address);
298
+ return await this.avnuWrapper.getSwapCallData(
299
+ quote,
300
+ this.config.vaultAllocator.address,
301
+ );
270
302
  }
271
303
 
272
304
  async getHealthFactor(): Promise<number> {
@@ -275,7 +307,7 @@ export class AvnuAdapter extends BaseAdapter<DepositParams, WithdrawParams> {
275
307
 
276
308
  async fetchQuoteWithRetry(
277
309
  params: Record<string, any>,
278
- retries: number = 5
310
+ retries: number = 5,
279
311
  ): Promise<any> {
280
312
  for (let attempt = 0; attempt < retries; attempt++) {
281
313
  try {
@@ -294,121 +326,4 @@ export class AvnuAdapter extends BaseAdapter<DepositParams, WithdrawParams> {
294
326
  }
295
327
  throw new Error("Failed to fetch quote after retries");
296
328
  }
297
-
298
- async getQuotesAvnu (
299
- from_token_address: string,
300
- to_token_address: string,
301
- amount: number, //amount in btc units
302
- takerAddress: string,
303
- toTokenDecimals: number,
304
- usdcToBtc: boolean,
305
- maxIterations: number = 5,
306
- tolerance: number = 1000
307
- ): Promise<Quote | null>{
308
- try {
309
- const fromToken = this.config.supportedPositions[0].asset;
310
- const toToken = this.config.supportedPositions[1].asset;
311
- if(!usdcToBtc) {
312
- const sellAmount = returnFormattedAmount(amount, toTokenDecimals);
313
- const params: Record<string, any> = {
314
- sellTokenAddress: from_token_address,
315
- buyTokenAddress: to_token_address,
316
- takerAddress,
317
- sellAmount:sellAmount,
318
- };
319
- const finalQuote = await this.fetchQuoteWithRetry(params);
320
- if (!finalQuote.data.length) {
321
- logger.error("No quotes available for this swap, error in quotes avnu");
322
- return null;
323
- }
324
- const dataObject: Quote = finalQuote.data[0];
325
- return dataObject;
326
- }
327
- const btcPrice = await this.getPriceOfToken(toToken.address.toString());
328
- if (!btcPrice) {
329
- logger.error(`error getting btc price: ${btcPrice}`);
330
- return null;
331
- }
332
- const estimatedUsdcAmount = Math.floor(amount * btcPrice);
333
- const targetBtcBig = BigInt(returnFormattedAmount(amount, toTokenDecimals));
334
- let low = BigInt(
335
- Math.floor(
336
- (estimatedUsdcAmount * 10 ** fromToken.decimals) * 0.9
337
- )
338
- );
339
- let high = BigInt(
340
- Math.floor(
341
- (estimatedUsdcAmount * 10 ** fromToken.decimals) * 1.1
342
- )
343
- );
344
- let mid = 0n;
345
- for (let i = 0; i < maxIterations; i++) {
346
- mid = (low + high) / 2n;
347
- const sellAmount = returnFormattedAmount(Number(mid), 0);
348
- const quote = await this.fetchQuoteWithRetry({
349
- sellTokenAddress: from_token_address,
350
- buyTokenAddress: to_token_address,
351
- takerAddress,
352
- sellAmount,
353
- });
354
-
355
- const gotBtc = BigInt(quote.data[0].buyAmount);
356
- if (gotBtc === targetBtcBig) return quote.data[0];
357
-
358
- if (gotBtc > targetBtcBig) {
359
- high = mid;
360
- } else {
361
- low = mid;
362
- }
363
-
364
- if (
365
- gotBtc >= targetBtcBig &&
366
- gotBtc <= targetBtcBig + BigInt(tolerance)
367
- ) {
368
- return quote.data[0];
369
- }
370
- }
371
- let sellAmount = returnFormattedAmount(
372
- Number(mid),
373
- 0
374
- );
375
- const params: Record<string, any> = {
376
- sellTokenAddress: from_token_address,
377
- buyTokenAddress: to_token_address,
378
- takerAddress,
379
- sellAmount: sellAmount,
380
- };
381
- const finalQuote = await this.fetchQuoteWithRetry(params);
382
- if (!finalQuote.data.length) {
383
- logger.error("No quotes available for this swap, error in quotes avnu");
384
- return null;
385
- }
386
- const dataObject: Quote = finalQuote.data[0];
387
- return dataObject;
388
- } catch (err) {
389
- logger.error(`No quotes available for this swap: ${err}`);
390
- return null;
391
- }
392
- };
393
-
394
- async getPriceOfToken (
395
- tokenAddress: string,
396
- retries: number = MAX_RETRIES
397
- ): Promise<number | null> {
398
- try {
399
- const url = `https://starknet.impulse.avnu.fi/v1/tokens/${tokenAddress}/prices/line`;
400
- const response = await axios.get(url);
401
- const length = response.data.length;
402
- return response.data[length - 1].value;
403
- } catch (err) {
404
- if (retries > 0) {
405
- await new Promise((resolve) => setTimeout(resolve, MAX_DELAY));
406
- return this.getPriceOfToken(tokenAddress, retries - 1);
407
- } else {
408
- logger.error(`Failed to fetch price for ${tokenAddress} after ${MAX_RETRIES} attempts`);
409
- return null;
410
- }
411
- }
412
- };
413
-
414
- }
329
+ }