@strkfarm/sdk 2.0.0-dev.5 → 2.0.0-dev.7

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.
@@ -1,4 +1,9 @@
1
- import { BaseAdapter, DepositParams, WithdrawParams, BaseAdapterConfig } from "./baseAdapter";
1
+ import {
2
+ BaseAdapter,
3
+ DepositParams,
4
+ WithdrawParams,
5
+ BaseAdapterConfig,
6
+ } from "./baseAdapter";
2
7
  import { Protocols } from "@/interfaces";
3
8
  import { SupportedPosition } from "./baseAdapter";
4
9
  import { PositionAPY, APYType, PositionAmount } from "./baseAdapter";
@@ -11,7 +16,12 @@ import { StandardMerkleTree } from "@/utils";
11
16
  import { hash, uint256 } from "starknet";
12
17
  import { Global } from "@/global";
13
18
  import { AdapterLeafType, GenerateCallFn } from "./baseAdapter";
14
- import { AVNU_LEGACY_SANITIZER, EXTENDED_SANITIZER, SIMPLE_SANITIZER, toBigInt } from "./adapter-utils";
19
+ import {
20
+ AVNU_LEGACY_SANITIZER,
21
+ EXTENDED_SANITIZER,
22
+ SIMPLE_SANITIZER,
23
+ toBigInt,
24
+ } from "./adapter-utils";
15
25
  import ExtendedWrapper, {
16
26
  AssetOperationStatus,
17
27
  AssetOperationType,
@@ -35,6 +45,8 @@ export interface ExtendedAdapterConfig extends BaseAdapterConfig {
35
45
  extendedMarketName: string;
36
46
  extendedPrecision: number;
37
47
  avnuAdapter: AvnuAdapter;
48
+ retryDelayForOrderStatus: number;
49
+ minimumExtendedMovementAmount: number;
38
50
  }
39
51
 
40
52
  export class ExtendedAdapter extends BaseAdapter<
@@ -43,6 +55,8 @@ export class ExtendedAdapter extends BaseAdapter<
43
55
  > {
44
56
  readonly config: ExtendedAdapterConfig;
45
57
  readonly client: ExtendedWrapper;
58
+ readonly retryDelayForOrderStatus: number;
59
+ readonly minimumExtendedMovementAmount: number;
46
60
 
47
61
  constructor(config: ExtendedAdapterConfig) {
48
62
  super(config, ExtendedAdapter.name, Protocols.EXTENDED);
@@ -53,7 +67,9 @@ export class ExtendedAdapter extends BaseAdapter<
53
67
  timeout: this.config.extendedTimeout,
54
68
  retries: this.config.extendedRetries,
55
69
  });
70
+ this.minimumExtendedMovementAmount = this.config.minimumExtendedMovementAmount ?? 5; //5 usdc
56
71
  this.client = client;
72
+ this.retryDelayForOrderStatus = this.config.retryDelayForOrderStatus ?? 3000;
57
73
  }
58
74
  //abstract means the method has no implementation in this class; instead, child classes must implement it.
59
75
  protected async getAPY(
@@ -61,12 +77,15 @@ export class ExtendedAdapter extends BaseAdapter<
61
77
  ): Promise<PositionAPY> {
62
78
  /** Considering supportedPosiiton.isDebt as side parameter to get the funding rates */
63
79
  const side = supportedPosition.isDebt ? "LONG" : "SHORT";
64
- const fundingRates = await this.client.getFundingRates(this.config.extendedMarketName, side);
80
+ const fundingRates = await this.client.getFundingRates(
81
+ this.config.extendedMarketName,
82
+ side
83
+ );
65
84
  if (fundingRates.status !== "OK") {
66
85
  logger.error("error getting funding rates", fundingRates);
67
86
  return { apy: 0, type: APYType.BASE };
68
87
  }
69
- const fundingRate:FundingRate = fundingRates.data[0];
88
+ const fundingRate: FundingRate = fundingRates.data[0];
70
89
  const apy = Number(fundingRate.f) * 365 * 24;
71
90
  return { apy: apy, type: APYType.BASE };
72
91
  }
@@ -118,14 +137,14 @@ export class ExtendedAdapter extends BaseAdapter<
118
137
  sanitizer: ContractAddr;
119
138
  id: string;
