@strkfarm/sdk 1.0.40 → 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 +138 -54
- package/dist/index.browser.mjs +138 -54
- package/dist/index.d.ts +18 -0
- package/dist/index.js +138 -54
- package/dist/index.mjs +138 -54
- package/package.json +1 -1
- package/src/modules/avnu.ts +18 -0
- package/src/strategies/ekubo-cl-vault.tsx +197 -79
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
|
);
|
|
@@ -19090,14 +19106,24 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19090
19106
|
_solveExpectedAmountsEq(availableAmount0, availableAmount1, ratio, price) {
|
|
19091
19107
|
const y = ratio.multipliedBy(availableAmount1).minus(availableAmount0).dividedBy(ratio.plus(1 / price));
|
|
19092
19108
|
const x = y.dividedBy(price);
|
|
19109
|
+
logger.verbose(
|
|
19110
|
+
`${_EkuboCLVault.name}: _solveExpectedAmountsEq => x: ${x.toString()}, y: ${y.toString()}, amount0: ${availableAmount0.toString()}, amount1: ${availableAmount1.toString()}`
|
|
19111
|
+
);
|
|
19112
|
+
if (ratio.eq(0)) {
|
|
19113
|
+
return {
|
|
19114
|
+
amount0: Web3Number.fromWei("0", availableAmount0.decimals),
|
|
19115
|
+
amount1: availableAmount1.minus(y),
|
|
19116
|
+
ratio: 0
|
|
19117
|
+
};
|
|
19118
|
+
}
|
|
19093
19119
|
return {
|
|
19094
19120
|
amount0: availableAmount0.plus(x),
|
|
19095
19121
|
amount1: availableAmount1.minus(y),
|
|
19096
19122
|
ratio: Number(ratio.toString())
|
|
19097
19123
|
};
|
|
19098
19124
|
}
|
|
19099
|
-
async
|
|
19100
|
-
const poolKey = await this.getPoolKey();
|
|
19125
|
+
async unusedBalances(_poolKey) {
|
|
19126
|
+
const poolKey = _poolKey || await this.getPoolKey();
|
|
19101
19127
|
const erc20Mod = new ERC20(this.config);
|
|
19102
19128
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
19103
19129
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
@@ -19118,11 +19144,24 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19118
19144
|
const token1Price = await this.pricer.getPrice(token1Info.symbol);
|
|
19119
19145
|
const token0PriceUsd = token0Price.price * Number(token0Bal1.toFixed(13));
|
|
19120
19146
|
const token1PriceUsd = token1Price.price * Number(token1Bal1.toFixed(13));
|
|
19121
|
-
|
|
19122
|
-
|
|
19123
|
-
|
|
19124
|
-
|
|
19125
|
-
|
|
19147
|
+
return {
|
|
19148
|
+
token0: {
|
|
19149
|
+
amount: token0Bal1,
|
|
19150
|
+
tokenInfo: token0Info,
|
|
19151
|
+
usdValue: token0PriceUsd
|
|
19152
|
+
},
|
|
19153
|
+
token1: {
|
|
19154
|
+
amount: token1Bal1,
|
|
19155
|
+
tokenInfo: token1Info,
|
|
19156
|
+
usdValue: token1PriceUsd
|
|
19157
|
+
}
|
|
19158
|
+
};
|
|
19159
|
+
}
|
|
19160
|
+
async getSwapInfoToHandleUnused(considerRebalance = true) {
|
|
19161
|
+
const poolKey = await this.getPoolKey();
|
|
19162
|
+
const unusedBalances = await this.unusedBalances(poolKey);
|
|
19163
|
+
const { amount: token0Bal1, usdValue: token0PriceUsd } = unusedBalances.token0;
|
|
19164
|
+
const { amount: token1Bal1, usdValue: token1PriceUsd } = unusedBalances.token1;
|
|
19126
19165
|
let token0Bal = token0Bal1;
|
|
19127
19166
|
let token1Bal = token1Bal1;
|
|
19128
19167
|
if (considerRebalance) {
|
|
@@ -19140,63 +19179,71 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19140
19179
|
logger.verbose(
|
|
19141
19180
|
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
|
|
19142
19181
|
);
|
|
19143
|
-
|
|
19182
|
+
let ekuboBounds;
|
|
19183
|
+
if (considerRebalance) {
|
|
19184
|
+
ekuboBounds = await this.getNewBounds();
|
|
19185
|
+
} else {
|
|
19186
|
+
ekuboBounds = await this.getCurrentBounds();
|
|
19187
|
+
}
|
|
19144
19188
|
logger.verbose(
|
|
19145
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newBounds: ${
|
|
19189
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newBounds: ${ekuboBounds.lowerTick}, ${ekuboBounds.upperTick}`
|
|
19146
19190
|
);
|
|
19147
19191
|
return await this.getSwapInfoGivenAmounts(
|
|
19148
19192
|
poolKey,
|
|
19149
19193
|
token0Bal,
|
|
19150
19194
|
token1Bal,
|
|
19151
|
-
|
|
19195
|
+
ekuboBounds
|
|
19152
19196
|
);
|
|
19153
19197
|
}
|
|
19154
19198
|
async getSwapInfoGivenAmounts(poolKey, token0Bal, token1Bal, bounds) {
|
|
19199
|
+
logger.verbose(
|
|
19200
|
+
`${_EkuboCLVault.name}: getSwapInfoGivenAmounts::pre => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
|
|
19201
|
+
);
|
|
19155
19202
|
let expectedAmounts = await this._getExpectedAmountsForLiquidity(
|
|
19156
19203
|
token0Bal,
|
|
19157
19204
|
token1Bal,
|
|
19158
19205
|
bounds
|
|
19159
19206
|
);
|
|
19160
19207
|
logger.verbose(
|
|
19161
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused =>
|
|
19208
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => expectedAmounts2: ${expectedAmounts.amount0.toString()}, ${expectedAmounts.amount1.toString()}`
|
|
19162
19209
|
);
|
|
19163
19210
|
let retry = 0;
|
|
19164
19211
|
const maxRetry = 10;
|
|
19165
|
-
|
|
19166
|
-
|
|
19167
|
-
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)) {
|
|
19168
19214
|
throw new Error("Both tokens are decreased, something is wrong");
|
|
19169
19215
|
}
|
|
19170
|
-
if (
|
|
19216
|
+
if (expectedAmounts2.amount0.greaterThan(token0Bal2) && expectedAmounts2.amount1.greaterThan(token1Bal2)) {
|
|
19171
19217
|
throw new Error("Both tokens are increased, something is wrong");
|
|
19172
19218
|
}
|
|
19173
|
-
|
|
19174
|
-
|
|
19175
|
-
|
|
19176
|
-
const
|
|
19177
|
-
const
|
|
19178
|
-
const
|
|
19179
|
-
|
|
19180
|
-
|
|
19181
|
-
|
|
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++;
|
|
19182
19229
|
logger.verbose(
|
|
19183
|
-
|
|
19230
|
+
`getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
|
|
19184
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;
|
|
19185
19236
|
logger.verbose(
|
|
19186
|
-
`${_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
|
+
})}`
|
|
19187
19244
|
);
|
|
19188
19245
|
if (amountToSell.eq(0)) {
|
|
19189
|
-
return
|
|
19190
|
-
token_from_address: tokenToSell.address,
|
|
19191
|
-
token_from_amount: import_starknet9.uint256.bnToUint256(0),
|
|
19192
|
-
token_to_address: tokenToSell.address,
|
|
19193
|
-
token_to_amount: import_starknet9.uint256.bnToUint256(0),
|
|
19194
|
-
token_to_min_amount: import_starknet9.uint256.bnToUint256(0),
|
|
19195
|
-
beneficiary: this.address.address,
|
|
19196
|
-
integrator_fee_amount_bps: 0,
|
|
19197
|
-
integrator_fee_recipient: this.address.address,
|
|
19198
|
-
routes: []
|
|
19199
|
-
};
|
|
19246
|
+
return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
|
|
19200
19247
|
}
|
|
19201
19248
|
const quote = await this.avnu.getQuotes(
|
|
19202
19249
|
tokenToSell.address,
|
|
@@ -19224,15 +19271,14 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19224
19271
|
const swapPrice = tokenToSell == poolKey.token0 ? amountOut.dividedBy(amountToSell) : amountToSell.dividedBy(amountOut);
|
|
19225
19272
|
const newRatio = tokenToSell == poolKey.token0 ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut)) : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
|
|
19226
19273
|
logger.verbose(
|
|
19227
|
-
`${_EkuboCLVault.name}
|
|
19274
|
+
`${_EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
|
|
19275
|
+
amountOut: amountOut.toString(),
|
|
19276
|
+
swapPrice: swapPrice.toString(),
|
|
19277
|
+
newRatio: newRatio.toString()
|
|
19278
|
+
})}`
|
|
19228
19279
|
);
|
|
19229
|
-
|
|
19230
|
-
|
|
19231
|
-
);
|
|
19232
|
-
logger.verbose(
|
|
19233
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
|
|
19234
|
-
);
|
|
19235
|
-
if (Number(newRatio.toString()) > expectedRatio * 1.0000001 || Number(newRatio.toString()) < expectedRatio * 0.9999999) {
|
|
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)) {
|
|
19236
19282
|
expectedAmounts = await this._solveExpectedAmountsEq(
|
|
19237
19283
|
token0Bal,
|
|
19238
19284
|
token1Bal,
|
|
@@ -19431,6 +19477,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19431
19477
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
19432
19478
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
19433
19479
|
const bounds = await this.getCurrentBounds();
|
|
19480
|
+
logger.verbose(
|
|
19481
|
+
`${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
|
|
19482
|
+
);
|
|
19434
19483
|
const calls = [];
|
|
19435
19484
|
for (let claim of unClaimedRewards) {
|
|
19436
19485
|
const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
|
|
@@ -19463,12 +19512,28 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19463
19512
|
18
|
|
19464
19513
|
// cause its always STRK?
|
|
19465
19514
|
);
|
|
19515
|
+
logger.verbose(
|
|
19516
|
+
`${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
|
|
19517
|
+
);
|
|
19466
19518
|
const remainingAmount = postFeeAmount.minus(swap1Amount);
|
|
19519
|
+
logger.verbose(
|
|
19520
|
+
`${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
|
|
19521
|
+
);
|
|
19467
19522
|
const swapInfo2 = {
|
|
19468
19523
|
...swapInfo,
|
|
19469
19524
|
token_from_amount: import_starknet9.uint256.bnToUint256(remainingAmount.toWei())
|
|
19470
19525
|
};
|
|
19471
19526
|
swapInfo2.token_to_address = token1Info.address.address;
|
|
19527
|
+
logger.verbose(
|
|
19528
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
19529
|
+
swapInfo
|
|
19530
|
+
)}`
|
|
19531
|
+
);
|
|
19532
|
+
logger.verbose(
|
|
19533
|
+
`${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
|
|
19534
|
+
swapInfo2
|
|
19535
|
+
)}`
|
|
19536
|
+
);
|
|
19472
19537
|
const calldata = [
|
|
19473
19538
|
claim.rewardsContract.address,
|
|
19474
19539
|
{
|
|
@@ -19572,8 +19637,16 @@ var faqs2 = [
|
|
|
19572
19637
|
{
|
|
19573
19638
|
question: "Is the strategy audited?",
|
|
19574
19639
|
answer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
19575
|
-
"Yes, the strategy has been audited. You can review the audit report in our docs
|
|
19576
|
-
|
|
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
|
+
),
|
|
19577
19650
|
"."
|
|
19578
19651
|
] })
|
|
19579
19652
|
}
|
|
@@ -19625,7 +19698,12 @@ var EkuboCLVaultStrategies = [
|
|
|
19625
19698
|
lstContract: ContractAddr.from(
|
|
19626
19699
|
"0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
|
|
19627
19700
|
),
|
|
19628
|
-
feeBps: 1e3
|
|
19701
|
+
feeBps: 1e3,
|
|
19702
|
+
rebalanceConditions: {
|
|
19703
|
+
customShouldRebalance: async (currentPrice) => true,
|
|
19704
|
+
minWaitHours: 24,
|
|
19705
|
+
direction: "uponly"
|
|
19706
|
+
}
|
|
19629
19707
|
},
|
|
19630
19708
|
faqs: [
|
|
19631
19709
|
...faqs2,
|
|
@@ -19666,7 +19744,10 @@ var EkuboCLVaultStrategies = [
|
|
|
19666
19744
|
maxTVL: Web3Number.fromWei("0", 6),
|
|
19667
19745
|
risk: {
|
|
19668
19746
|
riskFactor: _riskFactorStable,
|
|
19669
|
-
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),
|
|
19670
19751
|
notARisks: getNoRiskTags(_riskFactorStable)
|
|
19671
19752
|
},
|
|
19672
19753
|
apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
|
|
@@ -19676,11 +19757,14 @@ var EkuboCLVaultStrategies = [
|
|
|
19676
19757
|
upper: 1
|
|
19677
19758
|
},
|
|
19678
19759
|
truePrice: 1,
|
|
19679
|
-
feeBps: 1e3
|
|
19760
|
+
feeBps: 1e3,
|
|
19761
|
+
rebalanceConditions: {
|
|
19762
|
+
customShouldRebalance: async (currentPrice) => currentPrice > 0.99 && currentPrice < 1.01,
|
|
19763
|
+
minWaitHours: 6,
|
|
19764
|
+
direction: "any"
|
|
19765
|
+
}
|
|
19680
19766
|
},
|
|
19681
|
-
faqs: [
|
|
19682
|
-
...faqs2
|
|
19683
|
-
]
|
|
19767
|
+
faqs: [...faqs2]
|
|
19684
19768
|
}
|
|
19685
19769
|
];
|
|
19686
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
|
);
|
|
@@ -19025,14 +19041,24 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19025
19041
|
_solveExpectedAmountsEq(availableAmount0, availableAmount1, ratio, price) {
|
|
19026
19042
|
const y = ratio.multipliedBy(availableAmount1).minus(availableAmount0).dividedBy(ratio.plus(1 / price));
|
|
19027
19043
|
const x = y.dividedBy(price);
|
|
19044
|
+
logger.verbose(
|
|
19045
|
+
`${_EkuboCLVault.name}: _solveExpectedAmountsEq => x: ${x.toString()}, y: ${y.toString()}, amount0: ${availableAmount0.toString()}, amount1: ${availableAmount1.toString()}`
|
|
19046
|
+
);
|
|
19047
|
+
if (ratio.eq(0)) {
|
|
19048
|
+
return {
|
|
19049
|
+
amount0: Web3Number.fromWei("0", availableAmount0.decimals),
|
|
19050
|
+
amount1: availableAmount1.minus(y),
|
|
19051
|
+
ratio: 0
|
|
19052
|
+
};
|
|
19053
|
+
}
|
|
19028
19054
|
return {
|
|
19029
19055
|
amount0: availableAmount0.plus(x),
|
|
19030
19056
|
amount1: availableAmount1.minus(y),
|
|
19031
19057
|
ratio: Number(ratio.toString())
|
|
19032
19058
|
};
|
|
19033
19059
|
}
|
|
19034
|
-
async
|
|
19035
|
-
const poolKey = await this.getPoolKey();
|
|
19060
|
+
async unusedBalances(_poolKey) {
|
|
19061
|
+
const poolKey = _poolKey || await this.getPoolKey();
|
|
19036
19062
|
const erc20Mod = new ERC20(this.config);
|
|
19037
19063
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
19038
19064
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
@@ -19053,11 +19079,24 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19053
19079
|
const token1Price = await this.pricer.getPrice(token1Info.symbol);
|
|
19054
19080
|
const token0PriceUsd = token0Price.price * Number(token0Bal1.toFixed(13));
|
|
19055
19081
|
const token1PriceUsd = token1Price.price * Number(token1Bal1.toFixed(13));
|
|
19056
|
-
|
|
19057
|
-
|
|
19058
|
-
|
|
19059
|
-
|
|
19060
|
-
|
|
19082
|
+
return {
|
|
19083
|
+
token0: {
|
|
19084
|
+
amount: token0Bal1,
|
|
19085
|
+
tokenInfo: token0Info,
|
|
19086
|
+
usdValue: token0PriceUsd
|
|
19087
|
+
},
|
|
19088
|
+
token1: {
|
|
19089
|
+
amount: token1Bal1,
|
|
19090
|
+
tokenInfo: token1Info,
|
|
19091
|
+
usdValue: token1PriceUsd
|
|
19092
|
+
}
|
|
19093
|
+
};
|
|
19094
|
+
}
|
|
19095
|
+
async getSwapInfoToHandleUnused(considerRebalance = true) {
|
|
19096
|
+
const poolKey = await this.getPoolKey();
|
|
19097
|
+
const unusedBalances = await this.unusedBalances(poolKey);
|
|
19098
|
+
const { amount: token0Bal1, usdValue: token0PriceUsd } = unusedBalances.token0;
|
|
19099
|
+
const { amount: token1Bal1, usdValue: token1PriceUsd } = unusedBalances.token1;
|
|
19061
19100
|
let token0Bal = token0Bal1;
|
|
19062
19101
|
let token1Bal = token1Bal1;
|
|
19063
19102
|
if (considerRebalance) {
|
|
@@ -19075,63 +19114,71 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19075
19114
|
logger.verbose(
|
|
19076
19115
|
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
|
|
19077
19116
|
);
|
|
19078
|
-
|
|
19117
|
+
let ekuboBounds;
|
|
19118
|
+
if (considerRebalance) {
|
|
19119
|
+
ekuboBounds = await this.getNewBounds();
|
|
19120
|
+
} else {
|
|
19121
|
+
ekuboBounds = await this.getCurrentBounds();
|
|
19122
|
+
}
|
|
19079
19123
|
logger.verbose(
|
|
19080
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newBounds: ${
|
|
19124
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newBounds: ${ekuboBounds.lowerTick}, ${ekuboBounds.upperTick}`
|
|
19081
19125
|
);
|
|
19082
19126
|
return await this.getSwapInfoGivenAmounts(
|
|
19083
19127
|
poolKey,
|
|
19084
19128
|
token0Bal,
|
|
19085
19129
|
token1Bal,
|
|
19086
|
-
|
|
19130
|
+
ekuboBounds
|
|
19087
19131
|
);
|
|
19088
19132
|
}
|
|
19089
19133
|
async getSwapInfoGivenAmounts(poolKey, token0Bal, token1Bal, bounds) {
|
|
19134
|
+
logger.verbose(
|
|
19135
|
+
`${_EkuboCLVault.name}: getSwapInfoGivenAmounts::pre => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
|
|
19136
|
+
);
|
|
19090
19137
|
let expectedAmounts = await this._getExpectedAmountsForLiquidity(
|
|
19091
19138
|
token0Bal,
|
|
19092
19139
|
token1Bal,
|
|
19093
19140
|
bounds
|
|
19094
19141
|
);
|
|
19095
19142
|
logger.verbose(
|
|
19096
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused =>
|
|
19143
|
+
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => expectedAmounts2: ${expectedAmounts.amount0.toString()}, ${expectedAmounts.amount1.toString()}`
|
|
19097
19144
|
);
|
|
19098
19145
|
let retry = 0;
|
|
19099
19146
|
const maxRetry = 10;
|
|
19100
|
-
|
|
19101
|
-
|
|
19102
|
-
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)) {
|
|
19103
19149
|
throw new Error("Both tokens are decreased, something is wrong");
|
|
19104
19150
|
}
|
|
19105
|
-
if (
|
|
19151
|
+
if (expectedAmounts2.amount0.greaterThan(token0Bal2) && expectedAmounts2.amount1.greaterThan(token1Bal2)) {
|
|
19106
19152
|
throw new Error("Both tokens are increased, something is wrong");
|
|
19107
19153
|
}
|
|
19108
|
-
|
|
19109
|
-
|
|
19110
|
-
|
|
19111
|
-
const
|
|
19112
|
-
const
|
|
19113
|
-
const
|
|
19114
|
-
|
|
19115
|
-
|
|
19116
|
-
|
|
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++;
|
|
19117
19164
|
logger.verbose(
|
|
19118
|
-
|
|
19165
|
+
`getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
|
|
19119
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;
|
|
19120
19171
|
logger.verbose(
|
|
19121
|
-
`${_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
|
+
})}`
|
|
19122
19179
|
);
|
|
19123
19180
|
if (amountToSell.eq(0)) {
|
|
19124
|
-
return
|
|
19125
|
-
token_from_address: tokenToSell.address,
|
|
19126
|
-
token_from_amount: uint2564.bnToUint256(0),
|
|
19127
|
-
token_to_address: tokenToSell.address,
|
|
19128
|
-
token_to_amount: uint2564.bnToUint256(0),
|
|
19129
|
-
token_to_min_amount: uint2564.bnToUint256(0),
|
|
19130
|
-
beneficiary: this.address.address,
|
|
19131
|
-
integrator_fee_amount_bps: 0,
|
|
19132
|
-
integrator_fee_recipient: this.address.address,
|
|
19133
|
-
routes: []
|
|
19134
|
-
};
|
|
19181
|
+
return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
|
|
19135
19182
|
}
|
|
19136
19183
|
const quote = await this.avnu.getQuotes(
|
|
19137
19184
|
tokenToSell.address,
|
|
@@ -19159,15 +19206,14 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19159
19206
|
const swapPrice = tokenToSell == poolKey.token0 ? amountOut.dividedBy(amountToSell) : amountToSell.dividedBy(amountOut);
|
|
19160
19207
|
const newRatio = tokenToSell == poolKey.token0 ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut)) : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
|
|
19161
19208
|
logger.verbose(
|
|
19162
|
-
`${_EkuboCLVault.name}
|
|
19209
|
+
`${_EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
|
|
19210
|
+
amountOut: amountOut.toString(),
|
|
19211
|
+
swapPrice: swapPrice.toString(),
|
|
19212
|
+
newRatio: newRatio.toString()
|
|
19213
|
+
})}`
|
|
19163
19214
|
);
|
|
19164
|
-
|
|
19165
|
-
|
|
19166
|
-
);
|
|
19167
|
-
logger.verbose(
|
|
19168
|
-
`${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
|
|
19169
|
-
);
|
|
19170
|
-
if (Number(newRatio.toString()) > expectedRatio * 1.0000001 || Number(newRatio.toString()) < expectedRatio * 0.9999999) {
|
|
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)) {
|
|
19171
19217
|
expectedAmounts = await this._solveExpectedAmountsEq(
|
|
19172
19218
|
token0Bal,
|
|
19173
19219
|
token1Bal,
|
|
@@ -19366,6 +19412,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19366
19412
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
19367
19413
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
19368
19414
|
const bounds = await this.getCurrentBounds();
|
|
19415
|
+
logger.verbose(
|
|
19416
|
+
`${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
|
|
19417
|
+
);
|
|
19369
19418
|
const calls = [];
|
|
19370
19419
|
for (let claim of unClaimedRewards) {
|
|
19371
19420
|
const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
|
|
@@ -19398,12 +19447,28 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
19398
19447
|
18
|
|
19399
19448
|
// cause its always STRK?
|
|
19400
19449
|
);
|
|
19450
|
+
logger.verbose(
|
|
19451
|
+
`${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
|
|
19452
|
+
);
|
|
19401
19453
|
const remainingAmount = postFeeAmount.minus(swap1Amount);
|
|
19454
|
+
logger.verbose(
|
|
19455
|
+
`${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
|
|
19456
|
+
);
|
|
19402
19457
|
const swapInfo2 = {
|
|
19403
19458
|
...swapInfo,
|
|
19404
19459
|
token_from_amount: uint2564.bnToUint256(remainingAmount.toWei())
|
|
19405
19460
|
};
|
|
19406
19461
|
swapInfo2.token_to_address = token1Info.address.address;
|
|
19462
|
+
logger.verbose(
|
|
19463
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
19464
|
+
swapInfo
|
|
19465
|
+
)}`
|
|
19466
|
+
);
|
|
19467
|
+
logger.verbose(
|
|
19468
|
+
`${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
|
|
19469
|
+
swapInfo2
|
|
19470
|
+
)}`
|
|
19471
|
+
);
|
|
19407
19472
|
const calldata = [
|
|
19408
19473
|
claim.rewardsContract.address,
|
|
19409
19474
|
{
|
|
@@ -19507,8 +19572,16 @@ var faqs2 = [
|
|
|
19507
19572
|
{
|
|
19508
19573
|
question: "Is the strategy audited?",
|
|
19509
19574
|
answer: /* @__PURE__ */ jsxs2("div", { children: [
|
|
19510
|
-
"Yes, the strategy has been audited. You can review the audit report in our docs
|
|
19511
|
-
|
|
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
|
+
),
|
|
19512
19585
|
"."
|
|
19513
19586
|
] })
|
|
19514
19587
|
}
|
|
@@ -19560,7 +19633,12 @@ var EkuboCLVaultStrategies = [
|
|
|
19560
19633
|
lstContract: ContractAddr.from(
|
|
19561
19634
|
"0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
|
|
19562
19635
|
),
|
|
19563
|
-
feeBps: 1e3
|
|
19636
|
+
feeBps: 1e3,
|
|
19637
|
+
rebalanceConditions: {
|
|
19638
|
+
customShouldRebalance: async (currentPrice) => true,
|
|
19639
|
+
minWaitHours: 24,
|
|
19640
|
+
direction: "uponly"
|
|
19641
|
+
}
|
|
19564
19642
|
},
|
|
19565
19643
|
faqs: [
|
|
19566
19644
|
...faqs2,
|
|
@@ -19601,7 +19679,10 @@ var EkuboCLVaultStrategies = [
|
|
|
19601
19679
|
maxTVL: Web3Number.fromWei("0", 6),
|
|
19602
19680
|
risk: {
|
|
19603
19681
|
riskFactor: _riskFactorStable,
|
|
19604
|
-
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),
|
|
19605
19686
|
notARisks: getNoRiskTags(_riskFactorStable)
|
|
19606
19687
|
},
|
|
19607
19688
|
apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
|
|
@@ -19611,11 +19692,14 @@ var EkuboCLVaultStrategies = [
|
|
|
19611
19692
|
upper: 1
|
|
19612
19693
|
},
|
|
19613
19694
|
truePrice: 1,
|
|
19614
|
-
feeBps: 1e3
|
|
19695
|
+
feeBps: 1e3,
|
|
19696
|
+
rebalanceConditions: {
|
|
19697
|
+
customShouldRebalance: async (currentPrice) => currentPrice > 0.99 && currentPrice < 1.01,
|
|
19698
|
+
minWaitHours: 6,
|
|
19699
|
+
direction: "any"
|
|
19700
|
+
}
|
|
19615
19701
|
},
|
|
19616
|
-
faqs: [
|
|
19617
|
-
...faqs2
|
|
19618
|
-
]
|
|
19702
|
+
faqs: [...faqs2]
|
|
19619
19703
|
}
|
|
19620
19704
|
];
|
|
19621
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
|
}
|