@strkfarm/sdk 1.0.37 → 1.0.38
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 +236 -112
- package/dist/cli.mjs +241 -113
- package/dist/index.browser.global.js +869 -312
- package/dist/index.browser.mjs +870 -309
- package/dist/index.d.ts +9 -4
- package/dist/index.js +865 -308
- package/dist/index.mjs +870 -309
- package/package.json +1 -1
- package/src/interfaces/common.ts +111 -98
- package/src/strategies/ekubo-cl-vault.tsx +1434 -923
- package/src/strategies/vesu-rebalance.tsx +937 -610
package/dist/index.browser.mjs
CHANGED
|
@@ -2006,7 +2006,9 @@ var getRiskColor = (risk) => {
|
|
|
2006
2006
|
};
|
|
2007
2007
|
var getNoRiskTags = (risks) => {
|
|
2008
2008
|
const noRisks1 = risks.filter((risk) => risk.value === 0).map((risk) => risk.type);
|
|
2009
|
-
const noRisks2 = Object.values(RiskType).filter(
|
|
2009
|
+
const noRisks2 = Object.values(RiskType).filter(
|
|
2010
|
+
(risk) => !risks.map((risk2) => risk2.type).includes(risk)
|
|
2011
|
+
);
|
|
2010
2012
|
const mergedUnique = [.../* @__PURE__ */ new Set([...noRisks1, ...noRisks2])];
|
|
2011
2013
|
return mergedUnique.map((risk) => `No ${risk}`);
|
|
2012
2014
|
};
|
|
@@ -12698,6 +12700,7 @@ var vesu_pools_default = {
|
|
|
12698
12700
|
};
|
|
12699
12701
|
|
|
12700
12702
|
// src/strategies/vesu-rebalance.tsx
|
|
12703
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12701
12704
|
var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
12702
12705
|
// 10000 bps = 100%
|
|
12703
12706
|
/**
|
|
@@ -12711,10 +12714,17 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
12711
12714
|
super(config);
|
|
12712
12715
|
this.BASE_WEIGHT = 1e4;
|
|
12713
12716
|
this.pricer = pricer;
|
|
12714
|
-
assert(
|
|
12717
|
+
assert(
|
|
12718
|
+
metadata.depositTokens.length === 1,
|
|
12719
|
+
"VesuRebalance only supports 1 deposit token"
|
|
12720
|
+
);
|
|
12715
12721
|
this.metadata = metadata;
|
|
12716
12722
|
this.address = metadata.address;
|
|
12717
|
-
this.contract = new Contract5(
|
|
12723
|
+
this.contract = new Contract5(
|
|
12724
|
+
vesu_rebalance_abi_default,
|
|
12725
|
+
this.address.address,
|
|
12726
|
+
this.config.provider
|
|
12727
|
+
);
|
|
12718
12728
|
}
|
|
12719
12729
|
/**
|
|
12720
12730
|
* Creates a deposit call to the strategy contract.
|
|
@@ -12723,10 +12733,23 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
12723
12733
|
* @returns Populated contract call for deposit
|
|
12724
12734
|
*/
|
|
12725
12735
|
async depositCall(amountInfo, receiver) {
|
|
12726
|
-
assert(
|
|
12727
|
-
|
|
12728
|
-
|
|
12729
|
-
|
|
12736
|
+
assert(
|
|
12737
|
+
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
12738
|
+
"Deposit token mismatch"
|
|
12739
|
+
);
|
|
12740
|
+
const assetContract = new Contract5(
|
|
12741
|
+
vesu_rebalance_abi_default,
|
|
12742
|
+
this.asset().address.address,
|
|
12743
|
+
this.config.provider
|
|
12744
|
+
);
|
|
12745
|
+
const call1 = assetContract.populate("approve", [
|
|
12746
|
+
this.address.address,
|
|
12747
|
+
uint2563.bnToUint256(amountInfo.amount.toWei())
|
|
12748
|
+
]);
|
|
12749
|
+
const call2 = this.contract.populate("deposit", [
|
|
12750
|
+
uint2563.bnToUint256(amountInfo.amount.toWei()),
|
|
12751
|
+
receiver.address
|
|
12752
|
+
]);
|
|
12730
12753
|
return [call1, call2];
|
|
12731
12754
|
}
|
|
12732
12755
|
/**
|
|
@@ -12737,7 +12760,13 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
12737
12760
|
* @returns Populated contract call for withdrawal
|
|
12738
12761
|
*/
|
|
12739
12762
|
async withdrawCall(amountInfo, receiver, owner) {
|
|
12740
|
-
return [
|
|
12763
|
+
return [
|
|
12764
|
+
this.contract.populate("withdraw", [
|
|
12765
|
+
uint2563.bnToUint256(amountInfo.amount.toWei()),
|
|
12766
|
+
receiver.address,
|
|
12767
|
+
owner.address
|
|
12768
|
+
])
|
|
12769
|
+
];
|
|
12741
12770
|
}
|
|
12742
12771
|
/**
|
|
12743
12772
|
* Returns the underlying asset token of the strategy.
|
|
@@ -12760,9 +12789,16 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
12760
12789
|
*/
|
|
12761
12790
|
async getUserTVL(user) {
|
|
12762
12791
|
const shares = await this.contract.balanceOf(user.address);
|
|
12763
|
-
const assets = await this.contract.convert_to_assets(
|
|
12764
|
-
|
|
12765
|
-
|
|
12792
|
+
const assets = await this.contract.convert_to_assets(
|
|
12793
|
+
uint2563.bnToUint256(shares)
|
|
12794
|
+
);
|
|
12795
|
+
const amount = Web3Number.fromWei(
|
|
12796
|
+
assets.toString(),
|
|
12797
|
+
this.metadata.depositTokens[0].decimals
|
|
12798
|
+
);
|
|
12799
|
+
let price = await this.pricer.getPrice(
|
|
12800
|
+
this.metadata.depositTokens[0].symbol
|
|
12801
|
+
);
|
|
12766
12802
|
const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
12767
12803
|
return {
|
|
12768
12804
|
tokenInfo: this.asset(),
|
|
@@ -12776,8 +12812,13 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
12776
12812
|
*/
|
|
12777
12813
|
async getTVL() {
|
|
12778
12814
|
const assets = await this.contract.total_assets();
|
|
12779
|
-
const amount = Web3Number.fromWei(
|
|
12780
|
-
|
|
12815
|
+
const amount = Web3Number.fromWei(
|
|
12816
|
+
assets.toString(),
|
|
12817
|
+
this.metadata.depositTokens[0].decimals
|
|
12818
|
+
);
|
|
12819
|
+
let price = await this.pricer.getPrice(
|
|
12820
|
+
this.metadata.depositTokens[0].symbol
|
|
12821
|
+
);
|
|
12781
12822
|
const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
12782
12823
|
return {
|
|
12783
12824
|
tokenInfo: this.asset(),
|
|
@@ -12803,51 +12844,104 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
12803
12844
|
return pools;
|
|
12804
12845
|
}
|
|
12805
12846
|
async getPoolInfo(p, pools, vesuPositions, totalAssets, isErrorPositionsAPI, isErrorPoolsAPI) {
|
|
12806
|
-
const vesuPosition = vesuPositions.find(
|
|
12847
|
+
const vesuPosition = vesuPositions.find(
|
|
12848
|
+
(d) => d.pool.id.toString() === num3.getDecimalString(p.pool_id.address.toString())
|
|
12849
|
+
);
|
|
12807
12850
|
const _pool = pools.find((d) => {
|
|
12808
|
-
logger.verbose(
|
|
12851
|
+
logger.verbose(
|
|
12852
|
+
`pool check: ${d.id == num3.getDecimalString(p.pool_id.address.toString())}, id: ${d.id}, pool_id: ${num3.getDecimalString(
|
|
12853
|
+
p.pool_id.address.toString()
|
|
12854
|
+
)}`
|
|
12855
|
+
);
|
|
12809
12856
|
return d.id == num3.getDecimalString(p.pool_id.address.toString());
|
|
12810
12857
|
});
|
|
12811
12858
|
logger.verbose(`pool: ${JSON.stringify(_pool)}`);
|
|
12812
12859
|
logger.verbose(typeof _pool);
|
|
12813
12860
|
logger.verbose(`name: ${_pool?.name}`);
|
|
12814
12861
|
const name = _pool?.name;
|
|
12815
|
-
logger.verbose(
|
|
12816
|
-
|
|
12862
|
+
logger.verbose(
|
|
12863
|
+
`name2: ${name}, ${!name ? true : false}, ${name?.length}, ${typeof name}`
|
|
12864
|
+
);
|
|
12865
|
+
const assetInfo = _pool?.assets.find(
|
|
12866
|
+
(d) => this.asset().address.eqString(d.address)
|
|
12867
|
+
);
|
|
12817
12868
|
if (!name) {
|
|
12818
12869
|
logger.verbose(`Pool not found`);
|
|
12819
12870
|
throw new Error(`Pool name ${p.pool_id.address.toString()} not found`);
|
|
12820
12871
|
}
|
|
12821
12872
|
if (!assetInfo) {
|
|
12822
|
-
throw new Error(
|
|
12873
|
+
throw new Error(
|
|
12874
|
+
`Asset ${this.asset().address.toString()} not found in pool ${p.pool_id.address.toString()}`
|
|
12875
|
+
);
|
|
12823
12876
|
}
|
|
12824
|
-
let vTokenContract = new Contract5(
|
|
12877
|
+
let vTokenContract = new Contract5(
|
|
12878
|
+
vesu_rebalance_abi_default,
|
|
12879
|
+
p.v_token.address,
|
|
12880
|
+
this.config.provider
|
|
12881
|
+
);
|
|
12825
12882
|
const bal = await vTokenContract.balanceOf(this.address.address);
|
|
12826
|
-
const assets = await vTokenContract.convert_to_assets(
|
|
12883
|
+
const assets = await vTokenContract.convert_to_assets(
|
|
12884
|
+
uint2563.bnToUint256(bal.toString())
|
|
12885
|
+
);
|
|
12827
12886
|
logger.verbose(`Collateral: ${JSON.stringify(vesuPosition?.collateral)}`);
|
|
12828
12887
|
logger.verbose(`supplyApy: ${JSON.stringify(assetInfo?.stats.supplyApy)}`);
|
|
12829
|
-
logger.verbose(
|
|
12830
|
-
|
|
12831
|
-
|
|
12888
|
+
logger.verbose(
|
|
12889
|
+
`defiSpringSupplyApr: ${JSON.stringify(
|
|
12890
|
+
assetInfo?.stats.defiSpringSupplyApr
|
|
12891
|
+
)}`
|
|
12892
|
+
);
|
|
12893
|
+
logger.verbose(
|
|
12894
|
+
`currentUtilization: ${JSON.stringify(
|
|
12895
|
+
assetInfo?.stats.currentUtilization
|
|
12896
|
+
)}`
|
|
12897
|
+
);
|
|
12898
|
+
logger.verbose(
|
|
12899
|
+
`maxUtilization: ${JSON.stringify(assetInfo?.config.maxUtilization)}`
|
|
12900
|
+
);
|
|
12832
12901
|
const item = {
|
|
12833
12902
|
pool_id: p.pool_id,
|
|
12834
12903
|
pool_name: _pool?.name,
|
|
12835
12904
|
max_weight: p.max_weight,
|
|
12836
|
-
current_weight: isErrorPositionsAPI || !vesuPosition ? 0 : Number(
|
|
12905
|
+
current_weight: isErrorPositionsAPI || !vesuPosition ? 0 : Number(
|
|
12906
|
+
Web3Number.fromWei(vesuPosition.collateral.value, this.decimals()).dividedBy(totalAssets.toString()).toFixed(6)
|
|
12907
|
+
),
|
|
12837
12908
|
v_token: p.v_token,
|
|
12838
12909
|
amount: Web3Number.fromWei(assets.toString(), this.decimals()),
|
|
12839
|
-
usdValue: isErrorPositionsAPI || !vesuPosition ? Web3Number.fromWei("0", this.decimals()) : Web3Number.fromWei(
|
|
12910
|
+
usdValue: isErrorPositionsAPI || !vesuPosition ? Web3Number.fromWei("0", this.decimals()) : Web3Number.fromWei(
|
|
12911
|
+
vesuPosition.collateral.usdPrice.value,
|
|
12912
|
+
vesuPosition.collateral.usdPrice.decimals
|
|
12913
|
+
),
|
|
12840
12914
|
APY: isErrorPoolsAPI || !assetInfo ? {
|
|
12841
12915
|
baseApy: 0,
|
|
12842
12916
|
defiSpringApy: 0,
|
|
12843
12917
|
netApy: 0
|
|
12844
12918
|
} : {
|
|
12845
|
-
baseApy: Number(
|
|
12846
|
-
|
|
12919
|
+
baseApy: Number(
|
|
12920
|
+
Web3Number.fromWei(
|
|
12921
|
+
assetInfo.stats.supplyApy.value,
|
|
12922
|
+
assetInfo.stats.supplyApy.decimals
|
|
12923
|
+
).toFixed(6)
|
|
12924
|
+
),
|
|
12925
|
+
defiSpringApy: assetInfo.stats.defiSpringSupplyApr ? Number(
|
|
12926
|
+
Web3Number.fromWei(
|
|
12927
|
+
assetInfo.stats.defiSpringSupplyApr.value,
|
|
12928
|
+
assetInfo.stats.defiSpringSupplyApr.decimals
|
|
12929
|
+
).toFixed(6)
|
|
12930
|
+
) : 0,
|
|
12847
12931
|
netApy: 0
|
|
12848
12932
|
},
|
|
12849
|
-
currentUtilization: isErrorPoolsAPI || !assetInfo ? 0 : Number(
|
|
12850
|
-
|
|
12933
|
+
currentUtilization: isErrorPoolsAPI || !assetInfo ? 0 : Number(
|
|
12934
|
+
Web3Number.fromWei(
|
|
12935
|
+
assetInfo.stats.currentUtilization.value,
|
|
12936
|
+
assetInfo.stats.currentUtilization.decimals
|
|
12937
|
+
).toFixed(6)
|
|
12938
|
+
),
|
|
12939
|
+
maxUtilization: isErrorPoolsAPI || !assetInfo ? 0 : Number(
|
|
12940
|
+
Web3Number.fromWei(
|
|
12941
|
+
assetInfo.config.maxUtilization.value,
|
|
12942
|
+
assetInfo.config.maxUtilization.decimals
|
|
12943
|
+
).toFixed(6)
|
|
12944
|
+
)
|
|
12851
12945
|
};
|
|
12852
12946
|
item.APY.netApy = item.APY.baseApy + item.APY.defiSpringApy;
|
|
12853
12947
|
return item;
|
|
@@ -12857,7 +12951,7 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
12857
12951
|
* 1. Contract's allowed pools
|
|
12858
12952
|
* 2. Vesu positions API for current positions
|
|
12859
12953
|
* 3. Vesu pools API for APY and utilization data
|
|
12860
|
-
*
|
|
12954
|
+
*
|
|
12861
12955
|
* @returns {Promise<{
|
|
12862
12956
|
* data: Array<PoolInfoFull>,
|
|
12863
12957
|
* isErrorPositionsAPI: boolean
|
|
@@ -12874,15 +12968,29 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
12874
12968
|
let isErrorPositionsAPI = false;
|
|
12875
12969
|
let vesuPositions = [];
|
|
12876
12970
|
try {
|
|
12877
|
-
const data2 = await getAPIUsingHeadlessBrowser(
|
|
12971
|
+
const data2 = await getAPIUsingHeadlessBrowser(
|
|
12972
|
+
`https://api.vesu.xyz/positions?walletAddress=${this.address.address}`
|
|
12973
|
+
);
|
|
12878
12974
|
vesuPositions = data2.data;
|
|
12879
12975
|
} catch (e) {
|
|
12880
|
-
console.error(
|
|
12976
|
+
console.error(
|
|
12977
|
+
`${_VesuRebalance.name}: Error fetching positions for ${this.address.address}`,
|
|
12978
|
+
e
|
|
12979
|
+
);
|
|
12881
12980
|
isErrorPositionsAPI = true;
|
|
12882
12981
|
}
|
|
12883
12982
|
let { pools, isErrorPoolsAPI } = await this.getVesuPools();
|
|
12884
12983
|
const totalAssets = (await this.getTVL()).amount;
|
|
12885
|
-
const info = allowedPools.map(
|
|
12984
|
+
const info = allowedPools.map(
|
|
12985
|
+
(p) => this.getPoolInfo(
|
|
12986
|
+
p,
|
|
12987
|
+
pools,
|
|
12988
|
+
vesuPositions,
|
|
12989
|
+
totalAssets,
|
|
12990
|
+
isErrorPositionsAPI,
|
|
12991
|
+
isErrorPoolsAPI
|
|
12992
|
+
)
|
|
12993
|
+
);
|
|
12886
12994
|
const data = await Promise.all(info);
|
|
12887
12995
|
return {
|
|
12888
12996
|
data,
|
|
@@ -12895,18 +13003,25 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
12895
13003
|
let isErrorPoolsAPI = false;
|
|
12896
13004
|
let pools = [];
|
|
12897
13005
|
try {
|
|
12898
|
-
const data = await getAPIUsingHeadlessBrowser(
|
|
13006
|
+
const data = await getAPIUsingHeadlessBrowser(
|
|
13007
|
+
"https://api.vesu.xyz/pools"
|
|
13008
|
+
);
|
|
12899
13009
|
pools = data.data;
|
|
12900
13010
|
for (const pool of vesu_pools_default.data) {
|
|
12901
13011
|
const found = pools.find((d) => d.id === pool.id);
|
|
12902
13012
|
if (!found) {
|
|
12903
13013
|
logger.verbose(`VesuRebalance: pools: ${JSON.stringify(pools)}`);
|
|
12904
|
-
logger.verbose(
|
|
13014
|
+
logger.verbose(
|
|
13015
|
+
`VesuRebalance: Pool ${pool.id} not found in Vesu API, using hardcoded data`
|
|
13016
|
+
);
|
|
12905
13017
|
throw new Error("pool not found [sanity check]");
|
|
12906
13018
|
}
|
|
12907
13019
|
}
|
|
12908
13020
|
} catch (e) {
|
|
12909
|
-
logger.error(
|
|
13021
|
+
logger.error(
|
|
13022
|
+
`${_VesuRebalance.name}: Error fetching pools for ${this.address.address}, retry ${retry}`,
|
|
13023
|
+
e
|
|
13024
|
+
);
|
|
12910
13025
|
isErrorPoolsAPI = true;
|
|
12911
13026
|
if (retry < 10) {
|
|
12912
13027
|
await new Promise((resolve) => setTimeout(resolve, 5e3 * (retry + 1)));
|
|
@@ -12944,8 +13059,8 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
12944
13059
|
* 3. For each pool that needs more funds:
|
|
12945
13060
|
* - Takes funds from lowest APY pools that are over their target
|
|
12946
13061
|
* 4. Validates that total assets remain constant
|
|
12947
|
-
*
|
|
12948
|
-
* @returns {Promise<{
|
|
13062
|
+
*
|
|
13063
|
+
* @returns {Promise<{
|
|
12949
13064
|
* changes: Change[],
|
|
12950
13065
|
* finalPools: PoolInfoFull[],
|
|
12951
13066
|
* isAnyPoolOverMaxWeight: boolean
|
|
@@ -12961,27 +13076,38 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
12961
13076
|
_pools = _pools2;
|
|
12962
13077
|
}
|
|
12963
13078
|
const feeDeductions = await this.getFee(_pools);
|
|
12964
|
-
logger.verbose(
|
|
13079
|
+
logger.verbose(
|
|
13080
|
+
`VesuRebalance: feeDeductions: ${JSON.stringify(feeDeductions)}`
|
|
13081
|
+
);
|
|
12965
13082
|
const pools = _pools.map((p) => {
|
|
12966
13083
|
const fee = feeDeductions.find((f) => p.v_token.eq(f.vToken))?.fee || Web3Number.fromWei("0", this.decimals());
|
|
12967
|
-
logger.verbose(
|
|
13084
|
+
logger.verbose(
|
|
13085
|
+
`FeeAdjustment: ${p.pool_id} => ${fee.toString()}, amt: ${p.amount.toString()}`
|
|
13086
|
+
);
|
|
12968
13087
|
return {
|
|
12969
13088
|
...p,
|
|
12970
13089
|
amount: p.amount.minus(fee)
|
|
12971
13090
|
};
|
|
12972
13091
|
});
|
|
12973
13092
|
let totalAssets = (await this.getTVL()).amount;
|
|
12974
|
-
if (totalAssets.eq(0))
|
|
12975
|
-
|
|
12976
|
-
|
|
12977
|
-
|
|
13093
|
+
if (totalAssets.eq(0))
|
|
13094
|
+
return {
|
|
13095
|
+
changes: [],
|
|
13096
|
+
finalPools: []
|
|
13097
|
+
};
|
|
12978
13098
|
feeDeductions.forEach((f) => {
|
|
12979
13099
|
totalAssets = totalAssets.minus(f.fee);
|
|
12980
13100
|
});
|
|
12981
|
-
const sumPools = pools.reduce(
|
|
13101
|
+
const sumPools = pools.reduce(
|
|
13102
|
+
(acc, curr) => acc.plus(curr.amount.toString()),
|
|
13103
|
+
Web3Number.fromWei("0", this.decimals())
|
|
13104
|
+
);
|
|
12982
13105
|
logger.verbose(`Sum of pools: ${sumPools.toString()}`);
|
|
12983
13106
|
logger.verbose(`Total assets: ${totalAssets.toString()}`);
|
|
12984
|
-
assert(
|
|
13107
|
+
assert(
|
|
13108
|
+
sumPools.lte(totalAssets.multipliedBy(1.00001).toString()),
|
|
13109
|
+
"Sum of pools.amount must be less than or equal to totalAssets"
|
|
13110
|
+
);
|
|
12985
13111
|
const sortedPools = [...pools].sort((a, b) => b.APY.netApy - a.APY.netApy);
|
|
12986
13112
|
const targetAmounts = {};
|
|
12987
13113
|
let remainingAssets = totalAssets;
|
|
@@ -13003,7 +13129,10 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
13003
13129
|
assert(remainingAssets.lt(1e-5), "Remaining assets must be 0");
|
|
13004
13130
|
const changes = sortedPools.map((pool) => {
|
|
13005
13131
|
const target = targetAmounts[pool.pool_id.address.toString()] || Web3Number.fromWei("0", this.decimals());
|
|
13006
|
-
const change = Web3Number.fromWei(
|
|
13132
|
+
const change = Web3Number.fromWei(
|
|
13133
|
+
target.minus(pool.amount.toString()).toWei(),
|
|
13134
|
+
this.decimals()
|
|
13135
|
+
);
|
|
13007
13136
|
return {
|
|
13008
13137
|
pool_id: pool.pool_id,
|
|
13009
13138
|
changeAmt: change,
|
|
@@ -13012,14 +13141,21 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
13012
13141
|
};
|
|
13013
13142
|
});
|
|
13014
13143
|
logger.verbose(`Changes: ${JSON.stringify(changes)}`);
|
|
13015
|
-
const sumChanges = changes.reduce(
|
|
13016
|
-
|
|
13144
|
+
const sumChanges = changes.reduce(
|
|
13145
|
+
(sum, c) => sum.plus(c.changeAmt.toString()),
|
|
13146
|
+
Web3Number.fromWei("0", this.decimals())
|
|
13147
|
+
);
|
|
13148
|
+
const sumFinal = changes.reduce(
|
|
13149
|
+
(sum, c) => sum.plus(c.finalAmt.toString()),
|
|
13150
|
+
Web3Number.fromWei("0", this.decimals())
|
|
13151
|
+
);
|
|
13017
13152
|
const hasChanges = changes.some((c) => !c.changeAmt.eq(0));
|
|
13018
13153
|
logger.verbose(`Sum of changes: ${sumChanges.toString()}`);
|
|
13019
13154
|
if (!sumChanges.eq(0)) throw new Error("Sum of changes must be zero");
|
|
13020
13155
|
logger.verbose(`Sum of final: ${sumFinal.toString()}`);
|
|
13021
13156
|
logger.verbose(`Total assets: ${totalAssets.toString()}`);
|
|
13022
|
-
if (!sumFinal.eq(totalAssets.toString()))
|
|
13157
|
+
if (!sumFinal.eq(totalAssets.toString()))
|
|
13158
|
+
throw new Error("Sum of final amounts must equal total assets");
|
|
13023
13159
|
if (!hasChanges) throw new Error("No changes required");
|
|
13024
13160
|
const finalPools = pools.map((p) => {
|
|
13025
13161
|
const target = targetAmounts[p.pool_id.address.toString()] || Web3Number.fromWei("0", this.decimals());
|
|
@@ -13047,9 +13183,13 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
13047
13183
|
if (p.changeAmt.eq(0)) return null;
|
|
13048
13184
|
actions.push({
|
|
13049
13185
|
pool_id: p.pool_id.address,
|
|
13050
|
-
feature: new CairoCustomEnum(
|
|
13186
|
+
feature: new CairoCustomEnum(
|
|
13187
|
+
p.isDeposit ? { DEPOSIT: {} } : { WITHDRAW: {} }
|
|
13188
|
+
),
|
|
13051
13189
|
token: this.asset().address.address,
|
|
13052
|
-
amount: uint2563.bnToUint256(
|
|
13190
|
+
amount: uint2563.bnToUint256(
|
|
13191
|
+
p.changeAmt.multipliedBy(p.isDeposit ? 1 : -1).toWei()
|
|
13192
|
+
)
|
|
13053
13193
|
});
|
|
13054
13194
|
});
|
|
13055
13195
|
if (actions.length === 0) return null;
|
|
@@ -13062,18 +13202,29 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
13062
13202
|
const netYield = await this.netAPYGivenPools(pools);
|
|
13063
13203
|
const baseFlow = {
|
|
13064
13204
|
title: "Your Deposit",
|
|
13065
|
-
subItems: [
|
|
13205
|
+
subItems: [
|
|
13206
|
+
{ key: `Net yield`, value: `${(netYield * 100).toFixed(2)}%` },
|
|
13207
|
+
{
|
|
13208
|
+
key: `Performance Fee`,
|
|
13209
|
+
value: `${(this.metadata.additionalInfo.feeBps / 100).toFixed(2)}%`
|
|
13210
|
+
}
|
|
13211
|
+
],
|
|
13066
13212
|
linkedFlows: [],
|
|
13067
13213
|
style: { backgroundColor: "#6e53dc" /* Purple */.valueOf() }
|
|
13068
13214
|
};
|
|
13069
13215
|
let _pools = [...pools];
|
|
13070
|
-
_pools = _pools.sort(
|
|
13216
|
+
_pools = _pools.sort(
|
|
13217
|
+
(a, b) => Number(b.amount.toString()) - Number(a.amount.toString())
|
|
13218
|
+
);
|
|
13071
13219
|
_pools.forEach((p) => {
|
|
13072
13220
|
const flow = {
|
|
13073
13221
|
title: `Pool name: ${p.pool_name}`,
|
|
13074
13222
|
subItems: [
|
|
13075
13223
|
{ key: `APY`, value: `${(p.APY.netApy * 100).toFixed(2)}%` },
|
|
13076
|
-
{
|
|
13224
|
+
{
|
|
13225
|
+
key: "Weight",
|
|
13226
|
+
value: `${(p.current_weight * 100).toFixed(2)} / ${(p.max_weight * 100).toFixed(2)}%`
|
|
13227
|
+
}
|
|
13077
13228
|
],
|
|
13078
13229
|
linkedFlows: [],
|
|
13079
13230
|
style: p.amount.greaterThan(0) ? { backgroundColor: "#35484f" /* Blue */.valueOf() } : { color: "gray" }
|
|
@@ -13105,7 +13256,12 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
13105
13256
|
harvest.actualReward.toWei(),
|
|
13106
13257
|
this.address.address
|
|
13107
13258
|
);
|
|
13108
|
-
swapInfo = await avnu.getSwapInfo(
|
|
13259
|
+
swapInfo = await avnu.getSwapInfo(
|
|
13260
|
+
quote,
|
|
13261
|
+
this.address.address,
|
|
13262
|
+
0,
|
|
13263
|
+
this.address.address
|
|
13264
|
+
);
|
|
13109
13265
|
}
|
|
13110
13266
|
return [
|
|
13111
13267
|
this.contract.populate("harvest", [
|
|
@@ -13126,16 +13282,27 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
13126
13282
|
* @returns {Promise<Array<{ vToken: ContractAddr, fee: Web3Number }>>} Array of fees deducted in different vTokens
|
|
13127
13283
|
*/
|
|
13128
13284
|
async getFee(allowedPools) {
|
|
13129
|
-
const assets = Web3Number.fromWei(
|
|
13130
|
-
|
|
13131
|
-
|
|
13285
|
+
const assets = Web3Number.fromWei(
|
|
13286
|
+
(await this.contract.total_assets()).toString(),
|
|
13287
|
+
this.asset().decimals
|
|
13288
|
+
);
|
|
13289
|
+
const totalSupply = Web3Number.fromWei(
|
|
13290
|
+
(await this.contract.total_supply()).toString(),
|
|
13291
|
+
this.asset().decimals
|
|
13292
|
+
);
|
|
13293
|
+
const prevIndex = Web3Number.fromWei(
|
|
13294
|
+
(await this.contract.get_previous_index()).toString(),
|
|
13295
|
+
18
|
|
13296
|
+
);
|
|
13132
13297
|
const currIndex = new Web3Number(1, 18).multipliedBy(assets).dividedBy(totalSupply);
|
|
13133
13298
|
logger.verbose(`Previous index: ${prevIndex.toString()}`);
|
|
13134
13299
|
logger.verbose(`Assets: ${assets.toString()}`);
|
|
13135
13300
|
logger.verbose(`Total supply: ${totalSupply.toString()}`);
|
|
13136
13301
|
logger.verbose(`Current index: ${currIndex.toNumber()}`);
|
|
13137
13302
|
if (currIndex.lt(prevIndex)) {
|
|
13138
|
-
logger.verbose(
|
|
13303
|
+
logger.verbose(
|
|
13304
|
+
`getFee::Current index is less than previous index, no fees to be deducted`
|
|
13305
|
+
);
|
|
13139
13306
|
return [];
|
|
13140
13307
|
}
|
|
13141
13308
|
const indexDiff = currIndex.minus(prevIndex);
|
|
@@ -13148,7 +13315,9 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
13148
13315
|
return [];
|
|
13149
13316
|
}
|
|
13150
13317
|
const fees = [];
|
|
13151
|
-
let remainingFee = fee.plus(
|
|
13318
|
+
let remainingFee = fee.plus(
|
|
13319
|
+
Web3Number.fromWei("100", this.asset().decimals)
|
|
13320
|
+
);
|
|
13152
13321
|
for (const pool of allowedPools) {
|
|
13153
13322
|
const vToken = pool.v_token;
|
|
13154
13323
|
const balance = pool.amount;
|
|
@@ -13157,7 +13326,9 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
13157
13326
|
break;
|
|
13158
13327
|
} else {
|
|
13159
13328
|
fees.push({ vToken, fee: Web3Number.fromWei(balance.toString(), 18) });
|
|
13160
|
-
remainingFee = remainingFee.minus(
|
|
13329
|
+
remainingFee = remainingFee.minus(
|
|
13330
|
+
Web3Number.fromWei(balance.toString(), 18)
|
|
13331
|
+
);
|
|
13161
13332
|
}
|
|
13162
13333
|
}
|
|
13163
13334
|
logger.verbose(`Fees: ${JSON.stringify(fees)}`);
|
|
@@ -13165,101 +13336,175 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
13165
13336
|
}
|
|
13166
13337
|
};
|
|
13167
13338
|
var _description = "Automatically diversify {{TOKEN}} holdings into different Vesu pools while reducing risk and maximizing yield. Defi spring STRK Rewards are auto-compounded as well.";
|
|
13168
|
-
var _protocol = {
|
|
13339
|
+
var _protocol = {
|
|
13340
|
+
name: "Vesu",
|
|
13341
|
+
logo: "https://static-assets-8zct.onrender.com/integrations/vesu/logo.png"
|
|
13342
|
+
};
|
|
13169
13343
|
var _riskFactor = [
|
|
13170
13344
|
{ type: "Smart Contract Risk" /* SMART_CONTRACT_RISK */, value: 0.5, weight: 25 },
|
|
13171
13345
|
{ type: "Counterparty Risk" /* COUNTERPARTY_RISK */, value: 1, weight: 50 },
|
|
13172
13346
|
{ type: "Oracle Risk" /* ORACLE_RISK */, value: 0.5, weight: 25 }
|
|
13173
13347
|
];
|
|
13174
13348
|
var AUDIT_URL = "https://assets.strkfarm.com/strkfarm/audit_report_vesu_and_ekubo_strats.pdf";
|
|
13175
|
-
var
|
|
13176
|
-
|
|
13177
|
-
|
|
13178
|
-
|
|
13179
|
-
type: "ERC4626",
|
|
13180
|
-
depositTokens: [Global.getDefaultTokens().find((t) => t.symbol === "STRK")],
|
|
13181
|
-
protocols: [_protocol],
|
|
13182
|
-
auditUrl: AUDIT_URL,
|
|
13183
|
-
maxTVL: Web3Number.fromWei("0", 18),
|
|
13184
|
-
risk: {
|
|
13185
|
-
riskFactor: _riskFactor,
|
|
13186
|
-
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
13187
|
-
notARisks: getNoRiskTags(_riskFactor)
|
|
13349
|
+
var faqs = [
|
|
13350
|
+
{
|
|
13351
|
+
question: "What is the Vesu Rebalancing Strategy?",
|
|
13352
|
+
answer: "The Vesu Rebalancing Strategy is an automated investment strategy that diversifies your holdings across multiple Vesu pools. It optimizes yield by rebalancing assets based on pool performance while adhering to risk constraints."
|
|
13188
13353
|
},
|
|
13189
|
-
|
|
13190
|
-
|
|
13191
|
-
|
|
13192
|
-
}, {
|
|
13193
|
-
name: "Vesu Fusion ETH",
|
|
13194
|
-
description: _description.replace("{{TOKEN}}", "ETH"),
|
|
13195
|
-
address: ContractAddr.from("0x5eaf5ee75231cecf79921ff8ded4b5ffe96be718bcb3daf206690ad1a9ad0ca"),
|
|
13196
|
-
type: "ERC4626",
|
|
13197
|
-
auditUrl: AUDIT_URL,
|
|
13198
|
-
depositTokens: [Global.getDefaultTokens().find((t) => t.symbol === "ETH")],
|
|
13199
|
-
protocols: [_protocol],
|
|
13200
|
-
maxTVL: Web3Number.fromWei("0", 18),
|
|
13201
|
-
risk: {
|
|
13202
|
-
riskFactor: _riskFactor,
|
|
13203
|
-
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
13204
|
-
notARisks: getNoRiskTags(_riskFactor)
|
|
13354
|
+
{
|
|
13355
|
+
question: "Will I earn Vesu points?",
|
|
13356
|
+
answer: "Yes, of course! You will earn Vesu points for your deposits."
|
|
13205
13357
|
},
|
|
13206
|
-
|
|
13207
|
-
|
|
13208
|
-
|
|
13209
|
-
}, {
|
|
13210
|
-
name: "Vesu Fusion USDC",
|
|
13211
|
-
description: _description.replace("{{TOKEN}}", "USDC"),
|
|
13212
|
-
address: ContractAddr.from("0xa858c97e9454f407d1bd7c57472fc8d8d8449a777c822b41d18e387816f29c"),
|
|
13213
|
-
type: "ERC4626",
|
|
13214
|
-
auditUrl: AUDIT_URL,
|
|
13215
|
-
depositTokens: [Global.getDefaultTokens().find((t) => t.symbol === "USDC")],
|
|
13216
|
-
protocols: [_protocol],
|
|
13217
|
-
maxTVL: Web3Number.fromWei("0", 6),
|
|
13218
|
-
risk: {
|
|
13219
|
-
riskFactor: _riskFactor,
|
|
13220
|
-
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
13221
|
-
notARisks: getNoRiskTags(_riskFactor)
|
|
13358
|
+
{
|
|
13359
|
+
question: "How does the strategy optimize yield?",
|
|
13360
|
+
answer: "The strategy calculates the weighted average APY across all pools and reallocates assets to maximize returns. It prioritizes high-performing pools while ensuring compliance with maximum weight constraints."
|
|
13222
13361
|
},
|
|
13223
|
-
|
|
13224
|
-
|
|
13362
|
+
{
|
|
13363
|
+
question: "What are the risks associated with this strategy?",
|
|
13364
|
+
answer: "The strategy involves usual DeFi risks such as smart contract vulnerabilities, counterparty risks, and oracle inaccuracies. However, we try our best to reduce these risks through audits and careful pool selection."
|
|
13365
|
+
},
|
|
13366
|
+
{
|
|
13367
|
+
question: "How are fees calculated and deducted?",
|
|
13368
|
+
answer: "Fees are calculated based on the performance of the strategy and deducted proportionally from the total assets. We charge a 10% performance fee and is already accounted in the APY shown."
|
|
13369
|
+
},
|
|
13370
|
+
{
|
|
13371
|
+
question: "What happens if a pool exceeds its maximum weight?",
|
|
13372
|
+
answer: "If a pool exceeds its maximum weight, the strategy rebalances by withdrawing excess funds and reallocating them to other pools with available capacity."
|
|
13373
|
+
},
|
|
13374
|
+
{
|
|
13375
|
+
question: "Can I withdraw my assets at any time?",
|
|
13376
|
+
answer: "Yes, you can withdraw your assets at any time. In rare circumstances, if debt utilisation is high for certain pools on Vesu, it may not be possible to withdraw until markets restore balance."
|
|
13377
|
+
},
|
|
13378
|
+
{
|
|
13379
|
+
question: "What happens to my Defi Spring STRK rewards?",
|
|
13380
|
+
answer: "STRK rewards are automatically harvested and reinvested into the strategy every week to maximize compounding returns."
|
|
13381
|
+
},
|
|
13382
|
+
{
|
|
13383
|
+
question: "Is the strategy audited?",
|
|
13384
|
+
answer: /* @__PURE__ */ jsxs("div", { children: [
|
|
13385
|
+
"Yes, the strategy has been audited. You can review the audit report in our docs ",
|
|
13386
|
+
/* @__PURE__ */ jsx("a", { href: "https://docs.strkfarm.com/p/strategies/vesu-fusion-rebalancing-vaults#technical-details", style: { textDecoration: "underline", marginLeft: "5px" }, children: "Here" }),
|
|
13387
|
+
"."
|
|
13388
|
+
] })
|
|
13225
13389
|
}
|
|
13226
|
-
|
|
13227
|
-
|
|
13228
|
-
|
|
13229
|
-
|
|
13230
|
-
|
|
13231
|
-
|
|
13232
|
-
|
|
13233
|
-
|
|
13234
|
-
|
|
13235
|
-
|
|
13236
|
-
|
|
13237
|
-
|
|
13238
|
-
|
|
13390
|
+
];
|
|
13391
|
+
var VesuRebalanceStrategies = [
|
|
13392
|
+
{
|
|
13393
|
+
name: "Vesu Fusion STRK",
|
|
13394
|
+
description: _description.replace("{{TOKEN}}", "STRK"),
|
|
13395
|
+
address: ContractAddr.from(
|
|
13396
|
+
"0x7fb5bcb8525954a60fde4e8fb8220477696ce7117ef264775a1770e23571929"
|
|
13397
|
+
),
|
|
13398
|
+
type: "ERC4626",
|
|
13399
|
+
depositTokens: [
|
|
13400
|
+
Global.getDefaultTokens().find((t) => t.symbol === "STRK")
|
|
13401
|
+
],
|
|
13402
|
+
protocols: [_protocol],
|
|
13403
|
+
auditUrl: AUDIT_URL,
|
|
13404
|
+
maxTVL: Web3Number.fromWei("0", 18),
|
|
13405
|
+
risk: {
|
|
13406
|
+
riskFactor: _riskFactor,
|
|
13407
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
13408
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
13409
|
+
},
|
|
13410
|
+
additionalInfo: {
|
|
13411
|
+
feeBps: 1e3
|
|
13412
|
+
},
|
|
13413
|
+
faqs
|
|
13414
|
+
},
|
|
13415
|
+
{
|
|
13416
|
+
name: "Vesu Fusion ETH",
|
|
13417
|
+
description: _description.replace("{{TOKEN}}", "ETH"),
|
|
13418
|
+
address: ContractAddr.from(
|
|
13419
|
+
"0x5eaf5ee75231cecf79921ff8ded4b5ffe96be718bcb3daf206690ad1a9ad0ca"
|
|
13420
|
+
),
|
|
13421
|
+
type: "ERC4626",
|
|
13422
|
+
auditUrl: AUDIT_URL,
|
|
13423
|
+
depositTokens: [
|
|
13424
|
+
Global.getDefaultTokens().find((t) => t.symbol === "ETH")
|
|
13425
|
+
],
|
|
13426
|
+
protocols: [_protocol],
|
|
13427
|
+
maxTVL: Web3Number.fromWei("0", 18),
|
|
13428
|
+
risk: {
|
|
13429
|
+
riskFactor: _riskFactor,
|
|
13430
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
13431
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
13432
|
+
},
|
|
13433
|
+
additionalInfo: {
|
|
13434
|
+
feeBps: 1e3
|
|
13435
|
+
},
|
|
13436
|
+
faqs
|
|
13239
13437
|
},
|
|
13240
|
-
|
|
13241
|
-
|
|
13438
|
+
{
|
|
13439
|
+
name: "Vesu Fusion USDC",
|
|
13440
|
+
description: _description.replace("{{TOKEN}}", "USDC"),
|
|
13441
|
+
address: ContractAddr.from(
|
|
13442
|
+
"0xa858c97e9454f407d1bd7c57472fc8d8d8449a777c822b41d18e387816f29c"
|
|
13443
|
+
),
|
|
13444
|
+
type: "ERC4626",
|
|
13445
|
+
auditUrl: AUDIT_URL,
|
|
13446
|
+
depositTokens: [
|
|
13447
|
+
Global.getDefaultTokens().find((t) => t.symbol === "USDC")
|
|
13448
|
+
],
|
|
13449
|
+
protocols: [_protocol],
|
|
13450
|
+
maxTVL: Web3Number.fromWei("0", 6),
|
|
13451
|
+
risk: {
|
|
13452
|
+
riskFactor: _riskFactor,
|
|
13453
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
13454
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
13455
|
+
},
|
|
13456
|
+
additionalInfo: {
|
|
13457
|
+
feeBps: 1e3
|
|
13458
|
+
},
|
|
13459
|
+
faqs
|
|
13460
|
+
},
|
|
13461
|
+
{
|
|
13462
|
+
name: "Vesu Fusion USDT",
|
|
13463
|
+
description: _description.replace("{{TOKEN}}", "USDT"),
|
|
13464
|
+
address: ContractAddr.from(
|
|
13465
|
+
"0x115e94e722cfc4c77a2f15c4aefb0928c1c0029e5a57570df24c650cb7cec2c"
|
|
13466
|
+
),
|
|
13467
|
+
type: "ERC4626",
|
|
13468
|
+
depositTokens: [
|
|
13469
|
+
Global.getDefaultTokens().find((t) => t.symbol === "USDT")
|
|
13470
|
+
],
|
|
13471
|
+
auditUrl: AUDIT_URL,
|
|
13472
|
+
protocols: [_protocol],
|
|
13473
|
+
maxTVL: Web3Number.fromWei("0", 6),
|
|
13474
|
+
risk: {
|
|
13475
|
+
riskFactor: _riskFactor,
|
|
13476
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
13477
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
13478
|
+
},
|
|
13479
|
+
additionalInfo: {
|
|
13480
|
+
feeBps: 1e3
|
|
13481
|
+
},
|
|
13482
|
+
faqs
|
|
13483
|
+
// }, {
|
|
13484
|
+
// name: 'Vesu Fusion WBTC',
|
|
13485
|
+
// description: _description.replace('{{TOKEN}}', 'WBTC'),
|
|
13486
|
+
// address: ContractAddr.from('0x778007f8136a5b827325d21613803e796bda4d676fbe1e34aeab0b2a2ec027f'),
|
|
13487
|
+
// type: 'ERC4626',
|
|
13488
|
+
// depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'WBTC')!],
|
|
13489
|
+
// auditUrl: AUDIT_URL,
|
|
13490
|
+
// protocols: [_protocol],
|
|
13491
|
+
// maxTVL: Web3Number.fromWei('0', 8),
|
|
13492
|
+
// risk: {
|
|
13493
|
+
// riskFactor: _riskFactor,
|
|
13494
|
+
// netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
13495
|
+
// },
|
|
13496
|
+
// additionalInfo: {
|
|
13497
|
+
// feeBps: 1000,
|
|
13498
|
+
// },
|
|
13242
13499
|
}
|
|
13243
|
-
|
|
13244
|
-
// name: 'Vesu Fusion WBTC',
|
|
13245
|
-
// description: _description.replace('{{TOKEN}}', 'WBTC'),
|
|
13246
|
-
// address: ContractAddr.from('0x778007f8136a5b827325d21613803e796bda4d676fbe1e34aeab0b2a2ec027f'),
|
|
13247
|
-
// type: 'ERC4626',
|
|
13248
|
-
// depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'WBTC')!],
|
|
13249
|
-
// auditUrl: AUDIT_URL,
|
|
13250
|
-
// protocols: [_protocol],
|
|
13251
|
-
// maxTVL: Web3Number.fromWei('0', 8),
|
|
13252
|
-
// risk: {
|
|
13253
|
-
// riskFactor: _riskFactor,
|
|
13254
|
-
// netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
13255
|
-
// },
|
|
13256
|
-
// additionalInfo: {
|
|
13257
|
-
// feeBps: 1000,
|
|
13258
|
-
// },
|
|
13259
|
-
}];
|
|
13500
|
+
];
|
|
13260
13501
|
|
|
13261
13502
|
// src/strategies/ekubo-cl-vault.tsx
|
|
13262
|
-
import {
|
|
13503
|
+
import {
|
|
13504
|
+
Contract as Contract6,
|
|
13505
|
+
num as num4,
|
|
13506
|
+
uint256 as uint2564
|
|
13507
|
+
} from "starknet";
|
|
13263
13508
|
|
|
13264
13509
|
// src/data/cl-vault.abi.json
|
|
13265
13510
|
var cl_vault_abi_default = [
|
|
@@ -18161,7 +18406,7 @@ var erc4626_abi_default = [
|
|
|
18161
18406
|
];
|
|
18162
18407
|
|
|
18163
18408
|
// src/strategies/ekubo-cl-vault.tsx
|
|
18164
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18409
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
18165
18410
|
var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
18166
18411
|
/**
|
|
18167
18412
|
* Creates a new VesuRebalance strategy instance.
|
|
@@ -18174,15 +18419,34 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18174
18419
|
super(config);
|
|
18175
18420
|
this.BASE_WEIGHT = 1e4;
|
|
18176
18421
|
this.pricer = pricer;
|
|
18177
|
-
assert(
|
|
18422
|
+
assert(
|
|
18423
|
+
metadata.depositTokens.length === 2,
|
|
18424
|
+
"EkuboCL only supports 2 deposit token"
|
|
18425
|
+
);
|
|
18178
18426
|
this.metadata = metadata;
|
|
18179
18427
|
this.address = metadata.address;
|
|
18180
|
-
this.contract = new Contract6(
|
|
18181
|
-
|
|
18428
|
+
this.contract = new Contract6(
|
|
18429
|
+
cl_vault_abi_default,
|
|
18430
|
+
this.address.address,
|
|
18431
|
+
this.config.provider
|
|
18432
|
+
);
|
|
18433
|
+
this.lstContract = new Contract6(
|
|
18434
|
+
erc4626_abi_default,
|
|
18435
|
+
this.metadata.additionalInfo.lstContract.address,
|
|
18436
|
+
this.config.provider
|
|
18437
|
+
);
|
|
18182
18438
|
const EKUBO_POSITION = "0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067";
|
|
18183
|
-
this.ekuboPositionsContract = new Contract6(
|
|
18439
|
+
this.ekuboPositionsContract = new Contract6(
|
|
18440
|
+
ekubo_positions_abi_default,
|
|
18441
|
+
EKUBO_POSITION,
|
|
18442
|
+
this.config.provider
|
|
18443
|
+
);
|
|
18184
18444
|
const EKUBO_MATH = "0x04a72e9e166f6c0e9d800af4dc40f6b6fb4404b735d3f528d9250808b2481995";
|
|
18185
|
-
this.ekuboMathContract = new Contract6(
|
|
18445
|
+
this.ekuboMathContract = new Contract6(
|
|
18446
|
+
ekubo_math_abi_default,
|
|
18447
|
+
EKUBO_MATH,
|
|
18448
|
+
this.config.provider
|
|
18449
|
+
);
|
|
18186
18450
|
this.avnu = new AvnuWrapper();
|
|
18187
18451
|
}
|
|
18188
18452
|
async matchInputAmounts(amountInfo) {
|
|
@@ -18207,25 +18471,52 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18207
18471
|
/** Returns minimum amounts give given two amounts based on what can be added for liq */
|
|
18208
18472
|
async getMinDepositAmounts(amountInfo) {
|
|
18209
18473
|
const shares = await this.tokensToShares(amountInfo);
|
|
18210
|
-
const { amount0, amount1 } = await this.contract.call(
|
|
18474
|
+
const { amount0, amount1 } = await this.contract.call(
|
|
18475
|
+
"convert_to_assets",
|
|
18476
|
+
[uint2564.bnToUint256(shares.toWei())]
|
|
18477
|
+
);
|
|
18211
18478
|
return {
|
|
18212
18479
|
token0: {
|
|
18213
18480
|
tokenInfo: amountInfo.token0.tokenInfo,
|
|
18214
|
-
amount: Web3Number.fromWei(
|
|
18481
|
+
amount: Web3Number.fromWei(
|
|
18482
|
+
amount0.toString(),
|
|
18483
|
+
amountInfo.token0.tokenInfo.decimals
|
|
18484
|
+
)
|
|
18215
18485
|
},
|
|
18216
18486
|
token1: {
|
|
18217
18487
|
tokenInfo: amountInfo.token1.tokenInfo,
|
|
18218
|
-
amount: Web3Number.fromWei(
|
|
18488
|
+
amount: Web3Number.fromWei(
|
|
18489
|
+
amount1.toString(),
|
|
18490
|
+
amountInfo.token1.tokenInfo.decimals
|
|
18491
|
+
)
|
|
18219
18492
|
}
|
|
18220
18493
|
};
|
|
18221
18494
|
}
|
|
18222
18495
|
async depositCall(amountInfo, receiver) {
|
|
18223
18496
|
const updateAmountInfo = await this.getMinDepositAmounts(amountInfo);
|
|
18224
|
-
const token0Contract = new Contract6(
|
|
18225
|
-
|
|
18226
|
-
|
|
18227
|
-
|
|
18228
|
-
|
|
18497
|
+
const token0Contract = new Contract6(
|
|
18498
|
+
erc4626_abi_default,
|
|
18499
|
+
amountInfo.token0.tokenInfo.address.address,
|
|
18500
|
+
this.config.provider
|
|
18501
|
+
);
|
|
18502
|
+
const token1Contract = new Contract6(
|
|
18503
|
+
erc4626_abi_default,
|
|
18504
|
+
amountInfo.token1.tokenInfo.address.address,
|
|
18505
|
+
this.config.provider
|
|
18506
|
+
);
|
|
18507
|
+
const call1 = token0Contract.populate("approve", [
|
|
18508
|
+
this.address.address,
|
|
18509
|
+
uint2564.bnToUint256(updateAmountInfo.token0.amount.toWei())
|
|
18510
|
+
]);
|
|
18511
|
+
const call2 = token1Contract.populate("approve", [
|
|
18512
|
+
this.address.address,
|
|
18513
|
+
uint2564.bnToUint256(updateAmountInfo.token1.amount.toWei())
|
|
18514
|
+
]);
|
|
18515
|
+
const call3 = this.contract.populate("deposit", [
|
|
18516
|
+
uint2564.bnToUint256(updateAmountInfo.token0.amount.toWei()),
|
|
18517
|
+
uint2564.bnToUint256(updateAmountInfo.token1.amount.toWei()),
|
|
18518
|
+
receiver.address
|
|
18519
|
+
]);
|
|
18229
18520
|
const calls = [];
|
|
18230
18521
|
if (updateAmountInfo.token0.amount.greaterThan(0)) calls.push(call1);
|
|
18231
18522
|
if (updateAmountInfo.token1.amount.greaterThan(0)) calls.push(call2);
|
|
@@ -18240,25 +18531,29 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18240
18531
|
}
|
|
18241
18532
|
async withdrawCall(amountInfo, receiver, owner) {
|
|
18242
18533
|
const shares = await this.tokensToShares(amountInfo);
|
|
18243
|
-
logger.verbose(
|
|
18244
|
-
|
|
18245
|
-
|
|
18246
|
-
|
|
18247
|
-
|
|
18534
|
+
logger.verbose(
|
|
18535
|
+
`${_EkuboCLVault.name}: withdrawCall: shares=${shares.toString()}`
|
|
18536
|
+
);
|
|
18537
|
+
return [
|
|
18538
|
+
this.contract.populate("withdraw", [
|
|
18539
|
+
uint2564.bnToUint256(shares.toWei()),
|
|
18540
|
+
receiver.address
|
|
18541
|
+
])
|
|
18542
|
+
];
|
|
18248
18543
|
}
|
|
18249
18544
|
rebalanceCall(newBounds, swapParams) {
|
|
18250
|
-
return [
|
|
18251
|
-
|
|
18252
|
-
|
|
18253
|
-
|
|
18254
|
-
|
|
18255
|
-
|
|
18256
|
-
|
|
18545
|
+
return [
|
|
18546
|
+
this.contract.populate("rebalance", [
|
|
18547
|
+
{
|
|
18548
|
+
lower: _EkuboCLVault.tickToi129(Number(newBounds.lowerTick)),
|
|
18549
|
+
upper: _EkuboCLVault.tickToi129(Number(newBounds.upperTick))
|
|
18550
|
+
},
|
|
18551
|
+
swapParams
|
|
18552
|
+
])
|
|
18553
|
+
];
|
|
18257
18554
|
}
|
|
18258
18555
|
handleUnusedCall(swapParams) {
|
|
18259
|
-
return [this.contract.populate("handle_unused", [
|
|
18260
|
-
swapParams
|
|
18261
|
-
])];
|
|
18556
|
+
return [this.contract.populate("handle_unused", [swapParams])];
|
|
18262
18557
|
}
|
|
18263
18558
|
handleFeesCall() {
|
|
18264
18559
|
return [this.contract.populate("handle_fees", [])];
|
|
@@ -18274,8 +18569,12 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18274
18569
|
let blockNow = typeof blockIdentifier == "number" ? blockIdentifier : (await this.config.provider.getBlockLatestAccepted()).block_number;
|
|
18275
18570
|
const blockNowTime = typeof blockIdentifier == "number" ? (await this.config.provider.getBlockWithTxs(blockIdentifier)).timestamp : (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
18276
18571
|
const blockBefore = blockNow - sinceBlocks;
|
|
18277
|
-
const adjustedSupplyNow = supplyNow.minus(
|
|
18278
|
-
|
|
18572
|
+
const adjustedSupplyNow = supplyNow.minus(
|
|
18573
|
+
await this.getHarvestRewardShares(blockBefore, blockNow)
|
|
18574
|
+
);
|
|
18575
|
+
let blockBeforeInfo = await this.config.provider.getBlockWithTxs(
|
|
18576
|
+
blockBefore
|
|
18577
|
+
);
|
|
18279
18578
|
const tvlBefore = await this._getTVL(blockBefore);
|
|
18280
18579
|
const supplyBefore = await this.totalSupply(blockBefore);
|
|
18281
18580
|
const priceBefore = await this.getCurrentPrice(blockBefore);
|
|
@@ -18293,7 +18592,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18293
18592
|
logger.verbose(`Supply before: ${supplyBefore.toString()}`);
|
|
18294
18593
|
logger.verbose(`Supply now: ${adjustedSupplyNow.toString()}`);
|
|
18295
18594
|
logger.verbose(`Time diff in seconds: ${timeDiffSeconds}`);
|
|
18296
|
-
const apyForGivenBlocks = Number(
|
|
18595
|
+
const apyForGivenBlocks = Number(
|
|
18596
|
+
tvlPerShareNow.minus(tvlPerShareBf).multipliedBy(1e4).dividedBy(tvlPerShareBf)
|
|
18597
|
+
) / 1e4;
|
|
18297
18598
|
return apyForGivenBlocks * (365 * 24 * 3600) / timeDiffSeconds;
|
|
18298
18599
|
}
|
|
18299
18600
|
async getHarvestRewardShares(fromBlock, toBlock) {
|
|
@@ -18311,7 +18612,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18311
18612
|
} else {
|
|
18312
18613
|
shares = shares.plus(Web3Number.fromWei(record.shares.toString(), 18));
|
|
18313
18614
|
}
|
|
18314
|
-
logger.verbose(
|
|
18615
|
+
logger.verbose(
|
|
18616
|
+
`${_EkuboCLVault.name}: getHarvestRewardShares: ${i} => ${shares.toWei()}`
|
|
18617
|
+
);
|
|
18315
18618
|
}
|
|
18316
18619
|
return shares;
|
|
18317
18620
|
}
|
|
@@ -18321,15 +18624,25 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18321
18624
|
}
|
|
18322
18625
|
async getUserTVL(user, blockIdentifier = "pending") {
|
|
18323
18626
|
let bal = await this.balanceOf(user, blockIdentifier);
|
|
18324
|
-
const assets = await this.contract.call(
|
|
18325
|
-
|
|
18326
|
-
|
|
18627
|
+
const assets = await this.contract.call(
|
|
18628
|
+
"convert_to_assets",
|
|
18629
|
+
[uint2564.bnToUint256(bal.toWei())],
|
|
18630
|
+
{
|
|
18631
|
+
blockIdentifier
|
|
18632
|
+
}
|
|
18633
|
+
);
|
|
18327
18634
|
const poolKey = await this.getPoolKey(blockIdentifier);
|
|
18328
18635
|
this.assertValidDepositTokens(poolKey);
|
|
18329
18636
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
18330
18637
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
18331
|
-
const amount0 = Web3Number.fromWei(
|
|
18332
|
-
|
|
18638
|
+
const amount0 = Web3Number.fromWei(
|
|
18639
|
+
assets.amount0.toString(),
|
|
18640
|
+
token0Info.decimals
|
|
18641
|
+
);
|
|
18642
|
+
const amount1 = Web3Number.fromWei(
|
|
18643
|
+
assets.amount1.toString(),
|
|
18644
|
+
token1Info.decimals
|
|
18645
|
+
);
|
|
18333
18646
|
const P0 = await this.pricer.getPrice(token0Info.symbol);
|
|
18334
18647
|
const P1 = await this.pricer.getPrice(token1Info.symbol);
|
|
18335
18648
|
const token0Usd = Number(amount0.toFixed(13)) * P0.price;
|
|
@@ -18353,7 +18666,11 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18353
18666
|
blockIdentifier
|
|
18354
18667
|
});
|
|
18355
18668
|
const bounds = await this.getCurrentBounds(blockIdentifier);
|
|
18356
|
-
const { amount0, amount1 } = await this.getLiquidityToAmounts(
|
|
18669
|
+
const { amount0, amount1 } = await this.getLiquidityToAmounts(
|
|
18670
|
+
Web3Number.fromWei(result.toString(), 18),
|
|
18671
|
+
bounds,
|
|
18672
|
+
blockIdentifier
|
|
18673
|
+
);
|
|
18357
18674
|
return { amount0, amount1 };
|
|
18358
18675
|
}
|
|
18359
18676
|
async totalSupply(blockIdentifier = "pending") {
|
|
@@ -18363,8 +18680,14 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18363
18680
|
return Web3Number.fromWei(res.toString(), 18);
|
|
18364
18681
|
}
|
|
18365
18682
|
assertValidDepositTokens(poolKey) {
|
|
18366
|
-
assert(
|
|
18367
|
-
|
|
18683
|
+
assert(
|
|
18684
|
+
poolKey.token0.eq(this.metadata.depositTokens[0].address),
|
|
18685
|
+
"Expected token0 in depositTokens[0]"
|
|
18686
|
+
);
|
|
18687
|
+
assert(
|
|
18688
|
+
poolKey.token1.eq(this.metadata.depositTokens[1].address),
|
|
18689
|
+
"Expected token1 in depositTokens[1]"
|
|
18690
|
+
);
|
|
18368
18691
|
}
|
|
18369
18692
|
async getTVL(blockIdentifier = "pending") {
|
|
18370
18693
|
const { amount0, amount1 } = await this._getTVL(blockIdentifier);
|
|
@@ -18394,26 +18717,35 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18394
18717
|
const nftID = await this.getCurrentNFTID();
|
|
18395
18718
|
const poolKey = await this.getPoolKey();
|
|
18396
18719
|
const currentBounds = await this.getCurrentBounds();
|
|
18397
|
-
const result = await this.ekuboPositionsContract.call(
|
|
18398
|
-
|
|
18399
|
-
|
|
18400
|
-
|
|
18401
|
-
|
|
18402
|
-
|
|
18403
|
-
|
|
18404
|
-
|
|
18405
|
-
|
|
18406
|
-
|
|
18407
|
-
|
|
18408
|
-
|
|
18409
|
-
|
|
18410
|
-
|
|
18720
|
+
const result = await this.ekuboPositionsContract.call(
|
|
18721
|
+
"get_token_info",
|
|
18722
|
+
[
|
|
18723
|
+
nftID,
|
|
18724
|
+
{
|
|
18725
|
+
token0: poolKey.token0.address,
|
|
18726
|
+
token1: poolKey.token1.address,
|
|
18727
|
+
fee: poolKey.fee,
|
|
18728
|
+
tick_spacing: poolKey.tick_spacing,
|
|
18729
|
+
extension: poolKey.extension
|
|
18730
|
+
},
|
|
18731
|
+
{
|
|
18732
|
+
lower: _EkuboCLVault.tickToi129(Number(currentBounds.lowerTick)),
|
|
18733
|
+
upper: _EkuboCLVault.tickToi129(Number(currentBounds.upperTick))
|
|
18734
|
+
}
|
|
18735
|
+
]
|
|
18736
|
+
);
|
|
18411
18737
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
18412
18738
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
18413
18739
|
const P0 = await this.pricer.getPrice(token0Info.symbol);
|
|
18414
18740
|
const P1 = await this.pricer.getPrice(token1Info.symbol);
|
|
18415
|
-
const token0Web3 = Web3Number.fromWei(
|
|
18416
|
-
|
|
18741
|
+
const token0Web3 = Web3Number.fromWei(
|
|
18742
|
+
result.fees0.toString(),
|
|
18743
|
+
token0Info.decimals
|
|
18744
|
+
);
|
|
18745
|
+
const token1Web3 = Web3Number.fromWei(
|
|
18746
|
+
result.fees1.toString(),
|
|
18747
|
+
token1Info.decimals
|
|
18748
|
+
);
|
|
18417
18749
|
const token0Usd = Number(token0Web3.toFixed(13)) * P0.price;
|
|
18418
18750
|
const token1Usd = Number(token1Web3.toFixed(13)) * P1.price;
|
|
18419
18751
|
return {
|
|
@@ -18435,7 +18767,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18435
18767
|
return Number(result.salt.toString());
|
|
18436
18768
|
}
|
|
18437
18769
|
async truePrice() {
|
|
18438
|
-
const result = await this.lstContract.call("convert_to_assets", [
|
|
18770
|
+
const result = await this.lstContract.call("convert_to_assets", [
|
|
18771
|
+
uint2564.bnToUint256(BigInt(1e18).toString())
|
|
18772
|
+
]);
|
|
18439
18773
|
const truePrice = Number(BigInt(result.toString()) * BigInt(1e9) / BigInt(1e18)) / 1e9;
|
|
18440
18774
|
return truePrice;
|
|
18441
18775
|
}
|
|
@@ -18444,22 +18778,36 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18444
18778
|
return this._getCurrentPrice(poolKey, blockIdentifier);
|
|
18445
18779
|
}
|
|
18446
18780
|
async _getCurrentPrice(poolKey, blockIdentifier = "pending") {
|
|
18447
|
-
const priceInfo = await this.ekuboPositionsContract.call(
|
|
18781
|
+
const priceInfo = await this.ekuboPositionsContract.call(
|
|
18782
|
+
"get_pool_price",
|
|
18783
|
+
[
|
|
18784
|
+
{
|
|
18785
|
+
token0: poolKey.token0.address,
|
|
18786
|
+
token1: poolKey.token1.address,
|
|
18787
|
+
fee: poolKey.fee,
|
|
18788
|
+
tick_spacing: poolKey.tick_spacing,
|
|
18789
|
+
extension: poolKey.extension
|
|
18790
|
+
}
|
|
18791
|
+
],
|
|
18448
18792
|
{
|
|
18449
|
-
|
|
18450
|
-
token1: poolKey.token1.address,
|
|
18451
|
-
fee: poolKey.fee,
|
|
18452
|
-
tick_spacing: poolKey.tick_spacing,
|
|
18453
|
-
extension: poolKey.extension
|
|
18793
|
+
blockIdentifier
|
|
18454
18794
|
}
|
|
18455
|
-
|
|
18456
|
-
|
|
18457
|
-
|
|
18458
|
-
|
|
18459
|
-
console.log(
|
|
18795
|
+
);
|
|
18796
|
+
const sqrtRatio = _EkuboCLVault.div2Power128(
|
|
18797
|
+
BigInt(priceInfo.sqrt_ratio.toString())
|
|
18798
|
+
);
|
|
18799
|
+
console.log(
|
|
18800
|
+
`EkuboCLVault: getCurrentPrice: blockIdentifier: ${blockIdentifier}, sqrtRatio: ${sqrtRatio}, ${priceInfo.sqrt_ratio.toString()}`
|
|
18801
|
+
);
|
|
18460
18802
|
const price = sqrtRatio * sqrtRatio;
|
|
18461
|
-
const tick = _EkuboCLVault.priceToTick(
|
|
18462
|
-
|
|
18803
|
+
const tick = _EkuboCLVault.priceToTick(
|
|
18804
|
+
price,
|
|
18805
|
+
true,
|
|
18806
|
+
Number(poolKey.tick_spacing)
|
|
18807
|
+
);
|
|
18808
|
+
console.log(
|
|
18809
|
+
`EkuboCLVault: getCurrentPrice: blockIdentifier: ${blockIdentifier}, price: ${price}, tick: ${tick.mag}, ${tick.sign}`
|
|
18810
|
+
);
|
|
18463
18811
|
return {
|
|
18464
18812
|
price,
|
|
18465
18813
|
tick: tick.mag * (tick.sign == 0 ? 1 : -1),
|
|
@@ -18499,7 +18847,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18499
18847
|
};
|
|
18500
18848
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
18501
18849
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
18502
|
-
assert(
|
|
18850
|
+
assert(
|
|
18851
|
+
token0Info.decimals == token1Info.decimals,
|
|
18852
|
+
"Tested only for equal decimals"
|
|
18853
|
+
);
|
|
18503
18854
|
this.poolKey = poolKey;
|
|
18504
18855
|
return poolKey;
|
|
18505
18856
|
}
|
|
@@ -18523,11 +18874,18 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18523
18874
|
async _getExpectedAmountsForLiquidity(amount0, amount1, bounds, justUseInputAmount = true) {
|
|
18524
18875
|
assert(amount0.greaterThan(0) || amount1.greaterThan(0), "Amount is 0");
|
|
18525
18876
|
const sampleLiq = 1e20;
|
|
18526
|
-
const { amount0: sampleAmount0, amount1: sampleAmount1 } = await this.getLiquidityToAmounts(
|
|
18527
|
-
|
|
18877
|
+
const { amount0: sampleAmount0, amount1: sampleAmount1 } = await this.getLiquidityToAmounts(
|
|
18878
|
+
Web3Number.fromWei(sampleLiq.toString(), 18),
|
|
18879
|
+
bounds
|
|
18880
|
+
);
|
|
18881
|
+
logger.verbose(
|
|
18882
|
+
`${_EkuboCLVault.name}: _getExpectedAmountsForLiquidity => sampleAmount0: ${sampleAmount0.toString()}, sampleAmount1: ${sampleAmount1.toString()}`
|
|
18883
|
+
);
|
|
18528
18884
|
assert(!sampleAmount0.eq(0) || !sampleAmount1.eq(0), "Sample amount is 0");
|
|
18529
18885
|
const price = await (await this.getCurrentPrice()).price;
|
|
18530
|
-
logger.verbose(
|
|
18886
|
+
logger.verbose(
|
|
18887
|
+
`${_EkuboCLVault.name}: _getExpectedAmountsForLiquidity => price: ${price}`
|
|
18888
|
+
);
|
|
18531
18889
|
if (amount1.eq(0) && amount0.greaterThan(0)) {
|
|
18532
18890
|
if (sampleAmount1.eq(0)) {
|
|
18533
18891
|
return {
|
|
@@ -18557,12 +18915,22 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18557
18915
|
};
|
|
18558
18916
|
}
|
|
18559
18917
|
}
|
|
18560
|
-
assert(
|
|
18918
|
+
assert(
|
|
18919
|
+
sampleAmount0.decimals == sampleAmount1.decimals,
|
|
18920
|
+
"Sample amounts have different decimals"
|
|
18921
|
+
);
|
|
18561
18922
|
const ratioWeb3Number = sampleAmount0.multipliedBy(1e18).dividedBy(sampleAmount1.toString()).dividedBy(1e18);
|
|
18562
18923
|
const ratio = Number(ratioWeb3Number.toFixed(18));
|
|
18563
|
-
logger.verbose(
|
|
18924
|
+
logger.verbose(
|
|
18925
|
+
`${_EkuboCLVault.name}: ${this.metadata.name} => ratio: ${ratio.toString()}`
|
|
18926
|
+
);
|
|
18564
18927
|
if (justUseInputAmount)
|
|
18565
|
-
return this._solveExpectedAmountsEq(
|
|
18928
|
+
return this._solveExpectedAmountsEq(
|
|
18929
|
+
amount0,
|
|
18930
|
+
amount1,
|
|
18931
|
+
ratioWeb3Number,
|
|
18932
|
+
price
|
|
18933
|
+
);
|
|
18566
18934
|
if (amount1.eq(0) && amount0.greaterThan(0)) {
|
|
18567
18935
|
const _amount1 = amount0.dividedBy(ratioWeb3Number);
|
|
18568
18936
|
return {
|
|
@@ -18578,7 +18946,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18578
18946
|
ratio
|
|
18579
18947
|
};
|
|
18580
18948
|
} else {
|
|
18581
|
-
throw new Error(
|
|
18949
|
+
throw new Error(
|
|
18950
|
+
"Both amounts are non-zero, cannot compute expected amounts"
|
|
18951
|
+
);
|
|
18582
18952
|
}
|
|
18583
18953
|
}
|
|
18584
18954
|
_solveExpectedAmountsEq(availableAmount0, availableAmount1, ratio, price) {
|
|
@@ -18595,34 +18965,65 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18595
18965
|
const erc20Mod = new ERC20(this.config);
|
|
18596
18966
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
18597
18967
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
18598
|
-
const token0Bal1 = await erc20Mod.balanceOf(
|
|
18599
|
-
|
|
18600
|
-
|
|
18968
|
+
const token0Bal1 = await erc20Mod.balanceOf(
|
|
18969
|
+
poolKey.token0,
|
|
18970
|
+
this.address.address,
|
|
18971
|
+
token0Info.decimals
|
|
18972
|
+
);
|
|
18973
|
+
const token1Bal1 = await erc20Mod.balanceOf(
|
|
18974
|
+
poolKey.token1,
|
|
18975
|
+
this.address.address,
|
|
18976
|
+
token1Info.decimals
|
|
18977
|
+
);
|
|
18978
|
+
logger.verbose(
|
|
18979
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => token0Bal1: ${token0Bal1.toString()}, token1Bal1: ${token1Bal1.toString()}`
|
|
18980
|
+
);
|
|
18601
18981
|
const token0Price = await this.pricer.getPrice(token0Info.symbol);
|
|
18602
18982
|
const token1Price = await this.pricer.getPrice(token1Info.symbol);
|
|
18603
18983
|
const token0PriceUsd = token0Price.price * Number(token0Bal1.toFixed(13));
|
|
18604
18984
|
const token1PriceUsd = token1Price.price * Number(token1Bal1.toFixed(13));
|
|
18605
18985
|
if (token0PriceUsd > 1 && token1PriceUsd > 1) {
|
|
18606
|
-
throw new Error(
|
|
18986
|
+
throw new Error(
|
|
18987
|
+
"Both tokens are non-zero and above $1, call handle_fees first"
|
|
18988
|
+
);
|
|
18607
18989
|
}
|
|
18608
18990
|
let token0Bal = token0Bal1;
|
|
18609
18991
|
let token1Bal = token1Bal1;
|
|
18610
18992
|
if (considerRebalance) {
|
|
18611
|
-
logger.verbose(
|
|
18993
|
+
logger.verbose(
|
|
18994
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => considerRebalance: true`
|
|
18995
|
+
);
|
|
18612
18996
|
const tvl = await this.getTVL();
|
|
18613
18997
|
token0Bal = token0Bal.plus(tvl.token0.amount.toString());
|
|
18614
18998
|
token1Bal = token1Bal.plus(tvl.token1.amount.toString());
|
|
18615
18999
|
} else {
|
|
18616
|
-
logger.verbose(
|
|
19000
|
+
logger.verbose(
|
|
19001
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => considerRebalance: false`
|
|
19002
|
+
);
|
|
18617
19003
|
}
|
|
18618
|
-
logger.verbose(
|
|
19004
|
+
logger.verbose(
|
|
19005
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
|
|
19006
|
+
);
|
|
18619
19007
|
const newBounds = await this.getNewBounds();
|
|
18620
|
-
logger.verbose(
|
|
18621
|
-
|
|
19008
|
+
logger.verbose(
|
|
19009
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newBounds: ${newBounds.lowerTick}, ${newBounds.upperTick}`
|
|
19010
|
+
);
|
|
19011
|
+
return await this.getSwapInfoGivenAmounts(
|
|
19012
|
+
poolKey,
|
|
19013
|
+
token0Bal,
|
|
19014
|
+
token1Bal,
|
|
19015
|
+
newBounds
|
|
19016
|
+
);
|
|
18622
19017
|
}
|
|
18623
19018
|
async getSwapInfoGivenAmounts(poolKey, token0Bal, token1Bal, bounds) {
|
|
18624
|
-
let expectedAmounts = await this._getExpectedAmountsForLiquidity(
|
|
18625
|
-
|
|
19019
|
+
let expectedAmounts = await this._getExpectedAmountsForLiquidity(
|
|
19020
|
+
token0Bal,
|
|
19021
|
+
token1Bal,
|
|
19022
|
+
bounds
|
|
19023
|
+
);
|
|
19024
|
+
logger.verbose(
|
|
19025
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => expectedAmounts: ${expectedAmounts.amount0.toString()}, ${expectedAmounts.amount1.toString()}`
|
|
19026
|
+
);
|
|
18626
19027
|
let retry = 0;
|
|
18627
19028
|
const maxRetry = 10;
|
|
18628
19029
|
while (retry < maxRetry) {
|
|
@@ -18639,9 +19040,15 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18639
19040
|
const remainingSellAmount = tokenToSell == poolKey.token0 ? expectedAmounts.amount0 : expectedAmounts.amount1;
|
|
18640
19041
|
const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
|
|
18641
19042
|
const expectedRatio = expectedAmounts.ratio;
|
|
18642
|
-
logger.verbose(
|
|
18643
|
-
|
|
18644
|
-
|
|
19043
|
+
logger.verbose(
|
|
19044
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => tokenToSell: ${tokenToSell.address}, tokenToBuy: ${tokenToBuy.address}, amountToSell: ${amountToSell.toWei()}`
|
|
19045
|
+
);
|
|
19046
|
+
logger.verbose(
|
|
19047
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => remainingSellAmount: ${remainingSellAmount.toString()}`
|
|
19048
|
+
);
|
|
19049
|
+
logger.verbose(
|
|
19050
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => expectedRatio: ${expectedRatio}`
|
|
19051
|
+
);
|
|
18645
19052
|
if (amountToSell.eq(0)) {
|
|
18646
19053
|
return {
|
|
18647
19054
|
token_from_address: tokenToSell.address,
|
|
@@ -18655,23 +19062,62 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18655
19062
|
routes: []
|
|
18656
19063
|
};
|
|
18657
19064
|
}
|
|
18658
|
-
const quote = await this.avnu.getQuotes(
|
|
19065
|
+
const quote = await this.avnu.getQuotes(
|
|
19066
|
+
tokenToSell.address,
|
|
19067
|
+
tokenToBuy.address,
|
|
19068
|
+
amountToSell.toWei(),
|
|
19069
|
+
this.address.address
|
|
19070
|
+
);
|
|
18659
19071
|
if (remainingSellAmount.eq(0)) {
|
|
18660
|
-
const minAmountOut = Web3Number.fromWei(
|
|
18661
|
-
|
|
19072
|
+
const minAmountOut = Web3Number.fromWei(
|
|
19073
|
+
quote.buyAmount.toString(),
|
|
19074
|
+
tokenToBuyInfo.decimals
|
|
19075
|
+
).multipliedBy(0.9999);
|
|
19076
|
+
return await this.avnu.getSwapInfo(
|
|
19077
|
+
quote,
|
|
19078
|
+
this.address.address,
|
|
19079
|
+
0,
|
|
19080
|
+
this.address.address,
|
|
19081
|
+
minAmountOut.toWei()
|
|
19082
|
+
);
|
|
18662
19083
|
}
|
|
18663
|
-
const amountOut = Web3Number.fromWei(
|
|
19084
|
+
const amountOut = Web3Number.fromWei(
|
|
19085
|
+
quote.buyAmount.toString(),
|
|
19086
|
+
tokenToBuyInfo.decimals
|
|
19087
|
+
);
|
|
18664
19088
|
const swapPrice = tokenToSell == poolKey.token0 ? amountOut.dividedBy(amountToSell) : amountToSell.dividedBy(amountOut);
|
|
18665
19089
|
const newRatio = tokenToSell == poolKey.token0 ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut)) : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
|
|
18666
|
-
logger.verbose(
|
|
18667
|
-
|
|
18668
|
-
|
|
19090
|
+
logger.verbose(
|
|
19091
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => amountOut: ${amountOut.toString()}`
|
|
19092
|
+
);
|
|
19093
|
+
logger.verbose(
|
|
19094
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => swapPrice: ${swapPrice.toString()}`
|
|
19095
|
+
);
|
|
19096
|
+
logger.verbose(
|
|
19097
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
|
|
19098
|
+
);
|
|
18669
19099
|
if (Number(newRatio.toString()) > expectedRatio * 1.0000001 || Number(newRatio.toString()) < expectedRatio * 0.9999999) {
|
|
18670
|
-
expectedAmounts = await this._solveExpectedAmountsEq(
|
|
18671
|
-
|
|
19100
|
+
expectedAmounts = await this._solveExpectedAmountsEq(
|
|
19101
|
+
token0Bal,
|
|
19102
|
+
token1Bal,
|
|
19103
|
+
new Web3Number(Number(expectedRatio).toFixed(13), 18),
|
|
19104
|
+
Number(swapPrice.toString())
|
|
19105
|
+
);
|
|
19106
|
+
logger.verbose(
|
|
19107
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => expectedAmounts: ${expectedAmounts.amount0.toString()}, ${expectedAmounts.amount1.toString()}`
|
|
19108
|
+
);
|
|
18672
19109
|
} else {
|
|
18673
|
-
const minAmountOut = Web3Number.fromWei(
|
|
18674
|
-
|
|
19110
|
+
const minAmountOut = Web3Number.fromWei(
|
|
19111
|
+
quote.buyAmount.toString(),
|
|
19112
|
+
tokenToBuyInfo.decimals
|
|
19113
|
+
).multipliedBy(0.9999);
|
|
19114
|
+
return await this.avnu.getSwapInfo(
|
|
19115
|
+
quote,
|
|
19116
|
+
this.address.address,
|
|
19117
|
+
0,
|
|
19118
|
+
this.address.address,
|
|
19119
|
+
minAmountOut.toWei()
|
|
19120
|
+
);
|
|
18675
19121
|
}
|
|
18676
19122
|
retry++;
|
|
18677
19123
|
}
|
|
@@ -18680,8 +19126,8 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18680
19126
|
/**
|
|
18681
19127
|
* Attempts to rebalance the vault by iteratively adjusting swap amounts if initial attempt fails.
|
|
18682
19128
|
* Uses binary search approach to find optimal swap amount.
|
|
18683
|
-
*
|
|
18684
|
-
* @param newBounds - The new tick bounds to rebalance to
|
|
19129
|
+
*
|
|
19130
|
+
* @param newBounds - The new tick bounds to rebalance to
|
|
18685
19131
|
* @param swapInfo - Initial swap parameters for rebalancing
|
|
18686
19132
|
* @param acc - Account to estimate gas fees with
|
|
18687
19133
|
* @param retry - Current retry attempt number (default 0)
|
|
@@ -18708,7 +19154,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18708
19154
|
logger.error(`Rebalance failed after ${MAX_RETRIES} retries`);
|
|
18709
19155
|
throw err;
|
|
18710
19156
|
}
|
|
18711
|
-
logger.error(
|
|
19157
|
+
logger.error(
|
|
19158
|
+
`Rebalance attempt ${retry + 1} failed, adjusting swap amount...`
|
|
19159
|
+
);
|
|
18712
19160
|
const newSwapInfo = { ...swapInfo };
|
|
18713
19161
|
const currentAmount = Web3Number.fromWei(fromAmount.toString(), 18);
|
|
18714
19162
|
logger.verbose(`Current amount: ${currentAmount.toString()}`);
|
|
@@ -18800,23 +19248,39 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18800
19248
|
const currentPrice = _currentPrice || await this.getCurrentPrice(blockIdentifier);
|
|
18801
19249
|
const lowerPrice = _EkuboCLVault.tickToPrice(bounds.lowerTick);
|
|
18802
19250
|
const upperPrice = _EkuboCLVault.tickToPrice(bounds.upperTick);
|
|
18803
|
-
logger.verbose(
|
|
18804
|
-
|
|
18805
|
-
|
|
19251
|
+
logger.verbose(
|
|
19252
|
+
`${_EkuboCLVault.name}: getLiquidityToAmounts => currentPrice: ${currentPrice.price}, lowerPrice: ${lowerPrice}, upperPrice: ${upperPrice}`
|
|
19253
|
+
);
|
|
19254
|
+
const result = await this.ekuboMathContract.call(
|
|
19255
|
+
"liquidity_delta_to_amount_delta",
|
|
19256
|
+
[
|
|
19257
|
+
uint2564.bnToUint256(currentPrice.sqrtRatio),
|
|
19258
|
+
{
|
|
19259
|
+
mag: liquidity.toWei(),
|
|
19260
|
+
sign: 0
|
|
19261
|
+
},
|
|
19262
|
+
uint2564.bnToUint256(
|
|
19263
|
+
_EkuboCLVault.priceToSqrtRatio(lowerPrice).toString()
|
|
19264
|
+
),
|
|
19265
|
+
uint2564.bnToUint256(
|
|
19266
|
+
_EkuboCLVault.priceToSqrtRatio(upperPrice).toString()
|
|
19267
|
+
)
|
|
19268
|
+
],
|
|
18806
19269
|
{
|
|
18807
|
-
|
|
18808
|
-
|
|
18809
|
-
|
|
18810
|
-
uint2564.bnToUint256(_EkuboCLVault.priceToSqrtRatio(lowerPrice).toString()),
|
|
18811
|
-
uint2564.bnToUint256(_EkuboCLVault.priceToSqrtRatio(upperPrice).toString())
|
|
18812
|
-
], {
|
|
18813
|
-
blockIdentifier
|
|
18814
|
-
});
|
|
19270
|
+
blockIdentifier
|
|
19271
|
+
}
|
|
19272
|
+
);
|
|
18815
19273
|
const poolKey = _poolKey || await this.getPoolKey(blockIdentifier);
|
|
18816
19274
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
18817
19275
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
18818
|
-
const amount0 = Web3Number.fromWei(
|
|
18819
|
-
|
|
19276
|
+
const amount0 = Web3Number.fromWei(
|
|
19277
|
+
_EkuboCLVault.i129ToNumber(result.amount0).toString(),
|
|
19278
|
+
token0Info.decimals
|
|
19279
|
+
);
|
|
19280
|
+
const amount1 = Web3Number.fromWei(
|
|
19281
|
+
_EkuboCLVault.i129ToNumber(result.amount1).toString(),
|
|
19282
|
+
token1Info.decimals
|
|
19283
|
+
);
|
|
18820
19284
|
return {
|
|
18821
19285
|
amount0,
|
|
18822
19286
|
amount1
|
|
@@ -18824,7 +19288,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18824
19288
|
}
|
|
18825
19289
|
async harvest(acc) {
|
|
18826
19290
|
const ekuboHarvests = new EkuboHarvests(this.config);
|
|
18827
|
-
const unClaimedRewards = await ekuboHarvests.getUnHarvestedRewards(
|
|
19291
|
+
const unClaimedRewards = await ekuboHarvests.getUnHarvestedRewards(
|
|
19292
|
+
this.address
|
|
19293
|
+
);
|
|
18828
19294
|
const poolKey = await this.getPoolKey();
|
|
18829
19295
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
18830
19296
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
@@ -18834,18 +19300,37 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18834
19300
|
const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
|
|
18835
19301
|
const postFeeAmount = claim.claim.amount.minus(fee);
|
|
18836
19302
|
const isToken1 = claim.token.eq(poolKey.token1);
|
|
18837
|
-
logger.verbose(
|
|
19303
|
+
logger.verbose(
|
|
19304
|
+
`${_EkuboCLVault.name}: harvest => Processing claim, isToken1: ${isToken1} amount: ${postFeeAmount.toWei()}`
|
|
19305
|
+
);
|
|
18838
19306
|
const token0Amt = isToken1 ? new Web3Number(0, token0Info.decimals) : postFeeAmount;
|
|
18839
19307
|
const token1Amt = isToken1 ? postFeeAmount : new Web3Number(0, token0Info.decimals);
|
|
18840
|
-
logger.verbose(
|
|
18841
|
-
|
|
19308
|
+
logger.verbose(
|
|
19309
|
+
`${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toString()}, token1Amt: ${token1Amt.toString()}`
|
|
19310
|
+
);
|
|
19311
|
+
const swapInfo = await this.getSwapInfoGivenAmounts(
|
|
19312
|
+
poolKey,
|
|
19313
|
+
token0Amt,
|
|
19314
|
+
token1Amt,
|
|
19315
|
+
bounds
|
|
19316
|
+
);
|
|
18842
19317
|
swapInfo.token_to_address = token0Info.address.address;
|
|
18843
|
-
logger.verbose(
|
|
18844
|
-
|
|
19318
|
+
logger.verbose(
|
|
19319
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
|
|
19320
|
+
);
|
|
19321
|
+
logger.verbose(
|
|
19322
|
+
`${_EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
|
|
19323
|
+
);
|
|
18845
19324
|
const harvestEstimateCall = async (swapInfo1) => {
|
|
18846
|
-
const swap1Amount = Web3Number.fromWei(
|
|
19325
|
+
const swap1Amount = Web3Number.fromWei(
|
|
19326
|
+
uint2564.uint256ToBN(swapInfo1.token_from_amount).toString(),
|
|
19327
|
+
18
|
|
19328
|
+
);
|
|
18847
19329
|
const remainingAmount = postFeeAmount.minus(swap1Amount);
|
|
18848
|
-
const swapInfo2 = {
|
|
19330
|
+
const swapInfo2 = {
|
|
19331
|
+
...swapInfo,
|
|
19332
|
+
token_from_amount: uint2564.bnToUint256(remainingAmount.toWei())
|
|
19333
|
+
};
|
|
18849
19334
|
swapInfo2.token_to_address = token1Info.address.address;
|
|
18850
19335
|
const calldata = [
|
|
18851
19336
|
claim.rewardsContract.address,
|
|
@@ -18858,11 +19343,23 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18858
19343
|
swapInfo,
|
|
18859
19344
|
swapInfo2
|
|
18860
19345
|
];
|
|
18861
|
-
logger.verbose(
|
|
19346
|
+
logger.verbose(
|
|
19347
|
+
`${_EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
|
|
19348
|
+
calldata
|
|
19349
|
+
)}`
|
|
19350
|
+
);
|
|
18862
19351
|
return [this.contract.populate("harvest", calldata)];
|
|
18863
19352
|
};
|
|
18864
|
-
const _callsFinal = await this.rebalanceIter(
|
|
18865
|
-
|
|
19353
|
+
const _callsFinal = await this.rebalanceIter(
|
|
19354
|
+
swapInfo,
|
|
19355
|
+
acc,
|
|
19356
|
+
harvestEstimateCall
|
|
19357
|
+
);
|
|
19358
|
+
logger.verbose(
|
|
19359
|
+
`${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
|
|
19360
|
+
_callsFinal
|
|
19361
|
+
)}`
|
|
19362
|
+
);
|
|
18866
19363
|
calls.push(..._callsFinal);
|
|
18867
19364
|
}
|
|
18868
19365
|
return calls;
|
|
@@ -18872,24 +19369,37 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18872
19369
|
const poolKey = await this.getPoolKey();
|
|
18873
19370
|
const linkedFlow = {
|
|
18874
19371
|
title: this.metadata.name,
|
|
18875
|
-
subItems: [
|
|
19372
|
+
subItems: [
|
|
19373
|
+
{
|
|
19374
|
+
key: "Pool",
|
|
19375
|
+
value: `${(_EkuboCLVault.div2Power128(BigInt(poolKey.fee)) * 100).toFixed(2)}%, ${poolKey.tick_spacing} tick spacing`
|
|
19376
|
+
}
|
|
19377
|
+
],
|
|
18876
19378
|
linkedFlows: [],
|
|
18877
19379
|
style: { backgroundColor: "#35484f" /* Blue */.valueOf() }
|
|
18878
19380
|
};
|
|
18879
19381
|
const baseFlow = {
|
|
18880
19382
|
id: "base",
|
|
18881
19383
|
title: "Your Deposit",
|
|
18882
|
-
subItems: [
|
|
19384
|
+
subItems: [
|
|
19385
|
+
{ key: `Net yield`, value: `${(netYield * 100).toFixed(2)}%` },
|
|
19386
|
+
{
|
|
19387
|
+
key: `Performance Fee`,
|
|
19388
|
+
value: `${(this.metadata.additionalInfo.feeBps / 100).toFixed(2)}%`
|
|
19389
|
+
}
|
|
19390
|
+
],
|
|
18883
19391
|
linkedFlows: [linkedFlow],
|
|
18884
19392
|
style: { backgroundColor: "#6e53dc" /* Purple */.valueOf() }
|
|
18885
19393
|
};
|
|
18886
19394
|
const rebalanceFlow = {
|
|
18887
19395
|
id: "rebalance",
|
|
18888
19396
|
title: "Automated Rebalance",
|
|
18889
|
-
subItems: [
|
|
18890
|
-
|
|
18891
|
-
|
|
18892
|
-
|
|
19397
|
+
subItems: [
|
|
19398
|
+
{
|
|
19399
|
+
key: "Range selection",
|
|
19400
|
+
value: `${this.metadata.additionalInfo.newBounds.lower * Number(poolKey.tick_spacing)} to ${this.metadata.additionalInfo.newBounds.upper * Number(poolKey.tick_spacing)} ticks`
|
|
19401
|
+
}
|
|
19402
|
+
],
|
|
18893
19403
|
linkedFlows: [linkedFlow],
|
|
18894
19404
|
style: { backgroundColor: "purple" /* Green */.valueOf() }
|
|
18895
19405
|
};
|
|
@@ -18897,43 +19407,94 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18897
19407
|
}
|
|
18898
19408
|
};
|
|
18899
19409
|
var _description2 = "Deploys your {{POOL_NAME}} into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce the need for manual adjustments. Trading fees and DeFi Spring rewards are automatically compounded back into the strategy. In return, you receive an ERC-20 token representing your share of the strategy. The APY is calculated based on 7-day historical performance.";
|
|
18900
|
-
var _protocol2 = {
|
|
19410
|
+
var _protocol2 = {
|
|
19411
|
+
name: "Ekubo",
|
|
19412
|
+
logo: "https://app.ekubo.org/favicon.ico"
|
|
19413
|
+
};
|
|
18901
19414
|
var _riskFactor2 = [
|
|
18902
19415
|
{ type: "Smart Contract Risk" /* SMART_CONTRACT_RISK */, value: 0.5, weight: 25 },
|
|
18903
19416
|
{ type: "Impermanent Loss Risk" /* IMPERMANENT_LOSS */, value: 1, weight: 75 }
|
|
18904
19417
|
];
|
|
18905
19418
|
var AUDIT_URL2 = "https://assets.strkfarm.com/strkfarm/audit_report_vesu_and_ekubo_strats.pdf";
|
|
18906
|
-
var
|
|
18907
|
-
|
|
18908
|
-
|
|
18909
|
-
|
|
18910
|
-
|
|
18911
|
-
|
|
18912
|
-
|
|
18913
|
-
|
|
18914
|
-
] }),
|
|
18915
|
-
address: ContractAddr.from("0x01f083b98674bc21effee29ef443a00c7b9a500fd92cf30341a3da12c73f2324"),
|
|
18916
|
-
type: "Other",
|
|
18917
|
-
// must be same order as poolKey token0 and token1
|
|
18918
|
-
depositTokens: [Global.getDefaultTokens().find((t) => t.symbol === "xSTRK"), Global.getDefaultTokens().find((t) => t.symbol === "STRK")],
|
|
18919
|
-
protocols: [_protocol2],
|
|
18920
|
-
auditUrl: AUDIT_URL2,
|
|
18921
|
-
maxTVL: Web3Number.fromWei("0", 18),
|
|
18922
|
-
risk: {
|
|
18923
|
-
riskFactor: _riskFactor2,
|
|
18924
|
-
netRisk: _riskFactor2.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor2.reduce((acc, curr) => acc + curr.weight, 0),
|
|
18925
|
-
notARisks: getNoRiskTags(_riskFactor2)
|
|
19419
|
+
var faqs2 = [
|
|
19420
|
+
{
|
|
19421
|
+
question: "What is the Ekubo CL Vault strategy?",
|
|
19422
|
+
answer: "The Ekubo CL Vault strategy deploys your assets into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce manual adjustments."
|
|
19423
|
+
},
|
|
19424
|
+
{
|
|
19425
|
+
question: "How are trading fees and rewards handled?",
|
|
19426
|
+
answer: "Trading fees and DeFi Spring rewards are automatically compounded back into the strategy, increasing your overall returns."
|
|
18926
19427
|
},
|
|
18927
|
-
|
|
18928
|
-
|
|
18929
|
-
|
|
18930
|
-
|
|
18931
|
-
|
|
19428
|
+
{
|
|
19429
|
+
question: "What happens during withdrawal?",
|
|
19430
|
+
answer: "During withdrawal, you may receive either or both tokens depending on market conditions and prevailing prices."
|
|
19431
|
+
},
|
|
19432
|
+
{
|
|
19433
|
+
question: "Is the strategy audited?",
|
|
19434
|
+
answer: /* @__PURE__ */ jsxs2("div", { children: [
|
|
19435
|
+
"Yes, the strategy has been audited. You can review the audit report in our docs ",
|
|
19436
|
+
/* @__PURE__ */ jsx2("a", { href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details", style: { textDecoration: "underline", marginLeft: "5px" }, children: "Here" }),
|
|
19437
|
+
"."
|
|
19438
|
+
] })
|
|
19439
|
+
}
|
|
19440
|
+
];
|
|
19441
|
+
var EkuboCLVaultStrategies = [
|
|
19442
|
+
{
|
|
19443
|
+
name: "Ekubo xSTRK/STRK",
|
|
19444
|
+
description: /* @__PURE__ */ jsxs2("div", { children: [
|
|
19445
|
+
/* @__PURE__ */ jsx2("p", { children: _description2.replace("{{POOL_NAME}}", "xSTRK/STRK") }),
|
|
19446
|
+
/* @__PURE__ */ jsxs2(
|
|
19447
|
+
"ul",
|
|
19448
|
+
{
|
|
19449
|
+
style: {
|
|
19450
|
+
marginLeft: "20px",
|
|
19451
|
+
listStyle: "circle",
|
|
19452
|
+
fontSize: "12px"
|
|
19453
|
+
},
|
|
19454
|
+
children: [
|
|
19455
|
+
/* @__PURE__ */ jsx2("li", { style: { marginTop: "10px" }, children: "During withdrawal, you may receive either or both tokens depending on market conditions and prevailing prices." }),
|
|
19456
|
+
/* @__PURE__ */ jsx2("li", { style: { marginTop: "10px" }, children: "Sometimes you might see a negative APY \u2014 this is usually not a big deal. It happens when xSTRK's price drops on DEXes, but things typically bounce back within a few days or a week." })
|
|
19457
|
+
]
|
|
19458
|
+
}
|
|
19459
|
+
)
|
|
19460
|
+
] }),
|
|
19461
|
+
address: ContractAddr.from(
|
|
19462
|
+
"0x01f083b98674bc21effee29ef443a00c7b9a500fd92cf30341a3da12c73f2324"
|
|
19463
|
+
),
|
|
19464
|
+
type: "Other",
|
|
19465
|
+
// must be same order as poolKey token0 and token1
|
|
19466
|
+
depositTokens: [
|
|
19467
|
+
Global.getDefaultTokens().find((t) => t.symbol === "xSTRK"),
|
|
19468
|
+
Global.getDefaultTokens().find((t) => t.symbol === "STRK")
|
|
19469
|
+
],
|
|
19470
|
+
protocols: [_protocol2],
|
|
19471
|
+
auditUrl: AUDIT_URL2,
|
|
19472
|
+
maxTVL: Web3Number.fromWei("0", 18),
|
|
19473
|
+
risk: {
|
|
19474
|
+
riskFactor: _riskFactor2,
|
|
19475
|
+
netRisk: _riskFactor2.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor2.reduce((acc, curr) => acc + curr.weight, 0),
|
|
19476
|
+
notARisks: getNoRiskTags(_riskFactor2)
|
|
18932
19477
|
},
|
|
18933
|
-
|
|
18934
|
-
|
|
19478
|
+
apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
|
|
19479
|
+
additionalInfo: {
|
|
19480
|
+
newBounds: {
|
|
19481
|
+
lower: -1,
|
|
19482
|
+
upper: 1
|
|
19483
|
+
},
|
|
19484
|
+
lstContract: ContractAddr.from(
|
|
19485
|
+
"0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
|
|
19486
|
+
),
|
|
19487
|
+
feeBps: 1e3
|
|
19488
|
+
},
|
|
19489
|
+
faqs: [
|
|
19490
|
+
...faqs2,
|
|
19491
|
+
{
|
|
19492
|
+
question: "Why might I see a negative APY?",
|
|
19493
|
+
answer: "A negative APY can occur when xSTRK's price drops on DEXes. This is usually temporary and tends to recover within a few days or a week."
|
|
19494
|
+
}
|
|
19495
|
+
]
|
|
18935
19496
|
}
|
|
18936
|
-
|
|
19497
|
+
];
|
|
18937
19498
|
export {
|
|
18938
19499
|
AutoCompounderSTRK,
|
|
18939
19500
|
AvnuWrapper,
|