120
139
  }[] {
121
- const usdceToken = Global.getDefaultTokens().find(token => token.symbol === "USDCe");
140
+ const usdceToken = Global.getDefaultTokens().find(
141
+ (token) => token.symbol === "USDCe"
142
+ );
122
143
  return [
123
144
  {
124
145
  target: this.config.supportedPositions[0].asset.address,
125
146
  method: "approve",
126
- packedArguments: [
127
- AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt(),
128
- ],
147
+ packedArguments: [AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()],
129
148
  id: `extended_approve_${this.config.supportedPositions[0].asset.symbol}`,
130
149
  sanitizer: AVNU_LEGACY_SANITIZER,
131
150
  },
@@ -155,19 +174,27 @@ export class ExtendedAdapter extends BaseAdapter<
155
174
 
156
175
  getSwapFromLegacyLeaf(): AdapterLeafType<DepositParams> {
157
176
  const leafConfigs = this._getSwapFromLegacyLeaf();
158
- const leaves = leafConfigs.map(config => {
177
+ const leaves = leafConfigs.map((config) => {
159
178
  const { target, method, packedArguments, sanitizer, id } = config;
160
- const leaf = this.constructSimpleLeafData({
161
- id: id,
162
- target,
163
- method,
164
- packedArguments
165
- }, sanitizer);
179
+ const leaf = this.constructSimpleLeafData(
180
+ {
181
+ id: id,
182
+ target,
183
+ method,
184
+ packedArguments,
185
+ },
186
+ sanitizer
187
+ );
166
188
  return leaf;
167
189
  });
168
- return { leaves, callConstructor: this.getSwapFromLegacyCall.bind(this) as unknown as GenerateCallFn<DepositParams> };
190
+ return {
191
+ leaves,
192
+ callConstructor: this.getSwapFromLegacyCall.bind(
193
+ this
194
+ ) as unknown as GenerateCallFn<DepositParams>,
195
+ };
169
196
  }
170
-
197
+
171
198
  protected _getSwapFromLegacyLeaf(): {
172
199
  target: ContractAddr;
173
200
  method: string;
@@ -175,14 +202,14 @@ export class ExtendedAdapter extends BaseAdapter<
175
202
  sanitizer: ContractAddr;
176
203
  id: string;
177
204
  }[] {
178
- const usdceToken = Global.getDefaultTokens().find(token => token.symbol === "USDCe");
205
+ const usdceToken = Global.getDefaultTokens().find(
206
+ (token) => token.symbol === "USDCe"
207
+ );
179
208
  return [
180
209
  {
181
210
  target: usdceToken!.address,
182
211
  method: "approve",
183
- packedArguments: [
184
- AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt(),
185
- ],
212
+ packedArguments: [AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()],
186
213
  id: `extendedswaplegacyapprove_${usdceToken!.symbol}`,
187
214
  sanitizer: AVNU_LEGACY_SANITIZER,
188
215
  },
@@ -193,10 +220,9 @@ export class ExtendedAdapter extends BaseAdapter<
193
220
  id: `extended_swap_to_new_${usdceToken!.symbol}`,
194
221
  sanitizer: AVNU_LEGACY_SANITIZER,
195
222
  },
196
- ]
223
+ ];
197
224
  }
198
225
 
199
-
200
226
  protected _getWithdrawLeaf(): {
201
227
  target: ContractAddr;
202
228
  method: string;
@@ -213,12 +239,14 @@ export class ExtendedAdapter extends BaseAdapter<
213
239
  async getDepositCall(params: DepositParams): Promise<ManageCall[]> {
214
240
  try {
215
241
  const usdcToken = this.config.supportedPositions[0].asset;
216
- const usdceToken = Global.getDefaultTokens().find(token => token.symbol === "USDCe");
217
- const salt = Math.floor(
218
- Math.random() * 10 ** usdcToken.decimals
242
+ const usdceToken = Global.getDefaultTokens().find(
243
+ (token) => token.symbol === "USDCe"
219
244
  );
245
+ const salt = Math.floor(Math.random() * 10 ** usdcToken.decimals);
220
246
  // Give approval for more amount than the required amount
221
- const amount = uint256.bnToUint256(params.amount.multipliedBy(10).toWei());
247
+ const amount = uint256.bnToUint256(
248
+ params.amount.multipliedBy(10).toWei()
249
+ );
222
250
  const quotes = await this.config.avnuAdapter.getQuotesAvnu(
223
251
  usdcToken.address.toString(),
224
252
  usdceToken!.address.toString(),
@@ -226,15 +254,17 @@ export class ExtendedAdapter extends BaseAdapter<
226
254
  this.config.avnuAdapter.config.vaultAllocator.address.toString(),
227
255
  usdceToken!.decimals,
228
256
  false
229
- )
257
+ );
230
258
 
231
259
  if (!quotes) {
232
260
  logger.error("error getting quotes from avnu");
233
261
  return [];
234
262
  }
235
- const getCalldata = await this.config.avnuAdapter.getSwapCallData(quotes!);
263
+ const getCalldata = await this.config.avnuAdapter.getSwapCallData(
264
+ quotes!
265
+ );
236
266
  const swapCallData = getCalldata[0];
237
- //change extended sanitizer here
267
+ //change extended sanitizer here
238
268
  return [
239
269
  {
240
270
  sanitizer: AVNU_LEGACY_SANITIZER,
@@ -287,35 +317,44 @@ export class ExtendedAdapter extends BaseAdapter<
287
317
  }
288
318
  }
289
319
 
290
- getProofsForFromLegacySwap<T>(tree: StandardMerkleTree): { proofs: string[][], callConstructor: GenerateCallFn<DepositParams> | GenerateCallFn<WithdrawParams> } {
320
+ getProofsForFromLegacySwap<T>(tree: StandardMerkleTree): {
321
+ proofs: string[][];
322
+ callConstructor:
323
+ | GenerateCallFn<DepositParams>
324
+ | GenerateCallFn<WithdrawParams>;
325
+ } {
291
326
  let proofGroups: string[][] = [];
292
327
 
293
- const ids = this.getSwapFromLegacyLeaf().leaves.map(l => l.readableId)
328
+ const ids = this.getSwapFromLegacyLeaf().leaves.map((l) => l.readableId);
294
329
  // console.log(`${this.name}::getProofs ids: ${ids}`);
295
330
  for (const [i, v] of tree.entries()) {
296
- // console.log(`${this.name}::getProofs v: ${v.readableId}`);
331
+ // console.log(`${this.name}::getProofs v: ${v.readableId}`);
297
332
  if (ids.includes(v.readableId)) {
298
- //console.log(`${this.name}::getProofs found id: ${v.readableId}`);
333
+ //console.log(`${this.name}::getProofs found id: ${v.readableId}`);
299
334
  proofGroups.push(tree.getProof(i));
300
335
  }
301
336
  }
302
337
  if (proofGroups.length != ids.length) {
303
- throw new Error(`Not all proofs found for IDs: ${ids.join(', ')}`);
338
+ throw new Error(`Not all proofs found for IDs: ${ids.join(", ")}`);
304
339
  }
305
340
 
306
341
  // find leaf adapter
307
342
  return {
308
343
  proofs: proofGroups,
309
- callConstructor: this.getSwapFromLegacyCall.bind(this)
310
- };
311
- }
344
+ callConstructor: this.getSwapFromLegacyCall.bind(this),
345
+ };
346
+ }
312
347
 
313
348
  async getSwapFromLegacyCall(params: DepositParams): Promise<ManageCall[]> {
314
349
  try {
315
350
  const usdcToken = this.config.supportedPositions[0].asset;
316
- const usdceToken = Global.getDefaultTokens().find(token => token.symbol === "USDCe");
351
+ const usdceToken = Global.getDefaultTokens().find(
352
+ (token) => token.symbol === "USDCe"
353
+ );
317
354
  // Give approval for more amount than the required amount
318
- const amount = uint256.bnToUint256(params.amount.multipliedBy(10).toWei());
355
+ const amount = uint256.bnToUint256(
356
+ params.amount.multipliedBy(10).toWei()
357
+ );
319
358
  const quotes = await this.config.avnuAdapter.getQuotesAvnu(
320
359
  usdceToken!.address.toString(),
321
360
  usdcToken!.address.toString(),
@@ -323,15 +362,17 @@ export class ExtendedAdapter extends BaseAdapter<
323
362
  this.config.avnuAdapter.config.vaultAllocator.address.toString(),
324
363
  usdcToken!.decimals,
325
364
  false
326
- )
365
+ );
327
366
 
328
367
  if (!quotes) {
329
368
  logger.error("error getting quotes from avnu");
330
369
  return [];
331
370
  }
332
- const getCalldata = await this.config.avnuAdapter.getSwapCallData(quotes!);
371
+ const getCalldata = await this.config.avnuAdapter.getSwapCallData(
372
+ quotes!
373
+ );
333
374
  const swapCallData = getCalldata[0];
334
- //change extended sanitizer here
375
+ //change extended sanitizer here
335
376
  return [
336
377
  {
337
378
  sanitizer: AVNU_LEGACY_SANITIZER,
@@ -352,7 +393,7 @@ export class ExtendedAdapter extends BaseAdapter<
352
393
  selector: hash.getSelectorFromName("swap_to_new"),
353
394
  calldata: swapCallData,
354
395
  },
355
- }
396
+ },
356
397
  ];
357
398
  } catch (error) {
358
399
  logger.error(`Error creating Deposit Call: ${error}`);
@@ -377,9 +418,14 @@ export class ExtendedAdapter extends BaseAdapter<
377
418
  if (!this.client) {
378
419
  throw new Error("Client not initialized");
379
420
  }
380
- const withdrawalRequest = await this.client.withdrawUSDC(amount.toFixed(2));
421
+ const withdrawalRequest = await this.client.withdrawUSDC(
422
+ amount.toFixed(2)
423
+ );
381
424
  if (withdrawalRequest.status === "OK") {
382
- const withdrawalStatus = await this.getDepositOrWithdrawalStatus(withdrawalRequest.data, AssetOperationType.WITHDRAWAL);
425
+ const withdrawalStatus = await this.getDepositOrWithdrawalStatus(
426
+ withdrawalRequest.data,
427
+ AssetOperationType.WITHDRAWAL
428
+ );
383
429
  return withdrawalStatus;
384
430
  }
385
431
  return false;
@@ -461,21 +507,46 @@ export class ExtendedAdapter extends BaseAdapter<
461
507
  logger.error("error initializing client");
462
508
  return null;
463
509
  }
464
- await new Promise((resolve) => setTimeout(resolve, 5000));
465
- const orderhistory = await this.getOrderHistory(marketName);
510
+ let orderhistory = await this.getOrderHistory(marketName);
466
511
 
467
512
  if (!orderhistory || orderhistory.length === 0) {
468
- logger.error(`error getting order: ${orderId}`);
469
- return null;
513
+ logger.error(`error getting order history: ${orderId}`);
514
+ } else {
515
+ const order = orderhistory
516
+ .slice(0, 10)
517
+ .find((order) => order.id.toString() === orderId);
518
+ if (order) {
519
+ return order;
520
+ }
470
521
  }
471
- const order = orderhistory
472
- .slice(0, 3)
473
- .find((order) => order.id.toString() === orderId);
474
- if (!order) {
475
- logger.error(`error getting order: ${order}`);
476
- return null;
522
+
523
+ // Retry logic: 3 more attempts with 3 second delay each
524
+ for (let attempt = 1; attempt <= 5; attempt++) {
525
+ await new Promise((resolve) => setTimeout(resolve, this.retryDelayForOrderStatus));
526
+ orderhistory = await this.getOrderHistory(marketName);
527
+
528
+ if (!orderhistory || orderhistory.length === 0) {
529
+ logger.error(
530
+ `error getting order history on retry ${attempt}: ${orderId}`
531
+ );
532
+ continue;
533
+ }
534
+
535
+ const order = orderhistory
536
+ .slice(0, 5)
537
+ .find((order) => order.id.toString() === orderId);
538
+
539
+ if (order && order.status === OrderStatus.FILLED) {
540
+ return order;
541
+ }
542
+
543
+ logger.error(
544
+ `order not found in top 15 entries on retry ${attempt}: ${orderId}`
545
+ );
477
546
  }
478
- return order;
547
+
548
+ logger.error(`error getting order after all retries: ${orderId}`);
549
+ return null;
479
550
  }
480
551
 
481
552
  async fetchOrderBookBTCUSDC(): Promise<{
@@ -543,10 +614,10 @@ export class ExtendedAdapter extends BaseAdapter<
543
614
  }
544
615
  const { ask, bid } = await this.fetchOrderBookBTCUSDC();
545
616
  const spread = ask.minus(bid);
546
- let price = ask
547
- .plus(bid)
548
- .div(2)
549
- side === OrderSide.SELL ? price = price.minus(spread.times(0.2 * attempt)) : price = price.plus(spread.times(0.2 * attempt));
617
+ let price = ask.plus(bid).div(2);
618
+ side === OrderSide.SELL
619
+ ? (price = price.minus(spread.times(0.2 * attempt)))
620
+ : (price = price.plus(spread.times(0.2 * attempt)));
550
621
  const amount_in_token = (btcAmount * parseInt(leverage)).toFixed(
551
622
  this.config.extendedPrecision
552
623
  ); // gives the amount of wbtc
@@ -562,8 +633,11 @@ export class ExtendedAdapter extends BaseAdapter<
562
633
  return null;
563
634
  }
564
635
  await new Promise((resolve) => setTimeout(resolve, 5000));
565
- const openOrder = await this.getOrderStatus(result.position_id, this.config.extendedMarketName);
566
- if (!openOrder || openOrder.status !== OrderStatus.FILLED) {
636
+ const openOrder = await this.getOrderStatus(
637
+ result.position_id,
638
+ this.config.extendedMarketName
639
+ );
640
+ if (!openOrder) {
567
641
  if (attempt >= maxAttempts) {
568
642
  logger.error("Max retries reached — could not verify open position");
569
643
  return null;
@@ -585,7 +659,9 @@ export class ExtendedAdapter extends BaseAdapter<
585
659
  };
586
660
  }
587
661
  } catch (err: any) {
588
- logger.error(`createShortOrder failed on attempt ${attempt}: ${err.message}`);
662
+ logger.error(
663
+ `createShortOrder failed on attempt ${attempt}: ${err.message}`
664
+ );
589
665
 
590
666
  if (attempt < maxAttempts) {
591
667
  const backoff = 1200 * attempt;
@@ -635,26 +711,33 @@ export class ExtendedAdapter extends BaseAdapter<
635
711
  }
636
712
  }
637
713
 
638
- async getDepositOrWithdrawalStatus(orderId: number | string, operationsType: AssetOperationType): Promise<boolean> {
639
- try{
714
+ async getDepositOrWithdrawalStatus(
715
+ orderId: number | string,
716
+ operationsType: AssetOperationType
717
+ ): Promise<boolean> {
718
+ try {
640
719
  let transferHistory = await this.client.getAssetOperations({
641
- operationsType:[operationsType],
642
- operationsStatus:[AssetOperationStatus.COMPLETED]
643
- })
644
- if(operationsType === AssetOperationType.DEPOSIT){
645
- const myTransferStatus = transferHistory.data.find(operation => operation.transactionHash === orderId);
720
+ operationsType: [operationsType],
721
+ operationsStatus: [AssetOperationStatus.COMPLETED],
722
+ });
723
+ if (operationsType === AssetOperationType.DEPOSIT) {
724
+ const myTransferStatus = transferHistory.data.find(
725
+ (operation) => operation.transactionHash === orderId
726
+ );
646
727
  if (!myTransferStatus) {
647
728
  return true;
648
729
  }
649
730
  return true;
650
- }else{
651
- const myTransferStatus = transferHistory.data.find(operation => operation.id.toString() === orderId.toString());
731
+ } else {
732
+ const myTransferStatus = transferHistory.data.find(
733
+ (operation) => operation.id.toString() === orderId.toString()
734
+ );
652
735
  if (!myTransferStatus) {
653
736
  return true;
654
737
  }
655
738
  return true;
656
739
  }
657
- }catch(err){
740
+ } catch (err) {
658
741
  logger.error(`error getting deposit or withdrawal status: ${err}`);
659
742
  return false;
660
743
  }
@@ -50,6 +50,7 @@ export interface VesuMultiplyAdapterConfig extends BaseAdapterConfig {
50
50
  targetHealthFactor: number;
51
51
  minHealthFactor: number;
52
52
  quoteAmountToFetchPrice: Web3Number;
53
+ minimumVesuMovementAmount: number;
53
54
  }
54
55
 
55
56
  export class VesuMultiplyAdapter extends BaseAdapter<
@@ -59,7 +60,7 @@ export class VesuMultiplyAdapter extends BaseAdapter<
59
60
  readonly config: VesuMultiplyAdapterConfig;
60
61
  readonly vesuAdapter: VesuAdapter;
61
62
  readonly tokenMarketData: TokenMarketData;
62
-
63
+ readonly minimumVesuMovementAmount: number;
63
64
  constructor(config: VesuMultiplyAdapterConfig) {
64
65
  super(config, VesuMultiplyAdapter.name, Protocols.VESU);
65
66
  this.config = config;
@@ -70,6 +71,7 @@ export class VesuMultiplyAdapter extends BaseAdapter<
70
71
  vaultAllocator: config.vaultAllocator,
71
72
  id: "",
72
73
  });
74
+ this.minimumVesuMovementAmount = config.minimumVesuMovementAmount ?? 5; //5 usdc
73
75
  this.tokenMarketData = new TokenMarketData(
74
76
  this.config.pricer,
75
77
  this.config.networkConfig
@@ -786,7 +786,8 @@ function getLooperSettings(
786
786
  minHealthFactor: vaultSettings.minHealthFactor,
787
787
  quoteAmountToFetchPrice: vaultSettings.quoteAmountToFetchPrice,
788
788
  ...baseAdapterConfig,
789
- supportedPositions: [{asset: lstToken, isDebt: false}, {asset: Global.getDefaultTokens().find(token => token.symbol === position)!, isDebt: true}]
789
+ supportedPositions: [{asset: lstToken, isDebt: false}, {asset: Global.getDefaultTokens().find(token => token.symbol === position)!, isDebt: true}],
790
+ minimumVesuMovementAmount: 0
790
791
  }));
791
792
 
792
793
  const unusedBalanceAdapter = new UnusedBalanceAdapter({
@@ -22,7 +22,7 @@ export const STRK_API_RPC = process.env.STRK_API_RPC ?? "https://mainnet.starkne
22
22
  export const MAX_RETRIES = Number(process.env.MAX_RETRIES ?? 3);
23
23
  export const MAX_DELAY = Number(process.env.MAX_DELAY ?? 100);
24
24
  export const EXTEND_MARKET_NAME = "BTC-USD";
25
- export const LIMIT_BALANCE = Number(process.env.LIMIT_BALANCE ?? 10);
25
+ export const LIMIT_BALANCE = Number(process.env.LIMIT_BALANCE ?? 0.05);
26
26
  export const REBALANCER_INTERVAL = Number(process.env.REBALANCER_INTERVAL ?? 180000); //3 mins
27
27
  export const WITHDRAWAL_INTERVAL = Number(process.env.WITHDRAWAL_INTERVAL ?? 18000000); //5 hours
28
28
  export const INVESTING_INTERVAL = Number(process.env.INVESTING_INTERVAL ?? 180000); //3 mins
@@ -66,12 +66,10 @@ export const calculateAmountDistribution = async (
66
66
  vesu_leverage: 0,
67
67
  };
68
68
  }
69
- const extendedBTCExposure =
69
+ const extendedExposureUSD =
70
70
  extendedPosition.length > 0
71
- ? new Web3Number(extendedPosition[0].size, WBTC_TOKEN_DECIMALS)
71
+ ? new Web3Number(extendedPosition[0].value, WBTC_TOKEN_DECIMALS)
72
72
  : new Web3Number(0, WBTC_TOKEN_DECIMALS);
73
- const extendedExposureUSD =
74
- extendedBTCExposure.multipliedBy(collateralPrice);
75
73
  const vesuBTCExposureUSD = collateralUnits.multipliedBy(collateralPrice);
76
74
  const numerator1 = vesu_leverage * amount + vesuBTCExposureUSD.toNumber();
77
75
  const numerator2 = extendedExposureUSD.toNumber();
@@ -71,7 +71,6 @@ export class VesuExtendedMultiplierStrategy<
71
71
  >
72
72
  extends SVKStrategy<S>
73
73
  implements Operations {
74
-
75
74
  constructor(
76
75
  config: IConfig,
77
76
  pricer: PricerBase,
@@ -108,7 +107,7 @@ export class VesuExtendedMultiplierStrategy<
108
107
  debtPrice,
109
108
  };
110
109
  }
111
-
110
+
112
111
  async getUnusedBalanceUSDCE(): Promise<SingleTokenInfo> {
113
112
  const usdceToken = Global.getDefaultTokens().find(
114
113
  (token) => token.symbol === "USDCe"
@@ -238,8 +237,8 @@ export class VesuExtendedMultiplierStrategy<
238
237
  const balance = await this.getUnusedBalance();
239
238
  const usdcBalanceOnExtended = await extendedAdapter.getExtendedDepositAmount();
240
239
  /** The LIMIT_BALANCE is the bffer amount to keep in the investing Cycle */
241
- const amountToInvest = balance.amount.plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).minus(LIMIT_BALANCE);
242
-
240
+ const amountToInvest = new Web3Number(balance.usdValue, USDC_TOKEN_DECIMALS).plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).multipliedBy(1 - LIMIT_BALANCE);
241
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest amountToInvest: ${amountToInvest.toNumber()}`);
243
242
  if (amountToInvest.lessThan(0)) {
244
243
  return {
245
244
  shouldInvest: false,
@@ -301,6 +300,7 @@ export class VesuExtendedMultiplierStrategy<
301
300
  vesuLeverage: 0,
302
301
  };
303
302
  }
303
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest vesu_amount: ${vesu_amount.toNumber()}, extended_amount: ${extended_amount.toNumber()}`);
304
304
  return {
305
305
  shouldInvest: true,
306
306
  vesuAmount: vesu_amount,
@@ -335,7 +335,7 @@ export class VesuExtendedMultiplierStrategy<
335
335
  );
336
336
  return calls;
337
337
  }
