@strkfarm/sdk 1.0.21 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +53 -28
- package/dist/cli.mjs +53 -28
- package/dist/index.browser.global.js +60 -38
- package/dist/index.browser.mjs +60 -38
- package/dist/index.d.ts +4 -2
- package/dist/index.js +60 -38
- package/dist/index.mjs +60 -38
- package/package.json +2 -1
- package/src/dataTypes/_bignumber.ts +11 -7
- package/src/interfaces/common.ts +2 -1
- package/src/strategies/ekubo-cl-vault.ts +2 -1
- package/src/strategies/vesu-rebalance.ts +48 -31
package/dist/index.mjs
CHANGED
|
@@ -18,26 +18,26 @@ var _Web3Number = class extends BigNumber {
|
|
|
18
18
|
return this.mul(10 ** this.decimals).toFixed(0);
|
|
19
19
|
}
|
|
20
20
|
multipliedBy(value) {
|
|
21
|
-
let _value = Number(value).toFixed(
|
|
21
|
+
let _value = Number(value).toFixed(this.maxToFixedDecimals());
|
|
22
22
|
return this.construct(this.mul(_value).toString(), this.decimals);
|
|
23
23
|
}
|
|
24
24
|
dividedBy(value) {
|
|
25
|
-
let _value = Number(value).toFixed(
|
|
25
|
+
let _value = Number(value).toFixed(this.maxToFixedDecimals());
|
|
26
26
|
return this.construct(this.div(_value).toString(), this.decimals);
|
|
27
27
|
}
|
|
28
28
|
plus(value) {
|
|
29
|
-
const _value = Number(value).toFixed(
|
|
29
|
+
const _value = Number(value).toFixed(this.maxToFixedDecimals());
|
|
30
30
|
return this.construct(this.add(_value).toString(), this.decimals);
|
|
31
31
|
}
|
|
32
32
|
minus(n, base) {
|
|
33
|
-
const _value = Number(n).toFixed(
|
|
33
|
+
const _value = Number(n).toFixed(this.maxToFixedDecimals());
|
|
34
34
|
return this.construct(super.minus(_value, base).toString(), this.decimals);
|
|
35
35
|
}
|
|
36
36
|
construct(value, decimals) {
|
|
37
37
|
return new this.constructor(value, decimals);
|
|
38
38
|
}
|
|
39
|
-
toString(
|
|
40
|
-
return super.
|
|
39
|
+
toString(decimals = this.maxToFixedDecimals()) {
|
|
40
|
+
return super.toFixed(decimals);
|
|
41
41
|
}
|
|
42
42
|
toJSON() {
|
|
43
43
|
return this.toString();
|
|
@@ -45,6 +45,9 @@ var _Web3Number = class extends BigNumber {
|
|
|
45
45
|
valueOf() {
|
|
46
46
|
return this.toString();
|
|
47
47
|
}
|
|
48
|
+
maxToFixedDecimals() {
|
|
49
|
+
return Math.min(this.decimals, 13);
|
|
50
|
+
}
|
|
48
51
|
};
|
|
49
52
|
BigNumber.config({ DECIMAL_PLACES: 18 });
|
|
50
53
|
_Web3Number.config({ DECIMAL_PLACES: 18 });
|
|
@@ -3730,7 +3733,9 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
3730
3733
|
const totalAssets = (await this.getTVL()).amount;
|
|
3731
3734
|
const info = allowedPools.map(async (p) => {
|
|
3732
3735
|
const vesuPosition = vesuPositions.find((d) => d.pool.id.toString() === num2.getDecimalString(p.pool_id.address.toString()));
|
|
3733
|
-
const pool = pools.find((d) =>
|
|
3736
|
+
const pool = pools.find((d) => {
|
|
3737
|
+
return d.id == num2.getDecimalString(p.pool_id.address.toString());
|
|
3738
|
+
});
|
|
3734
3739
|
const assetInfo = pool?.assets.find((d) => this.asset().address.eqString(d.address));
|
|
3735
3740
|
let vTokenContract = new Contract4(vesu_rebalance_abi_default, p.v_token.address, this.config.provider);
|
|
3736
3741
|
const bal = await vTokenContract.balanceOf(this.address.address);
|
|
@@ -3778,11 +3783,13 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
3778
3783
|
* Calculates the weighted average APY across all pools based on USD value.
|
|
3779
3784
|
* @returns {Promise<number>} The weighted average APY across all pools
|
|
3780
3785
|
*/
|
|
3781
|
-
netAPYGivenPools(pools) {
|
|
3782
|
-
const
|
|
3786
|
+
async netAPYGivenPools(pools) {
|
|
3787
|
+
const weightedApyNumerator = pools.reduce((acc, curr) => {
|
|
3783
3788
|
const weight = curr.current_weight;
|
|
3784
|
-
return acc + curr.APY.netApy *
|
|
3789
|
+
return acc + curr.APY.netApy * Number(curr.amount.toString());
|
|
3785
3790
|
}, 0);
|
|
3791
|
+
const totalAssets = (await this.getTVL()).amount;
|
|
3792
|
+
const weightedApy = weightedApyNumerator / Number(totalAssets.toString());
|
|
3786
3793
|
return weightedApy * (1 - this.metadata.additionalInfo.feeBps / 1e4);
|
|
3787
3794
|
}
|
|
3788
3795
|
/**
|
|
@@ -3811,14 +3818,21 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
3811
3818
|
finalPools: []
|
|
3812
3819
|
};
|
|
3813
3820
|
const sumPools = pools.reduce((acc, curr) => acc.plus(curr.amount.toString()), Web3Number.fromWei("0", this.decimals()));
|
|
3814
|
-
|
|
3821
|
+
logger.verbose(`Sum of pools: ${sumPools.toString()}`);
|
|
3822
|
+
logger.verbose(`Total assets: ${totalAssets.toString()}`);
|
|
3823
|
+
assert(sumPools.lte(totalAssets.multipliedBy(1.00001).toString()), "Sum of pools.amount must be less than or equal to totalAssets");
|
|
3815
3824
|
const sortedPools = [...pools].sort((a, b) => b.APY.netApy - a.APY.netApy);
|
|
3816
3825
|
const targetAmounts = {};
|
|
3817
3826
|
let remainingAssets = totalAssets;
|
|
3827
|
+
logger.verbose(`Remaining assets: ${remainingAssets.toString()}`);
|
|
3818
3828
|
let isAnyPoolOverMaxWeight = false;
|
|
3819
3829
|
for (const pool of sortedPools) {
|
|
3820
|
-
const maxAmount = totalAssets.multipliedBy(pool.max_weight * 0.
|
|
3830
|
+
const maxAmount = totalAssets.multipliedBy(pool.max_weight * 0.98);
|
|
3821
3831
|
const targetAmount = remainingAssets.gte(maxAmount) ? maxAmount : remainingAssets;
|
|
3832
|
+
logger.verbose(`Target amount: ${targetAmount.toString()}`);
|
|
3833
|
+
logger.verbose(`Remaining assets: ${remainingAssets.toString()}`);
|
|
3834
|
+
logger.verbose(`Max amount: ${maxAmount.toString()}`);
|
|
3835
|
+
logger.verbose(`pool.max_weight: ${pool.max_weight}`);
|
|
3822
3836
|
targetAmounts[pool.pool_id.address.toString()] = targetAmount;
|
|
3823
3837
|
remainingAssets = remainingAssets.minus(targetAmount.toString());
|
|
3824
3838
|
if (pool.current_weight > pool.max_weight) {
|
|
@@ -3836,11 +3850,15 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
3836
3850
|
isDeposit: change.gt(0)
|
|
3837
3851
|
};
|
|
3838
3852
|
});
|
|
3853
|
+
logger.verbose(`Changes: ${JSON.stringify(changes)}`);
|
|
3839
3854
|
const sumChanges = changes.reduce((sum, c) => sum.plus(c.changeAmt.toString()), Web3Number.fromWei("0", this.decimals()));
|
|
3840
3855
|
const sumFinal = changes.reduce((sum, c) => sum.plus(c.finalAmt.toString()), Web3Number.fromWei("0", this.decimals()));
|
|
3841
3856
|
const hasChanges = changes.some((c) => !c.changeAmt.eq(0));
|
|
3842
3857
|
if (!sumChanges.eq(0)) throw new Error("Sum of changes must be zero");
|
|
3843
|
-
|
|
3858
|
+
logger.verbose(`Sum of changes: ${sumChanges.toString()}`);
|
|
3859
|
+
logger.verbose(`Sum of final: ${sumFinal.toString()}`);
|
|
3860
|
+
logger.verbose(`Total assets: ${totalAssets.toString()}`);
|
|
3861
|
+
if (!sumFinal.eq(totalAssets.toString())) throw new Error("Sum of final amounts must equal total assets");
|
|
3844
3862
|
if (!hasChanges) throw new Error("No changes required");
|
|
3845
3863
|
const finalPools = pools.map((p) => {
|
|
3846
3864
|
const target = targetAmounts[p.pool_id.address.toString()] || Web3Number.fromWei("0", this.decimals());
|
|
@@ -3864,13 +3882,12 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
3864
3882
|
async getRebalanceCall(pools, isOverWeightAdjustment) {
|
|
3865
3883
|
const actions = [];
|
|
3866
3884
|
pools.sort((a, b) => b.isDeposit ? -1 : 1);
|
|
3867
|
-
console.log("pools", pools);
|
|
3868
3885
|
pools.forEach((p) => {
|
|
3869
3886
|
if (p.changeAmt.eq(0)) return null;
|
|
3870
3887
|
actions.push({
|
|
3871
3888
|
pool_id: p.pool_id.address,
|
|
3872
3889
|
feature: new CairoCustomEnum(p.isDeposit ? { DEPOSIT: {} } : { WITHDRAW: {} }),
|
|
3873
|
-
token: this.asset().address,
|
|
3890
|
+
token: this.asset().address.address,
|
|
3874
3891
|
amount: uint2563.bnToUint256(p.changeAmt.multipliedBy(p.isDeposit ? 1 : -1).toWei())
|
|
3875
3892
|
});
|
|
3876
3893
|
});
|
|
@@ -3881,7 +3898,7 @@ var VesuRebalance = class _VesuRebalance extends BaseStrategy {
|
|
|
3881
3898
|
return this.contract.populate("rebalance", [actions]);
|
|
3882
3899
|
}
|
|
3883
3900
|
async getInvestmentFlows(pools) {
|
|
3884
|
-
const netYield = this.netAPYGivenPools(pools);
|
|
3901
|
+
const netYield = await this.netAPYGivenPools(pools);
|
|
3885
3902
|
const baseFlow = {
|
|
3886
3903
|
title: "Your Deposit",
|
|
3887
3904
|
subItems: [{ key: `Net yield`, value: `${(netYield * 100).toFixed(2)}%` }],
|
|
@@ -3916,7 +3933,7 @@ var AUDIT_URL = "https://assets.strkfarm.com/strkfarm/audit_report_vesu_and_ekub
|
|
|
3916
3933
|
var VesuRebalanceStrategies = [{
|
|
3917
3934
|
name: "Vesu Fusion STRK",
|
|
3918
3935
|
description: _description.replace("{{TOKEN}}", "STRK"),
|
|
3919
|
-
address: ContractAddr.from("
|
|
3936
|
+
address: ContractAddr.from("0x7fb5bcb8525954a60fde4e8fb8220477696ce7117ef264775a1770e23571929"),
|
|
3920
3937
|
type: "ERC4626",
|
|
3921
3938
|
depositTokens: [Global.getDefaultTokens().find((t) => t.symbol === "STRK")],
|
|
3922
3939
|
protocols: [_protocol],
|
|
@@ -3924,7 +3941,8 @@ var VesuRebalanceStrategies = [{
|
|
|
3924
3941
|
maxTVL: Web3Number.fromWei("0", 18),
|
|
3925
3942
|
risk: {
|
|
3926
3943
|
riskFactor: _riskFactor,
|
|
3927
|
-
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0)
|
|
3944
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
3945
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
3928
3946
|
},
|
|
3929
3947
|
additionalInfo: {
|
|
3930
3948
|
feeBps: 1e3
|
|
@@ -3932,7 +3950,7 @@ var VesuRebalanceStrategies = [{
|
|
|
3932
3950
|
}, {
|
|
3933
3951
|
name: "Vesu Fusion ETH",
|
|
3934
3952
|
description: _description.replace("{{TOKEN}}", "ETH"),
|
|
3935
|
-
address: ContractAddr.from("
|
|
3953
|
+
address: ContractAddr.from("0x5eaf5ee75231cecf79921ff8ded4b5ffe96be718bcb3daf206690ad1a9ad0ca"),
|
|
3936
3954
|
type: "ERC4626",
|
|
3937
3955
|
auditUrl: AUDIT_URL,
|
|
3938
3956
|
depositTokens: [Global.getDefaultTokens().find((t) => t.symbol === "ETH")],
|
|
@@ -3940,7 +3958,8 @@ var VesuRebalanceStrategies = [{
|
|
|
3940
3958
|
maxTVL: Web3Number.fromWei("0", 18),
|
|
3941
3959
|
risk: {
|
|
3942
3960
|
riskFactor: _riskFactor,
|
|
3943
|
-
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0)
|
|
3961
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
3962
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
3944
3963
|
},
|
|
3945
3964
|
additionalInfo: {
|
|
3946
3965
|
feeBps: 1e3
|
|
@@ -3948,7 +3967,7 @@ var VesuRebalanceStrategies = [{
|
|
|
3948
3967
|
}, {
|
|
3949
3968
|
name: "Vesu Fusion USDC",
|
|
3950
3969
|
description: _description.replace("{{TOKEN}}", "USDC"),
|
|
3951
|
-
address: ContractAddr.from("
|
|
3970
|
+
address: ContractAddr.from("0xa858c97e9454f407d1bd7c57472fc8d8d8449a777c822b41d18e387816f29c"),
|
|
3952
3971
|
type: "ERC4626",
|
|
3953
3972
|
auditUrl: AUDIT_URL,
|
|
3954
3973
|
depositTokens: [Global.getDefaultTokens().find((t) => t.symbol === "USDC")],
|
|
@@ -3956,26 +3975,28 @@ var VesuRebalanceStrategies = [{
|
|
|
3956
3975
|
maxTVL: Web3Number.fromWei("0", 6),
|
|
3957
3976
|
risk: {
|
|
3958
3977
|
riskFactor: _riskFactor,
|
|
3959
|
-
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0)
|
|
3978
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
3979
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
3980
|
+
},
|
|
3981
|
+
additionalInfo: {
|
|
3982
|
+
feeBps: 1e3
|
|
3983
|
+
}
|
|
3984
|
+
}, {
|
|
3985
|
+
name: "Vesu Fusion USDT",
|
|
3986
|
+
description: _description.replace("{{TOKEN}}", "USDT"),
|
|
3987
|
+
address: ContractAddr.from("0x115e94e722cfc4c77a2f15c4aefb0928c1c0029e5a57570df24c650cb7cec2c"),
|
|
3988
|
+
type: "ERC4626",
|
|
3989
|
+
depositTokens: [Global.getDefaultTokens().find((t) => t.symbol === "USDT")],
|
|
3990
|
+
protocols: [_protocol],
|
|
3991
|
+
maxTVL: Web3Number.fromWei("0", 6),
|
|
3992
|
+
risk: {
|
|
3993
|
+
riskFactor: _riskFactor,
|
|
3994
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
3995
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
3960
3996
|
},
|
|
3961
3997
|
additionalInfo: {
|
|
3962
3998
|
feeBps: 1e3
|
|
3963
3999
|
}
|
|
3964
|
-
// }, {
|
|
3965
|
-
// name: 'Vesu Fusion USDT',
|
|
3966
|
-
// description: _description.replace('{{TOKEN}}', 'USDT'),
|
|
3967
|
-
// address: ContractAddr.from('0x778007f8136a5b827325d21613803e796bda4d676fbe1e34aeab0b2a2ec027f'),
|
|
3968
|
-
// type: 'ERC4626',
|
|
3969
|
-
// depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'USDT')!],
|
|
3970
|
-
// protocols: [_protocol],
|
|
3971
|
-
// maxTVL: Web3Number.fromWei('0', 6),
|
|
3972
|
-
// risk: {
|
|
3973
|
-
// riskFactor: _riskFactor,
|
|
3974
|
-
// netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
3975
|
-
// },
|
|
3976
|
-
// additionalInfo: {
|
|
3977
|
-
// feeBps: 1000,
|
|
3978
|
-
// },
|
|
3979
4000
|
// }, {
|
|
3980
4001
|
// name: 'Vesu Fusion WBTC',
|
|
3981
4002
|
// description: _description.replace('{{TOKEN}}', 'WBTC'),
|
|
@@ -9274,7 +9295,8 @@ var EkuboCLVaultStrategies = [{
|
|
|
9274
9295
|
maxTVL: Web3Number.fromWei("0", 18),
|
|
9275
9296
|
risk: {
|
|
9276
9297
|
riskFactor: _riskFactor2,
|
|
9277
|
-
netRisk: _riskFactor2.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor2.reduce((acc, curr) => acc + curr.weight, 0)
|
|
9298
|
+
netRisk: _riskFactor2.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor2.reduce((acc, curr) => acc + curr.weight, 0),
|
|
9299
|
+
notARisks: getNoRiskTags(_riskFactor2)
|
|
9278
9300
|
},
|
|
9279
9301
|
additionalInfo: {
|
|
9280
9302
|
newBounds: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strkfarm/sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.23",
|
|
4
4
|
"description": "STRKFarm TS SDK (Meant for our internal use, but feel free to use it)",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"browser-assert": "^1.2.1",
|
|
57
57
|
"chalk": "^4.1.2",
|
|
58
58
|
"commander": "^12.1.0",
|
|
59
|
+
"ethers": "^6.13.5",
|
|
59
60
|
"form-data": "^4.0.2",
|
|
60
61
|
"inquirer": "^10.1.2",
|
|
61
62
|
"node-telegram-bot-api": "^0.66.0",
|
|
@@ -13,22 +13,22 @@ export class _Web3Number<T extends _Web3Number<T>> extends BigNumber {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
multipliedBy(value: string | number | T): T {
|
|
16
|
-
let _value = Number(value).toFixed(
|
|
16
|
+
let _value = Number(value).toFixed(this.maxToFixedDecimals());
|
|
17
17
|
return this.construct(this.mul(_value).toString(), this.decimals);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
dividedBy(value: string | number | T): T {
|
|
21
|
-
let _value = Number(value).toFixed(
|
|
21
|
+
let _value = Number(value).toFixed(this.maxToFixedDecimals());
|
|
22
22
|
return this.construct(this.div(_value).toString(), this.decimals);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
plus(value: string | number | T): T {
|
|
26
|
-
const _value = Number(value).toFixed(
|
|
26
|
+
const _value = Number(value).toFixed(this.maxToFixedDecimals());
|
|
27
27
|
return this.construct(this.add(_value).toString(), this.decimals);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
minus(n: number | string | T, base?: number): T {
|
|
31
|
-
const _value = Number(n).toFixed(
|
|
31
|
+
const _value = Number(n).toFixed(this.maxToFixedDecimals());
|
|
32
32
|
return this.construct(super.minus(_value, base).toString(), this.decimals);
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -36,10 +36,10 @@ export class _Web3Number<T extends _Web3Number<T>> extends BigNumber {
|
|
|
36
36
|
return new (this.constructor as { new (value: string | number, decimals: number): T })(value, decimals);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
toString(
|
|
40
|
-
return super.
|
|
39
|
+
toString(decimals: number | undefined = this.maxToFixedDecimals()): string {
|
|
40
|
+
return super.toFixed(decimals);
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
toJSON() {
|
|
44
44
|
return this.toString();
|
|
45
45
|
}
|
|
@@ -47,6 +47,10 @@ export class _Web3Number<T extends _Web3Number<T>> extends BigNumber {
|
|
|
47
47
|
valueOf() {
|
|
48
48
|
return this.toString();
|
|
49
49
|
}
|
|
50
|
+
|
|
51
|
+
private maxToFixedDecimals() {
|
|
52
|
+
return Math.min(this.decimals, 13);
|
|
53
|
+
}
|
|
50
54
|
}
|
|
51
55
|
|
|
52
56
|
BigNumber.config({ DECIMAL_PLACES: 18 })
|
package/src/interfaces/common.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
2
|
-
import { IConfig, IProtocol, IStrategyMetadata, RiskFactor, RiskType } from "@/interfaces";
|
|
2
|
+
import { getNoRiskTags, IConfig, IProtocol, IStrategyMetadata, RiskFactor, RiskType } from "@/interfaces";
|
|
3
3
|
import { PricerBase } from "@/modules/pricerBase";
|
|
4
4
|
import { assert } from "@/utils";
|
|
5
5
|
import { Call, Contract, uint256 } from "starknet";
|
|
@@ -524,6 +524,7 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
|
|
|
524
524
|
risk: {
|
|
525
525
|
riskFactor: _riskFactor,
|
|
526
526
|
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
527
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
527
528
|
},
|
|
528
529
|
additionalInfo: {
|
|
529
530
|
newBounds: {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
2
|
-
import { FlowChartColors, IConfig, IInvestmentFlow, IProtocol, IStrategyMetadata, RiskFactor, RiskType } from "@/interfaces";
|
|
2
|
+
import { FlowChartColors, getNoRiskTags, IConfig, IInvestmentFlow, IProtocol, IStrategyMetadata, RiskFactor, RiskType } from "@/interfaces";
|
|
3
3
|
import { Pricer } from "@/modules";
|
|
4
4
|
import { CairoCustomEnum, Contract, num, uint256 } from "starknet";
|
|
5
5
|
import VesuRebalanceAbi from '@/data/vesu-rebalance.abi.json';
|
|
6
|
-
import { Global } from "@/global";
|
|
6
|
+
import { Global, logger } from "@/global";
|
|
7
7
|
import { assert } from "@/utils";
|
|
8
8
|
import axios from "axios";
|
|
9
9
|
import { PricerBase } from "@/modules/pricerBase";
|
|
@@ -264,7 +264,9 @@ export class VesuRebalance extends BaseStrategy<SingleTokenInfo, SingleActionAmo
|
|
|
264
264
|
|
|
265
265
|
const info = allowedPools.map(async (p) => {
|
|
266
266
|
const vesuPosition = vesuPositions.find((d: any) => d.pool.id.toString() === num.getDecimalString(p.pool_id.address.toString()));
|
|
267
|
-
const pool = pools.find((d: any) =>
|
|
267
|
+
const pool = pools.find((d: any) => {
|
|
268
|
+
return d.id == num.getDecimalString(p.pool_id.address.toString());
|
|
269
|
+
});
|
|
268
270
|
const assetInfo = pool?.assets.find((d: any) => this.asset().address.eqString(d.address));
|
|
269
271
|
let vTokenContract = new Contract(VesuRebalanceAbi, p.v_token.address, this.config.provider);
|
|
270
272
|
const bal = await vTokenContract.balanceOf(this.address.address);
|
|
@@ -314,12 +316,13 @@ export class VesuRebalance extends BaseStrategy<SingleTokenInfo, SingleActionAmo
|
|
|
314
316
|
* Calculates the weighted average APY across all pools based on USD value.
|
|
315
317
|
* @returns {Promise<number>} The weighted average APY across all pools
|
|
316
318
|
*/
|
|
317
|
-
netAPYGivenPools(pools: PoolInfoFull[]): number {
|
|
318
|
-
const
|
|
319
|
+
async netAPYGivenPools(pools: PoolInfoFull[]): Promise<number> {
|
|
320
|
+
const weightedApyNumerator = pools.reduce((acc: number, curr) => {
|
|
319
321
|
const weight = curr.current_weight;
|
|
320
|
-
return acc + (curr.APY.netApy *
|
|
322
|
+
return acc + (curr.APY.netApy * Number(curr.amount.toString()));
|
|
321
323
|
}, 0);
|
|
322
|
-
|
|
324
|
+
const totalAssets = (await this.getTVL()).amount;
|
|
325
|
+
const weightedApy = weightedApyNumerator / Number(totalAssets.toString());
|
|
323
326
|
return weightedApy * (1 - (this.metadata.additionalInfo.feeBps / 10000));
|
|
324
327
|
}
|
|
325
328
|
|
|
@@ -351,18 +354,25 @@ export class VesuRebalance extends BaseStrategy<SingleTokenInfo, SingleActionAmo
|
|
|
351
354
|
|
|
352
355
|
// assert sum of pools.amount <= totalAssets
|
|
353
356
|
const sumPools = pools.reduce((acc, curr) => acc.plus(curr.amount.toString()), Web3Number.fromWei("0", this.decimals()));
|
|
354
|
-
|
|
357
|
+
logger.verbose(`Sum of pools: ${sumPools.toString()}`);
|
|
358
|
+
logger.verbose(`Total assets: ${totalAssets.toString()}`);
|
|
359
|
+
assert(sumPools.lte(totalAssets.multipliedBy(1.00001).toString()), 'Sum of pools.amount must be less than or equal to totalAssets');
|
|
355
360
|
|
|
356
361
|
// Sort pools by APY and calculate target amounts
|
|
357
362
|
const sortedPools = [...pools].sort((a, b) => b.APY.netApy - a.APY.netApy);
|
|
358
363
|
const targetAmounts: Record<string, Web3Number> = {};
|
|
359
364
|
let remainingAssets = totalAssets;
|
|
365
|
+
logger.verbose(`Remaining assets: ${remainingAssets.toString()}`);
|
|
360
366
|
|
|
361
367
|
// First pass: Allocate to high APY pools up to their max weight
|
|
362
368
|
let isAnyPoolOverMaxWeight = false;
|
|
363
369
|
for (const pool of sortedPools) {
|
|
364
|
-
const maxAmount = totalAssets.multipliedBy(pool.max_weight * 0.
|
|
370
|
+
const maxAmount = totalAssets.multipliedBy(pool.max_weight * 0.98); // some tolerance
|
|
365
371
|
const targetAmount = remainingAssets.gte(maxAmount) ? maxAmount : remainingAssets;
|
|
372
|
+
logger.verbose(`Target amount: ${targetAmount.toString()}`);
|
|
373
|
+
logger.verbose(`Remaining assets: ${remainingAssets.toString()}`);
|
|
374
|
+
logger.verbose(`Max amount: ${maxAmount.toString()}`);
|
|
375
|
+
logger.verbose(`pool.max_weight: ${pool.max_weight}`);
|
|
366
376
|
targetAmounts[pool.pool_id.address.toString()] = targetAmount;
|
|
367
377
|
remainingAssets = remainingAssets.minus(targetAmount.toString());
|
|
368
378
|
if (pool.current_weight > pool.max_weight) {
|
|
@@ -384,13 +394,17 @@ export class VesuRebalance extends BaseStrategy<SingleTokenInfo, SingleActionAmo
|
|
|
384
394
|
};
|
|
385
395
|
});
|
|
386
396
|
|
|
397
|
+
logger.verbose(`Changes: ${JSON.stringify(changes)}`);
|
|
387
398
|
// Validate changes
|
|
388
399
|
const sumChanges = changes.reduce((sum, c) => sum.plus(c.changeAmt.toString()), Web3Number.fromWei("0", this.decimals()));
|
|
389
400
|
const sumFinal = changes.reduce((sum, c) => sum.plus(c.finalAmt.toString()), Web3Number.fromWei("0", this.decimals()));
|
|
390
401
|
const hasChanges = changes.some(c => !c.changeAmt.eq(0));
|
|
391
402
|
|
|
392
403
|
if (!sumChanges.eq(0)) throw new Error('Sum of changes must be zero');
|
|
393
|
-
|
|
404
|
+
logger.verbose(`Sum of changes: ${sumChanges.toString()}`);
|
|
405
|
+
logger.verbose(`Sum of final: ${sumFinal.toString()}`);
|
|
406
|
+
logger.verbose(`Total assets: ${totalAssets.toString()}`);
|
|
407
|
+
if (!sumFinal.eq(totalAssets.toString())) throw new Error('Sum of final amounts must equal total assets');
|
|
394
408
|
if (!hasChanges) throw new Error('No changes required');
|
|
395
409
|
|
|
396
410
|
const finalPools: PoolInfoFull[] = pools.map((p) => {
|
|
@@ -420,13 +434,12 @@ export class VesuRebalance extends BaseStrategy<SingleTokenInfo, SingleActionAmo
|
|
|
420
434
|
const actions: any[] = [];
|
|
421
435
|
// sort to put withdrawals first
|
|
422
436
|
pools.sort((a, b) => b.isDeposit ? -1 : 1);
|
|
423
|
-
console.log('pools', pools);
|
|
424
437
|
pools.forEach((p) => {
|
|
425
438
|
if (p.changeAmt.eq(0)) return null;
|
|
426
439
|
actions.push({
|
|
427
440
|
pool_id: p.pool_id.address,
|
|
428
441
|
feature: new CairoCustomEnum(p.isDeposit ? {DEPOSIT: {}} : {WITHDRAW: {}}),
|
|
429
|
-
token: this.asset().address,
|
|
442
|
+
token: this.asset().address.address,
|
|
430
443
|
amount: uint256.bnToUint256(p.changeAmt.multipliedBy(p.isDeposit ? 1 : -1).toWei()),
|
|
431
444
|
});
|
|
432
445
|
});
|
|
@@ -438,7 +451,7 @@ export class VesuRebalance extends BaseStrategy<SingleTokenInfo, SingleActionAmo
|
|
|
438
451
|
}
|
|
439
452
|
|
|
440
453
|
async getInvestmentFlows(pools: PoolInfoFull[]) {
|
|
441
|
-
const netYield = this.netAPYGivenPools(pools);
|
|
454
|
+
const netYield = await this.netAPYGivenPools(pools);
|
|
442
455
|
|
|
443
456
|
const baseFlow: IInvestmentFlow = {
|
|
444
457
|
title: "Your Deposit",
|
|
@@ -480,7 +493,7 @@ const AUDIT_URL = 'https://assets.strkfarm.com/strkfarm/audit_report_vesu_and_ek
|
|
|
480
493
|
export const VesuRebalanceStrategies: IStrategyMetadata<VesuRebalanceSettings>[] = [{
|
|
481
494
|
name: 'Vesu Fusion STRK',
|
|
482
495
|
description: _description.replace('{{TOKEN}}', 'STRK'),
|
|
483
|
-
address: ContractAddr.from('
|
|
496
|
+
address: ContractAddr.from('0x7fb5bcb8525954a60fde4e8fb8220477696ce7117ef264775a1770e23571929'),
|
|
484
497
|
type: 'ERC4626',
|
|
485
498
|
depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'STRK')!],
|
|
486
499
|
protocols: [_protocol],
|
|
@@ -489,6 +502,7 @@ export const VesuRebalanceStrategies: IStrategyMetadata<VesuRebalanceSettings>[]
|
|
|
489
502
|
risk: {
|
|
490
503
|
riskFactor: _riskFactor,
|
|
491
504
|
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
505
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
492
506
|
},
|
|
493
507
|
additionalInfo: {
|
|
494
508
|
feeBps: 1000,
|
|
@@ -496,7 +510,7 @@ export const VesuRebalanceStrategies: IStrategyMetadata<VesuRebalanceSettings>[]
|
|
|
496
510
|
}, {
|
|
497
511
|
name: 'Vesu Fusion ETH',
|
|
498
512
|
description: _description.replace('{{TOKEN}}', 'ETH'),
|
|
499
|
-
address: ContractAddr.from('
|
|
513
|
+
address: ContractAddr.from('0x5eaf5ee75231cecf79921ff8ded4b5ffe96be718bcb3daf206690ad1a9ad0ca'),
|
|
500
514
|
type: 'ERC4626',
|
|
501
515
|
auditUrl: AUDIT_URL,
|
|
502
516
|
depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'ETH')!],
|
|
@@ -505,6 +519,7 @@ export const VesuRebalanceStrategies: IStrategyMetadata<VesuRebalanceSettings>[]
|
|
|
505
519
|
risk: {
|
|
506
520
|
riskFactor: _riskFactor,
|
|
507
521
|
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
522
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
508
523
|
},
|
|
509
524
|
additionalInfo: {
|
|
510
525
|
feeBps: 1000,
|
|
@@ -512,7 +527,7 @@ export const VesuRebalanceStrategies: IStrategyMetadata<VesuRebalanceSettings>[]
|
|
|
512
527
|
}, {
|
|
513
528
|
name: 'Vesu Fusion USDC',
|
|
514
529
|
description: _description.replace('{{TOKEN}}', 'USDC'),
|
|
515
|
-
address: ContractAddr.from('
|
|
530
|
+
address: ContractAddr.from('0xa858c97e9454f407d1bd7c57472fc8d8d8449a777c822b41d18e387816f29c'),
|
|
516
531
|
type: 'ERC4626',
|
|
517
532
|
auditUrl: AUDIT_URL,
|
|
518
533
|
depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'USDC')!],
|
|
@@ -521,25 +536,27 @@ export const VesuRebalanceStrategies: IStrategyMetadata<VesuRebalanceSettings>[]
|
|
|
521
536
|
risk: {
|
|
522
537
|
riskFactor: _riskFactor,
|
|
523
538
|
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
539
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
540
|
+
},
|
|
541
|
+
additionalInfo: {
|
|
542
|
+
feeBps: 1000,
|
|
543
|
+
},
|
|
544
|
+
}, {
|
|
545
|
+
name: 'Vesu Fusion USDT',
|
|
546
|
+
description: _description.replace('{{TOKEN}}', 'USDT'),
|
|
547
|
+
address: ContractAddr.from('0x115e94e722cfc4c77a2f15c4aefb0928c1c0029e5a57570df24c650cb7cec2c'),
|
|
548
|
+
type: 'ERC4626',
|
|
549
|
+
depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'USDT')!],
|
|
550
|
+
protocols: [_protocol],
|
|
551
|
+
maxTVL: Web3Number.fromWei('0', 6),
|
|
552
|
+
risk: {
|
|
553
|
+
riskFactor: _riskFactor,
|
|
554
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
555
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
524
556
|
},
|
|
525
557
|
additionalInfo: {
|
|
526
558
|
feeBps: 1000,
|
|
527
559
|
},
|
|
528
|
-
// }, {
|
|
529
|
-
// name: 'Vesu Fusion USDT',
|
|
530
|
-
// description: _description.replace('{{TOKEN}}', 'USDT'),
|
|
531
|
-
// address: ContractAddr.from('0x778007f8136a5b827325d21613803e796bda4d676fbe1e34aeab0b2a2ec027f'),
|
|
532
|
-
// type: 'ERC4626',
|
|
533
|
-
// depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'USDT')!],
|
|
534
|
-
// protocols: [_protocol],
|
|
535
|
-
// maxTVL: Web3Number.fromWei('0', 6),
|
|
536
|
-
// risk: {
|
|
537
|
-
// riskFactor: _riskFactor,
|
|
538
|
-
// netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
539
|
-
// },
|
|
540
|
-
// additionalInfo: {
|
|
541
|
-
// feeBps: 1000,
|
|
542
|
-
// },
|
|
543
560
|
// }, {
|
|
544
561
|
// name: 'Vesu Fusion WBTC',
|
|
545
562
|
// description: _description.replace('{{TOKEN}}', 'WBTC'),
|