@strkfarm/sdk 2.0.0-dev.26 → 2.0.0-dev.28
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/cli.js +190 -36
- package/dist/cli.mjs +188 -34
- package/dist/index.browser.global.js +79130 -49354
- package/dist/index.browser.mjs +18039 -11431
- package/dist/index.d.ts +2869 -898
- package/dist/index.js +19036 -12207
- package/dist/index.mjs +18942 -12158
- package/package.json +1 -1
- package/src/data/avnu.abi.json +840 -0
- package/src/data/ekubo-price-fethcer.abi.json +265 -0
- package/src/dataTypes/_bignumber.ts +13 -4
- package/src/dataTypes/index.ts +3 -2
- package/src/dataTypes/mynumber.ts +141 -0
- package/src/global.ts +76 -41
- package/src/index.browser.ts +2 -1
- package/src/interfaces/common.tsx +167 -2
- package/src/modules/ExtendedWrapperSDk/types.ts +26 -4
- package/src/modules/ExtendedWrapperSDk/wrapper.ts +110 -67
- package/src/modules/apollo-client-config.ts +28 -0
- package/src/modules/avnu.ts +4 -4
- package/src/modules/ekubo-pricer.ts +79 -0
- package/src/modules/ekubo-quoter.ts +46 -30
- package/src/modules/erc20.ts +17 -0
- package/src/modules/harvests.ts +43 -29
- package/src/modules/pragma.ts +23 -8
- package/src/modules/pricer-from-api.ts +156 -15
- package/src/modules/pricer-lst.ts +1 -1
- package/src/modules/pricer.ts +40 -4
- package/src/modules/pricerBase.ts +2 -1
- package/src/node/deployer.ts +36 -1
- package/src/node/pricer-redis.ts +2 -1
- package/src/strategies/base-strategy.ts +78 -10
- package/src/strategies/ekubo-cl-vault.tsx +906 -347
- package/src/strategies/factory.ts +159 -0
- package/src/strategies/index.ts +6 -1
- package/src/strategies/registry.ts +239 -0
- package/src/strategies/sensei.ts +335 -7
- package/src/strategies/svk-strategy.ts +97 -27
- package/src/strategies/types.ts +4 -0
- package/src/strategies/universal-adapters/adapter-utils.ts +2 -1
- package/src/strategies/universal-adapters/avnu-adapter.ts +177 -268
- package/src/strategies/universal-adapters/baseAdapter.ts +263 -251
- package/src/strategies/universal-adapters/common-adapter.ts +206 -203
- package/src/strategies/universal-adapters/extended-adapter.ts +155 -336
- package/src/strategies/universal-adapters/index.ts +9 -8
- package/src/strategies/universal-adapters/token-transfer-adapter.ts +200 -0
- package/src/strategies/universal-adapters/usdc<>usdce-adapter.ts +200 -0
- package/src/strategies/universal-adapters/vesu-adapter.ts +110 -75
- package/src/strategies/universal-adapters/vesu-modify-position-adapter.ts +476 -0
- package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +762 -844
- package/src/strategies/universal-adapters/vesu-position-common.ts +251 -0
- package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +18 -3
- package/src/strategies/universal-lst-muliplier-strategy.tsx +396 -204
- package/src/strategies/universal-strategy.tsx +1426 -1178
- package/src/strategies/vesu-extended-strategy/services/executionService.ts +2251 -0
- package/src/strategies/vesu-extended-strategy/services/extended-vesu-state-manager.ts +2941 -0
- package/src/strategies/vesu-extended-strategy/services/operationService.ts +12 -1
- package/src/strategies/vesu-extended-strategy/types/transaction-metadata.ts +52 -0
- package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +1 -0
- package/src/strategies/vesu-extended-strategy/utils/constants.ts +3 -1
- package/src/strategies/vesu-extended-strategy/utils/helper.ts +158 -124
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +377 -1781
- package/src/strategies/vesu-rebalance.tsx +255 -152
- package/src/utils/health-factor-math.ts +4 -1
- package/src/utils/index.ts +2 -1
- package/src/utils/logger.browser.ts +22 -4
- package/src/utils/logger.node.ts +259 -24
- package/src/utils/starknet-call-parser.ts +1036 -0
- package/src/utils/strategy-utils.ts +61 -0
- package/src/strategies/universal-adapters/unused-balance-adapter.ts +0 -109
|
@@ -11,8 +11,15 @@ import {
|
|
|
11
11
|
Protocols,
|
|
12
12
|
RiskFactor,
|
|
13
13
|
RiskType,
|
|
14
|
+
StrategyTag,
|
|
14
15
|
TokenInfo,
|
|
15
16
|
VaultPosition,
|
|
17
|
+
AuditStatus,
|
|
18
|
+
SourceCodeType,
|
|
19
|
+
AccessControlType,
|
|
20
|
+
InstantWithdrawalVault,
|
|
21
|
+
VaultType,
|
|
22
|
+
StrategyLiveStatus,
|
|
16
23
|
} from "@/interfaces";
|
|
17
24
|
import { PricerBase } from "@/modules/pricerBase";
|
|
18
25
|
import { assert } from "@/utils";
|
|
@@ -38,10 +45,11 @@ import { EkuboHarvests, HarvestInfo } from "@/modules/harvests";
|
|
|
38
45
|
import { logger } from "@/utils/logger";
|
|
39
46
|
import { COMMON_CONTRACTS } from "./constants";
|
|
40
47
|
import { DepegRiskLevel, ImpermanentLossLevel, MarketRiskLevel, SmartContractRiskLevel } from "@/interfaces/risks";
|
|
41
|
-
import { gql } from "@apollo/client";
|
|
48
|
+
import { from, gql } from "@apollo/client";
|
|
42
49
|
import apolloClient from "@/modules/apollo-client";
|
|
43
50
|
import { binarySearch } from "@/utils/math-utils";
|
|
44
51
|
import { PositionInfo } from "./universal-adapters/baseAdapter";
|
|
52
|
+
import { Quote } from "@avnu/avnu-sdk";
|
|
45
53
|
|
|
46
54
|
export interface EkuboPoolKey {
|
|
47
55
|
token0: ContractAddr;
|
|
@@ -296,7 +304,10 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
296
304
|
return [this.contract.populate("handle_fees", [])];
|
|
297
305
|
}
|
|
298
306
|
|
|
299
|
-
async getFeeHistory(
|
|
307
|
+
async getFeeHistory(
|
|
308
|
+
timePeriod: '24h' | '7d' | '30d' | '3m' | '6m' = '24h',
|
|
309
|
+
range?: { startTimestamp?: number; endTimestamp?: number }
|
|
310
|
+
): Promise<{
|
|
300
311
|
summary: DualTokenInfo,
|
|
301
312
|
history: FeeHistory[]
|
|
302
313
|
}> {
|
|
@@ -305,8 +316,15 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
305
316
|
query ContractFeeEarnings(
|
|
306
317
|
$timeframe: String!
|
|
307
318
|
$contract: String!
|
|
319
|
+
$startTimestamp: Float
|
|
320
|
+
$endTimestamp: Float
|
|
308
321
|
) {
|
|
309
|
-
contractFeeEarnings(
|
|
322
|
+
contractFeeEarnings(
|
|
323
|
+
timeframe: $timeframe
|
|
324
|
+
contract: $contract
|
|
325
|
+
startTimestamp: $startTimestamp
|
|
326
|
+
endTimestamp: $endTimestamp
|
|
327
|
+
) {
|
|
310
328
|
contract
|
|
311
329
|
dailyEarnings {
|
|
312
330
|
date
|
|
@@ -319,7 +337,9 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
319
337
|
`,
|
|
320
338
|
variables: {
|
|
321
339
|
timeframe: timePeriod,
|
|
322
|
-
contract: this.address.address
|
|
340
|
+
contract: this.address.address,
|
|
341
|
+
startTimestamp: range?.startTimestamp,
|
|
342
|
+
endTimestamp: range?.endTimestamp
|
|
323
343
|
},
|
|
324
344
|
fetchPolicy: 'no-cache',
|
|
325
345
|
});
|
|
@@ -418,22 +438,41 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
418
438
|
const tvlBefore = await this._getTVL(blockBefore);
|
|
419
439
|
const supplyBefore = await this.totalSupply(blockBefore);
|
|
420
440
|
const priceBefore = await this.getCurrentPrice(blockBefore);
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
441
|
+
const poolKey = await this.getPoolKey(blockBefore);
|
|
442
|
+
logger.verbose(`priceBefore: ${priceBefore.price.toString()}`);
|
|
443
|
+
logger.verbose(`priceNow: ${priceNow.price.toString()}`);
|
|
444
|
+
logger.verbose(`tvlBefore: ${JSON.stringify(tvlBefore)}`);
|
|
445
|
+
logger.verbose(`tvlNow: ${JSON.stringify(tvlNow)}`);
|
|
446
|
+
|
|
447
|
+
const isQuoteTokenToken0 = this.metadata.additionalInfo.quoteAsset.address.eq(poolKey.token0);
|
|
448
|
+
logger.verbose(`isQuoteTokenToken0: ${isQuoteTokenToken0}`);
|
|
449
|
+
let tvlBeforeInBaseAsset = Web3Number.fromWei(0, this.metadata.additionalInfo.quoteAsset.decimals);
|
|
450
|
+
let tvlNowInBaseAsset = Web3Number.fromWei(0, this.metadata.additionalInfo.quoteAsset.decimals);
|
|
451
|
+
if (!isQuoteTokenToken0) {
|
|
452
|
+
tvlNowInBaseAsset = (tvlNow.amount0
|
|
453
|
+
.multipliedBy(priceNow.price))
|
|
454
|
+
.plus(tvlNow.amount1);
|
|
455
|
+
tvlBeforeInBaseAsset = (tvlBefore.amount0
|
|
456
|
+
.multipliedBy(priceBefore.price))
|
|
457
|
+
.plus(tvlBefore.amount1);
|
|
458
|
+
} else {
|
|
459
|
+
tvlNowInBaseAsset = (tvlNow.amount1
|
|
460
|
+
.multipliedBy(1 / priceNow.price))
|
|
461
|
+
.plus(tvlNow.amount0);
|
|
462
|
+
tvlBeforeInBaseAsset = (tvlBefore.amount1
|
|
463
|
+
.multipliedBy(1 / priceBefore.price))
|
|
464
|
+
.plus(tvlBefore.amount0);
|
|
465
|
+
}
|
|
466
|
+
const tvlPerShareNow = tvlNowInBaseAsset
|
|
426
467
|
.multipliedBy(1e18)
|
|
427
468
|
.dividedBy(adjustedSupplyNow.toString());
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
.plus(tvlBefore.amount1);
|
|
431
|
-
const tvlPerShareBf = tvlInToken0Bf
|
|
469
|
+
|
|
470
|
+
const tvlPerShareBf = tvlBeforeInBaseAsset
|
|
432
471
|
.multipliedBy(1e18)
|
|
433
472
|
.dividedBy(supplyBefore.toString());
|
|
434
473
|
const timeDiffSeconds = blockNowTime - blockBeforeInfo.timestamp;
|
|
435
|
-
logger.verbose(`
|
|
436
|
-
logger.verbose(`
|
|
474
|
+
logger.verbose(`tvlNowInBaseAsset: ${tvlNowInBaseAsset.toString()}`);
|
|
475
|
+
logger.verbose(`tvlBeforeInBaseAsset: ${tvlBeforeInBaseAsset.toString()}`);
|
|
437
476
|
logger.verbose(`tvlPerShareNow: ${tvlPerShareNow.toString()}`);
|
|
438
477
|
logger.verbose(`tvlPerShareBf: ${tvlPerShareBf.toString()}`);
|
|
439
478
|
logger.verbose(`Price before: ${priceBefore.price.toString()}`);
|
|
@@ -451,6 +490,155 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
451
490
|
return (apyForGivenBlocks * (365 * 24 * 3600)) / timeDiffSeconds;
|
|
452
491
|
}
|
|
453
492
|
|
|
493
|
+
/**
|
|
494
|
+
* Calculate lifetime earnings for a user
|
|
495
|
+
* Not yet implemented for Ekubo CL Vault strategy
|
|
496
|
+
*/
|
|
497
|
+
getLifetimeEarnings(
|
|
498
|
+
userTVL: SingleTokenInfo,
|
|
499
|
+
investmentFlows: Array<{ amount: string; type: string; timestamp: number; tx_hash: string }>
|
|
500
|
+
): any {
|
|
501
|
+
throw new Error("getLifetimeEarnings is not implemented yet for this strategy");
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Calculates realized APY based on TVL per share growth, always valued in USDC.
|
|
506
|
+
* This is a vault-level metric (same for all users) and works for all strategies,
|
|
507
|
+
* regardless of quote asset configuration.
|
|
508
|
+
*/
|
|
509
|
+
async getUserRealizedAPY(
|
|
510
|
+
blockIdentifier: BlockIdentifier = "latest",
|
|
511
|
+
sinceBlocks = 600000
|
|
512
|
+
): Promise<number> {
|
|
513
|
+
throw new Error("getUserRealizedAPY not implemented yet for Ekubo CL Vault strategy");
|
|
514
|
+
|
|
515
|
+
/*
|
|
516
|
+
logger.verbose(
|
|
517
|
+
`${EkuboCLVault.name}: getUserRealizedAPY => starting with blockIdentifier=${blockIdentifier}, sinceBlocks=${sinceBlocks}`
|
|
518
|
+
);
|
|
519
|
+
|
|
520
|
+
// TVL amounts (in token units) at current reference block
|
|
521
|
+
const tvlNow = await this._getTVL(blockIdentifier);
|
|
522
|
+
const supplyNow = await this.totalSupply(blockIdentifier);
|
|
523
|
+
|
|
524
|
+
// Determine current block number and timestamp
|
|
525
|
+
let blockNow =
|
|
526
|
+
typeof blockIdentifier == "number"
|
|
527
|
+
? blockIdentifier
|
|
528
|
+
: (await this.config.provider.getBlockLatestAccepted()).block_number;
|
|
529
|
+
const blockNowTime =
|
|
530
|
+
typeof blockIdentifier == "number"
|
|
531
|
+
? (await this.config.provider.getBlockWithTxs(blockIdentifier))
|
|
532
|
+
.timestamp
|
|
533
|
+
: new Date().getTime() / 1000;
|
|
534
|
+
|
|
535
|
+
// Look back window, but never before launch block
|
|
536
|
+
const blockBefore = Math.max(
|
|
537
|
+
Number(blockNow) - sinceBlocks,
|
|
538
|
+
this.metadata.launchBlock
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
// Adjust current supply by subtracting harvest reward shares (same idea as netSharesBasedTrueAPY)
|
|
542
|
+
const adjustedSupplyNow = supplyNow.minus(
|
|
543
|
+
await this.getHarvestRewardShares(blockBefore, Number(blockNow))
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
// Historical block info and TVL
|
|
547
|
+
const blockBeforeInfo = await this.config.provider.getBlockWithTxs(
|
|
548
|
+
blockBefore
|
|
549
|
+
);
|
|
550
|
+
const tvlBefore = await this._getTVL(blockBefore);
|
|
551
|
+
const supplyBefore = await this.totalSupply(blockBefore);
|
|
552
|
+
|
|
553
|
+
// Always value TVL in USDC using the pricer for both tokens at both blocks
|
|
554
|
+
const token0Info = this.metadata.depositTokens[0];
|
|
555
|
+
const token1Info = this.metadata.depositTokens[1];
|
|
556
|
+
|
|
557
|
+
const P0Now = await this.pricer.getPrice(
|
|
558
|
+
token0Info.symbol,
|
|
559
|
+
Number(blockNow)
|
|
560
|
+
);
|
|
561
|
+
const P1Now = await this.pricer.getPrice(
|
|
562
|
+
token1Info.symbol,
|
|
563
|
+
Number(blockNow)
|
|
564
|
+
);
|
|
565
|
+
const P0Before = await this.pricer.getPrice(
|
|
566
|
+
token0Info.symbol,
|
|
567
|
+
blockBefore
|
|
568
|
+
);
|
|
569
|
+
const P1Before = await this.pricer.getPrice(
|
|
570
|
+
token1Info.symbol,
|
|
571
|
+
blockBefore
|
|
572
|
+
);
|
|
573
|
+
|
|
574
|
+
// Convert token balances to USDC TVL using current and historical prices
|
|
575
|
+
const tvlNowUsdNumber =
|
|
576
|
+
Number(tvlNow.amount0.toFixed(13)) * P0Now.price +
|
|
577
|
+
Number(tvlNow.amount1.toFixed(13)) * P1Now.price;
|
|
578
|
+
const tvlBeforeUsdNumber =
|
|
579
|
+
Number(tvlBefore.amount0.toFixed(13)) * P0Before.price +
|
|
580
|
+
Number(tvlBefore.amount1.toFixed(13)) * P1Before.price;
|
|
581
|
+
|
|
582
|
+
// Represent USDC TVL as Web3Number with 6 decimals (USDC standard)
|
|
583
|
+
const tvlNowInUSDC = new Web3Number(
|
|
584
|
+
tvlNowUsdNumber.toFixed(13),
|
|
585
|
+
6
|
|
586
|
+
);
|
|
587
|
+
const tvlBeforeInUSDC = new Web3Number(
|
|
588
|
+
tvlBeforeUsdNumber.toFixed(13),
|
|
589
|
+
6
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
const tvlPerShareNow = tvlNowInUSDC
|
|
593
|
+
.multipliedBy(1e18)
|
|
594
|
+
.dividedBy(adjustedSupplyNow.toString());
|
|
595
|
+
|
|
596
|
+
const tvlPerShareBf = tvlBeforeInUSDC
|
|
597
|
+
.multipliedBy(1e18)
|
|
598
|
+
.dividedBy(supplyBefore.toString());
|
|
599
|
+
|
|
600
|
+
const timeDiffSeconds = blockNowTime - blockBeforeInfo.timestamp;
|
|
601
|
+
|
|
602
|
+
logger.verbose(
|
|
603
|
+
`${EkuboCLVault.name}: getUserRealizedAPY => token0=${token0Info.symbol}, token1=${token1Info.symbol}`
|
|
604
|
+
);
|
|
605
|
+
logger.verbose(
|
|
606
|
+
`${EkuboCLVault.name}: getUserRealizedAPY => P0Now=${P0Now.price}, P1Now=${P1Now.price}, P0Before=${P0Before.price}, P1Before=${P1Before.price}`
|
|
607
|
+
);
|
|
608
|
+
logger.verbose(
|
|
609
|
+
`${EkuboCLVault.name}: getUserRealizedAPY => raw tvlNow amounts: token0=${tvlNow.amount0.toString()}, token1=${tvlNow.amount1.toString()}`
|
|
610
|
+
);
|
|
611
|
+
logger.verbose(
|
|
612
|
+
`${EkuboCLVault.name}: getUserRealizedAPY => raw tvlBefore amounts: token0=${tvlBefore.amount0.toString()}, token1=${tvlBefore.amount1.toString()}`
|
|
613
|
+
);
|
|
614
|
+
logger.verbose(
|
|
615
|
+
`${EkuboCLVault.name}: getUserRealizedAPY => tvlNowUsdNumber=${tvlNowUsdNumber}, tvlBeforeUsdNumber=${tvlBeforeUsdNumber}`
|
|
616
|
+
);
|
|
617
|
+
logger.verbose(
|
|
618
|
+
`${EkuboCLVault.name}: getUserRealizedAPY => tvlNowInUSDC: ${tvlNowInUSDC.toString()}, tvlBeforeInUSDC: ${tvlBeforeInUSDC.toString()}`
|
|
619
|
+
);
|
|
620
|
+
logger.verbose(
|
|
621
|
+
`${EkuboCLVault.name}: getUserRealizedAPY => tvlPerShareNow: ${tvlPerShareNow.toString()}, tvlPerShareBf: ${tvlPerShareBf.toString()}`
|
|
622
|
+
);
|
|
623
|
+
logger.verbose(
|
|
624
|
+
`${EkuboCLVault.name}: getUserRealizedAPY => Supply before: ${supplyBefore.toString()}, Supply now (adjusted): ${adjustedSupplyNow.toString()}`
|
|
625
|
+
);
|
|
626
|
+
logger.verbose(
|
|
627
|
+
`${EkuboCLVault.name}: getUserRealizedAPY => Time diff in seconds: ${timeDiffSeconds}`
|
|
628
|
+
);
|
|
629
|
+
|
|
630
|
+
const apyForGivenBlocks =
|
|
631
|
+
Number(
|
|
632
|
+
tvlPerShareNow
|
|
633
|
+
.minus(tvlPerShareBf)
|
|
634
|
+
.multipliedBy(10000)
|
|
635
|
+
.dividedBy(tvlPerShareBf)
|
|
636
|
+
) / 10000;
|
|
637
|
+
|
|
638
|
+
return (apyForGivenBlocks * (365 * 24 * 3600)) / timeDiffSeconds;
|
|
639
|
+
*/
|
|
640
|
+
}
|
|
641
|
+
|
|
454
642
|
async feeBasedAPY(
|
|
455
643
|
timeperiod: '24h' | '7d' | '30d' | '3m' = '24h'
|
|
456
644
|
): Promise<number> {
|
|
@@ -485,20 +673,15 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
485
673
|
blockIdentifier: BlockIdentifier = "latest",
|
|
486
674
|
sinceBlocks = 600000,
|
|
487
675
|
timeperiod: '24h' | '7d' | '30d' | '3m' = '24h' // temp thing for fee based APY
|
|
488
|
-
): Promise<
|
|
489
|
-
|
|
676
|
+
): Promise<number> {
|
|
677
|
+
// ! switch to USDC later
|
|
678
|
+
const isUSDCQouteToken = this.metadata.additionalInfo.quoteAsset.symbol === "USDC.e" || this.metadata.additionalInfo.quoteAsset.symbol === "USDC";
|
|
490
679
|
if (!isUSDCQouteToken) {
|
|
491
680
|
// good for LSTs and stables
|
|
492
|
-
|
|
493
|
-
net: await this.netSharesBasedTrueAPY(blockIdentifier, sinceBlocks),
|
|
494
|
-
splits: []
|
|
495
|
-
};
|
|
681
|
+
return await this.netSharesBasedTrueAPY(blockIdentifier, sinceBlocks);
|
|
496
682
|
} else {
|
|
497
683
|
// good for non-stables
|
|
498
|
-
return
|
|
499
|
-
net: await this.feeBasedAPY(timeperiod),
|
|
500
|
-
splits: []
|
|
501
|
-
};
|
|
684
|
+
return await this.feeBasedAPY(timeperiod);
|
|
502
685
|
}
|
|
503
686
|
}
|
|
504
687
|
|
|
@@ -559,8 +742,14 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
559
742
|
assets.amount1.toString(),
|
|
560
743
|
token1Info.decimals
|
|
561
744
|
);
|
|
562
|
-
|
|
563
|
-
|
|
745
|
+
|
|
746
|
+
// Convert blockIdentifier to block number for pricer if it's a number
|
|
747
|
+
const blockNumber = typeof blockIdentifier === 'number' || typeof blockIdentifier === 'bigint'
|
|
748
|
+
? Number(blockIdentifier)
|
|
749
|
+
: undefined;
|
|
750
|
+
|
|
751
|
+
const P0 = await this.pricer.getPrice(token0Info.symbol, blockNumber);
|
|
752
|
+
const P1 = await this.pricer.getPrice(token1Info.symbol, blockNumber);
|
|
564
753
|
const token0Usd = Number(amount0.toFixed(13)) * P0.price;
|
|
565
754
|
const token1Usd = Number(amount1.toFixed(13)) * P1.price;
|
|
566
755
|
|
|
@@ -1026,6 +1215,12 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1026
1215
|
amount1: availableAmount1.minus(y),
|
|
1027
1216
|
ratio: 0,
|
|
1028
1217
|
};
|
|
1218
|
+
} else if (ratio.eq(Infinity)) {
|
|
1219
|
+
return {
|
|
1220
|
+
amount0: availableAmount0,
|
|
1221
|
+
amount1: Web3Number.fromWei("0", availableAmount1.decimals),
|
|
1222
|
+
ratio: Infinity,
|
|
1223
|
+
};
|
|
1029
1224
|
}
|
|
1030
1225
|
return {
|
|
1031
1226
|
amount0: availableAmount0.plus(x),
|
|
@@ -1075,7 +1270,12 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1075
1270
|
};
|
|
1076
1271
|
}
|
|
1077
1272
|
|
|
1078
|
-
async getSwapInfoToHandleUnused(
|
|
1273
|
+
async getSwapInfoToHandleUnused(
|
|
1274
|
+
considerRebalance: boolean = true,
|
|
1275
|
+
newBounds: EkuboBounds | null = null,
|
|
1276
|
+
maxIterations = 20, priceRatioPrecision = 4,
|
|
1277
|
+
getQuoteCallback: (tokenToSell: string, tokenToBuy: string, amountWei: string, beneficiary: string) => Promise<Quote> = this.avnu.getQuotes
|
|
1278
|
+
): Promise<SwapInfo> {
|
|
1079
1279
|
const poolKey = await this.getPoolKey();
|
|
1080
1280
|
|
|
1081
1281
|
// fetch current unused balances of vault
|
|
@@ -1140,7 +1340,8 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1140
1340
|
token1Bal,
|
|
1141
1341
|
ekuboBounds,
|
|
1142
1342
|
maxIterations,
|
|
1143
|
-
priceRatioPrecision
|
|
1343
|
+
priceRatioPrecision,
|
|
1344
|
+
getQuoteCallback
|
|
1144
1345
|
);
|
|
1145
1346
|
}
|
|
1146
1347
|
|
|
@@ -1186,6 +1387,7 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1186
1387
|
const tokenToSell = expectedAmounts.amount0.lessThan(token0Bal)
|
|
1187
1388
|
? poolKey.token0
|
|
1188
1389
|
: poolKey.token1;
|
|
1390
|
+
logger.verbose(`getSwapParams => tokenToSell: ${tokenToSell.address}, expectedAmounts: ${expectedAmounts.amount0.toString()}, bal0: ${token0Bal.toString()}`);
|
|
1189
1391
|
// The other token is the one to buy
|
|
1190
1392
|
const tokenToBuy =
|
|
1191
1393
|
tokenToSell == poolKey.token0 ? poolKey.token1 : poolKey.token0;
|
|
@@ -1210,13 +1412,13 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1210
1412
|
/**
|
|
1211
1413
|
* @description Calculates swap info based on given amounts of token0 and token1
|
|
1212
1414
|
* Use token0 and token1 balances to determine the expected amounts for new bounds
|
|
1213
|
-
* @param poolKey
|
|
1214
|
-
* @param token0Bal
|
|
1215
|
-
* @param token1Bal
|
|
1415
|
+
* @param poolKey
|
|
1416
|
+
* @param token0Bal
|
|
1417
|
+
* @param token1Bal
|
|
1216
1418
|
* @param bounds // new bounds
|
|
1217
|
-
* @param maxIterations
|
|
1419
|
+
* @param maxIterations
|
|
1218
1420
|
* @returns {Promise<SwapInfo>}
|
|
1219
|
-
*
|
|
1421
|
+
*
|
|
1220
1422
|
*/
|
|
1221
1423
|
async getSwapInfoGivenAmounts(
|
|
1222
1424
|
poolKey: EkuboPoolKey,
|
|
@@ -1224,7 +1426,8 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1224
1426
|
token1Bal: Web3Number,
|
|
1225
1427
|
bounds: EkuboBounds,
|
|
1226
1428
|
maxIterations: number = 20,
|
|
1227
|
-
priceRatioPrecision: number = 4
|
|
1429
|
+
priceRatioPrecision: number = 4,
|
|
1430
|
+
getQuoteCallback: (tokenToSell: string, tokenToBuy: string, amountWei: string, beneficiary: string) => Promise<Quote> = this.avnu.getQuotes
|
|
1228
1431
|
): Promise<SwapInfo> {
|
|
1229
1432
|
logger.verbose(
|
|
1230
1433
|
`${
|
|
@@ -1279,12 +1482,7 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1279
1482
|
}
|
|
1280
1483
|
|
|
1281
1484
|
// Get a quote for swapping the calculated amount
|
|
1282
|
-
const quote = await this.
|
|
1283
|
-
tokenToSell.address,
|
|
1284
|
-
tokenToBuy.address,
|
|
1285
|
-
amountToSell.toWei(),
|
|
1286
|
-
this.address.address
|
|
1287
|
-
);
|
|
1485
|
+
const quote = await getQuoteCallback(tokenToSell.address, tokenToBuy.address, amountToSell.toWei(), this.address.address);
|
|
1288
1486
|
|
|
1289
1487
|
// If all of the token is to be swapped, return the swap info directly
|
|
1290
1488
|
if (remainingSellAmount.eq(0)) {
|
|
@@ -1394,8 +1592,11 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1394
1592
|
* @param retry - Current retry attempt number (default 0)
|
|
1395
1593
|
* @param adjustmentFactor - Percentage to adjust swap amount by (default 1)
|
|
1396
1594
|
* @param isToken0Deficit - Whether token0 balance needs increasing (default true)
|
|
1595
|
+
* @param MAX_RETRIES - Maximum number of retries (default 40)
|
|
1596
|
+
* @param sameErrorCount - For certain errors, we just retry with same amount again. This is the count of such retries (default { count: 0, error: null })
|
|
1597
|
+
* @param MAX_SAME_ERROR_COUNT - For certain errors, we just retry with same amount again. This limits such retries (default 10)
|
|
1397
1598
|
* @returns Array of contract calls needed for rebalancing
|
|
1398
|
-
* @throws Error if max retries reached without successful rebalance
|
|
1599
|
+
* @throws Error if max retries reached without successful rebalance or max same errors reached
|
|
1399
1600
|
*/
|
|
1400
1601
|
async rebalanceIter(
|
|
1401
1602
|
swapInfo: SwapInfo,
|
|
@@ -1405,15 +1606,23 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1405
1606
|
retry = 0,
|
|
1406
1607
|
lowerLimit = 0n,
|
|
1407
1608
|
upperLimit = 0n,
|
|
1408
|
-
MAX_RETRIES = 40
|
|
1609
|
+
MAX_RETRIES = 40,
|
|
1610
|
+
sameErrorCount: { count: number, error: null | string } = { count: 0, error: null },
|
|
1611
|
+
MAX_SAME_ERROR_COUNT = 10
|
|
1409
1612
|
): Promise<Call[]> {
|
|
1410
1613
|
|
|
1411
1614
|
logger.verbose(
|
|
1412
1615
|
`Rebalancing ${this.metadata.name}: ` +
|
|
1413
|
-
`retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}`
|
|
1616
|
+
`retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}, MAX_RETRIES=${MAX_RETRIES}, sameErrorCount=${sameErrorCount.error} (${sameErrorCount.count})`
|
|
1414
1617
|
);
|
|
1415
1618
|
|
|
1619
|
+
if (sameErrorCount.count >= MAX_SAME_ERROR_COUNT) {
|
|
1620
|
+
logger.error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
|
|
1621
|
+
throw new Error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1416
1624
|
const fromAmount = uint256.uint256ToBN(swapInfo.token_from_amount);
|
|
1625
|
+
const fromTokenInfo = await Global.getTokenInfoFromAddr(ContractAddr.from(swapInfo.token_from_address));
|
|
1417
1626
|
logger.verbose(
|
|
1418
1627
|
`Selling ${fromAmount.toString()} of token ${swapInfo.token_from_address}`
|
|
1419
1628
|
);
|
|
@@ -1433,8 +1642,8 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1433
1642
|
);
|
|
1434
1643
|
|
|
1435
1644
|
const newSwapInfo = { ...swapInfo };
|
|
1436
|
-
const currentAmount = Web3Number.fromWei(fromAmount.toString(),
|
|
1437
|
-
logger.verbose(`Current amount: ${currentAmount.toString()}`);
|
|
1645
|
+
const currentAmount = Web3Number.fromWei(fromAmount.toString(), fromTokenInfo.decimals);
|
|
1646
|
+
logger.verbose(`Current amount: ${currentAmount.toString()}, lowerLimit: ${lowerLimit.toString()}, upperLimit: ${upperLimit.toString()}`);
|
|
1438
1647
|
if (
|
|
1439
1648
|
err.message.includes("invalid token0 balance") ||
|
|
1440
1649
|
err.message.includes("invalid token0 amount")
|
|
@@ -1487,11 +1696,43 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1487
1696
|
}
|
|
1488
1697
|
newSwapInfo.token_from_amount = uint256.bnToUint256(nextAmount);
|
|
1489
1698
|
}
|
|
1699
|
+
} else if (err.message.includes("Residual tokens")) {
|
|
1700
|
+
logger.error("Residual tokens");
|
|
1701
|
+
if (sameErrorCount.error == "Residual tokens") {
|
|
1702
|
+
sameErrorCount.count++;
|
|
1703
|
+
} else {
|
|
1704
|
+
sameErrorCount.error = "Residual tokens";
|
|
1705
|
+
sameErrorCount.count = 1;
|
|
1706
|
+
}
|
|
1707
|
+
// dont do anything, just try again.
|
|
1708
|
+
} else if (err.message.includes("Insufficient tokens received")) {
|
|
1709
|
+
logger.error("Insufficient tokens received");
|
|
1710
|
+
if (sameErrorCount.error == "Insufficient tokens received") {
|
|
1711
|
+
sameErrorCount.count++;
|
|
1712
|
+
} else {
|
|
1713
|
+
sameErrorCount.error = "Insufficient tokens received";
|
|
1714
|
+
sameErrorCount.count = 1;
|
|
1715
|
+
}
|
|
1716
|
+
// dont do anything, just try again.
|
|
1717
|
+
} else if (err.message.includes("Could not reach the end of the program")) {
|
|
1718
|
+
logger.error("Could not reach the end of the program, may be the block is full (could be a temp/permanent gas issue)");
|
|
1719
|
+
if (sameErrorCount.error == "Could not reach the end of the program") {
|
|
1720
|
+
sameErrorCount.count++;
|
|
1721
|
+
} else {
|
|
1722
|
+
sameErrorCount.error = "Could not reach the end of the program";
|
|
1723
|
+
sameErrorCount.count = 1;
|
|
1724
|
+
}
|
|
1725
|
+
// just try again.
|
|
1490
1726
|
} else {
|
|
1491
1727
|
logger.error("Unexpected error:", err);
|
|
1492
1728
|
throw err;
|
|
1493
1729
|
}
|
|
1494
1730
|
newSwapInfo.token_to_min_amount = uint256.bnToUint256("0");
|
|
1731
|
+
|
|
1732
|
+
// if (uint256.uint256ToBN(newSwapInfo.token_from_amount) == fromAmount && sameErrorCount.error == 'loop-stuck') {
|
|
1733
|
+
// logger.error("Swap amount did not change, cannot proceed");
|
|
1734
|
+
// sameErrorCount = { count: MAX_SAME_ERROR_COUNT, error: null };
|
|
1735
|
+
// }
|
|
1495
1736
|
return this.rebalanceIter(
|
|
1496
1737
|
newSwapInfo,
|
|
1497
1738
|
acc,
|
|
@@ -1499,7 +1740,10 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1499
1740
|
isSellTokenToken0,
|
|
1500
1741
|
retry + 1,
|
|
1501
1742
|
lowerLimit,
|
|
1502
|
-
upperLimit
|
|
1743
|
+
upperLimit,
|
|
1744
|
+
MAX_RETRIES,
|
|
1745
|
+
sameErrorCount,
|
|
1746
|
+
MAX_SAME_ERROR_COUNT
|
|
1503
1747
|
);
|
|
1504
1748
|
}
|
|
1505
1749
|
}
|
|
@@ -1592,20 +1836,34 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1592
1836
|
};
|
|
1593
1837
|
}
|
|
1594
1838
|
|
|
1595
|
-
async
|
|
1839
|
+
async getPendingRewards(): Promise<HarvestInfo[]> {
|
|
1596
1840
|
const ekuboHarvests = new EkuboHarvests(this.config);
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1841
|
+
return await ekuboHarvests.getUnHarvestedRewards(this.address);
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
async harvest(acc: Account, maxIterations = 20, priceRatioPrecision = 4, minRewardAmount: Web3Number = new Web3Number(0, 18)): Promise<Call[]> {
|
|
1845
|
+
const _pendingRewards = await this.getPendingRewards();
|
|
1846
|
+
const pendingRewards = _pendingRewards.filter(claim => claim.actualReward.greaterThanOrEqualTo(minRewardAmount));
|
|
1847
|
+
if (pendingRewards.length == 0) {
|
|
1848
|
+
logger.verbose(`${EkuboCLVault.name}: harvest => no pending rewards found`);
|
|
1849
|
+
return [];
|
|
1850
|
+
}
|
|
1851
|
+
// get necessary info for the harvest
|
|
1600
1852
|
const poolKey = await this.getPoolKey();
|
|
1601
1853
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
1602
1854
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
1603
1855
|
const bounds = await this.getCurrentBounds();
|
|
1604
1856
|
logger.verbose(
|
|
1605
|
-
`${EkuboCLVault.name}: harvest => unClaimedRewards: ${
|
|
1857
|
+
`${EkuboCLVault.name}: harvest => unClaimedRewards: ${pendingRewards.length}`
|
|
1606
1858
|
);
|
|
1859
|
+
|
|
1860
|
+
// execute the harvest
|
|
1607
1861
|
const calls: Call[] = [];
|
|
1608
|
-
|
|
1862
|
+
// do one at a time.
|
|
1863
|
+
const chosenClaim = pendingRewards[0];
|
|
1864
|
+
logger.info(`${EkuboCLVault.name}: harvest => doing one at a time`);
|
|
1865
|
+
logger.info(`${EkuboCLVault.name}: harvest => chosenClaim -> Claim ID: ${chosenClaim.claim.id}, Amount: ${chosenClaim.claim.amount.toString()}, actualAmount: ${chosenClaim.actualReward.toString()}, addr: ${chosenClaim.claim.claimee.toString()}`);
|
|
1866
|
+
for (let claim of [chosenClaim]) {
|
|
1609
1867
|
const fee = claim.claim.amount
|
|
1610
1868
|
.multipliedBy(this.metadata.additionalInfo.feeBps)
|
|
1611
1869
|
.dividedBy(10000);
|
|
@@ -1653,8 +1911,8 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1653
1911
|
|
|
1654
1912
|
/**
|
|
1655
1913
|
* @description This funciton requires atleast one of the pool tokens to be reward token
|
|
1656
|
-
* i.e. STRK.
|
|
1657
|
-
* @param params
|
|
1914
|
+
* i.e. STRK.
|
|
1915
|
+
* @param params
|
|
1658
1916
|
*/
|
|
1659
1917
|
async _handleRewardAndVaultTokenMatchHarvest(params: {
|
|
1660
1918
|
claim: HarvestInfo;
|
|
@@ -1678,60 +1936,50 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1678
1936
|
logger.verbose(
|
|
1679
1937
|
`${
|
|
1680
1938
|
EkuboCLVault.name
|
|
1681
|
-
}: harvest => token0Amt: ${token0Amt.
|
|
1682
|
-
);
|
|
1683
|
-
|
|
1684
|
-
// THis function cannot handle swapping of non-STRK pool,
|
|
1685
|
-
// bcz atleast one of token0Amt or token1Amt are in STRK terms.
|
|
1686
|
-
const swapInfo = await this.getSwapInfoGivenAmounts(
|
|
1687
|
-
poolKey,
|
|
1688
|
-
token0Amt,
|
|
1689
|
-
token1Amt,
|
|
1690
|
-
bounds,
|
|
1691
|
-
maxIterations,
|
|
1692
|
-
priceRatioPrecision
|
|
1693
|
-
);
|
|
1694
|
-
swapInfo.token_to_address = token0Info.address.address;
|
|
1695
|
-
logger.verbose(
|
|
1696
|
-
`${EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
|
|
1939
|
+
}: harvest => token0Amt: ${token0Amt.toFixed(18)}, token1Amt: ${token1Amt.toFixed(18)}`
|
|
1697
1940
|
);
|
|
1698
1941
|
|
|
1699
1942
|
logger.verbose(
|
|
1700
1943
|
`${EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
|
|
1701
1944
|
);
|
|
1702
|
-
const
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1945
|
+
const claimTokenInfo = await Global.getTokenInfoFromAddr(claim.token);
|
|
1946
|
+
const harvestEstimateCall = async (baseSwapInfo: SwapInfo) => {
|
|
1947
|
+
// - the base swap if actual swap from claim token to non-claim token
|
|
1948
|
+
// - the other swap is just claim token to claim token (e.g. STRK to STRK)
|
|
1949
|
+
// which is just dummy
|
|
1950
|
+
let baseSwapAmount = Web3Number.fromWei(
|
|
1951
|
+
uint256.uint256ToBN(baseSwapInfo.token_from_amount).toString(),
|
|
1952
|
+
claimTokenInfo.decimals
|
|
1706
1953
|
).minimum(
|
|
1707
|
-
postFeeAmount.toFixed(
|
|
1954
|
+
postFeeAmount.toFixed(claimTokenInfo.decimals)
|
|
1708
1955
|
); // ensure we don't swap more than we have
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1956
|
+
if (baseSwapAmount.lt(0.0001)) {
|
|
1957
|
+
baseSwapAmount = new Web3Number(0, claimTokenInfo.decimals);
|
|
1958
|
+
}
|
|
1959
|
+
baseSwapInfo.token_from_amount = uint256.bnToUint256(baseSwapAmount.toWei());
|
|
1713
1960
|
|
|
1961
|
+
const isToken0ClaimToken = claim.token.eq(poolKey.token0);
|
|
1714
1962
|
logger.verbose(
|
|
1715
|
-
`${EkuboCLVault.name}: harvest =>
|
|
1963
|
+
`${EkuboCLVault.name}: harvest => isToken0ClaimToken: ${isToken0ClaimToken}, baseSwapAmount: ${baseSwapAmount}`
|
|
1716
1964
|
);
|
|
1717
1965
|
|
|
1718
|
-
const remainingAmount = postFeeAmount.minus(
|
|
1966
|
+
const remainingAmount = postFeeAmount.minus(baseSwapAmount).maximum(0);
|
|
1719
1967
|
logger.verbose(
|
|
1720
1968
|
`${EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
|
|
1721
1969
|
);
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1970
|
+
|
|
1971
|
+
// obv, same to same
|
|
1972
|
+
let dummySwapInfo = AvnuWrapper.buildZeroSwap(claim.token, this.address.address, claim.token);
|
|
1973
|
+
dummySwapInfo.token_from_amount = uint256.bnToUint256(remainingAmount.toWei());
|
|
1974
|
+
|
|
1727
1975
|
logger.verbose(
|
|
1728
|
-
`${EkuboCLVault.name}: harvest =>
|
|
1729
|
-
|
|
1976
|
+
`${EkuboCLVault.name}: harvest => dummySwapInfo: ${JSON.stringify(
|
|
1977
|
+
dummySwapInfo
|
|
1730
1978
|
)}`
|
|
1731
1979
|
);
|
|
1732
1980
|
logger.verbose(
|
|
1733
|
-
`${EkuboCLVault.name}: harvest =>
|
|
1734
|
-
|
|
1981
|
+
`${EkuboCLVault.name}: harvest => baseSwapInfo: ${JSON.stringify(
|
|
1982
|
+
baseSwapInfo
|
|
1735
1983
|
)}`
|
|
1736
1984
|
);
|
|
1737
1985
|
const calldata = [
|
|
@@ -1742,18 +1990,41 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1742
1990
|
claimee: claim.claim.claimee.address,
|
|
1743
1991
|
},
|
|
1744
1992
|
claim.proof.map((p) => num.getDecimalString(p)),
|
|
1745
|
-
|
|
1746
|
-
|
|
1993
|
+
isToken0ClaimToken ? dummySwapInfo : baseSwapInfo, // is token0 claim token, its just dummy swap
|
|
1994
|
+
isToken0ClaimToken ? baseSwapInfo : dummySwapInfo,
|
|
1747
1995
|
];
|
|
1748
|
-
logger.verbose(
|
|
1749
|
-
`${EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
|
|
1750
|
-
calldata
|
|
1751
|
-
)}`
|
|
1752
|
-
);
|
|
1753
1996
|
return [this.contract.populate("harvest", calldata)];
|
|
1754
1997
|
};
|
|
1998
|
+
|
|
1999
|
+
// if token0 == claim token, then the base swapInfo is from claim token to token1
|
|
2000
|
+
// if token1 == claim token, then the base swapInfo is from claim token to token0
|
|
2001
|
+
const isToken0ClaimToken = claim.token.eq(poolKey.token0);
|
|
2002
|
+
let baseSwapInfo = AvnuWrapper.buildZeroSwap(claim.token, this.address.address, isToken0ClaimToken ? token1Info.address : token0Info.address);
|
|
2003
|
+
baseSwapInfo.token_from_amount = uint256.bnToUint256(postFeeAmount.toWei()); // we try to swap all to start with
|
|
2004
|
+
|
|
2005
|
+
// if token0 != claim token, then we swap from claim token to token0
|
|
2006
|
+
if (postFeeAmount.greaterThan(0) && !isToken0ClaimToken) {
|
|
2007
|
+
const avnuWrapper = new AvnuWrapper();
|
|
2008
|
+
const quote = await avnuWrapper.getQuotes(
|
|
2009
|
+
claim.token.address,
|
|
2010
|
+
token0Info.address.address,
|
|
2011
|
+
postFeeAmount.toWei(),
|
|
2012
|
+
this.address.address
|
|
2013
|
+
);
|
|
2014
|
+
baseSwapInfo = await avnuWrapper.getSwapInfo(quote, this.address.address, 0, this.address.address);
|
|
2015
|
+
} else if (postFeeAmount.greaterThan(0) && isToken0ClaimToken) {
|
|
2016
|
+
// if token0 == claim token, then we swap from claim token to token1
|
|
2017
|
+
const avnuWrapper = new AvnuWrapper();
|
|
2018
|
+
const quote = await avnuWrapper.getQuotes(
|
|
2019
|
+
claim.token.address,
|
|
2020
|
+
token1Info.address.address,
|
|
2021
|
+
postFeeAmount.toWei(),
|
|
2022
|
+
this.address.address
|
|
2023
|
+
);
|
|
2024
|
+
baseSwapInfo = await avnuWrapper.getSwapInfo(quote, this.address.address, 0, this.address.address);
|
|
2025
|
+
}
|
|
1755
2026
|
const _callsFinal = await this.rebalanceIter(
|
|
1756
|
-
|
|
2027
|
+
baseSwapInfo,
|
|
1757
2028
|
acc,
|
|
1758
2029
|
harvestEstimateCall,
|
|
1759
2030
|
claim.token.eq(poolKey.token0),
|
|
@@ -1772,9 +2043,9 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1772
2043
|
|
|
1773
2044
|
/**
|
|
1774
2045
|
* @description This function handles harvesting of reward token that is not the same as any of the vault token
|
|
1775
|
-
* i.e. STRK is not part of vault tokens like BTC/ETH
|
|
1776
|
-
* @param params
|
|
1777
|
-
* @returns
|
|
2046
|
+
* i.e. STRK is not part of vault tokens like BTC/ETH
|
|
2047
|
+
* @param params
|
|
2048
|
+
* @returns
|
|
1778
2049
|
*/
|
|
1779
2050
|
async _handleRewardAndVaultTokenMismatchHarvest(params: {
|
|
1780
2051
|
claim: HarvestInfo;
|
|
@@ -1812,7 +2083,7 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1812
2083
|
return [harvestCall];
|
|
1813
2084
|
}
|
|
1814
2085
|
|
|
1815
|
-
// given an amount (i.e. portion of reward to use to swap to token0), returns info on increasing or decreasing
|
|
2086
|
+
// given an amount (i.e. portion of reward to use to swap to token0), returns info on increasing or decreasing
|
|
1816
2087
|
// amount for binary search
|
|
1817
2088
|
async harvestMismatchEstimateCallFn(params: {
|
|
1818
2089
|
postFeeAmount: Web3Number;
|
|
@@ -1823,39 +2094,47 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1823
2094
|
}) {
|
|
1824
2095
|
const { postFeeAmount, claim, token0Info, token1Info, acc } = params;
|
|
1825
2096
|
let harvestCall: Call | null = null;
|
|
2097
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => postFeeAmount: ${postFeeAmount.toString()}`);
|
|
1826
2098
|
|
|
2099
|
+
let attempt = 0;
|
|
2100
|
+
let MAX_ATTEMPTS = 50;
|
|
1827
2101
|
const binarySearchCallbackFn = async (mid: bigint) => {
|
|
2102
|
+
attempt++;
|
|
2103
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => mid: ${mid}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
|
|
1828
2104
|
const rewardPart2 = BigInt(postFeeAmount.toWei()) - mid;
|
|
1829
2105
|
const avnuWrapper = new AvnuWrapper();
|
|
1830
2106
|
const beneficiary = this.address.address;
|
|
1831
2107
|
|
|
1832
2108
|
// get quote for 1st part
|
|
1833
|
-
const
|
|
2109
|
+
const quote1Prom = avnuWrapper.getQuotes(
|
|
1834
2110
|
claim.token.address,
|
|
1835
2111
|
token0Info.address.address,
|
|
1836
2112
|
mid.toString(),
|
|
1837
2113
|
beneficiary
|
|
1838
2114
|
);
|
|
2115
|
+
const quote2Prom = avnuWrapper.getQuotes(
|
|
2116
|
+
claim.token.address,
|
|
2117
|
+
token1Info.address.address,
|
|
2118
|
+
rewardPart2.toString(),
|
|
2119
|
+
beneficiary
|
|
2120
|
+
);
|
|
2121
|
+
const [quote1, quote2] = await Promise.all([quote1Prom, quote2Prom]);
|
|
2122
|
+
|
|
1839
2123
|
// default min amount is ok
|
|
1840
2124
|
const swapInfo1 = await avnuWrapper.getSwapInfo(
|
|
1841
2125
|
quote1,
|
|
1842
2126
|
beneficiary,
|
|
1843
|
-
0,
|
|
2127
|
+
0, // fee bps
|
|
1844
2128
|
beneficiary
|
|
1845
2129
|
);
|
|
1846
2130
|
|
|
1847
2131
|
// get quote for 2nd part
|
|
1848
|
-
|
|
1849
|
-
claim.token.address,
|
|
1850
|
-
token1Info.address.address,
|
|
1851
|
-
rewardPart2.toString(),
|
|
1852
|
-
beneficiary
|
|
1853
|
-
);
|
|
2132
|
+
|
|
1854
2133
|
// default min amount is ok
|
|
1855
2134
|
const swapInfo2 = await avnuWrapper.getSwapInfo(
|
|
1856
2135
|
quote2,
|
|
1857
2136
|
beneficiary,
|
|
1858
|
-
0,
|
|
2137
|
+
0, // fee bps
|
|
1859
2138
|
beneficiary
|
|
1860
2139
|
);
|
|
1861
2140
|
|
|
@@ -1874,27 +2153,36 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1874
2153
|
];
|
|
1875
2154
|
harvestCall = this.contract.populate("harvest", calldata)
|
|
1876
2155
|
const gas = await acc.estimateInvokeFee(harvestCall);
|
|
2156
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => gas: ${gas.overall_fee.toString()}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
|
|
1877
2157
|
return 'found';
|
|
1878
2158
|
} catch (err: any) {
|
|
1879
2159
|
if (err.message.includes('invalid token0 amount')) {
|
|
2160
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => invalid token0 amount, attempt: ${attempt}/${MAX_ATTEMPTS}`);
|
|
1880
2161
|
// too much token0 amount left, may be swap less to token0
|
|
1881
2162
|
return 'go_low';
|
|
1882
2163
|
} else if (err.message.includes('invalid token1 amount')) {
|
|
2164
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => invalid token1 amount, attempt: ${attempt}/${MAX_ATTEMPTS}`);
|
|
1883
2165
|
// too much token1 balance left, may be swap more to token0
|
|
1884
2166
|
return 'go_high';
|
|
1885
2167
|
}
|
|
2168
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => error: ${err.message}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
|
|
1886
2169
|
return 'retry';
|
|
1887
2170
|
}
|
|
1888
2171
|
}
|
|
1889
2172
|
|
|
1890
2173
|
// run the binary search
|
|
1891
2174
|
await binarySearch(0n, BigInt(postFeeAmount.toWei()), binarySearchCallbackFn);
|
|
1892
|
-
|
|
2175
|
+
|
|
1893
2176
|
return harvestCall;
|
|
1894
2177
|
}
|
|
1895
2178
|
|
|
1896
2179
|
async getInvestmentFlows() {
|
|
1897
|
-
|
|
2180
|
+
// for LSTs, we use 30d, else 7d for the yield calculation
|
|
2181
|
+
// TODO Make the block compute more dynamic
|
|
2182
|
+
const blocksDiff = this.metadata.additionalInfo.lstContract
|
|
2183
|
+
? 600000
|
|
2184
|
+
: 600000 / 4;
|
|
2185
|
+
const netYield = await this.netAPY("latest", blocksDiff, "7d" as any);
|
|
1898
2186
|
const poolKey = await this.getPoolKey();
|
|
1899
2187
|
|
|
1900
2188
|
const linkedFlow: IInvestmentFlow = {
|
|
@@ -1915,7 +2203,7 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1915
2203
|
id: "base",
|
|
1916
2204
|
title: "Your Deposit",
|
|
1917
2205
|
subItems: [
|
|
1918
|
-
{ key: `Net yield`, value: `${(netYield
|
|
2206
|
+
{ key: `Net yield`, value: `${(netYield * 100).toFixed(2)}%` },
|
|
1919
2207
|
{
|
|
1920
2208
|
key: `Performance Fee`,
|
|
1921
2209
|
value: `${(this.metadata.additionalInfo.feeBps / 100).toFixed(2)}%`,
|
|
@@ -1931,8 +2219,8 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1931
2219
|
subItems: [
|
|
1932
2220
|
{
|
|
1933
2221
|
key: "Range selection",
|
|
1934
|
-
value: (typeof this.metadata.additionalInfo.newBounds == 'string') ?
|
|
1935
|
-
this.metadata.additionalInfo.newBounds :
|
|
2222
|
+
value: (typeof this.metadata.additionalInfo.newBounds == 'string') ?
|
|
2223
|
+
this.metadata.additionalInfo.newBounds :
|
|
1936
2224
|
`${
|
|
1937
2225
|
this.metadata.additionalInfo.newBounds.lower *
|
|
1938
2226
|
Number(poolKey.tick_spacing)
|
|
@@ -2053,7 +2341,11 @@ function getLSTFAQs(lstSymbol: string): FAQ[] {
|
|
|
2053
2341
|
]
|
|
2054
2342
|
}
|
|
2055
2343
|
|
|
2344
|
+
const vaultTypeDescription = 'Automatically collects fees and rebalances positions on Ekubo to optimize yield';
|
|
2345
|
+
const vaultType = VaultType.AUTOMATED_LP;
|
|
2346
|
+
|
|
2056
2347
|
const xSTRKSTRK: IStrategyMetadata<CLVaultStrategySettings> = {
|
|
2348
|
+
id: "ekubo_cl_xstrkstrk",
|
|
2057
2349
|
name: "Ekubo xSTRK/STRK",
|
|
2058
2350
|
description: <></>,
|
|
2059
2351
|
address: ContractAddr.from(
|
|
@@ -2061,6 +2353,10 @@ const xSTRKSTRK: IStrategyMetadata<CLVaultStrategySettings> = {
|
|
|
2061
2353
|
),
|
|
2062
2354
|
launchBlock: 1209881,
|
|
2063
2355
|
type: "Other",
|
|
2356
|
+
vaultType: {
|
|
2357
|
+
type: vaultType,
|
|
2358
|
+
description: vaultTypeDescription
|
|
2359
|
+
},
|
|
2064
2360
|
// must be same order as poolKey token0 and token1
|
|
2065
2361
|
depositTokens: [
|
|
2066
2362
|
Global.getDefaultTokens().find((t) => t.symbol === "xSTRK")!,
|
|
@@ -2068,7 +2364,10 @@ const xSTRKSTRK: IStrategyMetadata<CLVaultStrategySettings> = {
|
|
|
2068
2364
|
],
|
|
2069
2365
|
protocols: [_protocol],
|
|
2070
2366
|
auditUrl: AUDIT_URL,
|
|
2071
|
-
|
|
2367
|
+
curator: {
|
|
2368
|
+
name: "Unwrap Labs",
|
|
2369
|
+
logo: "https://assets.troves.fi/integrations/unwraplabs/white.png"
|
|
2370
|
+
},
|
|
2072
2371
|
risk: {
|
|
2073
2372
|
riskFactor: _lstPoolRiskFactors,
|
|
2074
2373
|
netRisk:
|
|
@@ -2078,6 +2377,7 @@ const xSTRKSTRK: IStrategyMetadata<CLVaultStrategySettings> = {
|
|
|
2078
2377
|
},
|
|
2079
2378
|
apyMethodology:
|
|
2080
2379
|
"APY based on 30-day historical performance, including fees and rewards.",
|
|
2380
|
+
realizedAPYMethodology: "The realizedAPY is based on past 14 days performance by the vault",
|
|
2081
2381
|
additionalInfo: {
|
|
2082
2382
|
newBounds: {
|
|
2083
2383
|
lower: -1,
|
|
@@ -2094,270 +2394,529 @@ const xSTRKSTRK: IStrategyMetadata<CLVaultStrategySettings> = {
|
|
|
2094
2394
|
},
|
|
2095
2395
|
quoteAsset: Global.getDefaultTokens().find((t) => t.symbol === "STRK")!,
|
|
2096
2396
|
},
|
|
2397
|
+
settings: {
|
|
2398
|
+
maxTVL: Web3Number.fromWei("0", 18),
|
|
2399
|
+
isAudited: true,
|
|
2400
|
+
isPaused: false,
|
|
2401
|
+
liveStatus: StrategyLiveStatus.ACTIVE,
|
|
2402
|
+
isInstantWithdrawal: true,
|
|
2403
|
+
hideNetEarnings: true,
|
|
2404
|
+
isTransactionHistDisabled: true,
|
|
2405
|
+
quoteToken: Global.getDefaultTokens().find((t) => t.symbol === "STRK")!,
|
|
2406
|
+
alerts: [
|
|
2407
|
+
{
|
|
2408
|
+
type: "info",
|
|
2409
|
+
text: (
|
|
2410
|
+
<p>
|
|
2411
|
+
Depending on the current position range and price, your
|
|
2412
|
+
input amounts are automatically adjusted to nearest
|
|
2413
|
+
required amounts. If you have insufficient tokens, you
|
|
2414
|
+
can acquire the required tokens on{" "}
|
|
2415
|
+
<a
|
|
2416
|
+
href="https://avnu.fi"
|
|
2417
|
+
target="_blank"
|
|
2418
|
+
rel="noopener noreferrer"
|
|
2419
|
+
>
|
|
2420
|
+
Avnu
|
|
2421
|
+
</a>
|
|
2422
|
+
</p>
|
|
2423
|
+
),
|
|
2424
|
+
tab: "deposit"
|
|
2425
|
+
},
|
|
2426
|
+
{
|
|
2427
|
+
type: "info",
|
|
2428
|
+
text: (
|
|
2429
|
+
<>
|
|
2430
|
+
Depending on the current position range and price, you
|
|
2431
|
+
may receive both of the tokens or one of the tokens
|
|
2432
|
+
depending on the price
|
|
2433
|
+
</>
|
|
2434
|
+
),
|
|
2435
|
+
tab: "withdraw"
|
|
2436
|
+
}
|
|
2437
|
+
],
|
|
2438
|
+
tags: [StrategyTag.AUTOMATED_LP]
|
|
2439
|
+
},
|
|
2097
2440
|
faqs: getLSTFAQs("xSTRK"),
|
|
2098
2441
|
points: [{
|
|
2099
|
-
multiplier:
|
|
2442
|
+
multiplier: 15,
|
|
2100
2443
|
logo: 'https://endur.fi/favicon.ico',
|
|
2101
2444
|
toolTip: "This strategy holds xSTRK and STRK tokens. Earn 1x Endur points on your xSTRK portion of Liquidity. STRK portion will earn Endur's DEX Bonus points. Points can be found on endur.fi.",
|
|
2102
2445
|
}],
|
|
2103
2446
|
contractDetails: [],
|
|
2104
|
-
investmentSteps: []
|
|
2447
|
+
investmentSteps: [],
|
|
2448
|
+
tags: [StrategyTag.AUTOMATED_LP],
|
|
2449
|
+
security: {
|
|
2450
|
+
auditStatus: AuditStatus.AUDITED,
|
|
2451
|
+
sourceCode: {
|
|
2452
|
+
type: SourceCodeType.OPEN_SOURCE,
|
|
2453
|
+
contractLink: "https://github.com/trovesfi/troves-contracts",
|
|
2454
|
+
},
|
|
2455
|
+
accessControl: {
|
|
2456
|
+
type: AccessControlType.STANDARD_ACCOUNT,
|
|
2457
|
+
addresses: [ContractAddr.from("0x0")],
|
|
2458
|
+
timeLock: "2 Days",
|
|
2459
|
+
},
|
|
2460
|
+
},
|
|
2461
|
+
redemptionInfo: {
|
|
2462
|
+
instantWithdrawalVault: InstantWithdrawalVault.YES,
|
|
2463
|
+
redemptionsInfo: [],
|
|
2464
|
+
alerts: [],
|
|
2465
|
+
},
|
|
2466
|
+
usualTimeToEarnings: null,
|
|
2467
|
+
usualTimeToEarningsDescription: null,
|
|
2105
2468
|
};
|
|
2106
2469
|
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
quoteAsset: Global.getDefaultTokens().find((t) => t.symbol === "WBTC")!,
|
|
2125
|
-
lstContract: Global.getDefaultTokens().find((t) => t.symbol === "xWBTC")!.address,
|
|
2470
|
+
// Helper to create common LST alerts
|
|
2471
|
+
const getLSTAlerts = () => [
|
|
2472
|
+
{
|
|
2473
|
+
tab: "deposit" as const,
|
|
2474
|
+
text: (
|
|
2475
|
+
<>
|
|
2476
|
+
To acquire the LST, please visit{" "}
|
|
2477
|
+
<a
|
|
2478
|
+
href="https://app.endur.fi"
|
|
2479
|
+
target="_blank"
|
|
2480
|
+
rel="noopener noreferrer"
|
|
2481
|
+
>
|
|
2482
|
+
endur.fi
|
|
2483
|
+
</a>
|
|
2484
|
+
</>
|
|
2485
|
+
),
|
|
2486
|
+
type: "info" as const
|
|
2126
2487
|
},
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
additionalInfo: {
|
|
2146
|
-
...xSTRKSTRK.additionalInfo,
|
|
2147
|
-
quoteAsset: Global.getDefaultTokens().find((t) => t.symbol === "tBTC")!,
|
|
2148
|
-
lstContract: Global.getDefaultTokens().find((t) => t.symbol === "xtBTC")!.address,
|
|
2488
|
+
{
|
|
2489
|
+
type: "info" as const,
|
|
2490
|
+
text: (
|
|
2491
|
+
<p>
|
|
2492
|
+
Depending on the current position range and price, your input
|
|
2493
|
+
amounts are automatically adjusted to nearest required amounts.
|
|
2494
|
+
If you have insufficient tokens, you can acquire the required
|
|
2495
|
+
tokens on{" "}
|
|
2496
|
+
<a
|
|
2497
|
+
href="https://avnu.fi"
|
|
2498
|
+
target="_blank"
|
|
2499
|
+
rel="noopener noreferrer"
|
|
2500
|
+
>
|
|
2501
|
+
Avnu
|
|
2502
|
+
</a>
|
|
2503
|
+
</p>
|
|
2504
|
+
),
|
|
2505
|
+
tab: "deposit" as const
|
|
2149
2506
|
},
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2507
|
+
{
|
|
2508
|
+
type: "info" as const,
|
|
2509
|
+
text: (
|
|
2510
|
+
<>
|
|
2511
|
+
Depending on the current position range and price, you may
|
|
2512
|
+
receive both of the tokens or one of the tokens depending on the
|
|
2513
|
+
price
|
|
2514
|
+
</>
|
|
2515
|
+
),
|
|
2516
|
+
tab: "withdraw" as const
|
|
2517
|
+
}
|
|
2518
|
+
];
|
|
2519
|
+
|
|
2520
|
+
// Helper to create LST strategy settings
|
|
2521
|
+
const createLSTSettings = (quoteTokenSymbol: string) => ({
|
|
2522
|
+
...xSTRKSTRK.settings,
|
|
2523
|
+
isAudited: true,
|
|
2524
|
+
liveStatus: StrategyLiveStatus.ACTIVE,
|
|
2525
|
+
isInstantWithdrawal: true,
|
|
2526
|
+
hideNetEarnings: true,
|
|
2527
|
+
isTransactionHistDisabled: true,
|
|
2528
|
+
quoteToken: Global.getDefaultTokens().find(
|
|
2529
|
+
(t) => t.symbol === quoteTokenSymbol
|
|
2530
|
+
)!,
|
|
2531
|
+
alerts: getLSTAlerts(),
|
|
2532
|
+
tags: [StrategyTag.AUTOMATED_LP] as StrategyTag[],
|
|
2533
|
+
});
|
|
2534
|
+
|
|
2535
|
+
// Helper to create an LST strategy
|
|
2536
|
+
const createLSTStrategy = (params: {
|
|
2537
|
+
id: string;
|
|
2538
|
+
name: string;
|
|
2539
|
+
address: string;
|
|
2540
|
+
launchBlock: number;
|
|
2541
|
+
depositToken0Symbol: string;
|
|
2542
|
+
depositToken1Symbol: string;
|
|
2543
|
+
quoteTokenSymbol: string;
|
|
2544
|
+
lstSymbol: string;
|
|
2545
|
+
lstContractAddress?: string;
|
|
2546
|
+
}): IStrategyMetadata<CLVaultStrategySettings> => ({
|
|
2156
2547
|
...xSTRKSTRK,
|
|
2157
|
-
|
|
2548
|
+
id: params.id,
|
|
2549
|
+
name: params.name,
|
|
2158
2550
|
description: <></>,
|
|
2159
|
-
address: ContractAddr.from(
|
|
2160
|
-
"0x3af1c7faa7c464cf2c494e988972ad1939f1103dbfb6e47e9bf0c47e49b14ef"
|
|
2161
|
-
),
|
|
2162
|
-
launchBlock: 2344809,
|
|
2163
2551
|
// must be same order as poolKey token0 and token1
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
...xSTRKSTRK.additionalInfo,
|
|
2170
|
-
quoteAsset: Global.getDefaultTokens().find((t) => t.symbol === "solvBTC")!,
|
|
2171
|
-
lstContract: Global.getDefaultTokens().find((t) => t.symbol === "xsBTC")!.address,
|
|
2552
|
+
address: ContractAddr.from(params.address),
|
|
2553
|
+
launchBlock: params.launchBlock,
|
|
2554
|
+
vaultType: {
|
|
2555
|
+
type: vaultType,
|
|
2556
|
+
description: vaultTypeDescription
|
|
2172
2557
|
},
|
|
2173
|
-
faqs: getLSTFAQs("xsBTC"),
|
|
2174
|
-
points: [],
|
|
2175
|
-
contractDetails: [],
|
|
2176
|
-
investmentSteps: []
|
|
2177
|
-
},
|
|
2178
|
-
{
|
|
2179
|
-
...xSTRKSTRK,
|
|
2180
|
-
name: "Ekubo xLBTC/LBTC",
|
|
2181
|
-
description: <></>,
|
|
2182
|
-
address: ContractAddr.from(
|
|
2183
|
-
"0x314c4653ab1aa01f5465773cb879f525d7e369a137bc3ae084761aee99a1712"
|
|
2184
|
-
),
|
|
2185
|
-
launchBlock: 2412442,
|
|
2186
|
-
// must be same order as poolKey token0 and token1
|
|
2187
2558
|
depositTokens: [
|
|
2188
|
-
|
|
2189
|
-
|
|
2559
|
+
Global.getDefaultTokens().find(
|
|
2560
|
+
(t) => t.symbol === params.depositToken0Symbol
|
|
2561
|
+
)!,
|
|
2562
|
+
Global.getDefaultTokens().find((t) => t.symbol === params.depositToken1Symbol)!
|
|
2190
2563
|
],
|
|
2564
|
+
realizedAPYMethodology: "The realizedAPY is based on past 14 days performance by the vault",
|
|
2191
2565
|
additionalInfo: {
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2566
|
+
...xSTRKSTRK.additionalInfo,
|
|
2567
|
+
quoteAsset: Global.getDefaultTokens().find(
|
|
2568
|
+
(t) => t.symbol === params.quoteTokenSymbol
|
|
2569
|
+
)!,
|
|
2570
|
+
lstContract: params.lstContractAddress
|
|
2571
|
+
? ContractAddr.from(params.lstContractAddress)
|
|
2572
|
+
: Global.getDefaultTokens().find((t) => t.symbol === params.lstSymbol)!
|
|
2573
|
+
.address
|
|
2195
2574
|
},
|
|
2196
|
-
|
|
2575
|
+
settings: createLSTSettings(params.quoteTokenSymbol),
|
|
2576
|
+
faqs: getLSTFAQs(params.lstSymbol),
|
|
2197
2577
|
points: [],
|
|
2198
2578
|
contractDetails: [],
|
|
2199
|
-
investmentSteps: []
|
|
2200
|
-
|
|
2579
|
+
investmentSteps: [],
|
|
2580
|
+
tags: params.id.toLowerCase().includes('btc') ? [StrategyTag.BTC, StrategyTag.AUTOMATED_LP] : [StrategyTag.AUTOMATED_LP]
|
|
2581
|
+
});
|
|
2582
|
+
|
|
2583
|
+
const lstStrategies: IStrategyMetadata<CLVaultStrategySettings>[] = [
|
|
2584
|
+
xSTRKSTRK,
|
|
2585
|
+
createLSTStrategy({
|
|
2586
|
+
id: "ekubo_cl_xwbtcwbtc",
|
|
2587
|
+
name: "Ekubo xWBTC/WBTC",
|
|
2588
|
+
address: "0x2ea99b4971d3c277fa4a9b4beb7d4d7d169e683393a29eef263d5d57b4380a",
|
|
2589
|
+
launchBlock: 2338309,
|
|
2590
|
+
depositToken0Symbol: "WBTC",
|
|
2591
|
+
depositToken1Symbol: "xWBTC",
|
|
2592
|
+
quoteTokenSymbol: "WBTC",
|
|
2593
|
+
lstSymbol: "xWBTC",
|
|
2594
|
+
}),
|
|
2595
|
+
createLSTStrategy({
|
|
2596
|
+
id: "ekubo_cl_xtbtctbtc",
|
|
2597
|
+
name: "Ekubo xtBTC/tBTC",
|
|
2598
|
+
address: "0x785dc3dfc4e80ef2690a99512481e3ed3a5266180adda5a47e856245d68a4af",
|
|
2599
|
+
launchBlock: 2415667,
|
|
2600
|
+
depositToken0Symbol: "xtBTC",
|
|
2601
|
+
depositToken1Symbol: "tBTC",
|
|
2602
|
+
quoteTokenSymbol: "tBTC",
|
|
2603
|
+
lstSymbol: "xtBTC",
|
|
2604
|
+
}),
|
|
2605
|
+
createLSTStrategy({
|
|
2606
|
+
id: "ekubo_cl_xsbtcsolvbtc",
|
|
2607
|
+
name: "Ekubo xsBTC/solvBTC",
|
|
2608
|
+
address: "0x3af1c7faa7c464cf2c494e988972ad1939f1103dbfb6e47e9bf0c47e49b14ef",
|
|
2609
|
+
launchBlock: 2344809,
|
|
2610
|
+
depositToken0Symbol: "xsBTC",
|
|
2611
|
+
depositToken1Symbol: "solvBTC",
|
|
2612
|
+
quoteTokenSymbol: "solvBTC",
|
|
2613
|
+
lstSymbol: "xsBTC",
|
|
2614
|
+
}),
|
|
2615
|
+
createLSTStrategy({
|
|
2616
|
+
id: "ekubo_cl_xlbtclbtc",
|
|
2617
|
+
name: "Ekubo xLBTC/LBTC",
|
|
2618
|
+
address: "0x314c4653ab1aa01f5465773cb879f525d7e369a137bc3ae084761aee99a1712",
|
|
2619
|
+
launchBlock: 2412442,
|
|
2620
|
+
depositToken0Symbol: "LBTC",
|
|
2621
|
+
depositToken1Symbol: "xLBTC",
|
|
2622
|
+
quoteTokenSymbol: "LBTC",
|
|
2623
|
+
lstSymbol: "xLBTC",
|
|
2624
|
+
})
|
|
2201
2625
|
];
|
|
2202
2626
|
|
|
2203
|
-
const
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
rebalanceConditions: {
|
|
2223
|
-
customShouldRebalance: async (currentPrice: number) =>
|
|
2224
|
-
currentPrice > 0.99 && currentPrice < 1.01,
|
|
2225
|
-
minWaitHours: 6,
|
|
2226
|
-
direction: "any"
|
|
2627
|
+
const getRe7Alerts = () => [
|
|
2628
|
+
{
|
|
2629
|
+
type: "info" as const,
|
|
2630
|
+
text: (
|
|
2631
|
+
<p>
|
|
2632
|
+
Depending on the current position range and price, your input
|
|
2633
|
+
amounts are automatically adjusted to nearest required amounts.
|
|
2634
|
+
If you have insufficient tokens, you can acquire the required
|
|
2635
|
+
tokens on{" "}
|
|
2636
|
+
<a
|
|
2637
|
+
href="https://avnu.fi"
|
|
2638
|
+
target="_blank"
|
|
2639
|
+
rel="noopener noreferrer"
|
|
2640
|
+
>
|
|
2641
|
+
Avnu
|
|
2642
|
+
</a>
|
|
2643
|
+
</p>
|
|
2644
|
+
),
|
|
2645
|
+
tab: "deposit" as const
|
|
2227
2646
|
},
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2647
|
+
{
|
|
2648
|
+
type: "info" as const,
|
|
2649
|
+
text: (
|
|
2650
|
+
<>
|
|
2651
|
+
Depending on the current position range and price, you may
|
|
2652
|
+
receive both of the tokens or one of the tokens depending on the
|
|
2653
|
+
price
|
|
2654
|
+
</>
|
|
2655
|
+
),
|
|
2656
|
+
tab: "withdraw" as const
|
|
2657
|
+
}
|
|
2658
|
+
];
|
|
2659
|
+
|
|
2660
|
+
// Helper to create Re7 strategy settings
|
|
2661
|
+
const createRe7Settings = (quoteTokenSymbol: string, isBTC: boolean, isDeprecated: boolean) => ({
|
|
2662
|
+
...xSTRKSTRK.settings,
|
|
2663
|
+
isAudited: true,
|
|
2664
|
+
liveStatus: isDeprecated ? StrategyLiveStatus.DEPRECATED : StrategyLiveStatus.ACTIVE,
|
|
2665
|
+
isInstantWithdrawal: true,
|
|
2666
|
+
hideNetEarnings: true,
|
|
2667
|
+
isTransactionHistDisabled: false,
|
|
2668
|
+
quoteToken: Global.getDefaultTokens().find(
|
|
2669
|
+
(t) => t.symbol === quoteTokenSymbol
|
|
2670
|
+
)!,
|
|
2671
|
+
alerts: getRe7Alerts(),
|
|
2672
|
+
tags: isBTC ? [StrategyTag.BTC, StrategyTag.AUTOMATED_LP] : [StrategyTag.AUTOMATED_LP] as StrategyTag[],
|
|
2673
|
+
});
|
|
2674
|
+
|
|
2675
|
+
// Helper to create Re7 FAQs
|
|
2676
|
+
const getRe7FAQs = () => [
|
|
2231
2677
|
...faqs,
|
|
2232
2678
|
{
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2679
|
+
question: "Who is the curator of this strategy?",
|
|
2680
|
+
answer: (
|
|
2681
|
+
<div>
|
|
2682
|
+
Re7 Labs is the curator of this strategy. Re7 Labs is a
|
|
2683
|
+
well-known Web3 asset management firm. This strategy is
|
|
2684
|
+
completely managed by them, including ownership of the vault.
|
|
2685
|
+
Troves is developer of the smart contracts and maintains
|
|
2686
|
+
infrastructure to help users access these strategies. You can
|
|
2687
|
+
find more information about them on their website{" "}
|
|
2688
|
+
<a
|
|
2689
|
+
href="https://www.re7labs.xyz"
|
|
2690
|
+
style={{
|
|
2691
|
+
textDecoration: "underline",
|
|
2692
|
+
marginLeft: "2px"
|
|
2693
|
+
}}
|
|
2694
|
+
target="_blank"
|
|
2695
|
+
>
|
|
2696
|
+
here
|
|
2697
|
+
</a>
|
|
2698
|
+
.
|
|
2699
|
+
</div>
|
|
2700
|
+
)
|
|
2236
2701
|
},
|
|
2237
2702
|
{
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2703
|
+
question: "How is the APY calculated?",
|
|
2704
|
+
answer: (
|
|
2705
|
+
<div>
|
|
2706
|
+
It's an annualized fee APY, calculated as fees earned in the
|
|
2707
|
+
last 24h divided by TVL. Factors like impermanent loss are not
|
|
2708
|
+
considered.
|
|
2709
|
+
</div>
|
|
2710
|
+
)
|
|
2711
|
+
}
|
|
2712
|
+
];
|
|
2713
|
+
|
|
2714
|
+
// Helper to create a Re7 strategy
|
|
2715
|
+
const createRe7Strategy = (
|
|
2716
|
+
id: string,
|
|
2717
|
+
name: string,
|
|
2718
|
+
address: string,
|
|
2719
|
+
launchBlock: number,
|
|
2720
|
+
depositToken0Symbol: string,
|
|
2721
|
+
depositToken1Symbol: string,
|
|
2722
|
+
quoteTokenSymbol: string,
|
|
2723
|
+
risk:
|
|
2724
|
+
| typeof highRisk
|
|
2725
|
+
| typeof mediumRisk
|
|
2726
|
+
| { riskFactor: RiskFactor[]; netRisk: number; notARisks: RiskType[] },
|
|
2727
|
+
isBTC: boolean
|
|
2728
|
+
): IStrategyMetadata<CLVaultStrategySettings> => {
|
|
2729
|
+
const isDeprecated = name.toLowerCase().includes('usdc.e');
|
|
2730
|
+
return {
|
|
2731
|
+
...xSTRKSTRK,
|
|
2732
|
+
id,
|
|
2733
|
+
name,
|
|
2734
|
+
description: <></>,
|
|
2735
|
+
address: ContractAddr.from(address),
|
|
2736
|
+
launchBlock,
|
|
2737
|
+
vaultType: {
|
|
2738
|
+
type: vaultType,
|
|
2739
|
+
description: vaultTypeDescription
|
|
2740
|
+
},
|
|
2741
|
+
depositTokens: [
|
|
2742
|
+
Global.getDefaultTokens().find(
|
|
2743
|
+
(t) => t.symbol === depositToken0Symbol
|
|
2744
|
+
)!,
|
|
2745
|
+
Global.getDefaultTokens().find((t) => t.symbol === depositToken1Symbol)!
|
|
2746
|
+
],
|
|
2747
|
+
apyMethodology:
|
|
2748
|
+
"Annualized fee APY, calculated as fees earned in the last 7d divided by TVL",
|
|
2749
|
+
additionalInfo: {
|
|
2750
|
+
newBounds: "Managed by Re7",
|
|
2751
|
+
truePrice: 1,
|
|
2752
|
+
feeBps: 1000,
|
|
2753
|
+
rebalanceConditions: {
|
|
2754
|
+
customShouldRebalance: async (currentPrice: number) =>
|
|
2755
|
+
currentPrice > 0.99 && currentPrice < 1.01,
|
|
2756
|
+
minWaitHours: 6,
|
|
2757
|
+
direction: "any" as const
|
|
2758
|
+
},
|
|
2759
|
+
quoteAsset: Global.getDefaultTokens().find(
|
|
2760
|
+
(t) => t.symbol === quoteTokenSymbol
|
|
2761
|
+
)!
|
|
2762
|
+
},
|
|
2763
|
+
settings: createRe7Settings(quoteTokenSymbol, isBTC, isDeprecated),
|
|
2764
|
+
faqs: getRe7FAQs(),
|
|
2765
|
+
risk,
|
|
2766
|
+
points: [],
|
|
2767
|
+
curator: { name: "Re7 Labs", logo: "https://www.re7labs.xyz/favicon.ico" },
|
|
2768
|
+
tags: isBTC ? [StrategyTag.BTC, StrategyTag.AUTOMATED_LP] : [StrategyTag.AUTOMATED_LP] as StrategyTag[],
|
|
2769
|
+
discontinuationInfo: isDeprecated ? {
|
|
2770
|
+
info: "This strategy has been deprecated and is no longer accepting new deposits."
|
|
2771
|
+
} : undefined,
|
|
2772
|
+
};
|
|
2773
|
+
};
|
|
2774
|
+
|
|
2775
|
+
const ETHUSDCRe7Strategy = createRe7Strategy(
|
|
2776
|
+
"ekubo_cl_ethusdc",
|
|
2777
|
+
"Ekubo ETH/USDC.e",
|
|
2778
|
+
"0x160d8fa4569ef6a12e6bf47cb943d7b5ebba8a41a69a14c1d943050ba5ff947",
|
|
2779
|
+
1504232,
|
|
2780
|
+
"ETH",
|
|
2781
|
+
"USDC.e",
|
|
2782
|
+
"USDC.e",
|
|
2783
|
+
highRisk,
|
|
2784
|
+
false // isBTC
|
|
2785
|
+
);
|
|
2786
|
+
|
|
2787
|
+
const stableCoinRisk = {
|
|
2788
|
+
riskFactor: _stableCoinPoolRiskFactors,
|
|
2789
|
+
netRisk:
|
|
2790
|
+
_stableCoinPoolRiskFactors.reduce(
|
|
2791
|
+
(acc, curr) => acc + curr.value * curr.weight,
|
|
2792
|
+
0
|
|
2793
|
+
) /
|
|
2794
|
+
_stableCoinPoolRiskFactors.reduce((acc, curr) => acc + curr.weight, 0),
|
|
2795
|
+
notARisks: getNoRiskTags(_stableCoinPoolRiskFactors)
|
|
2246
2796
|
};
|
|
2247
2797
|
|
|
2248
2798
|
const RE7Strategies: IStrategyMetadata<CLVaultStrategySettings>[] = [
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2799
|
+
ETHUSDCRe7Strategy,
|
|
2800
|
+
createRe7Strategy(
|
|
2801
|
+
"ekubo_cl_usdcusdt",
|
|
2802
|
+
"Ekubo USDC.e/USDT",
|
|
2803
|
+
"0x3a4f8debaf12af97bb911099bc011d63d6c208d4c5ba8e15d7f437785b0aaa2",
|
|
2804
|
+
1506139,
|
|
2805
|
+
"USDC.e",
|
|
2806
|
+
"USDT",
|
|
2807
|
+
"USDC.e",
|
|
2808
|
+
stableCoinRisk,
|
|
2809
|
+
false // isBTC
|
|
2256
2810
|
),
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
_stableCoinPoolRiskFactors.reduce((acc, curr) => acc + curr.weight, 0),
|
|
2268
|
-
notARisks: getNoRiskTags(_stableCoinPoolRiskFactors),
|
|
2269
|
-
}
|
|
2270
|
-
},
|
|
2271
|
-
{
|
|
2272
|
-
...ETHUSDCRe7Strategy,
|
|
2273
|
-
name: "Ekubo STRK/USDC",
|
|
2274
|
-
description: <></>,
|
|
2275
|
-
address: ContractAddr.from(
|
|
2276
|
-
"0x351b36d0d9d8b40010658825adeeddb1397436cd41acd0ff6c6e23aaa8b5b30"
|
|
2811
|
+
createRe7Strategy(
|
|
2812
|
+
"ekubo_cl_strkusdc",
|
|
2813
|
+
"Ekubo STRK/USDC.e",
|
|
2814
|
+
"0x351b36d0d9d8b40010658825adeeddb1397436cd41acd0ff6c6e23aaa8b5b30",
|
|
2815
|
+
1504079,
|
|
2816
|
+
"STRK",
|
|
2817
|
+
"USDC.e",
|
|
2818
|
+
"USDC.e",
|
|
2819
|
+
highRisk,
|
|
2820
|
+
false // isBTC
|
|
2277
2821
|
),
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
name: "Ekubo STRK/ETH",
|
|
2289
|
-
description: <></>,
|
|
2290
|
-
address: ContractAddr.from(
|
|
2291
|
-
"0x4ce3024b0ee879009112d7b0e073f8a87153dd35b029347d4247ffe48d28f51"
|
|
2822
|
+
createRe7Strategy(
|
|
2823
|
+
"ekubo_cl_strketh",
|
|
2824
|
+
"Ekubo STRK/ETH",
|
|
2825
|
+
"0x4ce3024b0ee879009112d7b0e073f8a87153dd35b029347d4247ffe48d28f51",
|
|
2826
|
+
1504149,
|
|
2827
|
+
"STRK",
|
|
2828
|
+
"ETH",
|
|
2829
|
+
"USDC",
|
|
2830
|
+
highRisk,
|
|
2831
|
+
false // isBTC
|
|
2292
2832
|
),
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
name: "Ekubo WBTC/USDC",
|
|
2304
|
-
description: <></>,
|
|
2305
|
-
address: ContractAddr.from(
|
|
2306
|
-
"0x2bcaef2eb7706875a5fdc6853dd961a0590f850bc3a031c59887189b5e84ba1"
|
|
2833
|
+
createRe7Strategy(
|
|
2834
|
+
"ekubo_cl_wbtcusdc",
|
|
2835
|
+
"Ekubo WBTC/USDC.e",
|
|
2836
|
+
"0x2bcaef2eb7706875a5fdc6853dd961a0590f850bc3a031c59887189b5e84ba1",
|
|
2837
|
+
1506144,
|
|
2838
|
+
"WBTC",
|
|
2839
|
+
"USDC.e",
|
|
2840
|
+
"USDC.e",
|
|
2841
|
+
mediumRisk,
|
|
2842
|
+
true // isBTC
|
|
2307
2843
|
),
|
|
2308
|
-
|
|
2309
|
-
//
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2844
|
+
// createRe7Strategy(
|
|
2845
|
+
// "ekubo_cl_tbtcusdce",
|
|
2846
|
+
// "Ekubo tBTC/USDC.e",
|
|
2847
|
+
// "0x4aad891a2d4432fba06b6558631bb13f6bbd7f6f33ab8c3111e344889ea4456",
|
|
2848
|
+
// 1501764,
|
|
2849
|
+
// "tBTC",
|
|
2850
|
+
// "USDC.e",
|
|
2851
|
+
// "USDC.e",
|
|
2852
|
+
// mediumRisk,
|
|
2853
|
+
// ),
|
|
2854
|
+
createRe7Strategy(
|
|
2855
|
+
"ekubo_cl_wbtceth",
|
|
2856
|
+
"Ekubo WBTC/ETH",
|
|
2857
|
+
"0x1c9232b8186d9317652f05055615f18a120c2ad9e5ee96c39e031c257fb945b",
|
|
2858
|
+
1506145,
|
|
2859
|
+
"WBTC",
|
|
2860
|
+
"ETH",
|
|
2861
|
+
"USDC",
|
|
2862
|
+
mediumRisk,
|
|
2863
|
+
true // isBTC
|
|
2322
2864
|
),
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
name: "Ekubo WBTC/ETH",
|
|
2334
|
-
description: <></>,
|
|
2335
|
-
address: ContractAddr.from(
|
|
2336
|
-
"0x1c9232b8186d9317652f05055615f18a120c2ad9e5ee96c39e031c257fb945b"
|
|
2865
|
+
createRe7Strategy(
|
|
2866
|
+
"ekubo_cl_wbtcstrk",
|
|
2867
|
+
"Ekubo WBTC/STRK",
|
|
2868
|
+
"0x1248e385c23a929a015ec298a26560fa7745bbd6e41a886550e337b02714b1b",
|
|
2869
|
+
1506147,
|
|
2870
|
+
"WBTC",
|
|
2871
|
+
"STRK",
|
|
2872
|
+
"USDC",
|
|
2873
|
+
highRisk,
|
|
2874
|
+
true // isBTC
|
|
2337
2875
|
),
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
name: "Ekubo WBTC/STRK",
|
|
2349
|
-
description: <></>,
|
|
2350
|
-
address: ContractAddr.from(
|
|
2351
|
-
"0x1248e385c23a929a015ec298a26560fa7745bbd6e41a886550e337b02714b1b"
|
|
2876
|
+
createRe7Strategy(
|
|
2877
|
+
"ekubo_cl_usdc_v2usdt",
|
|
2878
|
+
"Ekubo USDC/USDT",
|
|
2879
|
+
"0x5203a08b471e46bf33990ac83aff577bbe5a5d789e61de2c6531e3c4773d1c9",
|
|
2880
|
+
3998018,
|
|
2881
|
+
"USDC",
|
|
2882
|
+
"USDT",
|
|
2883
|
+
"USDC",
|
|
2884
|
+
stableCoinRisk,
|
|
2885
|
+
false // isBTC
|
|
2352
2886
|
),
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2887
|
+
createRe7Strategy(
|
|
2888
|
+
"ekubo_cl_ethusdc_v2",
|
|
2889
|
+
"Ekubo ETH/USDC",
|
|
2890
|
+
"0x4d00c7423b3c0fae3640f6099ac97acbfd8708f099e09bfe3a7a6a680399228",
|
|
2891
|
+
3998025,
|
|
2892
|
+
"USDC",
|
|
2893
|
+
"ETH",
|
|
2894
|
+
"USDC",
|
|
2895
|
+
highRisk,
|
|
2896
|
+
false // isBTC
|
|
2897
|
+
),
|
|
2898
|
+
createRe7Strategy(
|
|
2899
|
+
"ekubo_cl_strkusdc_v2",
|
|
2900
|
+
"Ekubo STRK/USDC",
|
|
2901
|
+
"0x4de22bd0a8eb4d0a18736e66dd36d20ba50bc106346bbfac3dbeaac1ab37ce1",
|
|
2902
|
+
3998030,
|
|
2903
|
+
"USDC",
|
|
2904
|
+
"STRK",
|
|
2905
|
+
"USDC",
|
|
2906
|
+
highRisk,
|
|
2907
|
+
false // isBTC
|
|
2908
|
+
),
|
|
2909
|
+
createRe7Strategy(
|
|
2910
|
+
"ekubo_cl_wbtcusdc_v2",
|
|
2911
|
+
"Ekubo WBTC/USDC",
|
|
2912
|
+
"0x76101c3b80af1103c9c6d541ca627f61b5ae7ae79d7fce96ccdf7bdb648450d",
|
|
2913
|
+
3998034,
|
|
2914
|
+
"USDC",
|
|
2915
|
+
"WBTC",
|
|
2916
|
+
"USDC",
|
|
2917
|
+
mediumRisk,
|
|
2918
|
+
true // isBTC
|
|
2919
|
+
)
|
|
2361
2920
|
];
|
|
2362
2921
|
|
|
2363
2922
|
/**
|
|
@@ -2375,7 +2934,7 @@ EkuboCLVaultStrategies.forEach((s) => {
|
|
|
2375
2934
|
address: s.address,
|
|
2376
2935
|
name: "Vault",
|
|
2377
2936
|
sourceCodeUrl: "https://github.com/strkfarm/strkfarm-contracts/tree/main/src/strategies/cl_vault"
|
|
2378
|
-
},
|
|
2937
|
+
},
|
|
2379
2938
|
// ...COMMON_CONTRACTS
|
|
2380
2939
|
];
|
|
2381
2940
|
// set docs link
|
|
@@ -2419,4 +2978,4 @@ EkuboCLVaultStrategies.forEach((s) => {
|
|
|
2419
2978
|
"Monitor and Rebalance position to optimize yield",
|
|
2420
2979
|
"Harvest and re-invest any rewards every week (Auto-compound)",
|
|
2421
2980
|
]
|
|
2422
|
-
});
|
|
2981
|
+
});
|