338
- if (extendedAmount.lessThan(0)) {
338
+ if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
339
339
  try {
340
340
  const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
341
341
  {
@@ -357,7 +357,7 @@ export class VesuExtendedMultiplierStrategy<
357
357
  }
358
358
  }
359
359
 
360
- if (vesuAmount.lessThan(0)) {
360
+ if (vesuAmount.isNegative() && vesuAmount.lessThan(vesuAdapter.minimumVesuMovementAmount)) {
361
361
  try {
362
362
  const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
363
363
  {
@@ -384,16 +384,16 @@ export class VesuExtendedMultiplierStrategy<
384
384
  }
385
385
  const usdcAmountInWallet = (await this.getUnusedBalance()).amount;
386
386
  const usdcAmountOnExtended = parseFloat(
387
- extendedHoldings.availableForTrade
387
+ extendedHoldings.availableForWithdrawal
388
388
  );
389
- if (extendedAmount.plus(BUFFER_USDC_IN_WITHDRAWAL).minus(usdcAmountOnExtended).greaterThan(0)) {
389
+ if (extendedAmount.minus(usdcAmountOnExtended).greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
390
390
  //move assets to extended
391
391
  try {
392
392
  const { calls: extendedCalls } = await this.moveAssets(
393
393
  {
394
394
  to: Protocols.EXTENDED.name,
395
395
  from: Protocols.VAULT.name,
396
- amount: extendedAmount.plus(BUFFER_USDC_IN_WITHDRAWAL).minus(usdcAmountOnExtended),
396
+ amount: extendedAmount.minus(usdcAmountOnExtended),
397
397
  },
398
398
  extendedAdapter,
399
399
  vesuAdapter
@@ -403,7 +403,7 @@ export class VesuExtendedMultiplierStrategy<
403
403
  logger.error(`Failed moving assets to extended: ${err}`);
404
404
  }
405
405
  }
406
- if (vesuAmount.minus(usdcAmountInWallet).greaterThan(0)) {
406
+ if (vesuAmount.minus(usdcAmountInWallet).greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
407
407
  //move assets to vesu
408
408
  try {
409
409
  const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
@@ -659,7 +659,7 @@ export class VesuExtendedMultiplierStrategy<
659
659
  };
660
660
  }
661
661
  const extendedHoldingAmount = new Web3Number(
662
- extendedHoldings.availableForTrade,
662
+ extendedHoldings.availableForWithdrawal,
663
663
  USDC_TOKEN_DECIMALS
664
664
  );
665
665
  const {
@@ -719,7 +719,7 @@ export class VesuExtendedMultiplierStrategy<
719
719
  return {
720
720
  extendedAmountInBTC: new Web3Number(0, 0),
721
721
  calls: [],
722
- };;
722
+ };
723
723
  }
724
724
  }
725
725
 
@@ -912,6 +912,9 @@ function getLooperSettings(
912
912
  extendedBackendUrl: string,
913
913
  extendedApiKey: string,
914
914
  vaultIdExtended: number,
915
+ minimumExtendedMovementAmount: number,
916
+ minimumVesuMovementAmount: number,
917
+ minimumExtendedRetriesDelayForOrderStatus: number,
915
918
  ) {
916
919
  vaultSettings.leafAdapters = [];
917
920
 
@@ -957,6 +960,8 @@ function getLooperSettings(
957
960
  extendedMarketName: "BTC-USD",
958
961
  extendedPrecision: 5,
959
962
  avnuAdapter: avnuAdapter,
963
+ retryDelayForOrderStatus: minimumExtendedRetriesDelayForOrderStatus ?? 3000,
964
+ minimumExtendedMovementAmount: minimumExtendedMovementAmount ?? 5, //5 usdcs
960
965
  });
961
966
 
962
967
  const vesuMultiplyAdapter = new VesuMultiplyAdapter({
@@ -971,6 +976,7 @@ function getLooperSettings(
971
976
  { asset: wbtcToken, isDebt: false },
972
977
  { asset: usdcToken, isDebt: true },
973
978
  ],
979
+ minimumVesuMovementAmount: minimumVesuMovementAmount ?? 5, //5 usdc
974
980
  });
975
981
 
976
982
  const unusedBalanceAdapter = new UnusedBalanceAdapter({
@@ -1104,15 +1110,15 @@ const re7UsdcPrimeDevansh: VesuExtendedStrategySettings = {
1104
1110
  minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
1105
1111
  }
1106
1112
 
1107
- export const VesuExtendedTestStrategies = (extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number): IStrategyMetadata<VesuExtendedStrategySettings>[] => {
1113
+ export const VesuExtendedTestStrategies = (extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number, minimumExtendedMovementAmount: number, minimumVesuMovementAmount: number, minimumExtendedRetriesDelayForOrderStatus: number): IStrategyMetadata<VesuExtendedStrategySettings>[] => {
1108
1114
  return [
1109
- getStrategySettingsVesuExtended('WBTC', 'USDC', re7UsdcPrimeDevansh, false, false, extendedBackendUrl, extendedApiKey, vaultIdExtended),
1115
+ getStrategySettingsVesuExtended('WBTC', 'USDC', re7UsdcPrimeDevansh, false, false, extendedBackendUrl, extendedApiKey, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus),
1110
1116
  ]
1111
1117
  }
1112
1118
 
1113
1119
 
1114
1120
 
1115
- function getStrategySettingsVesuExtended(lstSymbol: string, underlyingSymbol: string, addresses: VesuExtendedStrategySettings, isPreview: boolean = false, isLST: boolean, extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number): IStrategyMetadata<VesuExtendedStrategySettings> {
1121
+ function getStrategySettingsVesuExtended(lstSymbol: string, underlyingSymbol: string, addresses: VesuExtendedStrategySettings, isPreview: boolean = false, isLST: boolean, extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number, minimumExtendedMovementAmount: number, minimumVesuMovementAmount: number, minimumExtendedRetriesDelayForOrderStatus: number): IStrategyMetadata<VesuExtendedStrategySettings> {
1116
1122
  return {
1117
1123
  name: `Extended Test ${underlyingSymbol}`,
1118
1124
  description: getDescription(lstSymbol, underlyingSymbol),
@@ -1120,7 +1126,7 @@ function getStrategySettingsVesuExtended(lstSymbol: string, underlyingSymbol: st
1120
1126
  launchBlock: 0,
1121
1127
  type: 'Other',
1122
1128
  depositTokens: [Global.getDefaultTokens().find(token => token.symbol === underlyingSymbol)!],
1123
- additionalInfo: getLooperSettings(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7USDCPrime, extendedBackendUrl, extendedApiKey, vaultIdExtended),
1129
+ additionalInfo: getLooperSettings(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7USDCPrime, extendedBackendUrl, extendedApiKey, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus),
1124
1130
  risk: {
1125
1131
  riskFactor: _riskFactor,
1126
1132
  netRisk: