@strkfarm/sdk 1.0.41 → 1.0.42
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 +80 -44
- package/dist/index.browser.mjs +80 -44
- package/dist/index.d.ts +6 -0
- package/dist/index.js +80 -44
- package/dist/index.mjs +80 -44
- package/package.json +1 -1
- package/src/modules/avnu.ts +18 -0
- package/src/strategies/ekubo-cl-vault.tsx +127 -70
|
@@ -38168,6 +38168,19 @@ var strkfarm_risk_engine = (() => {
|
|
|
38168
38168
|
};
|
|
38169
38169
|
return swapInfo;
|
|
38170
38170
|
}
|
|
38171
|
+
static buildZeroSwap(tokenToSell, address) {
|
|
38172
|
+
return {
|
|
38173
|
+
token_from_address: tokenToSell.address,
|
|
38174
|
+
token_from_amount: uint256_exports.bnToUint256(0),
|
|
38175
|
+
token_to_address: tokenToSell.address,
|
|
38176
|
+
token_to_amount: uint256_exports.bnToUint256(0),
|
|
38177
|
+
token_to_min_amount: uint256_exports.bnToUint256(0),
|
|
38178
|
+
beneficiary: address,
|
|
38179
|
+
integrator_fee_amount_bps: 0,
|
|
38180
|
+
integrator_fee_recipient: address,
|
|
38181
|
+
routes: []
|
|
38182
|
+
};
|
|
38183
|
+
}
|
|
38171
38184
|
};
|
|
38172
38185
|
|
|
38173
38186
|
// src/interfaces/common.ts
|
|
@@ -54789,7 +54802,10 @@ var strkfarm_risk_engine = (() => {
|
|
|
54789
54802
|
const priceNow = await this.getCurrentPrice(blockIdentifier);
|
|
54790
54803
|
let blockNow = typeof blockIdentifier == "number" ? blockIdentifier : (await this.config.provider.getBlockLatestAccepted()).block_number;
|
|
54791
54804
|
const blockNowTime = typeof blockIdentifier == "number" ? (await this.config.provider.getBlockWithTxs(blockIdentifier)).timestamp : (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
54792
|
-
const blockBefore = Math.max(
|
|
54805
|
+
const blockBefore = Math.max(
|
|
54806
|
+
blockNow - sinceBlocks,
|
|
54807
|
+
this.metadata.launchBlock
|
|
54808
|
+
);
|
|
54793
54809
|
const adjustedSupplyNow = supplyNow.minus(
|
|
54794
54810
|
await this.getHarvestRewardShares(blockBefore, blockNow)
|
|
54795
54811
|
);
|
|
@@ -55285,41 +55301,41 @@ var strkfarm_risk_engine = (() => {
|
|
|
55285
55301
|
);
|
|
55286
55302
|
let retry = 0;
|
|
55287
55303
|
const maxRetry = 10;
|
|
55288
|
-
|
|
55289
|
-
|
|
55290
|
-
if (expectedAmounts.amount0.lessThan(token0Bal) && expectedAmounts.amount1.lessThan(token1Bal)) {
|
|
55304
|
+
function assertValidAmounts(expectedAmounts2, token0Bal2, token1Bal2) {
|
|
55305
|
+
if (expectedAmounts2.amount0.lessThan(token0Bal2) && expectedAmounts2.amount1.lessThan(token1Bal2)) {
|
|
55291
55306
|
throw new Error("Both tokens are decreased, something is wrong");
|
|
55292
55307
|
}
|
|
55293
|
-
if (
|
|
55308
|
+
if (expectedAmounts2.amount0.greaterThan(token0Bal2) && expectedAmounts2.amount1.greaterThan(token1Bal2)) {
|
|
55294
55309
|
throw new Error("Both tokens are increased, something is wrong");
|
|
55295
55310
|
}
|
|
55296
|
-
|
|
55297
|
-
|
|
55298
|
-
|
|
55299
|
-
const
|
|
55300
|
-
const
|
|
55301
|
-
const
|
|
55302
|
-
|
|
55303
|
-
|
|
55304
|
-
|
|
55311
|
+
}
|
|
55312
|
+
function getSwapParams(expectedAmounts2, poolKey2, token0Bal2, token1Bal2) {
|
|
55313
|
+
const tokenToSell = expectedAmounts2.amount0.lessThan(token0Bal2) ? poolKey2.token0 : poolKey2.token1;
|
|
55314
|
+
const tokenToBuy = tokenToSell == poolKey2.token0 ? poolKey2.token1 : poolKey2.token0;
|
|
55315
|
+
const amountToSell = tokenToSell == poolKey2.token0 ? token0Bal2.minus(expectedAmounts2.amount0) : token1Bal2.minus(expectedAmounts2.amount1);
|
|
55316
|
+
const remainingSellAmount = tokenToSell == poolKey2.token0 ? expectedAmounts2.amount0 : expectedAmounts2.amount1;
|
|
55317
|
+
return { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount };
|
|
55318
|
+
}
|
|
55319
|
+
while (retry < maxRetry) {
|
|
55320
|
+
retry++;
|
|
55305
55321
|
logger.verbose(
|
|
55306
|
-
|
|
55322
|
+
`getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
|
|
55307
55323
|
);
|
|
55324
|
+
assertValidAmounts(expectedAmounts, token0Bal, token1Bal);
|
|
55325
|
+
const { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount } = getSwapParams(expectedAmounts, poolKey, token0Bal, token1Bal);
|
|
55326
|
+
const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
|
|
55327
|
+
const expectedRatio = expectedAmounts.ratio;
|
|
55308
55328
|
logger.verbose(
|
|
55309
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused =>
|
|
55329
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => iteration info: ${JSON.stringify({
|
|
55330
|
+
tokenToSell: tokenToSell.address,
|
|
55331
|
+
tokenToBuy: tokenToBuy.address,
|
|
55332
|
+
amountToSell: amountToSell.toString(),
|
|
55333
|
+
remainingSellAmount: remainingSellAmount.toString(),
|
|
55334
|
+
expectedRatio
|
|
55335
|
+
})}`
|
|
55310
55336
|
);
|
|
55311
55337
|
if (amountToSell.eq(0)) {
|
|
55312
|
-
return
|
|
55313
|
-
token_from_address: tokenToSell.address,
|
|
55314
|
-
token_from_amount: uint256_exports.bnToUint256(0),
|
|
55315
|
-
token_to_address: tokenToSell.address,
|
|
55316
|
-
token_to_amount: uint256_exports.bnToUint256(0),
|
|
55317
|
-
token_to_min_amount: uint256_exports.bnToUint256(0),
|
|
55318
|
-
beneficiary: this.address.address,
|
|
55319
|
-
integrator_fee_amount_bps: 0,
|
|
55320
|
-
integrator_fee_recipient: this.address.address,
|
|
55321
|
-
routes: []
|
|
55322
|
-
};
|
|
55338
|
+
return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
|
|
55323
55339
|
}
|
|
55324
55340
|
const quote = await this.avnu.getQuotes(
|
|
55325
55341
|
tokenToSell.address,
|
|
@@ -55347,15 +55363,14 @@ var strkfarm_risk_engine = (() => {
|
|
|
55347
55363
|
const swapPrice = tokenToSell == poolKey.token0 ? amountOut.dividedBy(amountToSell) : amountToSell.dividedBy(amountOut);
|
|
55348
55364
|
const newRatio = tokenToSell == poolKey.token0 ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut)) : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
|
|
55349
55365
|
logger.verbose(
|
|
55350
|
-
`${_EkuboCLVault.name}
|
|
55351
|
-
|
|
55352
|
-
|
|
55353
|
-
|
|
55354
|
-
|
|
55355
|
-
logger.verbose(
|
|
55356
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
|
|
55366
|
+
`${_EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
|
|
55367
|
+
amountOut: amountOut.toString(),
|
|
55368
|
+
swapPrice: swapPrice.toString(),
|
|
55369
|
+
newRatio: newRatio.toString()
|
|
55370
|
+
})}`
|
|
55357
55371
|
);
|
|
55358
|
-
|
|
55372
|
+
const expectedPrecision = Math.min(7, tokenToBuyInfo.decimals - 2);
|
|
55373
|
+
if (Number(newRatio.toString()) > expectedRatio * (1 + 1 / 10 ** expectedPrecision) || Number(newRatio.toString()) < expectedRatio * (1 - 1 / 10 ** expectedPrecision)) {
|
|
55359
55374
|
expectedAmounts = await this._solveExpectedAmountsEq(
|
|
55360
55375
|
token0Bal,
|
|
55361
55376
|
token1Bal,
|
|
@@ -55554,7 +55569,9 @@ var strkfarm_risk_engine = (() => {
|
|
|
55554
55569
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
55555
55570
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
55556
55571
|
const bounds = await this.getCurrentBounds();
|
|
55557
|
-
logger.verbose(
|
|
55572
|
+
logger.verbose(
|
|
55573
|
+
`${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
|
|
55574
|
+
);
|
|
55558
55575
|
const calls = [];
|
|
55559
55576
|
for (let claim of unClaimedRewards) {
|
|
55560
55577
|
const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
|
|
@@ -55712,8 +55729,16 @@ var strkfarm_risk_engine = (() => {
|
|
|
55712
55729
|
{
|
|
55713
55730
|
question: "Is the strategy audited?",
|
|
55714
55731
|
answer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
55715
|
-
"Yes, the strategy has been audited. You can review the audit report in our docs
|
|
55716
|
-
|
|
55732
|
+
"Yes, the strategy has been audited. You can review the audit report in our docs",
|
|
55733
|
+
" ",
|
|
55734
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
55735
|
+
"a",
|
|
55736
|
+
{
|
|
55737
|
+
href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details",
|
|
55738
|
+
style: { textDecoration: "underline", marginLeft: "5px" },
|
|
55739
|
+
children: "Here"
|
|
55740
|
+
}
|
|
55741
|
+
),
|
|
55717
55742
|
"."
|
|
55718
55743
|
] })
|
|
55719
55744
|
}
|
|
@@ -55765,7 +55790,12 @@ var strkfarm_risk_engine = (() => {
|
|
|
55765
55790
|
lstContract: ContractAddr.from(
|
|
55766
55791
|
"0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
|
|
55767
55792
|
),
|
|
55768
|
-
feeBps: 1e3
|
|
55793
|
+
feeBps: 1e3,
|
|
55794
|
+
rebalanceConditions: {
|
|
55795
|
+
customShouldRebalance: async (currentPrice) => true,
|
|
55796
|
+
minWaitHours: 24,
|
|
55797
|
+
direction: "uponly"
|
|
55798
|
+
}
|
|
55769
55799
|
},
|
|
55770
55800
|
faqs: [
|
|
55771
55801
|
...faqs2,
|
|
@@ -55806,7 +55836,10 @@ var strkfarm_risk_engine = (() => {
|
|
|
55806
55836
|
maxTVL: Web3Number.fromWei("0", 6),
|
|
55807
55837
|
risk: {
|
|
55808
55838
|
riskFactor: _riskFactorStable,
|
|
55809
|
-
netRisk: _riskFactorStable.reduce(
|
|
55839
|
+
netRisk: _riskFactorStable.reduce(
|
|
55840
|
+
(acc, curr) => acc + curr.value * curr.weight,
|
|
55841
|
+
0
|
|
55842
|
+
) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
|
|
55810
55843
|
notARisks: getNoRiskTags(_riskFactorStable)
|
|
55811
55844
|
},
|
|
55812
55845
|
apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
|
|
@@ -55816,11 +55849,14 @@ var strkfarm_risk_engine = (() => {
|
|
|
55816
55849
|
upper: 1
|
|
55817
55850
|
},
|
|
55818
55851
|
truePrice: 1,
|
|
55819
|
-
feeBps: 1e3
|
|
55852
|
+
feeBps: 1e3,
|
|
55853
|
+
rebalanceConditions: {
|
|
55854
|
+
customShouldRebalance: async (currentPrice) => currentPrice > 0.99 && currentPrice < 1.01,
|
|
55855
|
+
minWaitHours: 6,
|
|
55856
|
+
direction: "any"
|
|
55857
|
+
}
|
|
55820
55858
|
},
|
|
55821
|
-
faqs: [
|
|
55822
|
-
...faqs2
|
|
55823
|
-
]
|
|
55859
|
+
faqs: [...faqs2]
|
|
55824
55860
|
}
|
|
55825
55861
|
];
|
|
55826
55862
|
return __toCommonJS(index_browser_exports);
|
package/dist/index.browser.mjs
CHANGED
|
@@ -1948,6 +1948,19 @@ var AvnuWrapper = class _AvnuWrapper {
|
|
|
1948
1948
|
};
|
|
1949
1949
|
return swapInfo;
|
|
1950
1950
|
}
|
|
1951
|
+
static buildZeroSwap(tokenToSell, address) {
|
|
1952
|
+
return {
|
|
1953
|
+
token_from_address: tokenToSell.address,
|
|
1954
|
+
token_from_amount: uint256.bnToUint256(0),
|
|
1955
|
+
token_to_address: tokenToSell.address,
|
|
1956
|
+
token_to_amount: uint256.bnToUint256(0),
|
|
1957
|
+
token_to_min_amount: uint256.bnToUint256(0),
|
|
1958
|
+
beneficiary: address,
|
|
1959
|
+
integrator_fee_amount_bps: 0,
|
|
1960
|
+
integrator_fee_recipient: address,
|
|
1961
|
+
routes: []
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1951
1964
|
};
|
|
1952
1965
|
|
|
1953
1966
|
// src/interfaces/common.ts
|
|
@@ -18583,7 +18596,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18583
18596
|
const priceNow = await this.getCurrentPrice(blockIdentifier);
|
|
18584
18597
|
let blockNow = typeof blockIdentifier == "number" ? blockIdentifier : (await this.config.provider.getBlockLatestAccepted()).block_number;
|
|
18585
18598
|
const blockNowTime = typeof blockIdentifier == "number" ? (await this.config.provider.getBlockWithTxs(blockIdentifier)).timestamp : (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
18586
|
-
const blockBefore = Math.max(
|
|
18599
|
+
const blockBefore = Math.max(
|
|
18600
|
+
blockNow - sinceBlocks,
|
|
18601
|
+
this.metadata.launchBlock
|
|
18602
|
+
);
|
|
18587
18603
|
const adjustedSupplyNow = supplyNow.minus(
|
|
18588
18604
|
await this.getHarvestRewardShares(blockBefore, blockNow)
|
|
18589
18605
|
);
|
|
@@ -19079,41 +19095,41 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19079
19095
|
);
|
|
19080
19096
|
let retry = 0;
|
|
19081
19097
|
const maxRetry = 10;
|
|
19082
|
-
|
|
19083
|
-
|
|
19084
|
-
if (expectedAmounts.amount0.lessThan(token0Bal) && expectedAmounts.amount1.lessThan(token1Bal)) {
|
|
19098
|
+
function assertValidAmounts(expectedAmounts2, token0Bal2, token1Bal2) {
|
|
19099
|
+
if (expectedAmounts2.amount0.lessThan(token0Bal2) && expectedAmounts2.amount1.lessThan(token1Bal2)) {
|
|
19085
19100
|
throw new Error("Both tokens are decreased, something is wrong");
|
|
19086
19101
|
}
|
|
19087
|
-
if (
|
|
19102
|
+
if (expectedAmounts2.amount0.greaterThan(token0Bal2) && expectedAmounts2.amount1.greaterThan(token1Bal2)) {
|
|
19088
19103
|
throw new Error("Both tokens are increased, something is wrong");
|
|
19089
19104
|
}
|
|
19090
|
-
|
|
19091
|
-
|
|
19092
|
-
|
|
19093
|
-
const
|
|
19094
|
-
const
|
|
19095
|
-
const
|
|
19096
|
-
|
|
19097
|
-
|
|
19098
|
-
|
|
19105
|
+
}
|
|
19106
|
+
function getSwapParams(expectedAmounts2, poolKey2, token0Bal2, token1Bal2) {
|
|
19107
|
+
const tokenToSell = expectedAmounts2.amount0.lessThan(token0Bal2) ? poolKey2.token0 : poolKey2.token1;
|
|
19108
|
+
const tokenToBuy = tokenToSell == poolKey2.token0 ? poolKey2.token1 : poolKey2.token0;
|
|
19109
|
+
const amountToSell = tokenToSell == poolKey2.token0 ? token0Bal2.minus(expectedAmounts2.amount0) : token1Bal2.minus(expectedAmounts2.amount1);
|
|
19110
|
+
const remainingSellAmount = tokenToSell == poolKey2.token0 ? expectedAmounts2.amount0 : expectedAmounts2.amount1;
|
|
19111
|
+
return { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount };
|
|
19112
|
+
}
|
|
19113
|
+
while (retry < maxRetry) {
|
|
19114
|
+
retry++;
|
|
19099
19115
|
logger.verbose(
|
|
19100
|
-
|
|
19116
|
+
`getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
|
|
19101
19117
|
);
|
|
19118
|
+
assertValidAmounts(expectedAmounts, token0Bal, token1Bal);
|
|
19119
|
+
const { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount } = getSwapParams(expectedAmounts, poolKey, token0Bal, token1Bal);
|
|
19120
|
+
const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
|
|
19121
|
+
const expectedRatio = expectedAmounts.ratio;
|
|
19102
19122
|
logger.verbose(
|
|
19103
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused =>
|
|
19123
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => iteration info: ${JSON.stringify({
|
|
19124
|
+
tokenToSell: tokenToSell.address,
|
|
19125
|
+
tokenToBuy: tokenToBuy.address,
|
|
19126
|
+
amountToSell: amountToSell.toString(),
|
|
19127
|
+
remainingSellAmount: remainingSellAmount.toString(),
|
|
19128
|
+
expectedRatio
|
|
19129
|
+
})}`
|
|
19104
19130
|
);
|
|
19105
19131
|
if (amountToSell.eq(0)) {
|
|
19106
|
-
return
|
|
19107
|
-
token_from_address: tokenToSell.address,
|
|
19108
|
-
token_from_amount: uint2564.bnToUint256(0),
|
|
19109
|
-
token_to_address: tokenToSell.address,
|
|
19110
|
-
token_to_amount: uint2564.bnToUint256(0),
|
|
19111
|
-
token_to_min_amount: uint2564.bnToUint256(0),
|
|
19112
|
-
beneficiary: this.address.address,
|
|
19113
|
-
integrator_fee_amount_bps: 0,
|
|
19114
|
-
integrator_fee_recipient: this.address.address,
|
|
19115
|
-
routes: []
|
|
19116
|
-
};
|
|
19132
|
+
return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
|
|
19117
19133
|
}
|
|
19118
19134
|
const quote = await this.avnu.getQuotes(
|
|
19119
19135
|
tokenToSell.address,
|
|
@@ -19141,15 +19157,14 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19141
19157
|
const swapPrice = tokenToSell == poolKey.token0 ? amountOut.dividedBy(amountToSell) : amountToSell.dividedBy(amountOut);
|
|
19142
19158
|
const newRatio = tokenToSell == poolKey.token0 ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut)) : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
|
|
19143
19159
|
logger.verbose(
|
|
19144
|
-
`${_EkuboCLVault.name}
|
|
19145
|
-
|
|
19146
|
-
|
|
19147
|
-
|
|
19148
|
-
|
|
19149
|
-
logger.verbose(
|
|
19150
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
|
|
19160
|
+
`${_EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
|
|
19161
|
+
amountOut: amountOut.toString(),
|
|
19162
|
+
swapPrice: swapPrice.toString(),
|
|
19163
|
+
newRatio: newRatio.toString()
|
|
19164
|
+
})}`
|
|
19151
19165
|
);
|
|
19152
|
-
|
|
19166
|
+
const expectedPrecision = Math.min(7, tokenToBuyInfo.decimals - 2);
|
|
19167
|
+
if (Number(newRatio.toString()) > expectedRatio * (1 + 1 / 10 ** expectedPrecision) || Number(newRatio.toString()) < expectedRatio * (1 - 1 / 10 ** expectedPrecision)) {
|
|
19153
19168
|
expectedAmounts = await this._solveExpectedAmountsEq(
|
|
19154
19169
|
token0Bal,
|
|
19155
19170
|
token1Bal,
|
|
@@ -19348,7 +19363,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19348
19363
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
19349
19364
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
19350
19365
|
const bounds = await this.getCurrentBounds();
|
|
19351
|
-
logger.verbose(
|
|
19366
|
+
logger.verbose(
|
|
19367
|
+
`${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
|
|
19368
|
+
);
|
|
19352
19369
|
const calls = [];
|
|
19353
19370
|
for (let claim of unClaimedRewards) {
|
|
19354
19371
|
const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
|
|
@@ -19506,8 +19523,16 @@ var faqs2 = [
|
|
|
19506
19523
|
{
|
|
19507
19524
|
question: "Is the strategy audited?",
|
|
19508
19525
|
answer: /* @__PURE__ */ jsxs2("div", { children: [
|
|
19509
|
-
"Yes, the strategy has been audited. You can review the audit report in our docs
|
|
19510
|
-
|
|
19526
|
+
"Yes, the strategy has been audited. You can review the audit report in our docs",
|
|
19527
|
+
" ",
|
|
19528
|
+
/* @__PURE__ */ jsx2(
|
|
19529
|
+
"a",
|
|
19530
|
+
{
|
|
19531
|
+
href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details",
|
|
19532
|
+
style: { textDecoration: "underline", marginLeft: "5px" },
|
|
19533
|
+
children: "Here"
|
|
19534
|
+
}
|
|
19535
|
+
),
|
|
19511
19536
|
"."
|
|
19512
19537
|
] })
|
|
19513
19538
|
}
|
|
@@ -19559,7 +19584,12 @@ var EkuboCLVaultStrategies = [
|
|
|
19559
19584
|
lstContract: ContractAddr.from(
|
|
19560
19585
|
"0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
|
|
19561
19586
|
),
|
|
19562
|
-
feeBps: 1e3
|
|
19587
|
+
feeBps: 1e3,
|
|
19588
|
+
rebalanceConditions: {
|
|
19589
|
+
customShouldRebalance: async (currentPrice) => true,
|
|
19590
|
+
minWaitHours: 24,
|
|
19591
|
+
direction: "uponly"
|
|
19592
|
+
}
|
|
19563
19593
|
},
|
|
19564
19594
|
faqs: [
|
|
19565
19595
|
...faqs2,
|
|
@@ -19600,7 +19630,10 @@ var EkuboCLVaultStrategies = [
|
|
|
19600
19630
|
maxTVL: Web3Number.fromWei("0", 6),
|
|
19601
19631
|
risk: {
|
|
19602
19632
|
riskFactor: _riskFactorStable,
|
|
19603
|
-
netRisk: _riskFactorStable.reduce(
|
|
19633
|
+
netRisk: _riskFactorStable.reduce(
|
|
19634
|
+
(acc, curr) => acc + curr.value * curr.weight,
|
|
19635
|
+
0
|
|
19636
|
+
) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
|
|
19604
19637
|
notARisks: getNoRiskTags(_riskFactorStable)
|
|
19605
19638
|
},
|
|
19606
19639
|
apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
|
|
@@ -19610,11 +19643,14 @@ var EkuboCLVaultStrategies = [
|
|
|
19610
19643
|
upper: 1
|
|
19611
19644
|
},
|
|
19612
19645
|
truePrice: 1,
|
|
19613
|
-
feeBps: 1e3
|
|
19646
|
+
feeBps: 1e3,
|
|
19647
|
+
rebalanceConditions: {
|
|
19648
|
+
customShouldRebalance: async (currentPrice) => currentPrice > 0.99 && currentPrice < 1.01,
|
|
19649
|
+
minWaitHours: 6,
|
|
19650
|
+
direction: "any"
|
|
19651
|
+
}
|
|
19614
19652
|
},
|
|
19615
|
-
faqs: [
|
|
19616
|
-
...faqs2
|
|
19617
|
-
]
|
|
19653
|
+
faqs: [...faqs2]
|
|
19618
19654
|
}
|
|
19619
19655
|
];
|
|
19620
19656
|
export {
|
package/dist/index.d.ts
CHANGED
|
@@ -289,6 +289,7 @@ interface SwapInfo {
|
|
|
289
289
|
declare class AvnuWrapper {
|
|
290
290
|
getQuotes(fromToken: string, toToken: string, amountWei: string, taker: string, retry?: number): Promise<Quote>;
|
|
291
291
|
getSwapInfo(quote: Quote, taker: string, integratorFeeBps: number, integratorFeeRecipient: string, minAmount?: string): Promise<SwapInfo>;
|
|
292
|
+
static buildZeroSwap(tokenToSell: ContractAddr, address: string): SwapInfo;
|
|
292
293
|
}
|
|
293
294
|
|
|
294
295
|
declare class FatalError extends Error {
|
|
@@ -598,6 +599,11 @@ interface CLVaultStrategySettings {
|
|
|
598
599
|
lstContract?: ContractAddr;
|
|
599
600
|
truePrice?: number;
|
|
600
601
|
feeBps: number;
|
|
602
|
+
rebalanceConditions: {
|
|
603
|
+
minWaitHours: number;
|
|
604
|
+
direction: "any" | "uponly";
|
|
605
|
+
customShouldRebalance: (currentPoolPrice: number) => Promise<boolean>;
|
|
606
|
+
};
|
|
601
607
|
}
|
|
602
608
|
declare class EkuboCLVault extends BaseStrategy<DualTokenInfo, DualActionAmount> {
|
|
603
609
|
/** Contract address of the strategy */
|
package/dist/index.js
CHANGED
|
@@ -2066,6 +2066,19 @@ var AvnuWrapper = class _AvnuWrapper {
|
|
|
2066
2066
|
};
|
|
2067
2067
|
return swapInfo;
|
|
2068
2068
|
}
|
|
2069
|
+
static buildZeroSwap(tokenToSell, address) {
|
|
2070
|
+
return {
|
|
2071
|
+
token_from_address: tokenToSell.address,
|
|
2072
|
+
token_from_amount: import_starknet4.uint256.bnToUint256(0),
|
|
2073
|
+
token_to_address: tokenToSell.address,
|
|
2074
|
+
token_to_amount: import_starknet4.uint256.bnToUint256(0),
|
|
2075
|
+
token_to_min_amount: import_starknet4.uint256.bnToUint256(0),
|
|
2076
|
+
beneficiary: address,
|
|
2077
|
+
integrator_fee_amount_bps: 0,
|
|
2078
|
+
integrator_fee_recipient: address,
|
|
2079
|
+
routes: []
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
2069
2082
|
};
|
|
2070
2083
|
|
|
2071
2084
|
// src/interfaces/common.ts
|
|
@@ -18697,7 +18710,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18697
18710
|
const priceNow = await this.getCurrentPrice(blockIdentifier);
|
|
18698
18711
|
let blockNow = typeof blockIdentifier == "number" ? blockIdentifier : (await this.config.provider.getBlockLatestAccepted()).block_number;
|
|
18699
18712
|
const blockNowTime = typeof blockIdentifier == "number" ? (await this.config.provider.getBlockWithTxs(blockIdentifier)).timestamp : (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
18700
|
-
const blockBefore = Math.max(
|
|
18713
|
+
const blockBefore = Math.max(
|
|
18714
|
+
blockNow - sinceBlocks,
|
|
18715
|
+
this.metadata.launchBlock
|
|
18716
|
+
);
|
|
18701
18717
|
const adjustedSupplyNow = supplyNow.minus(
|
|
18702
18718
|
await this.getHarvestRewardShares(blockBefore, blockNow)
|
|
18703
18719
|
);
|
|
@@ -19193,41 +19209,41 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19193
19209
|
);
|
|
19194
19210
|
let retry = 0;
|
|
19195
19211
|
const maxRetry = 10;
|
|
19196
|
-
|
|
19197
|
-
|
|
19198
|
-
if (expectedAmounts.amount0.lessThan(token0Bal) && expectedAmounts.amount1.lessThan(token1Bal)) {
|
|
19212
|
+
function assertValidAmounts(expectedAmounts2, token0Bal2, token1Bal2) {
|
|
19213
|
+
if (expectedAmounts2.amount0.lessThan(token0Bal2) && expectedAmounts2.amount1.lessThan(token1Bal2)) {
|
|
19199
19214
|
throw new Error("Both tokens are decreased, something is wrong");
|
|
19200
19215
|
}
|
|
19201
|
-
if (
|
|
19216
|
+
if (expectedAmounts2.amount0.greaterThan(token0Bal2) && expectedAmounts2.amount1.greaterThan(token1Bal2)) {
|
|
19202
19217
|
throw new Error("Both tokens are increased, something is wrong");
|
|
19203
19218
|
}
|
|
19204
|
-
|
|
19205
|
-
|
|
19206
|
-
|
|
19207
|
-
const
|
|
19208
|
-
const
|
|
19209
|
-
const
|
|
19210
|
-
|
|
19211
|
-
|
|
19212
|
-
|
|
19219
|
+
}
|
|
19220
|
+
function getSwapParams(expectedAmounts2, poolKey2, token0Bal2, token1Bal2) {
|
|
19221
|
+
const tokenToSell = expectedAmounts2.amount0.lessThan(token0Bal2) ? poolKey2.token0 : poolKey2.token1;
|
|
19222
|
+
const tokenToBuy = tokenToSell == poolKey2.token0 ? poolKey2.token1 : poolKey2.token0;
|
|
19223
|
+
const amountToSell = tokenToSell == poolKey2.token0 ? token0Bal2.minus(expectedAmounts2.amount0) : token1Bal2.minus(expectedAmounts2.amount1);
|
|
19224
|
+
const remainingSellAmount = tokenToSell == poolKey2.token0 ? expectedAmounts2.amount0 : expectedAmounts2.amount1;
|
|
19225
|
+
return { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount };
|
|
19226
|
+
}
|
|
19227
|
+
while (retry < maxRetry) {
|
|
19228
|
+
retry++;
|
|
19213
19229
|
logger.verbose(
|
|
19214
|
-
|
|
19230
|
+
`getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
|
|
19215
19231
|
);
|
|
19232
|
+
assertValidAmounts(expectedAmounts, token0Bal, token1Bal);
|
|
19233
|
+
const { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount } = getSwapParams(expectedAmounts, poolKey, token0Bal, token1Bal);
|
|
19234
|
+
const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
|
|
19235
|
+
const expectedRatio = expectedAmounts.ratio;
|
|
19216
19236
|
logger.verbose(
|
|
19217
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused =>
|
|
19237
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => iteration info: ${JSON.stringify({
|
|
19238
|
+
tokenToSell: tokenToSell.address,
|
|
19239
|
+
tokenToBuy: tokenToBuy.address,
|
|
19240
|
+
amountToSell: amountToSell.toString(),
|
|
19241
|
+
remainingSellAmount: remainingSellAmount.toString(),
|
|
19242
|
+
expectedRatio
|
|
19243
|
+
})}`
|
|
19218
19244
|
);
|
|
19219
19245
|
if (amountToSell.eq(0)) {
|
|
19220
|
-
return
|
|
19221
|
-
token_from_address: tokenToSell.address,
|
|
19222
|
-
token_from_amount: import_starknet9.uint256.bnToUint256(0),
|
|
19223
|
-
token_to_address: tokenToSell.address,
|
|
19224
|
-
token_to_amount: import_starknet9.uint256.bnToUint256(0),
|
|
19225
|
-
token_to_min_amount: import_starknet9.uint256.bnToUint256(0),
|
|
19226
|
-
beneficiary: this.address.address,
|
|
19227
|
-
integrator_fee_amount_bps: 0,
|
|
19228
|
-
integrator_fee_recipient: this.address.address,
|
|
19229
|
-
routes: []
|
|
19230
|
-
};
|
|
19246
|
+
return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
|
|
19231
19247
|
}
|
|
19232
19248
|
const quote = await this.avnu.getQuotes(
|
|
19233
19249
|
tokenToSell.address,
|
|
@@ -19255,15 +19271,14 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19255
19271
|
const swapPrice = tokenToSell == poolKey.token0 ? amountOut.dividedBy(amountToSell) : amountToSell.dividedBy(amountOut);
|
|
19256
19272
|
const newRatio = tokenToSell == poolKey.token0 ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut)) : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
|
|
19257
19273
|
logger.verbose(
|
|
19258
|
-
`${_EkuboCLVault.name}
|
|
19259
|
-
|
|
19260
|
-
|
|
19261
|
-
|
|
19262
|
-
|
|
19263
|
-
logger.verbose(
|
|
19264
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
|
|
19274
|
+
`${_EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
|
|
19275
|
+
amountOut: amountOut.toString(),
|
|
19276
|
+
swapPrice: swapPrice.toString(),
|
|
19277
|
+
newRatio: newRatio.toString()
|
|
19278
|
+
})}`
|
|
19265
19279
|
);
|
|
19266
|
-
|
|
19280
|
+
const expectedPrecision = Math.min(7, tokenToBuyInfo.decimals - 2);
|
|
19281
|
+
if (Number(newRatio.toString()) > expectedRatio * (1 + 1 / 10 ** expectedPrecision) || Number(newRatio.toString()) < expectedRatio * (1 - 1 / 10 ** expectedPrecision)) {
|
|
19267
19282
|
expectedAmounts = await this._solveExpectedAmountsEq(
|
|
19268
19283
|
token0Bal,
|
|
19269
19284
|
token1Bal,
|
|
@@ -19462,7 +19477,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19462
19477
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
19463
19478
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
19464
19479
|
const bounds = await this.getCurrentBounds();
|
|
19465
|
-
logger.verbose(
|
|
19480
|
+
logger.verbose(
|
|
19481
|
+
`${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
|
|
19482
|
+
);
|
|
19466
19483
|
const calls = [];
|
|
19467
19484
|
for (let claim of unClaimedRewards) {
|
|
19468
19485
|
const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
|
|
@@ -19620,8 +19637,16 @@ var faqs2 = [
|
|
|
19620
19637
|
{
|
|
19621
19638
|
question: "Is the strategy audited?",
|
|
19622
19639
|
answer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
19623
|
-
"Yes, the strategy has been audited. You can review the audit report in our docs
|
|
19624
|
-
|
|
19640
|
+
"Yes, the strategy has been audited. You can review the audit report in our docs",
|
|
19641
|
+
" ",
|
|
19642
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
19643
|
+
"a",
|
|
19644
|
+
{
|
|
19645
|
+
href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details",
|
|
19646
|
+
style: { textDecoration: "underline", marginLeft: "5px" },
|
|
19647
|
+
children: "Here"
|
|
19648
|
+
}
|
|
19649
|
+
),
|
|
19625
19650
|
"."
|
|
19626
19651
|
] })
|
|
19627
19652
|
}
|
|
@@ -19673,7 +19698,12 @@ var EkuboCLVaultStrategies = [
|
|
|
19673
19698
|
lstContract: ContractAddr.from(
|
|
19674
19699
|
"0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
|
|
19675
19700
|
),
|
|
19676
|
-
feeBps: 1e3
|
|
19701
|
+
feeBps: 1e3,
|
|
19702
|
+
rebalanceConditions: {
|
|
19703
|
+
customShouldRebalance: async (currentPrice) => true,
|
|
19704
|
+
minWaitHours: 24,
|
|
19705
|
+
direction: "uponly"
|
|
19706
|
+
}
|
|
19677
19707
|
},
|
|
19678
19708
|
faqs: [
|
|
19679
19709
|
...faqs2,
|
|
@@ -19714,7 +19744,10 @@ var EkuboCLVaultStrategies = [
|
|
|
19714
19744
|
maxTVL: Web3Number.fromWei("0", 6),
|
|
19715
19745
|
risk: {
|
|
19716
19746
|
riskFactor: _riskFactorStable,
|
|
19717
|
-
netRisk: _riskFactorStable.reduce(
|
|
19747
|
+
netRisk: _riskFactorStable.reduce(
|
|
19748
|
+
(acc, curr) => acc + curr.value * curr.weight,
|
|
19749
|
+
0
|
|
19750
|
+
) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
|
|
19718
19751
|
notARisks: getNoRiskTags(_riskFactorStable)
|
|
19719
19752
|
},
|
|
19720
19753
|
apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
|
|
@@ -19724,11 +19757,14 @@ var EkuboCLVaultStrategies = [
|
|
|
19724
19757
|
upper: 1
|
|
19725
19758
|
},
|
|
19726
19759
|
truePrice: 1,
|
|
19727
|
-
feeBps: 1e3
|
|
19760
|
+
feeBps: 1e3,
|
|
19761
|
+
rebalanceConditions: {
|
|
19762
|
+
customShouldRebalance: async (currentPrice) => currentPrice > 0.99 && currentPrice < 1.01,
|
|
19763
|
+
minWaitHours: 6,
|
|
19764
|
+
direction: "any"
|
|
19765
|
+
}
|
|
19728
19766
|
},
|
|
19729
|
-
faqs: [
|
|
19730
|
-
...faqs2
|
|
19731
|
-
]
|
|
19767
|
+
faqs: [...faqs2]
|
|
19732
19768
|
}
|
|
19733
19769
|
];
|
|
19734
19770
|
|
package/dist/index.mjs
CHANGED
|
@@ -1997,6 +1997,19 @@ var AvnuWrapper = class _AvnuWrapper {
|
|
|
1997
1997
|
};
|
|
1998
1998
|
return swapInfo;
|
|
1999
1999
|
}
|
|
2000
|
+
static buildZeroSwap(tokenToSell, address) {
|
|
2001
|
+
return {
|
|
2002
|
+
token_from_address: tokenToSell.address,
|
|
2003
|
+
token_from_amount: uint256.bnToUint256(0),
|
|
2004
|
+
token_to_address: tokenToSell.address,
|
|
2005
|
+
token_to_amount: uint256.bnToUint256(0),
|
|
2006
|
+
token_to_min_amount: uint256.bnToUint256(0),
|
|
2007
|
+
beneficiary: address,
|
|
2008
|
+
integrator_fee_amount_bps: 0,
|
|
2009
|
+
integrator_fee_recipient: address,
|
|
2010
|
+
routes: []
|
|
2011
|
+
};
|
|
2012
|
+
}
|
|
2000
2013
|
};
|
|
2001
2014
|
|
|
2002
2015
|
// src/interfaces/common.ts
|
|
@@ -18632,7 +18645,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
18632
18645
|
const priceNow = await this.getCurrentPrice(blockIdentifier);
|
|
18633
18646
|
let blockNow = typeof blockIdentifier == "number" ? blockIdentifier : (await this.config.provider.getBlockLatestAccepted()).block_number;
|
|
18634
18647
|
const blockNowTime = typeof blockIdentifier == "number" ? (await this.config.provider.getBlockWithTxs(blockIdentifier)).timestamp : (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
18635
|
-
const blockBefore = Math.max(
|
|
18648
|
+
const blockBefore = Math.max(
|
|
18649
|
+
blockNow - sinceBlocks,
|
|
18650
|
+
this.metadata.launchBlock
|
|
18651
|
+
);
|
|
18636
18652
|
const adjustedSupplyNow = supplyNow.minus(
|
|
18637
18653
|
await this.getHarvestRewardShares(blockBefore, blockNow)
|
|
18638
18654
|
);
|
|
@@ -19128,41 +19144,41 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19128
19144
|
);
|
|
19129
19145
|
let retry = 0;
|
|
19130
19146
|
const maxRetry = 10;
|
|
19131
|
-
|
|
19132
|
-
|
|
19133
|
-
if (expectedAmounts.amount0.lessThan(token0Bal) && expectedAmounts.amount1.lessThan(token1Bal)) {
|
|
19147
|
+
function assertValidAmounts(expectedAmounts2, token0Bal2, token1Bal2) {
|
|
19148
|
+
if (expectedAmounts2.amount0.lessThan(token0Bal2) && expectedAmounts2.amount1.lessThan(token1Bal2)) {
|
|
19134
19149
|
throw new Error("Both tokens are decreased, something is wrong");
|
|
19135
19150
|
}
|
|
19136
|
-
if (
|
|
19151
|
+
if (expectedAmounts2.amount0.greaterThan(token0Bal2) && expectedAmounts2.amount1.greaterThan(token1Bal2)) {
|
|
19137
19152
|
throw new Error("Both tokens are increased, something is wrong");
|
|
19138
19153
|
}
|
|
19139
|
-
|
|
19140
|
-
|
|
19141
|
-
|
|
19142
|
-
const
|
|
19143
|
-
const
|
|
19144
|
-
const
|
|
19145
|
-
|
|
19146
|
-
|
|
19147
|
-
|
|
19154
|
+
}
|
|
19155
|
+
function getSwapParams(expectedAmounts2, poolKey2, token0Bal2, token1Bal2) {
|
|
19156
|
+
const tokenToSell = expectedAmounts2.amount0.lessThan(token0Bal2) ? poolKey2.token0 : poolKey2.token1;
|
|
19157
|
+
const tokenToBuy = tokenToSell == poolKey2.token0 ? poolKey2.token1 : poolKey2.token0;
|
|
19158
|
+
const amountToSell = tokenToSell == poolKey2.token0 ? token0Bal2.minus(expectedAmounts2.amount0) : token1Bal2.minus(expectedAmounts2.amount1);
|
|
19159
|
+
const remainingSellAmount = tokenToSell == poolKey2.token0 ? expectedAmounts2.amount0 : expectedAmounts2.amount1;
|
|
19160
|
+
return { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount };
|
|
19161
|
+
}
|
|
19162
|
+
while (retry < maxRetry) {
|
|
19163
|
+
retry++;
|
|
19148
19164
|
logger.verbose(
|
|
19149
|
-
|
|
19165
|
+
`getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
|
|
19150
19166
|
);
|
|
19167
|
+
assertValidAmounts(expectedAmounts, token0Bal, token1Bal);
|
|
19168
|
+
const { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount } = getSwapParams(expectedAmounts, poolKey, token0Bal, token1Bal);
|
|
19169
|
+
const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
|
|
19170
|
+
const expectedRatio = expectedAmounts.ratio;
|
|
19151
19171
|
logger.verbose(
|
|
19152
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused =>
|
|
19172
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => iteration info: ${JSON.stringify({
|
|
19173
|
+
tokenToSell: tokenToSell.address,
|
|
19174
|
+
tokenToBuy: tokenToBuy.address,
|
|
19175
|
+
amountToSell: amountToSell.toString(),
|
|
19176
|
+
remainingSellAmount: remainingSellAmount.toString(),
|
|
19177
|
+
expectedRatio
|
|
19178
|
+
})}`
|
|
19153
19179
|
);
|
|
19154
19180
|
if (amountToSell.eq(0)) {
|
|
19155
|
-
return
|
|
19156
|
-
token_from_address: tokenToSell.address,
|
|
19157
|
-
token_from_amount: uint2564.bnToUint256(0),
|
|
19158
|
-
token_to_address: tokenToSell.address,
|
|
19159
|
-
token_to_amount: uint2564.bnToUint256(0),
|
|
19160
|
-
token_to_min_amount: uint2564.bnToUint256(0),
|
|
19161
|
-
beneficiary: this.address.address,
|
|
19162
|
-
integrator_fee_amount_bps: 0,
|
|
19163
|
-
integrator_fee_recipient: this.address.address,
|
|
19164
|
-
routes: []
|
|
19165
|
-
};
|
|
19181
|
+
return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
|
|
19166
19182
|
}
|
|
19167
19183
|
const quote = await this.avnu.getQuotes(
|
|
19168
19184
|
tokenToSell.address,
|
|
@@ -19190,15 +19206,14 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19190
19206
|
const swapPrice = tokenToSell == poolKey.token0 ? amountOut.dividedBy(amountToSell) : amountToSell.dividedBy(amountOut);
|
|
19191
19207
|
const newRatio = tokenToSell == poolKey.token0 ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut)) : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
|
|
19192
19208
|
logger.verbose(
|
|
19193
|
-
`${_EkuboCLVault.name}
|
|
19194
|
-
|
|
19195
|
-
|
|
19196
|
-
|
|
19197
|
-
|
|
19198
|
-
logger.verbose(
|
|
19199
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
|
|
19209
|
+
`${_EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
|
|
19210
|
+
amountOut: amountOut.toString(),
|
|
19211
|
+
swapPrice: swapPrice.toString(),
|
|
19212
|
+
newRatio: newRatio.toString()
|
|
19213
|
+
})}`
|
|
19200
19214
|
);
|
|
19201
|
-
|
|
19215
|
+
const expectedPrecision = Math.min(7, tokenToBuyInfo.decimals - 2);
|
|
19216
|
+
if (Number(newRatio.toString()) > expectedRatio * (1 + 1 / 10 ** expectedPrecision) || Number(newRatio.toString()) < expectedRatio * (1 - 1 / 10 ** expectedPrecision)) {
|
|
19202
19217
|
expectedAmounts = await this._solveExpectedAmountsEq(
|
|
19203
19218
|
token0Bal,
|
|
19204
19219
|
token1Bal,
|
|
@@ -19397,7 +19412,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19397
19412
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
19398
19413
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
19399
19414
|
const bounds = await this.getCurrentBounds();
|
|
19400
|
-
logger.verbose(
|
|
19415
|
+
logger.verbose(
|
|
19416
|
+
`${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
|
|
19417
|
+
);
|
|
19401
19418
|
const calls = [];
|
|
19402
19419
|
for (let claim of unClaimedRewards) {
|
|
19403
19420
|
const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
|
|
@@ -19555,8 +19572,16 @@ var faqs2 = [
|
|
|
19555
19572
|
{
|
|
19556
19573
|
question: "Is the strategy audited?",
|
|
19557
19574
|
answer: /* @__PURE__ */ jsxs2("div", { children: [
|
|
19558
|
-
"Yes, the strategy has been audited. You can review the audit report in our docs
|
|
19559
|
-
|
|
19575
|
+
"Yes, the strategy has been audited. You can review the audit report in our docs",
|
|
19576
|
+
" ",
|
|
19577
|
+
/* @__PURE__ */ jsx2(
|
|
19578
|
+
"a",
|
|
19579
|
+
{
|
|
19580
|
+
href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details",
|
|
19581
|
+
style: { textDecoration: "underline", marginLeft: "5px" },
|
|
19582
|
+
children: "Here"
|
|
19583
|
+
}
|
|
19584
|
+
),
|
|
19560
19585
|
"."
|
|
19561
19586
|
] })
|
|
19562
19587
|
}
|
|
@@ -19608,7 +19633,12 @@ var EkuboCLVaultStrategies = [
|
|
|
19608
19633
|
lstContract: ContractAddr.from(
|
|
19609
19634
|
"0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
|
|
19610
19635
|
),
|
|
19611
|
-
feeBps: 1e3
|
|
19636
|
+
feeBps: 1e3,
|
|
19637
|
+
rebalanceConditions: {
|
|
19638
|
+
customShouldRebalance: async (currentPrice) => true,
|
|
19639
|
+
minWaitHours: 24,
|
|
19640
|
+
direction: "uponly"
|
|
19641
|
+
}
|
|
19612
19642
|
},
|
|
19613
19643
|
faqs: [
|
|
19614
19644
|
...faqs2,
|
|
@@ -19649,7 +19679,10 @@ var EkuboCLVaultStrategies = [
|
|
|
19649
19679
|
maxTVL: Web3Number.fromWei("0", 6),
|
|
19650
19680
|
risk: {
|
|
19651
19681
|
riskFactor: _riskFactorStable,
|
|
19652
|
-
netRisk: _riskFactorStable.reduce(
|
|
19682
|
+
netRisk: _riskFactorStable.reduce(
|
|
19683
|
+
(acc, curr) => acc + curr.value * curr.weight,
|
|
19684
|
+
0
|
|
19685
|
+
) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
|
|
19653
19686
|
notARisks: getNoRiskTags(_riskFactorStable)
|
|
19654
19687
|
},
|
|
19655
19688
|
apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
|
|
@@ -19659,11 +19692,14 @@ var EkuboCLVaultStrategies = [
|
|
|
19659
19692
|
upper: 1
|
|
19660
19693
|
},
|
|
19661
19694
|
truePrice: 1,
|
|
19662
|
-
feeBps: 1e3
|
|
19695
|
+
feeBps: 1e3,
|
|
19696
|
+
rebalanceConditions: {
|
|
19697
|
+
customShouldRebalance: async (currentPrice) => currentPrice > 0.99 && currentPrice < 1.01,
|
|
19698
|
+
minWaitHours: 6,
|
|
19699
|
+
direction: "any"
|
|
19700
|
+
}
|
|
19663
19701
|
},
|
|
19664
|
-
faqs: [
|
|
19665
|
-
...faqs2
|
|
19666
|
-
]
|
|
19702
|
+
faqs: [...faqs2]
|
|
19667
19703
|
}
|
|
19668
19704
|
];
|
|
19669
19705
|
|
package/package.json
CHANGED
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
|
}
|
|
@@ -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,7 +1624,7 @@ 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
|
-
]
|
|
1627
|
+
],
|
|
1577
1628
|
},
|
|
1578
1629
|
{
|
|
1579
1630
|
name: "Ekubo USDC/USDT",
|
|
@@ -1610,8 +1661,10 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
|
|
|
1610
1661
|
risk: {
|
|
1611
1662
|
riskFactor: _riskFactorStable,
|
|
1612
1663
|
netRisk:
|
|
1613
|
-
|
|
1614
|
-
|
|
1664
|
+
_riskFactorStable.reduce(
|
|
1665
|
+
(acc, curr) => acc + curr.value * curr.weight,
|
|
1666
|
+
0
|
|
1667
|
+
) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1615
1668
|
notARisks: getNoRiskTags(_riskFactorStable),
|
|
1616
1669
|
},
|
|
1617
1670
|
apyMethodology:
|
|
@@ -1623,9 +1676,13 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
|
|
|
1623
1676
|
},
|
|
1624
1677
|
truePrice: 1,
|
|
1625
1678
|
feeBps: 1000,
|
|
1679
|
+
rebalanceConditions: {
|
|
1680
|
+
customShouldRebalance: async (currentPrice: number) =>
|
|
1681
|
+
currentPrice > 0.99 && currentPrice < 1.01,
|
|
1682
|
+
minWaitHours: 6,
|
|
1683
|
+
direction: "any",
|
|
1684
|
+
},
|
|
1626
1685
|
},
|
|
1627
|
-
faqs: [
|
|
1628
|
-
...faqs,
|
|
1629
|
-
]
|
|
1686
|
+
faqs: [...faqs],
|
|
1630
1687
|
},
|
|
1631
1688
|
];
|