@strkfarm/sdk 1.0.41 → 1.0.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.browser.global.js +1628 -5152
- package/dist/index.browser.mjs +1629 -5153
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1629 -5153
- package/dist/index.mjs +1629 -5153
- package/package.json +1 -1
- package/src/data/vesu_pools.json +5342 -8914
- package/src/modules/avnu.ts +18 -0
- package/src/modules/harvests.ts +10 -1
- package/src/strategies/ekubo-cl-vault.tsx +174 -117
- package/src/strategies/vesu-rebalance.tsx +1 -1
package/src/modules/avnu.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Call, Uint256 } from "starknet";
|
|
|
4
4
|
import { fetchBuildExecuteTransaction, fetchQuotes, Quote } from "@avnu/avnu-sdk";
|
|
5
5
|
import { assert } from "../utils";
|
|
6
6
|
import { logger } from "@/utils/logger";
|
|
7
|
+
import { ContractAddr } from "@/dataTypes";
|
|
7
8
|
|
|
8
9
|
export interface Route {
|
|
9
10
|
token_from: string,
|
|
@@ -109,4 +110,21 @@ export class AvnuWrapper {
|
|
|
109
110
|
|
|
110
111
|
return swapInfo;
|
|
111
112
|
}
|
|
113
|
+
|
|
114
|
+
static buildZeroSwap(
|
|
115
|
+
tokenToSell: ContractAddr,
|
|
116
|
+
address: string
|
|
117
|
+
): SwapInfo {
|
|
118
|
+
return {
|
|
119
|
+
token_from_address: tokenToSell.address,
|
|
120
|
+
token_from_amount: uint256.bnToUint256(0),
|
|
121
|
+
token_to_address: tokenToSell.address,
|
|
122
|
+
token_to_amount: uint256.bnToUint256(0),
|
|
123
|
+
token_to_min_amount: uint256.bnToUint256(0),
|
|
124
|
+
beneficiary: address,
|
|
125
|
+
integrator_fee_amount_bps: 0,
|
|
126
|
+
integrator_fee_recipient: address,
|
|
127
|
+
routes: [],
|
|
128
|
+
};
|
|
129
|
+
}
|
|
112
130
|
}
|
package/src/modules/harvests.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { logger } from "@/utils/logger";
|
|
|
3
3
|
import { IConfig } from "@/interfaces";
|
|
4
4
|
import { assert } from "@/utils";
|
|
5
5
|
import { Contract, num } from "starknet";
|
|
6
|
+
import { ERC20 } from "./erc20";
|
|
6
7
|
|
|
7
8
|
export interface HarvestInfo {
|
|
8
9
|
rewardsContract: ContractAddr,
|
|
@@ -36,8 +37,16 @@ export class Harvests {
|
|
|
36
37
|
const contract = new Contract(cls.abi, reward.rewardsContract.address, this.config.provider);
|
|
37
38
|
const isClaimed = await contract.call('is_claimed', [reward.claim.id]);
|
|
38
39
|
logger.verbose(`${Harvests.name}: isClaimed: ${isClaimed}`);
|
|
39
|
-
if (isClaimed)
|
|
40
|
+
if (isClaimed) {
|
|
40
41
|
return unClaimed;
|
|
42
|
+
}
|
|
43
|
+
// rewards contract must have enough balance to claim
|
|
44
|
+
const bal = await (new ERC20(this.config)).balanceOf(reward.token, reward.rewardsContract.address, 18);
|
|
45
|
+
if (bal.lessThan(reward.claim.amount)) {
|
|
46
|
+
logger.verbose(`${Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
41
50
|
unClaimed.unshift(reward); // to ensure older harvest is first
|
|
42
51
|
}
|
|
43
52
|
return unClaimed;
|
|
@@ -62,6 +62,11 @@ export interface CLVaultStrategySettings {
|
|
|
62
62
|
lstContract?: ContractAddr;
|
|
63
63
|
truePrice?: number; // useful for pools where price is known (e.g. USDC/USDT as 1)
|
|
64
64
|
feeBps: number;
|
|
65
|
+
rebalanceConditions: {
|
|
66
|
+
minWaitHours: number; // number of hours out of range to rebalance
|
|
67
|
+
direction: "any" | "uponly"; // any for pools like USDC/USDT, uponly for pools like xSTRK/STRK
|
|
68
|
+
customShouldRebalance: (currentPoolPrice: number) => Promise<boolean>; // any additional logic for deciding factor to rebalance or not based on pools
|
|
69
|
+
};
|
|
65
70
|
}
|
|
66
71
|
|
|
67
72
|
export class EkuboCLVault extends BaseStrategy<
|
|
@@ -297,7 +302,10 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
297
302
|
? (await this.config.provider.getBlockWithTxs(blockIdentifier))
|
|
298
303
|
.timestamp
|
|
299
304
|
: new Date().getTime() / 1000;
|
|
300
|
-
const blockBefore = Math.max(
|
|
305
|
+
const blockBefore = Math.max(
|
|
306
|
+
blockNow - sinceBlocks,
|
|
307
|
+
this.metadata.launchBlock
|
|
308
|
+
);
|
|
301
309
|
const adjustedSupplyNow = supplyNow.minus(
|
|
302
310
|
await this.getHarvestRewardShares(blockBefore, blockNow)
|
|
303
311
|
);
|
|
@@ -369,7 +377,7 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
369
377
|
blockIdentifier: BlockIdentifier = "pending"
|
|
370
378
|
): Promise<Web3Number> {
|
|
371
379
|
let bal = await this.contract.call("balance_of", [user.address], {
|
|
372
|
-
blockIdentifier
|
|
380
|
+
blockIdentifier,
|
|
373
381
|
});
|
|
374
382
|
return Web3Number.fromWei(bal.toString(), 18);
|
|
375
383
|
}
|
|
@@ -795,7 +803,6 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
795
803
|
ratio: Web3Number,
|
|
796
804
|
price: number
|
|
797
805
|
) {
|
|
798
|
-
|
|
799
806
|
// (amount0 + x) / (amount1 - y) = ratio
|
|
800
807
|
// x = y * Py / Px ---- (1)
|
|
801
808
|
// => (amount0 + y * Py / Px) / (amount1 - y) = ratio
|
|
@@ -809,7 +816,9 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
809
816
|
.dividedBy(ratio.plus(1 / price));
|
|
810
817
|
const x = y.dividedBy(price);
|
|
811
818
|
logger.verbose(
|
|
812
|
-
`${
|
|
819
|
+
`${
|
|
820
|
+
EkuboCLVault.name
|
|
821
|
+
}: _solveExpectedAmountsEq => x: ${x.toString()}, y: ${y.toString()}, amount0: ${availableAmount0.toString()}, amount1: ${availableAmount1.toString()}`
|
|
813
822
|
);
|
|
814
823
|
|
|
815
824
|
if (ratio.eq(0)) {
|
|
@@ -864,7 +873,7 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
864
873
|
tokenInfo: token1Info,
|
|
865
874
|
usdValue: token1PriceUsd,
|
|
866
875
|
},
|
|
867
|
-
}
|
|
876
|
+
};
|
|
868
877
|
}
|
|
869
878
|
|
|
870
879
|
async getSwapInfoToHandleUnused(considerRebalance: boolean = true) {
|
|
@@ -872,8 +881,10 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
872
881
|
|
|
873
882
|
// fetch current unused balances of vault
|
|
874
883
|
const unusedBalances = await this.unusedBalances(poolKey);
|
|
875
|
-
const { amount: token0Bal1, usdValue: token0PriceUsd} =
|
|
876
|
-
|
|
884
|
+
const { amount: token0Bal1, usdValue: token0PriceUsd } =
|
|
885
|
+
unusedBalances.token0;
|
|
886
|
+
const { amount: token1Bal1, usdValue: token1PriceUsd } =
|
|
887
|
+
unusedBalances.token1;
|
|
877
888
|
|
|
878
889
|
// if (token0PriceUsd > 1 && token1PriceUsd > 1) {
|
|
879
890
|
// // the swap is designed to handle one token only.
|
|
@@ -934,8 +945,12 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
934
945
|
bounds: EkuboBounds
|
|
935
946
|
): Promise<SwapInfo> {
|
|
936
947
|
logger.verbose(
|
|
937
|
-
`${
|
|
948
|
+
`${
|
|
949
|
+
EkuboCLVault.name
|
|
950
|
+
}: getSwapInfoGivenAmounts::pre => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
|
|
938
951
|
);
|
|
952
|
+
|
|
953
|
+
// Compute the expected amounts of token0 and token1 for the given liquidity bounds
|
|
939
954
|
let expectedAmounts = await this._getExpectedAmountsForLiquidity(
|
|
940
955
|
token0Bal,
|
|
941
956
|
token1Bal,
|
|
@@ -947,14 +962,16 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
947
962
|
}: getSwapInfoToHandleUnused => expectedAmounts2: ${expectedAmounts.amount0.toString()}, ${expectedAmounts.amount1.toString()}`
|
|
948
963
|
);
|
|
949
964
|
|
|
950
|
-
// get swap info
|
|
951
|
-
// fetch avnu routes to ensure expected amounts
|
|
952
965
|
let retry = 0;
|
|
953
966
|
const maxRetry = 10;
|
|
954
|
-
while (retry < maxRetry) {
|
|
955
|
-
retry++;
|
|
956
|
-
// assert one token is increased and other is decreased
|
|
957
967
|
|
|
968
|
+
// Helper to check for invalid states:
|
|
969
|
+
// Throws if both tokens are decreased or both are increased, which is not expected
|
|
970
|
+
function assertValidAmounts(
|
|
971
|
+
expectedAmounts: any,
|
|
972
|
+
token0Bal: Web3Number,
|
|
973
|
+
token1Bal: Web3Number
|
|
974
|
+
) {
|
|
958
975
|
if (
|
|
959
976
|
expectedAmounts.amount0.lessThan(token0Bal) &&
|
|
960
977
|
expectedAmounts.amount1.lessThan(token1Bal)
|
|
@@ -967,58 +984,75 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
967
984
|
) {
|
|
968
985
|
throw new Error("Both tokens are increased, something is wrong");
|
|
969
986
|
}
|
|
987
|
+
}
|
|
970
988
|
|
|
989
|
+
// Helper to determine which token to sell, which to buy, and the amounts to use
|
|
990
|
+
function getSwapParams(
|
|
991
|
+
expectedAmounts: any,
|
|
992
|
+
poolKey: EkuboPoolKey,
|
|
993
|
+
token0Bal: Web3Number,
|
|
994
|
+
token1Bal: Web3Number
|
|
995
|
+
) {
|
|
996
|
+
// Decide which token to sell based on which expected amount is less than the balance
|
|
971
997
|
const tokenToSell = expectedAmounts.amount0.lessThan(token0Bal)
|
|
972
998
|
? poolKey.token0
|
|
973
999
|
: poolKey.token1;
|
|
1000
|
+
// The other token is the one to buy
|
|
974
1001
|
const tokenToBuy =
|
|
975
1002
|
tokenToSell == poolKey.token0 ? poolKey.token1 : poolKey.token0;
|
|
976
|
-
|
|
1003
|
+
// Calculate how much to sell
|
|
1004
|
+
const amountToSell =
|
|
977
1005
|
tokenToSell == poolKey.token0
|
|
978
1006
|
? token0Bal.minus(expectedAmounts.amount0)
|
|
979
1007
|
: token1Bal.minus(expectedAmounts.amount1);
|
|
1008
|
+
// The remaining amount of the sold token after swap
|
|
980
1009
|
const remainingSellAmount =
|
|
981
1010
|
tokenToSell == poolKey.token0
|
|
982
1011
|
? expectedAmounts.amount0
|
|
983
1012
|
: expectedAmounts.amount1;
|
|
984
|
-
|
|
985
|
-
|
|
1013
|
+
return { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount };
|
|
1014
|
+
}
|
|
986
1015
|
|
|
1016
|
+
// Main retry loop: attempts to find a swap that matches the expected ratio within tolerance
|
|
1017
|
+
while (retry < maxRetry) {
|
|
1018
|
+
retry++;
|
|
987
1019
|
logger.verbose(
|
|
988
|
-
|
|
989
|
-
tokenToSell.address
|
|
990
|
-
}, tokenToBuy: ${
|
|
991
|
-
tokenToBuy.address
|
|
992
|
-
}, amountToSell: ${amountToSell.toWei()}`
|
|
993
|
-
);
|
|
994
|
-
logger.verbose(
|
|
995
|
-
`${
|
|
996
|
-
EkuboCLVault.name
|
|
997
|
-
}: getSwapInfoToHandleUnused => remainingSellAmount: ${remainingSellAmount.toString()}`
|
|
998
|
-
);
|
|
999
|
-
logger.verbose(
|
|
1000
|
-
`${EkuboCLVault.name}: getSwapInfoToHandleUnused => expectedRatio: ${expectedRatio}`
|
|
1020
|
+
`getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
|
|
1001
1021
|
);
|
|
1002
1022
|
|
|
1023
|
+
// Ensure the expected amounts are valid for swap logic
|
|
1024
|
+
assertValidAmounts(expectedAmounts, token0Bal, token1Bal);
|
|
1025
|
+
|
|
1026
|
+
// Get swap parameters for this iteration
|
|
1027
|
+
const { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount } =
|
|
1028
|
+
getSwapParams(expectedAmounts, poolKey, token0Bal, token1Bal);
|
|
1029
|
+
|
|
1030
|
+
const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
|
|
1031
|
+
const expectedRatio = expectedAmounts.ratio;
|
|
1032
|
+
|
|
1033
|
+
logger.verbose(
|
|
1034
|
+
`${EkuboCLVault.name}: getSwapInfoToHandleUnused => iteration info: ${JSON.stringify({
|
|
1035
|
+
tokenToSell: tokenToSell.address,
|
|
1036
|
+
tokenToBuy: tokenToBuy.address,
|
|
1037
|
+
amountToSell: amountToSell.toString(),
|
|
1038
|
+
remainingSellAmount: remainingSellAmount.toString(),
|
|
1039
|
+
expectedRatio: expectedRatio
|
|
1040
|
+
})}`);
|
|
1041
|
+
|
|
1042
|
+
// If nothing to sell, return a zero swap
|
|
1003
1043
|
if (amountToSell.eq(0)) {
|
|
1004
|
-
return
|
|
1005
|
-
token_from_address: tokenToSell.address,
|
|
1006
|
-
token_from_amount: uint256.bnToUint256(0),
|
|
1007
|
-
token_to_address: tokenToSell.address,
|
|
1008
|
-
token_to_amount: uint256.bnToUint256(0),
|
|
1009
|
-
token_to_min_amount: uint256.bnToUint256(0),
|
|
1010
|
-
beneficiary: this.address.address,
|
|
1011
|
-
integrator_fee_amount_bps: 0,
|
|
1012
|
-
integrator_fee_recipient: this.address.address,
|
|
1013
|
-
routes: [],
|
|
1014
|
-
};
|
|
1044
|
+
return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
|
|
1015
1045
|
}
|
|
1046
|
+
|
|
1047
|
+
// Get a quote for swapping the calculated amount
|
|
1016
1048
|
const quote = await this.avnu.getQuotes(
|
|
1017
1049
|
tokenToSell.address,
|
|
1018
1050
|
tokenToBuy.address,
|
|
1019
1051
|
amountToSell.toWei(),
|
|
1020
1052
|
this.address.address
|
|
1021
1053
|
);
|
|
1054
|
+
|
|
1055
|
+
// If all of the token is to be swapped, return the swap info directly
|
|
1022
1056
|
if (remainingSellAmount.eq(0)) {
|
|
1023
1057
|
const minAmountOut = Web3Number.fromWei(
|
|
1024
1058
|
quote.buyAmount.toString(),
|
|
@@ -1033,36 +1067,34 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1033
1067
|
);
|
|
1034
1068
|
}
|
|
1035
1069
|
|
|
1070
|
+
// Calculate the actual output and price from the quote
|
|
1036
1071
|
const amountOut = Web3Number.fromWei(
|
|
1037
1072
|
quote.buyAmount.toString(),
|
|
1038
1073
|
tokenToBuyInfo.decimals
|
|
1039
1074
|
);
|
|
1075
|
+
// Calculate the swap price depending on which token is being sold
|
|
1040
1076
|
const swapPrice =
|
|
1041
1077
|
tokenToSell == poolKey.token0
|
|
1042
1078
|
? amountOut.dividedBy(amountToSell)
|
|
1043
1079
|
: amountToSell.dividedBy(amountOut);
|
|
1080
|
+
// Calculate the new ratio after the swap
|
|
1044
1081
|
const newRatio =
|
|
1045
1082
|
tokenToSell == poolKey.token0
|
|
1046
1083
|
? remainingSellAmount.dividedBy(token1Bal.plus(amountOut))
|
|
1047
1084
|
: token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
`${
|
|
1055
|
-
EkuboCLVault.name
|
|
1056
|
-
}: getSwapInfoToHandleUnused => swapPrice: ${swapPrice.toString()}`
|
|
1057
|
-
);
|
|
1058
|
-
logger.verbose(
|
|
1059
|
-
`${
|
|
1060
|
-
EkuboCLVault.name
|
|
1061
|
-
}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
|
|
1085
|
+
|
|
1086
|
+
logger.verbose(`${EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
|
|
1087
|
+
amountOut: amountOut.toString(),
|
|
1088
|
+
swapPrice: swapPrice.toString(),
|
|
1089
|
+
newRatio: newRatio.toString(),
|
|
1090
|
+
})}`
|
|
1062
1091
|
);
|
|
1092
|
+
|
|
1093
|
+
// If the new ratio is not within tolerance, adjust expected amounts and retry
|
|
1094
|
+
const expectedPrecision = Math.min(7, tokenToBuyInfo.decimals - 2);
|
|
1063
1095
|
if (
|
|
1064
|
-
Number(newRatio.toString()) > expectedRatio * 1
|
|
1065
|
-
Number(newRatio.toString()) < expectedRatio *
|
|
1096
|
+
Number(newRatio.toString()) > expectedRatio * (1 + 1 / 10 ** expectedPrecision) ||
|
|
1097
|
+
Number(newRatio.toString()) < expectedRatio * (1 - 1 / 10 ** expectedPrecision)
|
|
1066
1098
|
) {
|
|
1067
1099
|
expectedAmounts = await this._solveExpectedAmountsEq(
|
|
1068
1100
|
token0Bal,
|
|
@@ -1076,6 +1108,7 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1076
1108
|
}: getSwapInfoToHandleUnused => expectedAmounts: ${expectedAmounts.amount0.toString()}, ${expectedAmounts.amount1.toString()}`
|
|
1077
1109
|
);
|
|
1078
1110
|
} else {
|
|
1111
|
+
// Otherwise, return the swap info with a slippage buffer
|
|
1079
1112
|
const minAmountOut = Web3Number.fromWei(
|
|
1080
1113
|
quote.buyAmount.toString(),
|
|
1081
1114
|
tokenToBuyInfo.decimals
|
|
@@ -1088,10 +1121,10 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1088
1121
|
minAmountOut.toWei()
|
|
1089
1122
|
);
|
|
1090
1123
|
}
|
|
1091
|
-
|
|
1092
1124
|
retry++;
|
|
1093
1125
|
}
|
|
1094
1126
|
|
|
1127
|
+
// If no suitable swap found after max retries, throw error
|
|
1095
1128
|
throw new Error("Failed to get swap info");
|
|
1096
1129
|
}
|
|
1097
1130
|
|
|
@@ -1308,7 +1341,9 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1308
1341
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
1309
1342
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
1310
1343
|
const bounds = await this.getCurrentBounds();
|
|
1311
|
-
logger.verbose(
|
|
1344
|
+
logger.verbose(
|
|
1345
|
+
`${EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
|
|
1346
|
+
);
|
|
1312
1347
|
const calls: Call[] = [];
|
|
1313
1348
|
for (let claim of unClaimedRewards) {
|
|
1314
1349
|
const fee = claim.claim.amount
|
|
@@ -1353,7 +1388,7 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1353
1388
|
const harvestEstimateCall = async (swapInfo1: SwapInfo) => {
|
|
1354
1389
|
const swap1Amount = Web3Number.fromWei(
|
|
1355
1390
|
uint256.uint256ToBN(swapInfo1.token_from_amount).toString(),
|
|
1356
|
-
18
|
|
1391
|
+
18 // cause its always STRK?
|
|
1357
1392
|
);
|
|
1358
1393
|
logger.verbose(
|
|
1359
1394
|
`${EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
|
|
@@ -1371,12 +1406,12 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1371
1406
|
`${EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
1372
1407
|
swapInfo
|
|
1373
1408
|
)}`
|
|
1374
|
-
);
|
|
1409
|
+
);
|
|
1375
1410
|
logger.verbose(
|
|
1376
1411
|
`${EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
|
|
1377
1412
|
swapInfo2
|
|
1378
1413
|
)}`
|
|
1379
|
-
);
|
|
1414
|
+
);
|
|
1380
1415
|
const calldata = [
|
|
1381
1416
|
claim.rewardsContract.address,
|
|
1382
1417
|
{
|
|
@@ -1501,9 +1536,20 @@ const faqs: FAQ[] = [
|
|
|
1501
1536
|
},
|
|
1502
1537
|
{
|
|
1503
1538
|
question: "Is the strategy audited?",
|
|
1504
|
-
answer:
|
|
1505
|
-
<div>
|
|
1506
|
-
|
|
1539
|
+
answer: (
|
|
1540
|
+
<div>
|
|
1541
|
+
Yes, the strategy has been audited. You can review the audit report in
|
|
1542
|
+
our docs{" "}
|
|
1543
|
+
<a
|
|
1544
|
+
href="https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details"
|
|
1545
|
+
style={{ textDecoration: "underline", marginLeft: "5px" }}
|
|
1546
|
+
>
|
|
1547
|
+
Here
|
|
1548
|
+
</a>
|
|
1549
|
+
.
|
|
1550
|
+
</div>
|
|
1551
|
+
),
|
|
1552
|
+
},
|
|
1507
1553
|
];
|
|
1508
1554
|
/**
|
|
1509
1555
|
* Represents the Vesu Rebalance Strategies.
|
|
@@ -1565,6 +1611,11 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
|
|
|
1565
1611
|
"0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
|
|
1566
1612
|
),
|
|
1567
1613
|
feeBps: 1000,
|
|
1614
|
+
rebalanceConditions: {
|
|
1615
|
+
customShouldRebalance: async (currentPrice: number) => true,
|
|
1616
|
+
minWaitHours: 24,
|
|
1617
|
+
direction: "uponly",
|
|
1618
|
+
},
|
|
1568
1619
|
},
|
|
1569
1620
|
faqs: [
|
|
1570
1621
|
...faqs,
|
|
@@ -1573,59 +1624,65 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
|
|
|
1573
1624
|
answer:
|
|
1574
1625
|
"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.",
|
|
1575
1626
|
},
|
|
1576
|
-
]
|
|
1577
|
-
},
|
|
1578
|
-
{
|
|
1579
|
-
name: "Ekubo USDC/USDT",
|
|
1580
|
-
description: (
|
|
1581
|
-
<div>
|
|
1582
|
-
<p>{_description.replace("{{POOL_NAME}}", "USDC/USDT")}</p>
|
|
1583
|
-
<ul
|
|
1584
|
-
style={{
|
|
1585
|
-
marginLeft: "20px",
|
|
1586
|
-
listStyle: "circle",
|
|
1587
|
-
fontSize: "12px",
|
|
1588
|
-
}}
|
|
1589
|
-
>
|
|
1590
|
-
<li style={{ marginTop: "10px" }}>
|
|
1591
|
-
During withdrawal, you may receive either or both tokens depending
|
|
1592
|
-
on market conditions and prevailing prices.
|
|
1593
|
-
</li>
|
|
1594
|
-
</ul>
|
|
1595
|
-
</div>
|
|
1596
|
-
),
|
|
1597
|
-
address: ContractAddr.from(
|
|
1598
|
-
"0xd647ed735f0db52f2a5502b6e06ed21dc4284a43a36af4b60d3c80fbc56c91"
|
|
1599
|
-
),
|
|
1600
|
-
launchBlock: 1385576,
|
|
1601
|
-
type: "Other",
|
|
1602
|
-
// must be same order as poolKey token0 and token1
|
|
1603
|
-
depositTokens: [
|
|
1604
|
-
Global.getDefaultTokens().find((t) => t.symbol === "USDC")!,
|
|
1605
|
-
Global.getDefaultTokens().find((t) => t.symbol === "USDT")!,
|
|
1606
1627
|
],
|
|
1607
|
-
protocols: [_protocol],
|
|
1608
|
-
auditUrl: AUDIT_URL,
|
|
1609
|
-
maxTVL: Web3Number.fromWei("0", 6),
|
|
1610
|
-
risk: {
|
|
1611
|
-
riskFactor: _riskFactorStable,
|
|
1612
|
-
netRisk:
|
|
1613
|
-
_riskFactorStable.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
1614
|
-
_riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1615
|
-
notARisks: getNoRiskTags(_riskFactorStable),
|
|
1616
|
-
},
|
|
1617
|
-
apyMethodology:
|
|
1618
|
-
"APY based on 7-day historical performance, including fees and rewards.",
|
|
1619
|
-
additionalInfo: {
|
|
1620
|
-
newBounds: {
|
|
1621
|
-
lower: -1,
|
|
1622
|
-
upper: 1,
|
|
1623
|
-
},
|
|
1624
|
-
truePrice: 1,
|
|
1625
|
-
feeBps: 1000,
|
|
1626
|
-
},
|
|
1627
|
-
faqs: [
|
|
1628
|
-
...faqs,
|
|
1629
|
-
]
|
|
1630
1628
|
},
|
|
1629
|
+
// {
|
|
1630
|
+
// name: "Ekubo USDC/USDT",
|
|
1631
|
+
// description: (
|
|
1632
|
+
// <div>
|
|
1633
|
+
// <p>{_description.replace("{{POOL_NAME}}", "USDC/USDT")}</p>
|
|
1634
|
+
// <ul
|
|
1635
|
+
// style={{
|
|
1636
|
+
// marginLeft: "20px",
|
|
1637
|
+
// listStyle: "circle",
|
|
1638
|
+
// fontSize: "12px",
|
|
1639
|
+
// }}
|
|
1640
|
+
// >
|
|
1641
|
+
// <li style={{ marginTop: "10px" }}>
|
|
1642
|
+
// During withdrawal, you may receive either or both tokens depending
|
|
1643
|
+
// on market conditions and prevailing prices.
|
|
1644
|
+
// </li>
|
|
1645
|
+
// </ul>
|
|
1646
|
+
// </div>
|
|
1647
|
+
// ),
|
|
1648
|
+
// address: ContractAddr.from(
|
|
1649
|
+
// "0xd647ed735f0db52f2a5502b6e06ed21dc4284a43a36af4b60d3c80fbc56c91"
|
|
1650
|
+
// ),
|
|
1651
|
+
// launchBlock: 1385576,
|
|
1652
|
+
// type: "Other",
|
|
1653
|
+
// // must be same order as poolKey token0 and token1
|
|
1654
|
+
// depositTokens: [
|
|
1655
|
+
// Global.getDefaultTokens().find((t) => t.symbol === "USDC")!,
|
|
1656
|
+
// Global.getDefaultTokens().find((t) => t.symbol === "USDT")!,
|
|
1657
|
+
// ],
|
|
1658
|
+
// protocols: [_protocol],
|
|
1659
|
+
// auditUrl: AUDIT_URL,
|
|
1660
|
+
// maxTVL: Web3Number.fromWei("0", 6),
|
|
1661
|
+
// risk: {
|
|
1662
|
+
// riskFactor: _riskFactorStable,
|
|
1663
|
+
// netRisk:
|
|
1664
|
+
// _riskFactorStable.reduce(
|
|
1665
|
+
// (acc, curr) => acc + curr.value * curr.weight,
|
|
1666
|
+
// 0
|
|
1667
|
+
// ) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1668
|
+
// notARisks: getNoRiskTags(_riskFactorStable),
|
|
1669
|
+
// },
|
|
1670
|
+
// apyMethodology:
|
|
1671
|
+
// "APY based on 7-day historical performance, including fees and rewards.",
|
|
1672
|
+
// additionalInfo: {
|
|
1673
|
+
// newBounds: {
|
|
1674
|
+
// lower: -1,
|
|
1675
|
+
// upper: 1,
|
|
1676
|
+
// },
|
|
1677
|
+
// truePrice: 1,
|
|
1678
|
+
// feeBps: 1000,
|
|
1679
|
+
// rebalanceConditions: {
|
|
1680
|
+
// customShouldRebalance: async (currentPrice: number) =>
|
|
1681
|
+
// currentPrice > 0.99 && currentPrice < 1.01,
|
|
1682
|
+
// minWaitHours: 6,
|
|
1683
|
+
// direction: "any",
|
|
1684
|
+
// },
|
|
1685
|
+
// },
|
|
1686
|
+
// faqs: [...faqs],
|
|
1687
|
+
// },
|
|
1631
1688
|
];
|
|
@@ -500,7 +500,7 @@ export class VesuRebalance extends BaseStrategy<
|
|
|
500
500
|
logger.verbose(
|
|
501
501
|
`VesuRebalance: Pool ${pool.id} not found in Vesu API, using hardcoded data`
|
|
502
502
|
);
|
|
503
|
-
throw new Error(
|
|
503
|
+
throw new Error(`pool not found [sanity check]: ${pool.id}`);
|
|
504
504
|
}
|
|
505
505
|
}
|
|
506
506
|
} catch (e) {
|