@strkfarm/sdk 2.0.0-dev.22 → 2.0.0-dev.23
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.
- package/dist/index.browser.global.js +867 -246
- package/dist/index.browser.mjs +793 -172
- package/dist/index.d.ts +15 -2
- package/dist/index.js +794 -172
- package/dist/index.mjs +793 -172
- package/package.json +1 -1
- package/src/strategies/universal-adapters/avnu-adapter.ts +2 -1
- package/src/strategies/vesu-extended-strategy/services/operationService.ts +1 -0
- package/src/strategies/vesu-extended-strategy/utils/helper.ts +32 -2
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +1101 -327
|
@@ -8,12 +8,21 @@ import {
|
|
|
8
8
|
UNIVERSAL_MANAGE_IDS,
|
|
9
9
|
UniversalStrategySettings,
|
|
10
10
|
} from "../universal-strategy";
|
|
11
|
-
import { calculateExtendedLevergae } from "./utils/helper";
|
|
11
|
+
import { calculateDebtAmount, calculateDeltaDebtAmount, calculateExtendedLevergae } from "./utils/helper";
|
|
12
12
|
import { logger } from "@/utils";
|
|
13
13
|
import { AUDIT_URL } from "../universal-lst-muliplier-strategy";
|
|
14
14
|
import { getNoRiskTags } from "@/interfaces";
|
|
15
15
|
import { _riskFactor } from "../universal-lst-muliplier-strategy";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
BUFFER_USDC_IN_WITHDRAWAL,
|
|
18
|
+
LIMIT_BALANCE,
|
|
19
|
+
LIMIT_BALANCE_VALUE,
|
|
20
|
+
MAX_LTV_BTC_USDC,
|
|
21
|
+
MINIMUM_EXTENDED_POSITION_SIZE,
|
|
22
|
+
USDC_TOKEN_DECIMALS,
|
|
23
|
+
WALLET_ADDRESS,
|
|
24
|
+
WBTC_TOKEN_DECIMALS,
|
|
25
|
+
} from "./utils/constants";
|
|
17
26
|
import { CycleType } from "./types/transaction-metadata";
|
|
18
27
|
import { PricerBase } from "@/modules/pricerBase";
|
|
19
28
|
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
@@ -22,7 +31,10 @@ import { ERC20 } from "@/modules";
|
|
|
22
31
|
import { Balance, OrderSide } from "@/modules/ExtendedWrapperSDk";
|
|
23
32
|
import { Protocols } from "@/interfaces";
|
|
24
33
|
import { MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP } from "./utils/constants";
|
|
25
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
getInvestmentSteps,
|
|
36
|
+
getFAQs,
|
|
37
|
+
} from "../universal-lst-muliplier-strategy";
|
|
26
38
|
import { getContractDetails } from "../universal-strategy";
|
|
27
39
|
import { highlightTextWithLinks } from "@/interfaces";
|
|
28
40
|
import { PositionInfo } from "../universal-adapters";
|
|
@@ -50,13 +62,15 @@ import {
|
|
|
50
62
|
calculateAmountDistribution,
|
|
51
63
|
calculateAmountDistributionForWithdrawal,
|
|
52
64
|
calculateVesuLeverage,
|
|
53
|
-
calculateVesUPositionSizeGivenExtended
|
|
65
|
+
calculateVesUPositionSizeGivenExtended,
|
|
54
66
|
} from "./utils/helper";
|
|
55
67
|
import { SingleTokenInfo } from "../base-strategy";
|
|
56
68
|
import { Call } from "starknet";
|
|
57
69
|
import { PositionTypeAvnuExtended } from "../universal-strategy";
|
|
58
|
-
import {
|
|
59
|
-
|
|
70
|
+
import {
|
|
71
|
+
TransactionMetadata,
|
|
72
|
+
TransactionResult,
|
|
73
|
+
} from "./types/transaction-metadata";
|
|
60
74
|
|
|
61
75
|
export interface VesuExtendedStrategySettings
|
|
62
76
|
extends UniversalStrategySettings {
|
|
@@ -71,10 +85,11 @@ export interface VesuExtendedStrategySettings
|
|
|
71
85
|
}
|
|
72
86
|
|
|
73
87
|
export class VesuExtendedMultiplierStrategy<
|
|
74
|
-
|
|
75
|
-
>
|
|
88
|
+
S extends VesuExtendedStrategySettings
|
|
89
|
+
>
|
|
76
90
|
extends SVKStrategy<S>
|
|
77
|
-
implements Operations
|
|
91
|
+
implements Operations
|
|
92
|
+
{
|
|
78
93
|
constructor(
|
|
79
94
|
config: IConfig,
|
|
80
95
|
pricer: PricerBase,
|
|
@@ -122,8 +137,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
122
137
|
usdceToken.decimals
|
|
123
138
|
);
|
|
124
139
|
const price = await this.pricer.getPrice(usdceToken.symbol);
|
|
125
|
-
const usdValue =
|
|
126
|
-
Number(balance.toFixed(usdceToken.decimals)) * price.price;
|
|
140
|
+
const usdValue = Number(balance.toFixed(usdceToken.decimals)) * price.price;
|
|
127
141
|
return {
|
|
128
142
|
tokenInfo: usdceToken,
|
|
129
143
|
amount: balance,
|
|
@@ -131,7 +145,6 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
131
145
|
};
|
|
132
146
|
}
|
|
133
147
|
|
|
134
|
-
|
|
135
148
|
async getUnusedBalanceWBTC(): Promise<SingleTokenInfo> {
|
|
136
149
|
const collateralToken = this.metadata.additionalInfo.borrowable_assets[0]!;
|
|
137
150
|
const balance = await new ERC20(this.config).balanceOf(
|
|
@@ -182,9 +195,12 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
182
195
|
return extendedAdapter.adapter as ExtendedAdapter;
|
|
183
196
|
}
|
|
184
197
|
|
|
185
|
-
async moveAssetsToVaultAllocator(
|
|
186
|
-
|
|
187
|
-
|
|
198
|
+
async moveAssetsToVaultAllocator(
|
|
199
|
+
amount: Web3Number,
|
|
200
|
+
extendedAdapter: ExtendedAdapter
|
|
201
|
+
): Promise<{
|
|
202
|
+
calls: Call[];
|
|
203
|
+
status: boolean;
|
|
188
204
|
}> {
|
|
189
205
|
try {
|
|
190
206
|
const usdceToken = Global.getDefaultTokens().find(
|
|
@@ -195,12 +211,22 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
195
211
|
WALLET_ADDRESS,
|
|
196
212
|
usdceToken.decimals
|
|
197
213
|
);
|
|
198
|
-
logger.info(
|
|
214
|
+
logger.info(
|
|
215
|
+
`${VesuExtendedMultiplierStrategy.name}::moveAssetsToVaultAllocator walletBalance: ${walletBalance}`
|
|
216
|
+
);
|
|
199
217
|
const amountToBeTransferred = amount.minimum(walletBalance);
|
|
200
|
-
logger.info(
|
|
201
|
-
|
|
218
|
+
logger.info(
|
|
219
|
+
`${
|
|
220
|
+
VesuExtendedMultiplierStrategy.name
|
|
221
|
+
}::moveAssetsToVaultAllocator amountToBeTransferred: ${amountToBeTransferred.toNumber()}`
|
|
222
|
+
);
|
|
223
|
+
|
|
202
224
|
if (amountToBeTransferred.lessThan(0)) {
|
|
203
|
-
logger.error(
|
|
225
|
+
logger.error(
|
|
226
|
+
`${
|
|
227
|
+
VesuExtendedMultiplierStrategy.name
|
|
228
|
+
}::moveAssetsToVaultAllocator amountToBeTransferred is less than 0: ${amountToBeTransferred.toNumber()}`
|
|
229
|
+
);
|
|
204
230
|
return {
|
|
205
231
|
calls: [],
|
|
206
232
|
status: false,
|
|
@@ -246,12 +272,19 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
246
272
|
collateralPrice: number;
|
|
247
273
|
debtPrice: number;
|
|
248
274
|
vesuLeverage: number;
|
|
275
|
+
debtAmountToBeRepaid: Web3Number;
|
|
249
276
|
}> {
|
|
250
277
|
try {
|
|
251
|
-
logger.info(
|
|
278
|
+
logger.info(
|
|
279
|
+
`${VesuExtendedMultiplierStrategy.name}::shouldInvest starting`
|
|
280
|
+
);
|
|
252
281
|
const vesuAdapter = await this.getVesuAdapter();
|
|
253
282
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
254
|
-
logger.info(
|
|
283
|
+
logger.info(
|
|
284
|
+
`${
|
|
285
|
+
VesuExtendedMultiplierStrategy.name
|
|
286
|
+
}::shouldInvest adapters fetched: vesuAdapter=${!!vesuAdapter}, extendedAdapter=${!!extendedAdapter}, extendedAdapter.client=${!!extendedAdapter?.client}`
|
|
287
|
+
);
|
|
255
288
|
|
|
256
289
|
if (!vesuAdapter) {
|
|
257
290
|
logger.error(
|
|
@@ -265,6 +298,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
265
298
|
collateralPrice: 0,
|
|
266
299
|
debtPrice: 0,
|
|
267
300
|
vesuLeverage: 0,
|
|
301
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
268
302
|
};
|
|
269
303
|
}
|
|
270
304
|
if (!extendedAdapter) {
|
|
@@ -279,6 +313,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
279
313
|
collateralPrice: 0,
|
|
280
314
|
debtPrice: 0,
|
|
281
315
|
vesuLeverage: 0,
|
|
316
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
282
317
|
};
|
|
283
318
|
}
|
|
284
319
|
if (!extendedAdapter.client) {
|
|
@@ -293,10 +328,13 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
293
328
|
collateralPrice: 0,
|
|
294
329
|
debtPrice: 0,
|
|
295
330
|
vesuLeverage: 0,
|
|
331
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
296
332
|
};
|
|
297
333
|
}
|
|
298
334
|
|
|
299
|
-
logger.info(
|
|
335
|
+
logger.info(
|
|
336
|
+
`${VesuExtendedMultiplierStrategy.name}::shouldInvest calling getUnusedBalance`
|
|
337
|
+
);
|
|
300
338
|
const balance = await this.getUnusedBalance();
|
|
301
339
|
|
|
302
340
|
if (!Number.isFinite(balance.usdValue) || balance.usdValue < 0) {
|
|
@@ -311,14 +349,23 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
311
349
|
collateralPrice: 0,
|
|
312
350
|
debtPrice: 0,
|
|
313
351
|
vesuLeverage: 0,
|
|
352
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
314
353
|
};
|
|
315
354
|
}
|
|
316
|
-
logger.info(
|
|
317
|
-
|
|
355
|
+
logger.info(
|
|
356
|
+
`${VesuExtendedMultiplierStrategy.name}::shouldInvest balance: ${balance.usdValue}`
|
|
357
|
+
);
|
|
358
|
+
const usdcBalanceOnExtended =
|
|
359
|
+
await extendedAdapter.getExtendedDepositAmount();
|
|
318
360
|
|
|
319
361
|
if (usdcBalanceOnExtended) {
|
|
320
|
-
const availableForWithdrawal = parseFloat(
|
|
321
|
-
|
|
362
|
+
const availableForWithdrawal = parseFloat(
|
|
363
|
+
usdcBalanceOnExtended.availableForWithdrawal
|
|
364
|
+
);
|
|
365
|
+
if (
|
|
366
|
+
!Number.isFinite(availableForWithdrawal) ||
|
|
367
|
+
availableForWithdrawal < 0
|
|
368
|
+
) {
|
|
322
369
|
logger.error(
|
|
323
370
|
`Invalid usdcBalanceOnExtended.availableForWithdrawal: ${usdcBalanceOnExtended.availableForWithdrawal}. Expected a finite, non-negative number.`
|
|
324
371
|
);
|
|
@@ -330,13 +377,18 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
330
377
|
collateralPrice: 0,
|
|
331
378
|
debtPrice: 0,
|
|
332
379
|
vesuLeverage: 0,
|
|
380
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
333
381
|
};
|
|
334
382
|
}
|
|
335
383
|
}
|
|
336
384
|
|
|
337
385
|
/** The LIMIT_BALANCE is the bffer amount to keep in the investing Cycle */
|
|
338
|
-
const amountToInvest = new Web3Number(
|
|
339
|
-
|
|
386
|
+
const amountToInvest = new Web3Number(
|
|
387
|
+
balance.usdValue,
|
|
388
|
+
USDC_TOKEN_DECIMALS
|
|
389
|
+
)
|
|
390
|
+
.plus(usdcBalanceOnExtended?.availableForTrade ?? 0)
|
|
391
|
+
.multipliedBy(1 - LIMIT_BALANCE);
|
|
340
392
|
|
|
341
393
|
const amountToInvestNumber = amountToInvest.toNumber();
|
|
342
394
|
if (!Number.isFinite(amountToInvestNumber)) {
|
|
@@ -351,10 +403,14 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
351
403
|
collateralPrice: 0,
|
|
352
404
|
debtPrice: 0,
|
|
353
405
|
vesuLeverage: 0,
|
|
406
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
354
407
|
};
|
|
355
408
|
}
|
|
356
409
|
|
|
357
|
-
logger.info(
|
|
410
|
+
logger.info(
|
|
411
|
+
`${VesuExtendedMultiplierStrategy.name}::shouldInvest amountToInvest: ${amountToInvestNumber}`
|
|
412
|
+
);
|
|
413
|
+
|
|
358
414
|
if (amountToInvest.lessThan(LIMIT_BALANCE_VALUE)) {
|
|
359
415
|
return {
|
|
360
416
|
shouldInvest: false,
|
|
@@ -364,6 +420,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
364
420
|
collateralPrice: 0,
|
|
365
421
|
debtPrice: 0,
|
|
366
422
|
vesuLeverage: 0,
|
|
423
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
367
424
|
};
|
|
368
425
|
}
|
|
369
426
|
|
|
@@ -378,18 +435,18 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
378
435
|
collateralPrice: 0,
|
|
379
436
|
debtPrice: 0,
|
|
380
437
|
vesuLeverage: 0,
|
|
438
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
381
439
|
};
|
|
382
440
|
}
|
|
383
|
-
const { collateralTokenAmount } =
|
|
441
|
+
const { collateralTokenAmount, debtTokenAmount } =
|
|
384
442
|
await vesuAdapter.vesuAdapter.getAssetPrices();
|
|
385
443
|
|
|
386
|
-
const {
|
|
387
|
-
collateralPrice,
|
|
388
|
-
debtPrice
|
|
389
|
-
} = await this.getAssetPrices();
|
|
390
|
-
|
|
444
|
+
const { collateralPrice, debtPrice } = await this.getAssetPrices();
|
|
391
445
|
|
|
392
|
-
if (
|
|
446
|
+
if (
|
|
447
|
+
!Number.isFinite(collateralPrice.price) ||
|
|
448
|
+
collateralPrice.price <= 0
|
|
449
|
+
) {
|
|
393
450
|
logger.error(
|
|
394
451
|
`Invalid collateralPrice: ${collateralPrice.price}. Expected a finite, positive number.`
|
|
395
452
|
);
|
|
@@ -401,6 +458,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
401
458
|
collateralPrice: 0,
|
|
402
459
|
debtPrice: 0,
|
|
403
460
|
vesuLeverage: 0,
|
|
461
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
404
462
|
};
|
|
405
463
|
}
|
|
406
464
|
if (!Number.isFinite(debtPrice.price) || debtPrice.price <= 0) {
|
|
@@ -415,12 +473,35 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
415
473
|
collateralPrice: 0,
|
|
416
474
|
debtPrice: 0,
|
|
417
475
|
vesuLeverage: 0,
|
|
476
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
418
477
|
};
|
|
419
478
|
}
|
|
420
479
|
|
|
480
|
+
const debtAmountToBeRepaid = calculateDeltaDebtAmount(
|
|
481
|
+
MAX_LTV_BTC_USDC,
|
|
482
|
+
collateralTokenAmount,
|
|
483
|
+
debtTokenAmount,
|
|
484
|
+
collateralPrice.price,
|
|
485
|
+
debtPrice.price,
|
|
486
|
+
this.metadata.additionalInfo.targetHealthFactor
|
|
487
|
+
);
|
|
488
|
+
if (!debtAmountToBeRepaid) {
|
|
489
|
+
logger.error("error calculating debt amount to be repaid");
|
|
490
|
+
return {
|
|
491
|
+
shouldInvest: false,
|
|
492
|
+
vesuAmount: new Web3Number(0, 0),
|
|
493
|
+
extendedAmount: new Web3Number(0, 0),
|
|
494
|
+
extendedLeverage: 0,
|
|
495
|
+
collateralPrice: 0,
|
|
496
|
+
debtPrice: 0,
|
|
497
|
+
vesuLeverage: 0,
|
|
498
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
const amountToInvestAfterRepayingDebt = amountToInvest.minus(debtAmountToBeRepaid);
|
|
421
502
|
const { vesu_amount, extended_amount, extended_leverage, vesu_leverage } =
|
|
422
503
|
await calculateAmountDistribution(
|
|
423
|
-
|
|
504
|
+
amountToInvestAfterRepayingDebt.toNumber(),
|
|
424
505
|
extendedAdapter.client,
|
|
425
506
|
extendedAdapter.config.extendedMarketName,
|
|
426
507
|
collateralPrice.price,
|
|
@@ -445,9 +526,14 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
445
526
|
collateralPrice: 0,
|
|
446
527
|
debtPrice: 0,
|
|
447
528
|
vesuLeverage: 0,
|
|
529
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
448
530
|
};
|
|
449
531
|
}
|
|
450
|
-
logger.info(
|
|
532
|
+
logger.info(
|
|
533
|
+
`${
|
|
534
|
+
VesuExtendedMultiplierStrategy.name
|
|
535
|
+
}::shouldInvest vesu_amount: ${vesu_amount.toNumber()}, extended_amount: ${extended_amount.toNumber()}`
|
|
536
|
+
);
|
|
451
537
|
return {
|
|
452
538
|
shouldInvest: true,
|
|
453
539
|
vesuAmount: vesu_amount,
|
|
@@ -456,6 +542,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
456
542
|
vesuLeverage: vesu_leverage,
|
|
457
543
|
collateralPrice: collateralPrice.price,
|
|
458
544
|
debtPrice: debtPrice.price,
|
|
545
|
+
debtAmountToBeRepaid: debtAmountToBeRepaid,
|
|
459
546
|
};
|
|
460
547
|
} catch (err) {
|
|
461
548
|
logger.error(`error deciding invest: ${err}`);
|
|
@@ -467,11 +554,15 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
467
554
|
collateralPrice: 0,
|
|
468
555
|
debtPrice: 0,
|
|
469
556
|
vesuLeverage: 0,
|
|
557
|
+
debtAmountToBeRepaid: new Web3Number(0, 0),
|
|
470
558
|
};
|
|
471
559
|
}
|
|
472
560
|
}
|
|
473
561
|
|
|
474
|
-
async shouldMoveAssets(
|
|
562
|
+
async shouldMoveAssets(
|
|
563
|
+
extendedAmount: Web3Number,
|
|
564
|
+
vesuAmount: Web3Number
|
|
565
|
+
): Promise<TransactionResult[]> {
|
|
475
566
|
try {
|
|
476
567
|
const vesuAdapter = await this.getVesuAdapter();
|
|
477
568
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
@@ -495,13 +586,24 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
495
586
|
extendedHoldings.availableForTrade
|
|
496
587
|
);
|
|
497
588
|
|
|
498
|
-
logger.info(
|
|
589
|
+
logger.info(
|
|
590
|
+
`${
|
|
591
|
+
VesuExtendedMultiplierStrategy.name
|
|
592
|
+
}::shouldMoveAssets calculating movements - Extended current: ${usdcAmountOnExtendedAvailableForTrade}, Wallet: ${usdcAmountInWallet.toNumber()}, Target Extended: ${extendedAmount.toNumber()}, Target Vesu: ${vesuAmount.toNumber()}`
|
|
593
|
+
);
|
|
499
594
|
|
|
500
595
|
let totalExtendedWithdrawal = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
501
596
|
let totalExtendedDeposit = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
502
597
|
|
|
503
|
-
if (
|
|
504
|
-
|
|
598
|
+
if (
|
|
599
|
+
extendedAmount.isNegative() &&
|
|
600
|
+
extendedAmount
|
|
601
|
+
.abs()
|
|
602
|
+
.greaterThan(extendedAdapter.minimumExtendedMovementAmount)
|
|
603
|
+
) {
|
|
604
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(
|
|
605
|
+
extendedAmount.abs()
|
|
606
|
+
);
|
|
505
607
|
}
|
|
506
608
|
|
|
507
609
|
// Calculate remaining Extended difference (target vs current)
|
|
@@ -511,17 +613,24 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
511
613
|
let projectedExtendedBalance = usdcAmountOnExtendedAvailableForTrade;
|
|
512
614
|
|
|
513
615
|
if (extendedAmount.isNegative()) {
|
|
514
|
-
projectedExtendedBalance =
|
|
616
|
+
projectedExtendedBalance =
|
|
617
|
+
projectedExtendedBalance - extendedAmount.abs().toNumber();
|
|
515
618
|
}
|
|
516
619
|
|
|
517
|
-
const extendedAmountDifference = extendedTargetAmount.minus(
|
|
620
|
+
const extendedAmountDifference = extendedTargetAmount.minus(
|
|
621
|
+
projectedExtendedBalance
|
|
622
|
+
);
|
|
518
623
|
const extendedAmountDifferenceAbs = extendedAmountDifference.abs();
|
|
519
624
|
|
|
520
625
|
// Track additional Extended movements
|
|
521
626
|
if (extendedAmountDifference.lessThan(0)) {
|
|
522
|
-
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(
|
|
627
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(
|
|
628
|
+
extendedAmountDifferenceAbs
|
|
629
|
+
);
|
|
523
630
|
} else if (extendedAmountDifference.greaterThan(0)) {
|
|
524
|
-
totalExtendedDeposit = totalExtendedDeposit.plus(
|
|
631
|
+
totalExtendedDeposit = totalExtendedDeposit.plus(
|
|
632
|
+
extendedAmountDifference
|
|
633
|
+
);
|
|
525
634
|
}
|
|
526
635
|
|
|
527
636
|
const vesuTargetAmount = vesuAmount.abs();
|
|
@@ -532,18 +641,31 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
532
641
|
let vesuAmountDifference = vesuTargetAmount.minus(projectedWalletBalance);
|
|
533
642
|
const vesuAmountDifferenceAbs = vesuAmountDifference.abs();
|
|
534
643
|
|
|
535
|
-
logger.info(
|
|
644
|
+
logger.info(
|
|
645
|
+
`${
|
|
646
|
+
VesuExtendedMultiplierStrategy.name
|
|
647
|
+
}::shouldMoveAssets calculated movements - Extended withdrawal: ${totalExtendedWithdrawal.toNumber()}, Extended deposit: ${totalExtendedDeposit.toNumber()}, Extended diff: ${extendedAmountDifference.toNumber()}, Projected wallet: ${projectedWalletBalance.toNumber()}, Vesu diff: ${vesuAmountDifference.toNumber()}`
|
|
648
|
+
);
|
|
536
649
|
let transactionResults: TransactionResult[] = [];
|
|
537
650
|
|
|
538
651
|
// Handle negative extendedAmount (initial withdrawal needed)
|
|
539
|
-
if (
|
|
652
|
+
if (
|
|
653
|
+
extendedAmount.isNegative() &&
|
|
654
|
+
extendedAmount
|
|
655
|
+
.abs()
|
|
656
|
+
.greaterThan(extendedAdapter.minimumExtendedMovementAmount)
|
|
657
|
+
) {
|
|
540
658
|
try {
|
|
541
|
-
const {
|
|
659
|
+
const {
|
|
660
|
+
calls: extendedCalls,
|
|
661
|
+
status: extendedStatus,
|
|
662
|
+
transactionMetadata: extendedTransactionMetadata,
|
|
663
|
+
} = await this.moveAssets(
|
|
542
664
|
{
|
|
543
665
|
to: Protocols.VAULT.name,
|
|
544
666
|
from: Protocols.EXTENDED.name,
|
|
545
667
|
amount: extendedAmount.abs(),
|
|
546
|
-
cycleType: CycleType.INVESTMENT
|
|
668
|
+
cycleType: CycleType.INVESTMENT,
|
|
547
669
|
},
|
|
548
670
|
extendedAdapter,
|
|
549
671
|
vesuAdapter
|
|
@@ -556,30 +678,73 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
556
678
|
...extendedTransactionMetadata,
|
|
557
679
|
transactionType: "DEPOSIT",
|
|
558
680
|
},
|
|
559
|
-
})
|
|
681
|
+
});
|
|
560
682
|
} else {
|
|
561
|
-
return [
|
|
683
|
+
return [
|
|
684
|
+
this.createTransactionResult(
|
|
685
|
+
[],
|
|
686
|
+
false,
|
|
687
|
+
{
|
|
688
|
+
from: Protocols.EXTENDED.name,
|
|
689
|
+
to: Protocols.VAULT.name,
|
|
690
|
+
amount: extendedAmount.abs(),
|
|
691
|
+
},
|
|
692
|
+
"NONE",
|
|
693
|
+
CycleType.INVESTMENT
|
|
694
|
+
),
|
|
695
|
+
];
|
|
562
696
|
}
|
|
563
697
|
} catch (err) {
|
|
564
698
|
logger.error(`Failed moving assets to vault: ${err}`);
|
|
565
|
-
return [
|
|
699
|
+
return [
|
|
700
|
+
this.createTransactionResult(
|
|
701
|
+
[],
|
|
702
|
+
false,
|
|
703
|
+
{
|
|
704
|
+
from: Protocols.EXTENDED.name,
|
|
705
|
+
to: Protocols.VAULT.name,
|
|
706
|
+
amount: extendedAmount.abs(),
|
|
707
|
+
},
|
|
708
|
+
"NONE",
|
|
709
|
+
CycleType.INVESTMENT
|
|
710
|
+
),
|
|
711
|
+
];
|
|
566
712
|
}
|
|
567
713
|
}
|
|
568
714
|
|
|
569
|
-
if (
|
|
715
|
+
if (
|
|
716
|
+
vesuAmount.isNegative() &&
|
|
717
|
+
vesuAmount.abs().greaterThan(vesuAdapter.minimumVesuMovementAmount)
|
|
718
|
+
) {
|
|
570
719
|
try {
|
|
571
|
-
const {
|
|
720
|
+
const {
|
|
721
|
+
calls: vesuCalls,
|
|
722
|
+
status: vesuStatus,
|
|
723
|
+
transactionMetadata: vesuTransactionMetadata,
|
|
724
|
+
} = await this.moveAssets(
|
|
572
725
|
{
|
|
573
726
|
to: Protocols.EXTENDED.name,
|
|
574
727
|
from: Protocols.VESU.name,
|
|
575
728
|
amount: vesuAmount.abs(),
|
|
576
|
-
cycleType: CycleType.INVESTMENT
|
|
729
|
+
cycleType: CycleType.INVESTMENT,
|
|
577
730
|
},
|
|
578
731
|
extendedAdapter,
|
|
579
732
|
vesuAdapter
|
|
580
733
|
);
|
|
581
734
|
if (!vesuStatus) {
|
|
582
|
-
return [
|
|
735
|
+
return [
|
|
736
|
+
this.createTransactionResult(
|
|
737
|
+
[],
|
|
738
|
+
false,
|
|
739
|
+
{
|
|
740
|
+
from: Protocols.VESU.name,
|
|
741
|
+
to: Protocols.EXTENDED.name,
|
|
742
|
+
amount: vesuAmount.abs(),
|
|
743
|
+
},
|
|
744
|
+
"NONE",
|
|
745
|
+
CycleType.INVESTMENT
|
|
746
|
+
),
|
|
747
|
+
];
|
|
583
748
|
}
|
|
584
749
|
transactionResults.push({
|
|
585
750
|
status: vesuStatus,
|
|
@@ -587,24 +752,46 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
587
752
|
transactionMetadata: {
|
|
588
753
|
...vesuTransactionMetadata,
|
|
589
754
|
transactionType: "DEPOSIT",
|
|
590
|
-
}
|
|
591
|
-
})
|
|
755
|
+
},
|
|
756
|
+
});
|
|
592
757
|
} catch (err) {
|
|
593
|
-
logger.error(
|
|
594
|
-
|
|
758
|
+
logger.error(
|
|
759
|
+
`Failed moving assets to extended via vault allocator: ${err}`
|
|
760
|
+
);
|
|
761
|
+
return [
|
|
762
|
+
this.createTransactionResult(
|
|
763
|
+
[],
|
|
764
|
+
false,
|
|
765
|
+
{
|
|
766
|
+
from: Protocols.VESU.name,
|
|
767
|
+
to: Protocols.EXTENDED.name,
|
|
768
|
+
amount: vesuAmount.abs(),
|
|
769
|
+
},
|
|
770
|
+
"NONE",
|
|
771
|
+
CycleType.INVESTMENT
|
|
772
|
+
),
|
|
773
|
+
];
|
|
595
774
|
}
|
|
596
775
|
}
|
|
597
776
|
|
|
598
777
|
// Handle Extended adjustments based on calculated difference
|
|
599
|
-
if (
|
|
778
|
+
if (
|
|
779
|
+
extendedAmountDifferenceAbs.greaterThan(
|
|
780
|
+
extendedAdapter.minimumExtendedMovementAmount
|
|
781
|
+
)
|
|
782
|
+
) {
|
|
600
783
|
if (extendedAmountDifference.greaterThan(0)) {
|
|
601
784
|
try {
|
|
602
|
-
const {
|
|
785
|
+
const {
|
|
786
|
+
calls: extendedCalls,
|
|
787
|
+
status: extendedStatus,
|
|
788
|
+
transactionMetadata: extendedTransactionMetadata,
|
|
789
|
+
} = await this.moveAssets(
|
|
603
790
|
{
|
|
604
791
|
to: Protocols.EXTENDED.name,
|
|
605
792
|
from: Protocols.VAULT.name,
|
|
606
793
|
amount: extendedAmountDifference,
|
|
607
|
-
cycleType: CycleType.INVESTMENT
|
|
794
|
+
cycleType: CycleType.INVESTMENT,
|
|
608
795
|
},
|
|
609
796
|
extendedAdapter,
|
|
610
797
|
vesuAdapter
|
|
@@ -613,24 +800,54 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
613
800
|
transactionResults.push({
|
|
614
801
|
status: extendedStatus,
|
|
615
802
|
calls: extendedCalls,
|
|
616
|
-
transactionMetadata: extendedTransactionMetadata
|
|
617
|
-
})
|
|
803
|
+
transactionMetadata: extendedTransactionMetadata,
|
|
804
|
+
});
|
|
618
805
|
} else {
|
|
619
|
-
logger.error(
|
|
620
|
-
|
|
806
|
+
logger.error(
|
|
807
|
+
`Failed to move assets to extended - operation returned false status`
|
|
808
|
+
);
|
|
809
|
+
return [
|
|
810
|
+
this.createTransactionResult(
|
|
811
|
+
[],
|
|
812
|
+
false,
|
|
813
|
+
{
|
|
814
|
+
from: Protocols.VAULT.name,
|
|
815
|
+
to: Protocols.EXTENDED.name,
|
|
816
|
+
amount: extendedAmountDifference,
|
|
817
|
+
},
|
|
818
|
+
"NONE",
|
|
819
|
+
CycleType.INVESTMENT
|
|
820
|
+
),
|
|
821
|
+
];
|
|
621
822
|
}
|
|
622
823
|
} catch (err) {
|
|
623
824
|
logger.error(`Failed moving assets to extended: ${err}`);
|
|
624
|
-
return [
|
|
825
|
+
return [
|
|
826
|
+
this.createTransactionResult(
|
|
827
|
+
[],
|
|
828
|
+
false,
|
|
829
|
+
{
|
|
830
|
+
from: Protocols.VAULT.name,
|
|
831
|
+
to: Protocols.EXTENDED.name,
|
|
832
|
+
amount: extendedAmountDifference,
|
|
833
|
+
},
|
|
834
|
+
"NONE",
|
|
835
|
+
CycleType.INVESTMENT
|
|
836
|
+
),
|
|
837
|
+
];
|
|
625
838
|
}
|
|
626
839
|
} else if (extendedAmountDifference.lessThan(0)) {
|
|
627
840
|
try {
|
|
628
|
-
const {
|
|
841
|
+
const {
|
|
842
|
+
calls: extendedCalls,
|
|
843
|
+
status: extendedStatus,
|
|
844
|
+
transactionMetadata: extendedTransactionMetadata,
|
|
845
|
+
} = await this.moveAssets(
|
|
629
846
|
{
|
|
630
847
|
to: Protocols.VAULT.name,
|
|
631
848
|
from: Protocols.EXTENDED.name,
|
|
632
849
|
amount: extendedAmountDifferenceAbs,
|
|
633
|
-
cycleType: CycleType.INVESTMENT
|
|
850
|
+
cycleType: CycleType.INVESTMENT,
|
|
634
851
|
},
|
|
635
852
|
extendedAdapter,
|
|
636
853
|
vesuAdapter
|
|
@@ -642,21 +859,51 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
642
859
|
transactionMetadata: {
|
|
643
860
|
...extendedTransactionMetadata,
|
|
644
861
|
transactionType: "DEPOSIT",
|
|
645
|
-
}
|
|
646
|
-
})
|
|
862
|
+
},
|
|
863
|
+
});
|
|
647
864
|
} else {
|
|
648
|
-
logger.error(
|
|
649
|
-
|
|
865
|
+
logger.error(
|
|
866
|
+
`Failed to withdraw from extended - operation returned false status`
|
|
867
|
+
);
|
|
868
|
+
return [
|
|
869
|
+
this.createTransactionResult(
|
|
870
|
+
[],
|
|
871
|
+
false,
|
|
872
|
+
{
|
|
873
|
+
from: Protocols.EXTENDED.name,
|
|
874
|
+
to: Protocols.VAULT.name,
|
|
875
|
+
amount: extendedAmountDifferenceAbs,
|
|
876
|
+
},
|
|
877
|
+
"NONE",
|
|
878
|
+
CycleType.INVESTMENT
|
|
879
|
+
),
|
|
880
|
+
];
|
|
650
881
|
}
|
|
651
882
|
} catch (err) {
|
|
652
883
|
logger.error(`Failed moving assets from extended to vault: ${err}`);
|
|
653
|
-
return [
|
|
884
|
+
return [
|
|
885
|
+
this.createTransactionResult(
|
|
886
|
+
[],
|
|
887
|
+
false,
|
|
888
|
+
{
|
|
889
|
+
from: Protocols.EXTENDED.name,
|
|
890
|
+
to: Protocols.VAULT.name,
|
|
891
|
+
amount: extendedAmountDifferenceAbs,
|
|
892
|
+
},
|
|
893
|
+
"NONE",
|
|
894
|
+
CycleType.INVESTMENT
|
|
895
|
+
),
|
|
896
|
+
];
|
|
654
897
|
}
|
|
655
898
|
}
|
|
656
899
|
}
|
|
657
900
|
|
|
658
901
|
// Handle Vesu adjustments based on calculated difference (already adjusted for Extended movements)
|
|
659
|
-
if (
|
|
902
|
+
if (
|
|
903
|
+
vesuAmountDifferenceAbs.greaterThan(
|
|
904
|
+
vesuAdapter.minimumVesuMovementAmount
|
|
905
|
+
)
|
|
906
|
+
) {
|
|
660
907
|
if (vesuAmountDifference.lessThanOrEqualTo(0)) {
|
|
661
908
|
logger.warn(
|
|
662
909
|
`Vesu amount difference is negative or zero: ${vesuAmountDifference.toNumber()}. Skipping operation.`
|
|
@@ -664,19 +911,37 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
664
911
|
} else {
|
|
665
912
|
// Move assets from Extended to Vault (which will then go to Vesu)
|
|
666
913
|
try {
|
|
667
|
-
const {
|
|
914
|
+
const {
|
|
915
|
+
calls: vesuCalls,
|
|
916
|
+
status: vesuStatus,
|
|
917
|
+
transactionMetadata: vesuTransactionMetadata,
|
|
918
|
+
} = await this.moveAssets(
|
|
668
919
|
{
|
|
669
920
|
to: Protocols.VAULT.name,
|
|
670
921
|
from: Protocols.EXTENDED.name,
|
|
671
922
|
amount: vesuAmountDifference,
|
|
672
|
-
cycleType: CycleType.INVESTMENT
|
|
923
|
+
cycleType: CycleType.INVESTMENT,
|
|
673
924
|
},
|
|
674
925
|
extendedAdapter,
|
|
675
926
|
vesuAdapter
|
|
676
927
|
);
|
|
677
928
|
if (!vesuStatus) {
|
|
678
|
-
logger.error(
|
|
679
|
-
|
|
929
|
+
logger.error(
|
|
930
|
+
`Failed to move assets to vesu - operation returned false status`
|
|
931
|
+
);
|
|
932
|
+
return [
|
|
933
|
+
this.createTransactionResult(
|
|
934
|
+
[],
|
|
935
|
+
false,
|
|
936
|
+
{
|
|
937
|
+
from: Protocols.EXTENDED.name,
|
|
938
|
+
to: Protocols.VAULT.name,
|
|
939
|
+
amount: vesuAmountDifference,
|
|
940
|
+
},
|
|
941
|
+
"NONE",
|
|
942
|
+
CycleType.INVESTMENT
|
|
943
|
+
),
|
|
944
|
+
];
|
|
680
945
|
}
|
|
681
946
|
transactionResults.push({
|
|
682
947
|
status: vesuStatus,
|
|
@@ -684,18 +949,42 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
684
949
|
transactionMetadata: {
|
|
685
950
|
...vesuTransactionMetadata,
|
|
686
951
|
transactionType: "DEPOSIT",
|
|
687
|
-
}
|
|
688
|
-
})
|
|
952
|
+
},
|
|
953
|
+
});
|
|
689
954
|
} catch (err) {
|
|
690
955
|
logger.error(`Failed moving assets to vault: ${err}`);
|
|
691
|
-
return [
|
|
956
|
+
return [
|
|
957
|
+
this.createTransactionResult(
|
|
958
|
+
[],
|
|
959
|
+
false,
|
|
960
|
+
{
|
|
961
|
+
from: Protocols.EXTENDED.name,
|
|
962
|
+
to: Protocols.VAULT.name,
|
|
963
|
+
amount: vesuAmountDifference,
|
|
964
|
+
},
|
|
965
|
+
"NONE",
|
|
966
|
+
CycleType.INVESTMENT
|
|
967
|
+
),
|
|
968
|
+
];
|
|
692
969
|
}
|
|
693
970
|
}
|
|
694
971
|
}
|
|
695
972
|
return transactionResults;
|
|
696
973
|
} catch (err) {
|
|
697
974
|
logger.error(`Failed moving assets to vesu: ${err}`);
|
|
698
|
-
return [
|
|
975
|
+
return [
|
|
976
|
+
this.createTransactionResult(
|
|
977
|
+
[],
|
|
978
|
+
false,
|
|
979
|
+
{
|
|
980
|
+
from: Protocols.EXTENDED.name,
|
|
981
|
+
to: Protocols.VAULT.name,
|
|
982
|
+
amount: new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
983
|
+
},
|
|
984
|
+
"NONE",
|
|
985
|
+
CycleType.INVESTMENT
|
|
986
|
+
),
|
|
987
|
+
];
|
|
699
988
|
}
|
|
700
989
|
}
|
|
701
990
|
|
|
@@ -706,7 +995,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
706
995
|
calls: Call[],
|
|
707
996
|
status: boolean,
|
|
708
997
|
params: { from: string; to: string; amount: Web3Number },
|
|
709
|
-
transactionType:
|
|
998
|
+
transactionType: "DEPOSIT" | "WITHDRAWAL" | "NONE",
|
|
710
999
|
cycleType: CycleType
|
|
711
1000
|
): TransactionResult {
|
|
712
1001
|
if (status) {
|
|
@@ -718,12 +1007,23 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
718
1007
|
protocolTo: params.to,
|
|
719
1008
|
transactionType: transactionType,
|
|
720
1009
|
usdAmount: params.amount.abs().toFixed(),
|
|
721
|
-
status:
|
|
722
|
-
cycleType: cycleType
|
|
723
|
-
}
|
|
1010
|
+
status: "PENDING",
|
|
1011
|
+
cycleType: cycleType,
|
|
1012
|
+
},
|
|
724
1013
|
};
|
|
725
1014
|
}
|
|
726
|
-
return {
|
|
1015
|
+
return {
|
|
1016
|
+
calls: [],
|
|
1017
|
+
status: false,
|
|
1018
|
+
transactionMetadata: {
|
|
1019
|
+
protocolFrom: "",
|
|
1020
|
+
protocolTo: "",
|
|
1021
|
+
transactionType: "DEPOSIT",
|
|
1022
|
+
usdAmount: "0",
|
|
1023
|
+
status: "FAILED",
|
|
1024
|
+
cycleType: cycleType,
|
|
1025
|
+
},
|
|
1026
|
+
};
|
|
727
1027
|
}
|
|
728
1028
|
|
|
729
1029
|
/**
|
|
@@ -732,7 +1032,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
732
1032
|
* @param extendedAdapter - The extended adapter
|
|
733
1033
|
* @param vesuAdapter - The vesu adapter
|
|
734
1034
|
* @returns The transaction result
|
|
735
|
-
* If Extended amount is greater than amount of withdrawal from extended, then we need to open a long position
|
|
1035
|
+
* If Extended amount is greater than amount of withdrawal from extended, then we need to open a long position
|
|
736
1036
|
* so that the amount of withdrawal from extended is fullfilled
|
|
737
1037
|
*/
|
|
738
1038
|
async moveAssets(
|
|
@@ -743,7 +1043,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
743
1043
|
cycleType: CycleType;
|
|
744
1044
|
},
|
|
745
1045
|
extendedAdapter: ExtendedAdapter,
|
|
746
|
-
vesuAdapter: VesuMultiplyAdapter
|
|
1046
|
+
vesuAdapter: VesuMultiplyAdapter
|
|
747
1047
|
): Promise<TransactionResult> {
|
|
748
1048
|
try {
|
|
749
1049
|
// Validate amount is positive before starting operations
|
|
@@ -751,7 +1051,13 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
751
1051
|
logger.error(
|
|
752
1052
|
`Invalid amount for moveAssets: ${params.amount.toNumber()}. Amount must be positive.`
|
|
753
1053
|
);
|
|
754
|
-
return this.createTransactionResult(
|
|
1054
|
+
return this.createTransactionResult(
|
|
1055
|
+
[],
|
|
1056
|
+
false,
|
|
1057
|
+
params,
|
|
1058
|
+
"NONE",
|
|
1059
|
+
params.cycleType
|
|
1060
|
+
);
|
|
755
1061
|
}
|
|
756
1062
|
|
|
757
1063
|
// Check minimum movement amounts before starting operations
|
|
@@ -776,15 +1082,22 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
776
1082
|
const avnuAdapter = await this.getAvnuAdapter();
|
|
777
1083
|
if (!avnuAdapter) {
|
|
778
1084
|
logger.error(`avnu adapter not found: ${avnuAdapter}`);
|
|
779
|
-
return this.createTransactionResult(
|
|
1085
|
+
return this.createTransactionResult(
|
|
1086
|
+
[],
|
|
1087
|
+
false,
|
|
1088
|
+
params,
|
|
1089
|
+
"NONE",
|
|
1090
|
+
params.cycleType
|
|
1091
|
+
);
|
|
780
1092
|
}
|
|
781
1093
|
logger.info(`moveAssets params, ${JSON.stringify(params)}`);
|
|
782
1094
|
const collateralToken = vesuAdapter.config.supportedPositions[0].asset;
|
|
783
|
-
const {
|
|
784
|
-
collateralPrice,
|
|
785
|
-
} = await this.getAssetPrices();
|
|
1095
|
+
const { collateralPrice } = await this.getAssetPrices();
|
|
786
1096
|
|
|
787
|
-
if (
|
|
1097
|
+
if (
|
|
1098
|
+
params.to === Protocols.EXTENDED.name &&
|
|
1099
|
+
params.from === Protocols.VAULT.name
|
|
1100
|
+
) {
|
|
788
1101
|
const proofsInfo = extendedAdapter.getProofs(
|
|
789
1102
|
true,
|
|
790
1103
|
this.getMerkleTree()
|
|
@@ -796,29 +1109,54 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
796
1109
|
await proofsInfo.callConstructor({ amount: params.amount })
|
|
797
1110
|
);
|
|
798
1111
|
calls.push(call);
|
|
799
|
-
return this.createTransactionResult(
|
|
800
|
-
|
|
801
|
-
|
|
1112
|
+
return this.createTransactionResult(
|
|
1113
|
+
calls,
|
|
1114
|
+
true,
|
|
1115
|
+
params,
|
|
1116
|
+
"DEPOSIT",
|
|
1117
|
+
params.cycleType
|
|
1118
|
+
);
|
|
1119
|
+
} else if (
|
|
1120
|
+
params.to === Protocols.VAULT.name &&
|
|
1121
|
+
params.from === Protocols.EXTENDED.name
|
|
1122
|
+
) {
|
|
802
1123
|
const extendedLeverage = calculateExtendedLevergae();
|
|
803
|
-
const extendedHoldings =
|
|
1124
|
+
const extendedHoldings =
|
|
1125
|
+
await extendedAdapter.getExtendedDepositAmount();
|
|
804
1126
|
if (!extendedHoldings) {
|
|
805
1127
|
logger.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
806
|
-
return this.createTransactionResult(
|
|
1128
|
+
return this.createTransactionResult(
|
|
1129
|
+
[],
|
|
1130
|
+
false,
|
|
1131
|
+
params,
|
|
1132
|
+
"NONE",
|
|
1133
|
+
params.cycleType
|
|
1134
|
+
);
|
|
807
1135
|
}
|
|
808
1136
|
const extendedHoldingAmount = new Web3Number(
|
|
809
1137
|
extendedHoldings.availableForWithdrawal,
|
|
810
1138
|
USDC_TOKEN_DECIMALS
|
|
811
1139
|
);
|
|
812
|
-
logger.info(
|
|
1140
|
+
logger.info(
|
|
1141
|
+
`${
|
|
1142
|
+
VesuExtendedMultiplierStrategy.name
|
|
1143
|
+
}::moveAssets extendedHoldingAmount: ${extendedHoldingAmount.toNumber()}`
|
|
1144
|
+
);
|
|
813
1145
|
if (params.amount.abs().greaterThan(extendedHoldingAmount)) {
|
|
814
|
-
const leftAmountAfterWithdrawalAmountInAccount = new Web3Number(
|
|
815
|
-
|
|
1146
|
+
const leftAmountAfterWithdrawalAmountInAccount = new Web3Number(
|
|
1147
|
+
Math.ceil(
|
|
1148
|
+
params.amount.abs().minus(extendedHoldingAmount).toNumber()
|
|
1149
|
+
),
|
|
1150
|
+
USDC_TOKEN_DECIMALS
|
|
1151
|
+
);
|
|
1152
|
+
logger.info(
|
|
1153
|
+
`${
|
|
1154
|
+
VesuExtendedMultiplierStrategy.name
|
|
1155
|
+
}::moveAssets leftAmountAfterWithdrawalAmountInAccount: ${leftAmountAfterWithdrawalAmountInAccount.toNumber()}`
|
|
1156
|
+
);
|
|
816
1157
|
let priceOfBTC;
|
|
817
|
-
const {
|
|
818
|
-
|
|
819
|
-
bid,
|
|
820
|
-
status
|
|
821
|
-
} = await extendedAdapter.fetchOrderBookBTCUSDC();
|
|
1158
|
+
const { ask, bid, status } =
|
|
1159
|
+
await extendedAdapter.fetchOrderBookBTCUSDC();
|
|
822
1160
|
const price = ask.plus(bid).dividedBy(2);
|
|
823
1161
|
if (status) {
|
|
824
1162
|
priceOfBTC = price;
|
|
@@ -826,73 +1164,149 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
826
1164
|
logger.error(`error fetching order book btc usdc: ${status}`);
|
|
827
1165
|
priceOfBTC = collateralPrice.price;
|
|
828
1166
|
}
|
|
829
|
-
const btcAmount =
|
|
1167
|
+
const btcAmount =
|
|
1168
|
+
leftAmountAfterWithdrawalAmountInAccount.dividedBy(priceOfBTC);
|
|
830
1169
|
/**
|
|
831
1170
|
* If amount for withdrawal is greater than the amount in extended available for withdrawal,
|
|
832
1171
|
* then we need to open a long position depending on the difference between the two
|
|
833
1172
|
*/
|
|
834
|
-
const openLongPosition = btcAmount
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
1173
|
+
const openLongPosition = btcAmount
|
|
1174
|
+
.multipliedBy(3)
|
|
1175
|
+
.greaterThan(MINIMUM_EXTENDED_POSITION_SIZE)
|
|
1176
|
+
? await extendedAdapter.createOrder(
|
|
1177
|
+
extendedLeverage.toString(),
|
|
1178
|
+
btcAmount.toNumber(),
|
|
1179
|
+
OrderSide.BUY
|
|
1180
|
+
)
|
|
1181
|
+
: await extendedAdapter.createOrder(
|
|
1182
|
+
extendedLeverage.toString(),
|
|
1183
|
+
0.000034, // just in case amount falls short then we need to create a withdrawal
|
|
1184
|
+
OrderSide.BUY
|
|
1185
|
+
);
|
|
843
1186
|
if (!openLongPosition) {
|
|
844
1187
|
logger.error(`error opening long position: ${openLongPosition}`);
|
|
845
1188
|
}
|
|
846
|
-
const updatedHoldings =
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1189
|
+
const updatedHoldings =
|
|
1190
|
+
await extendedAdapter.getExtendedDepositAmount();
|
|
1191
|
+
if (
|
|
1192
|
+
!updatedHoldings ||
|
|
1193
|
+
new Web3Number(
|
|
1194
|
+
updatedHoldings.availableForWithdrawal,
|
|
1195
|
+
USDC_TOKEN_DECIMALS
|
|
1196
|
+
).lessThan(params.amount.abs())
|
|
1197
|
+
) {
|
|
1198
|
+
logger.error(
|
|
1199
|
+
`Insufficient balance after opening position. Available: ${
|
|
1200
|
+
updatedHoldings?.availableForWithdrawal
|
|
1201
|
+
}, Needed: ${params.amount.abs()}`
|
|
1202
|
+
);
|
|
1203
|
+
return this.createTransactionResult(
|
|
1204
|
+
[],
|
|
1205
|
+
false,
|
|
1206
|
+
params,
|
|
1207
|
+
"NONE",
|
|
1208
|
+
params.cycleType
|
|
1209
|
+
);
|
|
850
1210
|
}
|
|
851
1211
|
}
|
|
852
1212
|
const {
|
|
853
1213
|
status: withdrawalFromExtendedStatus,
|
|
854
1214
|
receivedTxnHash: withdrawalFromExtendedTxnHash,
|
|
855
|
-
} =
|
|
856
|
-
await extendedAdapter.withdrawFromExtended(params.amount);
|
|
1215
|
+
} = await extendedAdapter.withdrawFromExtended(params.amount);
|
|
857
1216
|
/**
|
|
858
1217
|
* This logic needs fixing
|
|
859
1218
|
*/
|
|
860
|
-
logger.info(
|
|
1219
|
+
logger.info(
|
|
1220
|
+
`withdrawalFromExtendedStatus: ${withdrawalFromExtendedStatus}, withdrawalFromExtendedTxnHash: ${withdrawalFromExtendedTxnHash}`
|
|
1221
|
+
);
|
|
861
1222
|
if (withdrawalFromExtendedStatus && withdrawalFromExtendedTxnHash) {
|
|
862
1223
|
/**
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
const extendedHoldings =
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
1224
|
+
* We need to move assets from my wallet back to vault contract
|
|
1225
|
+
*/
|
|
1226
|
+
const extendedHoldings =
|
|
1227
|
+
await extendedAdapter.getExtendedDepositAmount();
|
|
1228
|
+
logger.info(
|
|
1229
|
+
`extendedHoldings after withdrawal ${extendedHoldings?.availableForWithdrawal}`
|
|
1230
|
+
);
|
|
1231
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
1232
|
+
const { calls, status } = await this.moveAssetsToVaultAllocator(
|
|
1233
|
+
params.amount,
|
|
1234
|
+
extendedAdapter
|
|
1235
|
+
);
|
|
869
1236
|
if (calls.length > 0 && status) {
|
|
870
|
-
return this.createTransactionResult(
|
|
1237
|
+
return this.createTransactionResult(
|
|
1238
|
+
calls,
|
|
1239
|
+
true,
|
|
1240
|
+
params,
|
|
1241
|
+
"WITHDRAWAL",
|
|
1242
|
+
params.cycleType
|
|
1243
|
+
);
|
|
871
1244
|
} else {
|
|
872
1245
|
/**
|
|
873
1246
|
* This is a fallback scenario, where the funds were withdrawn from extended, but didn't get transferred to the wallet
|
|
874
1247
|
* We need to return a successful transaction result, but with no calls
|
|
875
1248
|
* Db update will be handled by the risk engine for this specific case
|
|
876
1249
|
*/
|
|
877
|
-
return this.createTransactionResult(
|
|
1250
|
+
return this.createTransactionResult(
|
|
1251
|
+
[],
|
|
1252
|
+
true,
|
|
1253
|
+
params,
|
|
1254
|
+
"WITHDRAWAL",
|
|
1255
|
+
params.cycleType
|
|
1256
|
+
);
|
|
878
1257
|
}
|
|
879
|
-
} else if (
|
|
880
|
-
|
|
881
|
-
|
|
1258
|
+
} else if (
|
|
1259
|
+
withdrawalFromExtendedStatus &&
|
|
1260
|
+
!withdrawalFromExtendedTxnHash
|
|
1261
|
+
) {
|
|
1262
|
+
logger.error(
|
|
1263
|
+
"withdrawal from extended successful, but funds didn't get transferred to the wallet"
|
|
1264
|
+
);
|
|
1265
|
+
return this.createTransactionResult(
|
|
1266
|
+
[],
|
|
1267
|
+
true,
|
|
1268
|
+
params,
|
|
1269
|
+
"WITHDRAWAL",
|
|
1270
|
+
params.cycleType
|
|
1271
|
+
);
|
|
882
1272
|
} else {
|
|
883
1273
|
logger.error("withdrawal from extended failed");
|
|
884
|
-
return this.createTransactionResult(
|
|
1274
|
+
return this.createTransactionResult(
|
|
1275
|
+
[],
|
|
1276
|
+
false,
|
|
1277
|
+
params,
|
|
1278
|
+
"NONE",
|
|
1279
|
+
params.cycleType
|
|
1280
|
+
);
|
|
885
1281
|
}
|
|
886
|
-
} else if (
|
|
887
|
-
|
|
888
|
-
|
|
1282
|
+
} else if (
|
|
1283
|
+
params.to === Protocols.VAULT.name &&
|
|
1284
|
+
params.from === Protocols.VESU.name
|
|
1285
|
+
) {
|
|
1286
|
+
const isPriceDifferenceBetweenAvnuAndExtended =
|
|
1287
|
+
await this.checkPriceDifferenceBetweenAvnuAndExtended(
|
|
1288
|
+
extendedAdapter,
|
|
1289
|
+
vesuAdapter,
|
|
1290
|
+
avnuAdapter,
|
|
1291
|
+
PositionTypeAvnuExtended.CLOSE
|
|
1292
|
+
);
|
|
889
1293
|
if (!isPriceDifferenceBetweenAvnuAndExtended) {
|
|
890
|
-
logger.warn(
|
|
891
|
-
|
|
1294
|
+
logger.warn(
|
|
1295
|
+
`price difference between avnu and extended doesn't fit the range for close position, ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`
|
|
1296
|
+
);
|
|
1297
|
+
return this.createTransactionResult(
|
|
1298
|
+
[],
|
|
1299
|
+
false,
|
|
1300
|
+
params,
|
|
1301
|
+
"NONE",
|
|
1302
|
+
params.cycleType
|
|
1303
|
+
);
|
|
892
1304
|
}
|
|
893
|
-
//withdraw from vesu
|
|
1305
|
+
//withdraw from vesu
|
|
894
1306
|
const vesuAmountInBTC = new Web3Number(
|
|
895
|
-
params.amount
|
|
1307
|
+
params.amount
|
|
1308
|
+
.dividedBy(collateralPrice.price)
|
|
1309
|
+
.toFixed(WBTC_TOKEN_DECIMALS),
|
|
896
1310
|
collateralToken.decimals
|
|
897
1311
|
);
|
|
898
1312
|
const proofsInfo = vesuAdapter.getProofs(false, this.getMerkleTree());
|
|
@@ -903,22 +1317,45 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
903
1317
|
await proofsInfo.callConstructor({ amount: vesuAmountInBTC })
|
|
904
1318
|
);
|
|
905
1319
|
calls.push(call);
|
|
906
|
-
const swapProofsInfo = avnuAdapter.getProofs(
|
|
1320
|
+
const swapProofsInfo = avnuAdapter.getProofs(
|
|
1321
|
+
false,
|
|
1322
|
+
this.getMerkleTree()
|
|
1323
|
+
);
|
|
907
1324
|
const swapProofGroups = swapProofsInfo.proofs;
|
|
908
1325
|
const swapCall = this.getManageCall(
|
|
909
1326
|
swapProofGroups,
|
|
910
1327
|
await swapProofsInfo.callConstructor({ amount: vesuAmountInBTC })
|
|
911
1328
|
);
|
|
912
1329
|
calls.push(swapCall);
|
|
913
|
-
return this.createTransactionResult(
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1330
|
+
return this.createTransactionResult(
|
|
1331
|
+
calls,
|
|
1332
|
+
true,
|
|
1333
|
+
params,
|
|
1334
|
+
"WITHDRAWAL",
|
|
1335
|
+
params.cycleType
|
|
1336
|
+
);
|
|
1337
|
+
} else if (
|
|
1338
|
+
params.to === Protocols.EXTENDED.name &&
|
|
1339
|
+
params.from === Protocols.VESU.name
|
|
1340
|
+
) {
|
|
1341
|
+
const isPriceDifferenceBetweenAvnuAndExtended =
|
|
1342
|
+
await this.checkPriceDifferenceBetweenAvnuAndExtended(
|
|
1343
|
+
extendedAdapter,
|
|
1344
|
+
vesuAdapter,
|
|
1345
|
+
avnuAdapter,
|
|
1346
|
+
PositionTypeAvnuExtended.CLOSE
|
|
1347
|
+
);
|
|
919
1348
|
if (!isPriceDifferenceBetweenAvnuAndExtended) {
|
|
920
|
-
logger.warn(
|
|
921
|
-
|
|
1349
|
+
logger.warn(
|
|
1350
|
+
`price difference between avnu and extended doesn't fit the range for close position, ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`
|
|
1351
|
+
);
|
|
1352
|
+
return this.createTransactionResult(
|
|
1353
|
+
[],
|
|
1354
|
+
false,
|
|
1355
|
+
params,
|
|
1356
|
+
"NONE",
|
|
1357
|
+
params.cycleType
|
|
1358
|
+
);
|
|
922
1359
|
}
|
|
923
1360
|
const vesuAmountInBTC = new Web3Number(
|
|
924
1361
|
params.amount.dividedBy(collateralPrice.price).toNumber(),
|
|
@@ -932,7 +1369,10 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
932
1369
|
await proofsInfo.callConstructor({ amount: vesuAmountInBTC })
|
|
933
1370
|
);
|
|
934
1371
|
calls.push(call);
|
|
935
|
-
const swapProofsInfo = avnuAdapter.getProofs(
|
|
1372
|
+
const swapProofsInfo = avnuAdapter.getProofs(
|
|
1373
|
+
false,
|
|
1374
|
+
this.getMerkleTree()
|
|
1375
|
+
);
|
|
936
1376
|
const swapProofGroups = swapProofsInfo.proofs;
|
|
937
1377
|
const swapCall = this.getManageCall(
|
|
938
1378
|
swapProofGroups,
|
|
@@ -950,14 +1390,33 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
950
1390
|
await proofsInfoDeposit.callConstructor({ amount: params.amount })
|
|
951
1391
|
);
|
|
952
1392
|
calls.push(callDeposit);
|
|
953
|
-
return this.createTransactionResult(
|
|
1393
|
+
return this.createTransactionResult(
|
|
1394
|
+
calls,
|
|
1395
|
+
true,
|
|
1396
|
+
params,
|
|
1397
|
+
"DEPOSIT",
|
|
1398
|
+
params.cycleType
|
|
1399
|
+
);
|
|
954
1400
|
}
|
|
955
|
-
logger.error(
|
|
956
|
-
|
|
957
|
-
|
|
1401
|
+
logger.error(
|
|
1402
|
+
`Unsupported assets movement: ${params.from} to ${params.to}`
|
|
1403
|
+
);
|
|
1404
|
+
return this.createTransactionResult(
|
|
1405
|
+
[],
|
|
1406
|
+
false,
|
|
1407
|
+
params,
|
|
1408
|
+
"NONE",
|
|
1409
|
+
params.cycleType
|
|
1410
|
+
);
|
|
958
1411
|
} catch (err) {
|
|
959
1412
|
logger.error(`error moving assets: ${err}`);
|
|
960
|
-
return this.createTransactionResult(
|
|
1413
|
+
return this.createTransactionResult(
|
|
1414
|
+
[],
|
|
1415
|
+
false,
|
|
1416
|
+
params,
|
|
1417
|
+
"NONE",
|
|
1418
|
+
params.cycleType
|
|
1419
|
+
);
|
|
961
1420
|
}
|
|
962
1421
|
}
|
|
963
1422
|
|
|
@@ -966,14 +1425,33 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
966
1425
|
/**
|
|
967
1426
|
* Just a demo function, not used in the risk engine
|
|
968
1427
|
*/
|
|
969
|
-
return this.createTransactionResult(
|
|
1428
|
+
return this.createTransactionResult(
|
|
1429
|
+
[],
|
|
1430
|
+
false,
|
|
1431
|
+
{
|
|
1432
|
+
from: Protocols.VAULT.name,
|
|
1433
|
+
to: Protocols.VAULT.name,
|
|
1434
|
+
amount: new Web3Number(0, 0),
|
|
1435
|
+
},
|
|
1436
|
+
"NONE",
|
|
1437
|
+
CycleType.INVESTMENT
|
|
1438
|
+
);
|
|
970
1439
|
} catch (err) {
|
|
971
1440
|
logger.error(`error handling deposit: ${err}`);
|
|
972
|
-
return this.createTransactionResult(
|
|
1441
|
+
return this.createTransactionResult(
|
|
1442
|
+
[],
|
|
1443
|
+
false,
|
|
1444
|
+
{
|
|
1445
|
+
from: Protocols.VAULT.name,
|
|
1446
|
+
to: Protocols.VAULT.name,
|
|
1447
|
+
amount: new Web3Number(0, 0),
|
|
1448
|
+
},
|
|
1449
|
+
"NONE",
|
|
1450
|
+
CycleType.INVESTMENT
|
|
1451
|
+
);
|
|
973
1452
|
}
|
|
974
1453
|
}
|
|
975
1454
|
|
|
976
|
-
|
|
977
1455
|
/**
|
|
978
1456
|
* Check if the price difference between avnu and extended is within the acceptable range to enhance the position size or close the position
|
|
979
1457
|
* @param extendedAdapter - the extended adapter
|
|
@@ -982,13 +1460,18 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
982
1460
|
* @param positionType - the position type (open or close)
|
|
983
1461
|
* @returns true if the price difference is within the acceptable range, false otherwise
|
|
984
1462
|
*/
|
|
985
|
-
async checkPriceDifferenceBetweenAvnuAndExtended(
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1463
|
+
async checkPriceDifferenceBetweenAvnuAndExtended(
|
|
1464
|
+
extendedAdapter: ExtendedAdapter,
|
|
1465
|
+
vesuAdapter: VesuMultiplyAdapter,
|
|
1466
|
+
avnuAdapter: AvnuAdapter,
|
|
1467
|
+
positionType: PositionTypeAvnuExtended
|
|
1468
|
+
): Promise<boolean> {
|
|
1469
|
+
const { ask, bid } = await extendedAdapter.fetchOrderBookBTCUSDC();
|
|
989
1470
|
const price = ask.plus(bid).dividedBy(2);
|
|
990
1471
|
const btcToken = vesuAdapter.config.supportedPositions[0].asset;
|
|
991
|
-
const btcPriceAvnu = await avnuAdapter.getPriceOfToken(
|
|
1472
|
+
const btcPriceAvnu = await avnuAdapter.getPriceOfToken(
|
|
1473
|
+
btcToken.address.toString()
|
|
1474
|
+
);
|
|
992
1475
|
|
|
993
1476
|
if (!btcPriceAvnu) {
|
|
994
1477
|
logger.error(`error getting btc price avnu: ${btcPriceAvnu}`);
|
|
@@ -996,19 +1479,34 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
996
1479
|
}
|
|
997
1480
|
logger.info(`price: ${price}`);
|
|
998
1481
|
logger.info(`btcPriceAvnu: ${btcPriceAvnu}`);
|
|
999
|
-
const priceDifference = new Web3Number(
|
|
1482
|
+
const priceDifference = new Web3Number(
|
|
1483
|
+
price.minus(btcPriceAvnu).toFixed(2),
|
|
1484
|
+
0
|
|
1485
|
+
);
|
|
1000
1486
|
logger.info(`priceDifference: ${priceDifference}`);
|
|
1001
1487
|
if (priceDifference.isNegative()) {
|
|
1002
1488
|
return false;
|
|
1003
1489
|
}
|
|
1004
1490
|
if (positionType === PositionTypeAvnuExtended.OPEN) {
|
|
1005
|
-
logger.info(
|
|
1006
|
-
|
|
1491
|
+
logger.info(
|
|
1492
|
+
`price difference between avnu and extended for open position: ${priceDifference.toNumber()}, minimumExtendedPriceDifferenceForSwapOpen: ${
|
|
1493
|
+
avnuAdapter.config.minimumExtendedPriceDifferenceForSwapOpen
|
|
1494
|
+
}`
|
|
1495
|
+
);
|
|
1496
|
+
const result = priceDifference.greaterThanOrEqualTo(
|
|
1497
|
+
avnuAdapter.config.minimumExtendedPriceDifferenceForSwapOpen
|
|
1498
|
+
); // 500 for now
|
|
1007
1499
|
logger.info(`result: ${result}`);
|
|
1008
1500
|
return result;
|
|
1009
1501
|
} else {
|
|
1010
|
-
logger.info(
|
|
1011
|
-
|
|
1502
|
+
logger.info(
|
|
1503
|
+
`price difference between avnu and extended for close position: ${priceDifference.toNumber()}, maximumExtendedPriceDifferenceForSwapClosing: ${
|
|
1504
|
+
avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing
|
|
1505
|
+
}`
|
|
1506
|
+
);
|
|
1507
|
+
const result = priceDifference.lessThanOrEqualTo(
|
|
1508
|
+
avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing
|
|
1509
|
+
); // 1000 for now
|
|
1012
1510
|
logger.info(`result: ${result}`);
|
|
1013
1511
|
return result;
|
|
1014
1512
|
}
|
|
@@ -1022,16 +1520,30 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
1022
1520
|
async handleWithdraw(amount: Web3Number): Promise<TransactionResult[]> {
|
|
1023
1521
|
try {
|
|
1024
1522
|
const usdcBalanceVaultAllocator = await this.getUnusedBalance();
|
|
1025
|
-
const usdcBalanceDifference = amount
|
|
1523
|
+
const usdcBalanceDifference = amount
|
|
1524
|
+
.plus(BUFFER_USDC_IN_WITHDRAWAL)
|
|
1525
|
+
.minus(usdcBalanceVaultAllocator.usdValue);
|
|
1026
1526
|
logger.info(`usdcBalanceDifference, ${usdcBalanceDifference.toNumber()}`);
|
|
1027
1527
|
let calls: Call[] = [];
|
|
1028
1528
|
let status: boolean = true;
|
|
1029
1529
|
if (usdcBalanceDifference.lessThan(0)) {
|
|
1030
1530
|
const withdrawCall = await this.getBringLiquidityCall({
|
|
1031
|
-
amount: usdcBalanceVaultAllocator.amount
|
|
1032
|
-
})
|
|
1531
|
+
amount: usdcBalanceVaultAllocator.amount,
|
|
1532
|
+
});
|
|
1033
1533
|
calls.push(withdrawCall);
|
|
1034
|
-
return [
|
|
1534
|
+
return [
|
|
1535
|
+
this.createTransactionResult(
|
|
1536
|
+
calls,
|
|
1537
|
+
true,
|
|
1538
|
+
{
|
|
1539
|
+
from: Protocols.VAULT.name,
|
|
1540
|
+
to: Protocols.NONE.name,
|
|
1541
|
+
amount: amount,
|
|
1542
|
+
},
|
|
1543
|
+
"WITHDRAWAL",
|
|
1544
|
+
CycleType.WITHDRAWAL
|
|
1545
|
+
),
|
|
1546
|
+
];
|
|
1035
1547
|
}
|
|
1036
1548
|
const vesuAdapter = await this.getVesuAdapter();
|
|
1037
1549
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
@@ -1040,19 +1552,41 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
1040
1552
|
logger.error(
|
|
1041
1553
|
`vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
|
|
1042
1554
|
);
|
|
1043
|
-
return [
|
|
1555
|
+
return [
|
|
1556
|
+
this.createTransactionResult(
|
|
1557
|
+
calls,
|
|
1558
|
+
status,
|
|
1559
|
+
{
|
|
1560
|
+
from: Protocols.VAULT.name,
|
|
1561
|
+
to: Protocols.NONE.name,
|
|
1562
|
+
amount: amount,
|
|
1563
|
+
},
|
|
1564
|
+
"NONE",
|
|
1565
|
+
CycleType.WITHDRAWAL
|
|
1566
|
+
),
|
|
1567
|
+
];
|
|
1044
1568
|
}
|
|
1045
1569
|
let transactionResults: TransactionResult[] = [];
|
|
1046
1570
|
const { collateralTokenAmount } =
|
|
1047
1571
|
await vesuAdapter.vesuAdapter.getAssetPrices();
|
|
1048
|
-
const {
|
|
1049
|
-
collateralPrice
|
|
1050
|
-
} = await this.getAssetPrices();
|
|
1572
|
+
const { collateralPrice } = await this.getAssetPrices();
|
|
1051
1573
|
const extendedPositon = await extendedAdapter.getAllOpenPositions();
|
|
1052
1574
|
if (!extendedPositon) {
|
|
1053
1575
|
status = false;
|
|
1054
1576
|
logger.error("error getting extended position", extendedPositon);
|
|
1055
|
-
return [
|
|
1577
|
+
return [
|
|
1578
|
+
this.createTransactionResult(
|
|
1579
|
+
calls,
|
|
1580
|
+
status,
|
|
1581
|
+
{
|
|
1582
|
+
from: Protocols.VAULT.name,
|
|
1583
|
+
to: Protocols.NONE.name,
|
|
1584
|
+
amount: amount,
|
|
1585
|
+
},
|
|
1586
|
+
"NONE",
|
|
1587
|
+
CycleType.WITHDRAWAL
|
|
1588
|
+
),
|
|
1589
|
+
];
|
|
1056
1590
|
}
|
|
1057
1591
|
const amountDistributionForWithdrawal =
|
|
1058
1592
|
await calculateAmountDistributionForWithdrawal(
|
|
@@ -1066,17 +1600,33 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
1066
1600
|
logger.error(
|
|
1067
1601
|
`error calculating amount distribution for withdrawal: ${amountDistributionForWithdrawal}`
|
|
1068
1602
|
);
|
|
1069
|
-
return [
|
|
1603
|
+
return [
|
|
1604
|
+
this.createTransactionResult(
|
|
1605
|
+
calls,
|
|
1606
|
+
status,
|
|
1607
|
+
{
|
|
1608
|
+
from: Protocols.VAULT.name,
|
|
1609
|
+
to: Protocols.NONE.name,
|
|
1610
|
+
amount: amount,
|
|
1611
|
+
},
|
|
1612
|
+
"NONE",
|
|
1613
|
+
CycleType.WITHDRAWAL
|
|
1614
|
+
),
|
|
1615
|
+
];
|
|
1070
1616
|
}
|
|
1071
1617
|
const { vesu_amount, extended_amount } = amountDistributionForWithdrawal;
|
|
1072
1618
|
|
|
1073
1619
|
if (status && vesu_amount.greaterThan(0)) {
|
|
1074
|
-
const {
|
|
1620
|
+
const {
|
|
1621
|
+
calls: vesuCalls,
|
|
1622
|
+
status: vesuStatus,
|
|
1623
|
+
transactionMetadata: vesuTransactionMetadata,
|
|
1624
|
+
} = await this.moveAssets(
|
|
1075
1625
|
{
|
|
1076
1626
|
amount: vesu_amount,
|
|
1077
1627
|
from: Protocols.VESU.name,
|
|
1078
1628
|
to: Protocols.VAULT.name,
|
|
1079
|
-
cycleType: CycleType.WITHDRAWAL
|
|
1629
|
+
cycleType: CycleType.WITHDRAWAL,
|
|
1080
1630
|
},
|
|
1081
1631
|
extendedAdapter,
|
|
1082
1632
|
vesuAdapter
|
|
@@ -1085,16 +1635,20 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
1085
1635
|
transactionResults.push({
|
|
1086
1636
|
status: vesuStatus,
|
|
1087
1637
|
calls: vesuCalls,
|
|
1088
|
-
transactionMetadata: vesuTransactionMetadata
|
|
1089
|
-
})
|
|
1638
|
+
transactionMetadata: vesuTransactionMetadata,
|
|
1639
|
+
});
|
|
1090
1640
|
}
|
|
1091
1641
|
if (status && extended_amount.greaterThan(0)) {
|
|
1092
|
-
const {
|
|
1642
|
+
const {
|
|
1643
|
+
calls: extendedCalls,
|
|
1644
|
+
status: extendedStatus,
|
|
1645
|
+
transactionMetadata: extendedTransactionMetadata,
|
|
1646
|
+
} = await this.moveAssets(
|
|
1093
1647
|
{
|
|
1094
1648
|
amount: extended_amount,
|
|
1095
1649
|
from: Protocols.EXTENDED.name,
|
|
1096
1650
|
to: Protocols.VAULT.name,
|
|
1097
|
-
cycleType: CycleType.WITHDRAWAL
|
|
1651
|
+
cycleType: CycleType.WITHDRAWAL,
|
|
1098
1652
|
},
|
|
1099
1653
|
extendedAdapter,
|
|
1100
1654
|
vesuAdapter
|
|
@@ -1104,16 +1658,30 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
1104
1658
|
transactionResults.push({
|
|
1105
1659
|
status: extendedStatus,
|
|
1106
1660
|
calls: extendedCalls,
|
|
1107
|
-
transactionMetadata: extendedTransactionMetadata
|
|
1108
|
-
})
|
|
1661
|
+
transactionMetadata: extendedTransactionMetadata,
|
|
1662
|
+
});
|
|
1109
1663
|
} else {
|
|
1110
|
-
logger.error(
|
|
1111
|
-
|
|
1664
|
+
logger.error(
|
|
1665
|
+
"error moving assets to vault: extendedStatus: ${extendedStatus}"
|
|
1666
|
+
);
|
|
1667
|
+
return [
|
|
1668
|
+
this.createTransactionResult(
|
|
1669
|
+
[],
|
|
1670
|
+
status,
|
|
1671
|
+
{
|
|
1672
|
+
from: Protocols.VAULT.name,
|
|
1673
|
+
to: Protocols.NONE.name,
|
|
1674
|
+
amount: amount,
|
|
1675
|
+
},
|
|
1676
|
+
"NONE",
|
|
1677
|
+
CycleType.WITHDRAWAL
|
|
1678
|
+
),
|
|
1679
|
+
];
|
|
1112
1680
|
}
|
|
1113
1681
|
}
|
|
1114
1682
|
const withdrawCall = await this.getBringLiquidityCall({
|
|
1115
|
-
amount: amount
|
|
1116
|
-
})
|
|
1683
|
+
amount: amount,
|
|
1684
|
+
});
|
|
1117
1685
|
logger.info("withdraw call", withdrawCall);
|
|
1118
1686
|
transactionResults.push({
|
|
1119
1687
|
status: status,
|
|
@@ -1123,18 +1691,34 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
1123
1691
|
protocolTo: Protocols.NONE.name,
|
|
1124
1692
|
transactionType: "WITHDRAWAL",
|
|
1125
1693
|
usdAmount: amount.toFixed(),
|
|
1126
|
-
status:
|
|
1127
|
-
cycleType: CycleType.WITHDRAWAL
|
|
1128
|
-
}
|
|
1129
|
-
})
|
|
1694
|
+
status: "PENDING",
|
|
1695
|
+
cycleType: CycleType.WITHDRAWAL,
|
|
1696
|
+
},
|
|
1697
|
+
});
|
|
1130
1698
|
return transactionResults;
|
|
1131
1699
|
} catch (err) {
|
|
1132
1700
|
logger.error(`error handling withdrawal: ${err}`);
|
|
1133
|
-
return [
|
|
1701
|
+
return [
|
|
1702
|
+
this.createTransactionResult(
|
|
1703
|
+
[],
|
|
1704
|
+
false,
|
|
1705
|
+
{
|
|
1706
|
+
from: Protocols.VAULT.name,
|
|
1707
|
+
to: Protocols.NONE.name,
|
|
1708
|
+
amount: amount,
|
|
1709
|
+
},
|
|
1710
|
+
"NONE",
|
|
1711
|
+
CycleType.WITHDRAWAL
|
|
1712
|
+
),
|
|
1713
|
+
];
|
|
1134
1714
|
}
|
|
1135
1715
|
}
|
|
1136
1716
|
|
|
1137
|
-
async getAUM(): Promise<{
|
|
1717
|
+
async getAUM(): Promise<{
|
|
1718
|
+
net: SingleTokenInfo;
|
|
1719
|
+
prevAum: Web3Number;
|
|
1720
|
+
splits: PositionInfo[];
|
|
1721
|
+
}> {
|
|
1138
1722
|
const allPositions: PositionInfo[] = [];
|
|
1139
1723
|
for (let adapter of this.metadata.additionalInfo.adapters) {
|
|
1140
1724
|
const positions = await adapter.adapter.getPositions();
|
|
@@ -1158,34 +1742,49 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
1158
1742
|
usdValue: netAUM.toNumber() * assetPrice.price,
|
|
1159
1743
|
apy: { apy: netAUM.toNumber() * assetPrice.price, type: APYType.BASE },
|
|
1160
1744
|
remarks: AUMTypes.FINALISED,
|
|
1161
|
-
protocol: Protocols.NONE // just placeholder
|
|
1745
|
+
protocol: Protocols.NONE, // just placeholder
|
|
1162
1746
|
};
|
|
1163
1747
|
|
|
1164
1748
|
const estimatedAUMDelta: PositionInfo = {
|
|
1165
1749
|
tokenInfo: this.asset(),
|
|
1166
|
-
amount: Web3Number.fromWei(
|
|
1750
|
+
amount: Web3Number.fromWei("0", this.asset().decimals),
|
|
1167
1751
|
usdValue: 0,
|
|
1168
1752
|
apy: { apy: 0, type: APYType.BASE },
|
|
1169
1753
|
remarks: AUMTypes.DEFISPRING,
|
|
1170
|
-
protocol: Protocols.NONE // just placeholder
|
|
1754
|
+
protocol: Protocols.NONE, // just placeholder
|
|
1171
1755
|
};
|
|
1172
1756
|
|
|
1173
1757
|
return {
|
|
1174
1758
|
net: {
|
|
1175
1759
|
tokenInfo: this.asset(),
|
|
1176
1760
|
amount: netAUM,
|
|
1177
|
-
usdValue: netAUM.toNumber() * assetPrice.price
|
|
1178
|
-
},
|
|
1761
|
+
usdValue: netAUM.toNumber() * assetPrice.price,
|
|
1762
|
+
},
|
|
1763
|
+
prevAum: prevAum,
|
|
1764
|
+
splits: [realAUM, estimatedAUMDelta],
|
|
1179
1765
|
};
|
|
1180
1766
|
}
|
|
1181
1767
|
|
|
1182
|
-
async processTransactionDataFromSDK(
|
|
1768
|
+
async processTransactionDataFromSDK(
|
|
1769
|
+
txnData: TransactionResult<any>[]
|
|
1770
|
+
): Promise<{
|
|
1771
|
+
callsToBeExecutedFinal: Call[];
|
|
1772
|
+
txnMetadata: TransactionMetadata[];
|
|
1773
|
+
} | null> {
|
|
1183
1774
|
try {
|
|
1184
|
-
const txnsToBeExecuted = txnData.filter(txn => {
|
|
1185
|
-
return
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1775
|
+
const txnsToBeExecuted = txnData.filter((txn) => {
|
|
1776
|
+
return (
|
|
1777
|
+
txn.transactionMetadata.transactionType !== "NONE" &&
|
|
1778
|
+
txn.transactionMetadata.protocolFrom !== "" &&
|
|
1779
|
+
txn.transactionMetadata.protocolTo !== ""
|
|
1780
|
+
);
|
|
1781
|
+
});
|
|
1782
|
+
const callsToBeExecutedFinal = txnsToBeExecuted.flatMap(
|
|
1783
|
+
(txn) => txn.calls
|
|
1784
|
+
);
|
|
1785
|
+
const txnMetadata = txnsToBeExecuted.map(
|
|
1786
|
+
(txn) => txn.transactionMetadata
|
|
1787
|
+
);
|
|
1189
1788
|
return { callsToBeExecutedFinal, txnMetadata };
|
|
1190
1789
|
} catch (err) {
|
|
1191
1790
|
logger.error(`error processing transaction data from SDK: ${err}`);
|
|
@@ -1193,18 +1792,23 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
1193
1792
|
}
|
|
1194
1793
|
}
|
|
1195
1794
|
|
|
1196
|
-
async processTransactionMetadata(
|
|
1795
|
+
async processTransactionMetadata(
|
|
1796
|
+
txnMetadata: TransactionMetadata[],
|
|
1797
|
+
extendedIntentFulfilled: boolean
|
|
1798
|
+
): Promise<TransactionMetadata[] | null> {
|
|
1197
1799
|
try {
|
|
1198
|
-
const txnMetadataNew = txnMetadata.map(txn => {
|
|
1199
|
-
const isExtendedProtocol =
|
|
1800
|
+
const txnMetadataNew = txnMetadata.map((txn) => {
|
|
1801
|
+
const isExtendedProtocol =
|
|
1802
|
+
txn.protocolFrom === Protocols.EXTENDED.name ||
|
|
1803
|
+
txn.protocolTo === Protocols.EXTENDED.name;
|
|
1200
1804
|
// Only update status for extended protocol transactions since thsoe only cause delays
|
|
1201
1805
|
if (isExtendedProtocol) {
|
|
1202
|
-
txn.status = extendedIntentFulfilled ?
|
|
1806
|
+
txn.status = extendedIntentFulfilled ? "COMPLETED" : "PENDING";
|
|
1203
1807
|
} else {
|
|
1204
|
-
txn.status =
|
|
1808
|
+
txn.status = "COMPLETED";
|
|
1205
1809
|
}
|
|
1206
1810
|
return txn;
|
|
1207
|
-
})
|
|
1811
|
+
});
|
|
1208
1812
|
return txnMetadataNew;
|
|
1209
1813
|
} catch (err) {
|
|
1210
1814
|
logger.error(`error processing transaction data from SDK: ${err}`);
|
|
@@ -1218,23 +1822,43 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
1218
1822
|
if (!vesuAdapter || !extendedAdapter) {
|
|
1219
1823
|
return new Web3Number(0, 0);
|
|
1220
1824
|
}
|
|
1221
|
-
const extendedFundingRate = new Web3Number(
|
|
1825
|
+
const extendedFundingRate = new Web3Number(
|
|
1826
|
+
(await extendedAdapter.getNetAPY()).toFixed(4),
|
|
1827
|
+
0
|
|
1828
|
+
);
|
|
1222
1829
|
const extendedPositions = await extendedAdapter.getAllOpenPositions();
|
|
1223
1830
|
if (!extendedPositions || extendedPositions.length === 0) {
|
|
1224
1831
|
logger.info(`no extended positions found`);
|
|
1225
1832
|
return new Web3Number(0, 0);
|
|
1226
1833
|
}
|
|
1227
|
-
const extendePositionSizeUSD = new Web3Number(
|
|
1834
|
+
const extendePositionSizeUSD = new Web3Number(
|
|
1835
|
+
extendedPositions[0].value || 0,
|
|
1836
|
+
0
|
|
1837
|
+
);
|
|
1228
1838
|
const vesuPositions = await vesuAdapter.getPositions();
|
|
1229
1839
|
const vesuSupplyApy = vesuPositions[0].apy.apy;
|
|
1230
|
-
const vesuCollateralSizeUSD = new Web3Number(
|
|
1231
|
-
|
|
1232
|
-
|
|
1840
|
+
const vesuCollateralSizeUSD = new Web3Number(
|
|
1841
|
+
vesuPositions[0].usdValue.toFixed(USDC_TOKEN_DECIMALS),
|
|
1842
|
+
USDC_TOKEN_DECIMALS
|
|
1843
|
+
);
|
|
1844
|
+
const vesuDebtSizeUSD = new Web3Number(
|
|
1845
|
+
vesuPositions[1].usdValue.toFixed(USDC_TOKEN_DECIMALS),
|
|
1846
|
+
USDC_TOKEN_DECIMALS
|
|
1847
|
+
);
|
|
1848
|
+
const num1 = extendePositionSizeUSD.multipliedBy(extendedFundingRate);
|
|
1233
1849
|
const num2 = vesuCollateralSizeUSD.multipliedBy(vesuSupplyApy);
|
|
1234
|
-
const num3 = vesuDebtSizeUSD.abs()
|
|
1850
|
+
const num3 = vesuDebtSizeUSD.abs();
|
|
1235
1851
|
const maxBorrowApy = num1.plus(num2).minus(0.1).dividedBy(num3);
|
|
1236
|
-
const vesuMaxBorrowableAmount =
|
|
1237
|
-
|
|
1852
|
+
const vesuMaxBorrowableAmount =
|
|
1853
|
+
await vesuAdapter.vesuAdapter.getMaxBorrowableByInterestRate(
|
|
1854
|
+
this.config,
|
|
1855
|
+
vesuAdapter.config.debt,
|
|
1856
|
+
maxBorrowApy.toNumber()
|
|
1857
|
+
);
|
|
1858
|
+
return new Web3Number(
|
|
1859
|
+
vesuMaxBorrowableAmount.toFixed(USDC_TOKEN_DECIMALS),
|
|
1860
|
+
USDC_TOKEN_DECIMALS
|
|
1861
|
+
);
|
|
1238
1862
|
}
|
|
1239
1863
|
|
|
1240
1864
|
async getVesuHealthFactors(): Promise<number[]> {
|
|
@@ -1244,83 +1868,124 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
1244
1868
|
return [0, 0];
|
|
1245
1869
|
}
|
|
1246
1870
|
const vesuPositions = await vesuAdapter.getPositions();
|
|
1247
|
-
const vesuCollateralSizeUSD = new Web3Number(
|
|
1248
|
-
|
|
1871
|
+
const vesuCollateralSizeUSD = new Web3Number(
|
|
1872
|
+
vesuPositions[0].usdValue.toFixed(USDC_TOKEN_DECIMALS),
|
|
1873
|
+
0
|
|
1874
|
+
);
|
|
1875
|
+
const vesuDebtSizeUSD = new Web3Number(
|
|
1876
|
+
vesuPositions[1].usdValue.toFixed(USDC_TOKEN_DECIMALS),
|
|
1877
|
+
0
|
|
1878
|
+
);
|
|
1249
1879
|
const actualLtv = vesuDebtSizeUSD.dividedBy(vesuCollateralSizeUSD).abs();
|
|
1250
1880
|
logger.info(`actualLtv: ${actualLtv.toNumber()}`);
|
|
1251
|
-
const maxLtv = new Web3Number(
|
|
1252
|
-
|
|
1881
|
+
const maxLtv = new Web3Number(
|
|
1882
|
+
await vesuAdapter.vesuAdapter.getLTVConfig(this.config),
|
|
1883
|
+
4
|
|
1884
|
+
);
|
|
1885
|
+
const healthFactor = new Web3Number(
|
|
1886
|
+
maxLtv.dividedBy(actualLtv).toFixed(4),
|
|
1887
|
+
4
|
|
1888
|
+
);
|
|
1253
1889
|
logger.info(`healthFactor: ${healthFactor.toNumber()}`);
|
|
1254
1890
|
const extendedBalance = await extendedAdapter.getExtendedDepositAmount();
|
|
1255
1891
|
if (!extendedBalance) {
|
|
1256
1892
|
return [0, 0];
|
|
1257
1893
|
}
|
|
1258
|
-
const extendedLeverage = new Web3Number(
|
|
1894
|
+
const extendedLeverage = new Web3Number(
|
|
1895
|
+
(Number(extendedBalance.marginRatio) * 100).toFixed(4),
|
|
1896
|
+
4
|
|
1897
|
+
);
|
|
1259
1898
|
logger.info(`extendedLeverage: ${extendedLeverage.toNumber()}`);
|
|
1260
1899
|
return [healthFactor.toNumber(), extendedLeverage.toNumber()];
|
|
1261
1900
|
}
|
|
1262
1901
|
|
|
1263
|
-
async netAPY(): Promise<{
|
|
1902
|
+
async netAPY(): Promise<{
|
|
1903
|
+
net: number;
|
|
1904
|
+
splits: { apy: number; id: string }[];
|
|
1905
|
+
}> {
|
|
1264
1906
|
const allPositions: PositionInfo[] = [];
|
|
1265
1907
|
for (let adapter of this.metadata.additionalInfo.adapters) {
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
}
|
|
1908
|
+
if (adapter.adapter.name !== ExtendedAdapter.name) {
|
|
1909
|
+
let positions = await adapter.adapter.getPositions();
|
|
1910
|
+
if (positions.length > 0) {
|
|
1911
|
+
allPositions.push(...positions);
|
|
1271
1912
|
}
|
|
1272
1913
|
}
|
|
1273
|
-
|
|
1274
|
-
|
|
1914
|
+
}
|
|
1915
|
+
const extendedAdapter = await this.getExtendedAdapter();
|
|
1916
|
+
if (!extendedAdapter) {
|
|
1275
1917
|
return {
|
|
1276
1918
|
net: 0,
|
|
1277
|
-
splits: []
|
|
1278
|
-
}
|
|
1919
|
+
splits: [],
|
|
1920
|
+
};
|
|
1279
1921
|
}
|
|
1280
|
-
let vesuPositions = allPositions.filter(
|
|
1281
|
-
|
|
1922
|
+
let vesuPositions = allPositions.filter(
|
|
1923
|
+
(item) => item.protocol === Protocols.VESU
|
|
1924
|
+
);
|
|
1925
|
+
vesuPositions.map((item) => {
|
|
1282
1926
|
item.apy.apy = item.apy.apy * 0.1;
|
|
1283
|
-
})
|
|
1927
|
+
});
|
|
1284
1928
|
const extendedPositions = await extendedAdapter.getAllOpenPositions();
|
|
1285
|
-
const usdcToken = Global.getDefaultTokens().find(
|
|
1286
|
-
|
|
1929
|
+
const usdcToken = Global.getDefaultTokens().find(
|
|
1930
|
+
(token) => token.symbol === "USDC"
|
|
1931
|
+
);
|
|
1932
|
+
if (!extendedPositions || !usdcToken) {
|
|
1287
1933
|
return {
|
|
1288
1934
|
net: 0,
|
|
1289
|
-
splits: []
|
|
1290
|
-
}
|
|
1935
|
+
splits: [],
|
|
1936
|
+
};
|
|
1291
1937
|
}
|
|
1292
1938
|
const extendedPosition = extendedPositions[0] || 0;
|
|
1293
|
-
const extendedEquity =
|
|
1939
|
+
const extendedEquity =
|
|
1940
|
+
(await extendedAdapter.getExtendedDepositAmount())?.equity || 0;
|
|
1294
1941
|
const extendedApy = await extendedAdapter.getNetAPY();
|
|
1295
|
-
const totalHoldingsUSDValue =
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1942
|
+
const totalHoldingsUSDValue =
|
|
1943
|
+
allPositions.reduce((acc, curr) => acc + curr.usdValue, 0) +
|
|
1944
|
+
Number(extendedEquity);
|
|
1945
|
+
console.log(totalHoldingsUSDValue);
|
|
1946
|
+
const extendedPositionSizeMultipliedByApy =
|
|
1947
|
+
Number(extendedPosition.value) * extendedApy;
|
|
1948
|
+
let weightedAPYs =
|
|
1949
|
+
allPositions.reduce(
|
|
1950
|
+
(acc, curr) => acc + curr.apy.apy * curr.usdValue,
|
|
1951
|
+
0
|
|
1952
|
+
) + extendedPositionSizeMultipliedByApy;
|
|
1953
|
+
console.log(weightedAPYs);
|
|
1300
1954
|
const netAPY = weightedAPYs / totalHoldingsUSDValue;
|
|
1301
|
-
console.log(netAPY)
|
|
1955
|
+
console.log(netAPY);
|
|
1302
1956
|
allPositions.push({
|
|
1303
1957
|
tokenInfo: usdcToken,
|
|
1304
1958
|
amount: new Web3Number(extendedPosition.size, 0),
|
|
1305
1959
|
usdValue: Number(extendedEquity),
|
|
1306
1960
|
apy: { apy: extendedApy, type: APYType.BASE },
|
|
1307
1961
|
remarks: AUMTypes.FINALISED,
|
|
1308
|
-
protocol: Protocols.EXTENDED
|
|
1309
|
-
})
|
|
1962
|
+
protocol: Protocols.EXTENDED,
|
|
1963
|
+
});
|
|
1310
1964
|
return {
|
|
1311
1965
|
net: netAPY,
|
|
1312
|
-
splits: allPositions.map(p => ({
|
|
1966
|
+
splits: allPositions.map((p) => ({
|
|
1967
|
+
apy: p.apy.apy,
|
|
1968
|
+
id: p.remarks ?? "",
|
|
1969
|
+
})),
|
|
1313
1970
|
};
|
|
1314
1971
|
}
|
|
1315
1972
|
|
|
1316
|
-
async getWalletHoldings(): Promise<
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
const
|
|
1973
|
+
async getWalletHoldings(): Promise<
|
|
1974
|
+
{
|
|
1975
|
+
tokenInfo: TokenInfo;
|
|
1976
|
+
amount: Web3Number;
|
|
1977
|
+
usdValue: number;
|
|
1978
|
+
}[]
|
|
1979
|
+
> {
|
|
1980
|
+
const usdceToken = Global.getDefaultTokens().find(
|
|
1981
|
+
(token) => token.symbol === "USDCe"
|
|
1982
|
+
);
|
|
1983
|
+
const wbtcToken = Global.getDefaultTokens().find(
|
|
1984
|
+
(token) => token.symbol === "WBTC"
|
|
1985
|
+
);
|
|
1986
|
+
const usdcToken = Global.getDefaultTokens().find(
|
|
1987
|
+
(token) => token.symbol === "USDC"
|
|
1988
|
+
);
|
|
1324
1989
|
if (!usdceToken || !wbtcToken || !usdcToken) {
|
|
1325
1990
|
return [];
|
|
1326
1991
|
}
|
|
@@ -1342,23 +2007,29 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
1342
2007
|
);
|
|
1343
2008
|
const price = await this.pricer.getPrice(usdceToken.symbol);
|
|
1344
2009
|
const wbtcPrice = await this.pricer.getPrice(wbtcToken.symbol);
|
|
1345
|
-
const usdceUsdValue =
|
|
1346
|
-
|
|
1347
|
-
const
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
2010
|
+
const usdceUsdValue =
|
|
2011
|
+
Number(usdceWalletBalance.toFixed(usdceToken.decimals)) * price.price;
|
|
2012
|
+
const usdcUsdValue =
|
|
2013
|
+
Number(usdcWalletBalance.toFixed(usdcToken.decimals)) * price.price;
|
|
2014
|
+
const wbtcUsdValue =
|
|
2015
|
+
Number(wbtcWalletBalance.toFixed(wbtcToken.decimals)) * wbtcPrice.price;
|
|
2016
|
+
return [
|
|
2017
|
+
{
|
|
2018
|
+
tokenInfo: usdceToken,
|
|
2019
|
+
amount: usdceWalletBalance,
|
|
2020
|
+
usdValue: usdceUsdValue,
|
|
2021
|
+
},
|
|
2022
|
+
{
|
|
2023
|
+
tokenInfo: usdcToken,
|
|
2024
|
+
amount: usdcWalletBalance,
|
|
2025
|
+
usdValue: usdcUsdValue,
|
|
2026
|
+
},
|
|
2027
|
+
{
|
|
2028
|
+
tokenInfo: wbtcToken,
|
|
2029
|
+
amount: wbtcWalletBalance,
|
|
2030
|
+
usdValue: wbtcUsdValue,
|
|
2031
|
+
},
|
|
2032
|
+
];
|
|
1362
2033
|
}
|
|
1363
2034
|
}
|
|
1364
2035
|
|
|
@@ -1374,7 +2045,7 @@ function getLooperSettings(
|
|
|
1374
2045
|
minimumVesuMovementAmount: number,
|
|
1375
2046
|
minimumExtendedRetriesDelayForOrderStatus: number,
|
|
1376
2047
|
minimumExtendedPriceDifferenceForSwapOpen: number,
|
|
1377
|
-
maximumExtendedPriceDifferenceForSwapClosing: number
|
|
2048
|
+
maximumExtendedPriceDifferenceForSwapClosing: number
|
|
1378
2049
|
) {
|
|
1379
2050
|
vaultSettings.leafAdapters = [];
|
|
1380
2051
|
|
|
@@ -1403,15 +2074,15 @@ function getLooperSettings(
|
|
|
1403
2074
|
avnuContract: AVNU_MIDDLEWARE,
|
|
1404
2075
|
slippage: 0.01,
|
|
1405
2076
|
baseUrl: AVNU_QUOTE_URL,
|
|
1406
|
-
minimumExtendedPriceDifferenceForSwapOpen:
|
|
1407
|
-
|
|
2077
|
+
minimumExtendedPriceDifferenceForSwapOpen:
|
|
2078
|
+
minimumExtendedPriceDifferenceForSwapOpen,
|
|
2079
|
+
maximumExtendedPriceDifferenceForSwapClosing:
|
|
2080
|
+
maximumExtendedPriceDifferenceForSwapClosing,
|
|
1408
2081
|
});
|
|
1409
2082
|
|
|
1410
2083
|
const extendedAdapter = new ExtendedAdapter({
|
|
1411
2084
|
...baseAdapterConfig,
|
|
1412
|
-
supportedPositions: [
|
|
1413
|
-
{ asset: usdcToken, isDebt: true },
|
|
1414
|
-
],
|
|
2085
|
+
supportedPositions: [{ asset: usdcToken, isDebt: true }],
|
|
1415
2086
|
vaultIdExtended: vaultIdExtended,
|
|
1416
2087
|
extendedContract: EXTENDED_CONTRACT,
|
|
1417
2088
|
extendedBackendWriteUrl: extendedBackendWriteUrl,
|
|
@@ -1474,11 +2145,11 @@ function getLooperSettings(
|
|
|
1474
2145
|
});
|
|
1475
2146
|
|
|
1476
2147
|
vaultSettings.leafAdapters.push(() => vesuMultiplyAdapter.getDepositLeaf());
|
|
2148
|
+
vaultSettings.leafAdapters.push(() => vesuMultiplyAdapter.getWithdrawLeaf());
|
|
2149
|
+
vaultSettings.leafAdapters.push(() => extendedAdapter.getDepositLeaf());
|
|
1477
2150
|
vaultSettings.leafAdapters.push(() =>
|
|
1478
|
-
|
|
2151
|
+
extendedAdapter.getSwapFromLegacyLeaf()
|
|
1479
2152
|
);
|
|
1480
|
-
vaultSettings.leafAdapters.push(() => extendedAdapter.getDepositLeaf());
|
|
1481
|
-
vaultSettings.leafAdapters.push(() => extendedAdapter.getSwapFromLegacyLeaf());
|
|
1482
2153
|
vaultSettings.leafAdapters.push(() => avnuAdapter.getDepositLeaf());
|
|
1483
2154
|
vaultSettings.leafAdapters.push(() => avnuAdapter.getWithdrawLeaf());
|
|
1484
2155
|
vaultSettings.leafAdapters.push(
|
|
@@ -1499,7 +2170,6 @@ function getLooperSettings(
|
|
|
1499
2170
|
return vaultSettings;
|
|
1500
2171
|
}
|
|
1501
2172
|
|
|
1502
|
-
|
|
1503
2173
|
function getDescription(tokenSymbol: string, underlyingSymbol: string) {
|
|
1504
2174
|
return VaultDescription(tokenSymbol, underlyingSymbol);
|
|
1505
2175
|
}
|
|
@@ -1519,26 +2189,64 @@ export default function VaultDescription(
|
|
|
1519
2189
|
|
|
1520
2190
|
return (
|
|
1521
2191
|
<div style={containerStyle}>
|
|
1522
|
-
<h1 style={{ fontSize: "18px", marginBottom: "10px" }}>
|
|
2192
|
+
<h1 style={{ fontSize: "18px", marginBottom: "10px" }}>
|
|
2193
|
+
Liquidation risk managed leverged {lstSymbol} Vault
|
|
2194
|
+
</h1>
|
|
1523
2195
|
<p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
|
|
1524
|
-
This Levered Endur {lstSymbol} vault is a tokenized leveraged Vault,
|
|
1525
|
-
|
|
1526
|
-
|
|
2196
|
+
This Levered Endur {lstSymbol} vault is a tokenized leveraged Vault,
|
|
2197
|
+
auto-compounding strategy that takes upto 5x leverage on {lstSymbol} by
|
|
2198
|
+
borrow {underlyingSymbol}. Borrowed amount is swapped to {lstSymbol} to
|
|
2199
|
+
create leverage. Depositors receive vault shares that represent a
|
|
2200
|
+
proportional claim on the underlying assets and accrued yield.
|
|
1527
2201
|
</p>
|
|
1528
2202
|
|
|
1529
2203
|
<p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
|
|
1530
|
-
This vault uses Vesu for lending and borrowing. The oracle used by this
|
|
1531
|
-
{" "}
|
|
2204
|
+
This vault uses Vesu for lending and borrowing. The oracle used by this
|
|
2205
|
+
pool is a{" "}
|
|
2206
|
+
{highlightTextWithLinks("conversion rate oracle", [
|
|
2207
|
+
{
|
|
2208
|
+
highlight: "conversion rate oracle",
|
|
2209
|
+
link: "https://docs.pragma.build/starknet/development#conversion-rate",
|
|
2210
|
+
},
|
|
2211
|
+
])}{" "}
|
|
2212
|
+
which is resilient to liquidity issues and price volatility, hence
|
|
2213
|
+
reducing the risk of liquidation. However, overtime, if left
|
|
2214
|
+
un-monitored, debt can increase enough to trigger a liquidation. But no
|
|
2215
|
+
worries, our continuous monitoring systems look for situations with
|
|
2216
|
+
reduced health factor and balance collateral/debt to bring it back to
|
|
2217
|
+
safe levels. With Troves, you can have a peaceful sleep.
|
|
1532
2218
|
</p>
|
|
1533
2219
|
|
|
1534
|
-
<div
|
|
2220
|
+
<div
|
|
2221
|
+
style={{
|
|
2222
|
+
backgroundColor: "#222",
|
|
2223
|
+
padding: "10px",
|
|
2224
|
+
borderRadius: "8px",
|
|
2225
|
+
marginBottom: "20px",
|
|
2226
|
+
border: "1px solid #444",
|
|
2227
|
+
}}
|
|
2228
|
+
>
|
|
1535
2229
|
<p style={{ fontSize: "13px", color: "#ccc" }}>
|
|
1536
|
-
<strong>Withdrawals:</strong> Requests can take up to
|
|
2230
|
+
<strong>Withdrawals:</strong> Requests can take up to{" "}
|
|
2231
|
+
<strong>1-2 hours</strong> to process as the vault unwinds and settles
|
|
2232
|
+
routing.
|
|
1537
2233
|
</p>
|
|
1538
2234
|
</div>
|
|
1539
|
-
<div
|
|
2235
|
+
<div
|
|
2236
|
+
style={{
|
|
2237
|
+
backgroundColor: "#222",
|
|
2238
|
+
padding: "10px",
|
|
2239
|
+
borderRadius: "8px",
|
|
2240
|
+
marginBottom: "20px",
|
|
2241
|
+
border: "1px solid #444",
|
|
2242
|
+
}}
|
|
2243
|
+
>
|
|
1540
2244
|
<p style={{ fontSize: "13px", color: "#ccc" }}>
|
|
1541
|
-
<strong>Debt limits:</strong> Pools on Vesu have debt caps that are
|
|
2245
|
+
<strong>Debt limits:</strong> Pools on Vesu have debt caps that are
|
|
2246
|
+
gradually increased over time. Until caps are raised, deposited Tokens
|
|
2247
|
+
remain in the vault, generating a shared net return for all
|
|
2248
|
+
depositors. There is no additional fee taken by Troves on Yield
|
|
2249
|
+
token's APY, its only on added gain.
|
|
1542
2250
|
</p>
|
|
1543
2251
|
</div>
|
|
1544
2252
|
{/* <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
|
|
@@ -1551,11 +2259,21 @@ export default function VaultDescription(
|
|
|
1551
2259
|
}
|
|
1552
2260
|
|
|
1553
2261
|
const re7UsdcPrimeDevansh: VesuExtendedStrategySettings = {
|
|
1554
|
-
vaultAddress: ContractAddr.from(
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
2262
|
+
vaultAddress: ContractAddr.from(
|
|
2263
|
+
"0x058905be22d6a81792df79425dc9641cf3e1b77f36748631b7d7e5d713a32b55"
|
|
2264
|
+
),
|
|
2265
|
+
manager: ContractAddr.from(
|
|
2266
|
+
"0x02648d703783feb2d967cf0520314cb5aa800d69a9426f3e3b317395af44de16"
|
|
2267
|
+
),
|
|
2268
|
+
vaultAllocator: ContractAddr.from(
|
|
2269
|
+
"0x07d533c838eab6a4d854dd3aea96a55993fccd35821921970d00bde946b63b6f"
|
|
2270
|
+
),
|
|
2271
|
+
redeemRequestNFT: ContractAddr.from(
|
|
2272
|
+
"0x01ef91f08fb99729c00f82fc6e0ece37917bcc43952596c19996259dc8adbbba"
|
|
2273
|
+
),
|
|
2274
|
+
aumOracle: ContractAddr.from(
|
|
2275
|
+
"0x030b6acfec162f5d6e72b8a4d2798aedce78fb39de78a8f549f7cd277ae8bc8d"
|
|
2276
|
+
),
|
|
1559
2277
|
leafAdapters: [],
|
|
1560
2278
|
adapters: [],
|
|
1561
2279
|
targetHealthFactor: 1.4,
|
|
@@ -1567,34 +2285,88 @@ const re7UsdcPrimeDevansh: VesuExtendedStrategySettings = {
|
|
|
1567
2285
|
"0.001",
|
|
1568
2286
|
Global.getDefaultTokens().find((token) => token.symbol === "WBTC")!.decimals
|
|
1569
2287
|
),
|
|
1570
|
-
borrowable_assets: [
|
|
2288
|
+
borrowable_assets: [
|
|
2289
|
+
Global.getDefaultTokens().find((token) => token.symbol === "WBTC")!,
|
|
2290
|
+
],
|
|
1571
2291
|
minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
|
|
1572
2292
|
walletAddress: WALLET_ADDRESS,
|
|
1573
|
-
}
|
|
2293
|
+
};
|
|
1574
2294
|
|
|
1575
|
-
export const VesuExtendedTestStrategies = (
|
|
2295
|
+
export const VesuExtendedTestStrategies = (
|
|
2296
|
+
extendedBackendReadUrl: string,
|
|
2297
|
+
extendedBackendWriteUrl: string,
|
|
2298
|
+
vaultIdExtended: number,
|
|
2299
|
+
minimumExtendedMovementAmount: number,
|
|
2300
|
+
minimumVesuMovementAmount: number,
|
|
2301
|
+
minimumExtendedRetriesDelayForOrderStatus: number,
|
|
2302
|
+
minimumExtendedPriceDifferenceForSwapOpen: number,
|
|
2303
|
+
maximumExtendedPriceDifferenceForSwapClosing: number
|
|
2304
|
+
): IStrategyMetadata<VesuExtendedStrategySettings>[] => {
|
|
1576
2305
|
return [
|
|
1577
|
-
getStrategySettingsVesuExtended(
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
2306
|
+
getStrategySettingsVesuExtended(
|
|
2307
|
+
"WBTC",
|
|
2308
|
+
"USDC",
|
|
2309
|
+
re7UsdcPrimeDevansh,
|
|
2310
|
+
false,
|
|
2311
|
+
false,
|
|
2312
|
+
extendedBackendReadUrl,
|
|
2313
|
+
extendedBackendWriteUrl,
|
|
2314
|
+
vaultIdExtended,
|
|
2315
|
+
minimumExtendedMovementAmount,
|
|
2316
|
+
minimumVesuMovementAmount,
|
|
2317
|
+
minimumExtendedRetriesDelayForOrderStatus,
|
|
2318
|
+
minimumExtendedPriceDifferenceForSwapOpen,
|
|
2319
|
+
maximumExtendedPriceDifferenceForSwapClosing
|
|
2320
|
+
),
|
|
2321
|
+
];
|
|
2322
|
+
};
|
|
2323
|
+
|
|
2324
|
+
function getStrategySettingsVesuExtended(
|
|
2325
|
+
lstSymbol: string,
|
|
2326
|
+
underlyingSymbol: string,
|
|
2327
|
+
addresses: VesuExtendedStrategySettings,
|
|
2328
|
+
isPreview: boolean = false,
|
|
2329
|
+
isLST: boolean,
|
|
2330
|
+
extendedBackendReadUrl: string,
|
|
2331
|
+
extendedBackendWriteUrl: string,
|
|
2332
|
+
vaultIdExtended: number,
|
|
2333
|
+
minimumExtendedMovementAmount: number,
|
|
2334
|
+
minimumVesuMovementAmount: number,
|
|
2335
|
+
minimumExtendedRetriesDelayForOrderStatus: number,
|
|
2336
|
+
minimumExtendedPriceDifferenceForSwapOpen: number,
|
|
2337
|
+
maximumExtendedPriceDifferenceForSwapClosing: number
|
|
2338
|
+
): IStrategyMetadata<VesuExtendedStrategySettings> {
|
|
1584
2339
|
return {
|
|
1585
2340
|
name: `Extended Test ${underlyingSymbol}`,
|
|
1586
2341
|
description: getDescription(lstSymbol, underlyingSymbol),
|
|
1587
2342
|
address: addresses.vaultAddress,
|
|
1588
2343
|
launchBlock: 0,
|
|
1589
|
-
type:
|
|
1590
|
-
depositTokens: [
|
|
1591
|
-
|
|
2344
|
+
type: "Other",
|
|
2345
|
+
depositTokens: [
|
|
2346
|
+
Global.getDefaultTokens().find(
|
|
2347
|
+
(token) => token.symbol === underlyingSymbol
|
|
2348
|
+
)!,
|
|
2349
|
+
],
|
|
2350
|
+
additionalInfo: getLooperSettings(
|
|
2351
|
+
lstSymbol,
|
|
2352
|
+
underlyingSymbol,
|
|
2353
|
+
addresses,
|
|
2354
|
+
VesuPools.Re7USDCPrime,
|
|
2355
|
+
extendedBackendReadUrl,
|
|
2356
|
+
extendedBackendWriteUrl,
|
|
2357
|
+
vaultIdExtended,
|
|
2358
|
+
minimumExtendedMovementAmount,
|
|
2359
|
+
minimumVesuMovementAmount,
|
|
2360
|
+
minimumExtendedRetriesDelayForOrderStatus,
|
|
2361
|
+
minimumExtendedPriceDifferenceForSwapOpen,
|
|
2362
|
+
maximumExtendedPriceDifferenceForSwapClosing
|
|
2363
|
+
),
|
|
1592
2364
|
risk: {
|
|
1593
2365
|
riskFactor: _riskFactor,
|
|
1594
2366
|
netRisk:
|
|
1595
2367
|
_riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
1596
2368
|
_riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1597
|
-
notARisks: getNoRiskTags(_riskFactor)
|
|
2369
|
+
notARisks: getNoRiskTags(_riskFactor),
|
|
1598
2370
|
},
|
|
1599
2371
|
auditUrl: AUDIT_URL,
|
|
1600
2372
|
protocols: [Protocols.ENDUR, Protocols.VESU],
|
|
@@ -1603,6 +2375,8 @@ function getStrategySettingsVesuExtended(lstSymbol: string, underlyingSymbol: st
|
|
|
1603
2375
|
faqs: getFAQs(lstSymbol, underlyingSymbol, isLST),
|
|
1604
2376
|
investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
|
|
1605
2377
|
isPreview: isPreview,
|
|
1606
|
-
apyMethodology: isLST
|
|
1607
|
-
|
|
1608
|
-
|
|
2378
|
+
apyMethodology: isLST
|
|
2379
|
+
? "Current annualized APY in terms of base asset of the LST. There is no additional fee taken by Troves on LST APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown."
|
|
2380
|
+
: "Current annualized APY in terms of base asset of the Yield Token. There is no additional fee taken by Troves on yield token APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown.",
|
|
2381
|
+
};
|
|
2382
|
+
}
|