@strkfarm/sdk 1.1.50 → 1.1.52
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 +101 -76
- package/dist/index.browser.mjs +99 -74
- package/dist/index.d.ts +5 -1
- package/dist/index.js +129 -75
- package/dist/index.mjs +129 -75
- package/package.json +1 -1
- package/src/modules/avnu.ts +4 -4
- package/src/modules/harvests.ts +22 -15
- package/src/node/deployer.ts +36 -1
- package/src/strategies/ekubo-cl-vault.tsx +97 -57
- package/src/strategies/universal-lst-muliplier-strategy.tsx +8 -4
|
@@ -1597,11 +1597,20 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1597
1597
|
};
|
|
1598
1598
|
}
|
|
1599
1599
|
|
|
1600
|
-
async harvest(acc: Account, maxIterations = 20, priceRatioPrecision = 4): Promise<Call[]> {
|
|
1600
|
+
async harvest(acc: Account, maxIterations = 20, priceRatioPrecision = 4, minRewardAmount: Web3Number = new Web3Number(0, 18)): Promise<Call[]> {
|
|
1601
1601
|
const ekuboHarvests = new EkuboHarvests(this.config);
|
|
1602
|
-
|
|
1602
|
+
|
|
1603
|
+
// get unclaimed rewards and filter out those less than the minimum reward amount
|
|
1604
|
+
const unClaimedRewards = (await ekuboHarvests.getUnHarvestedRewards(
|
|
1603
1605
|
this.address
|
|
1604
|
-
);
|
|
1606
|
+
)).filter(claim => claim.actualReward.greaterThanOrEqualTo(minRewardAmount));
|
|
1607
|
+
|
|
1608
|
+
if (unClaimedRewards.length == 0) {
|
|
1609
|
+
logger.verbose(`${EkuboCLVault.name}: harvest => no unclaimed rewards found`);
|
|
1610
|
+
return [];
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
// get necessary info for the harvest
|
|
1605
1614
|
const poolKey = await this.getPoolKey();
|
|
1606
1615
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
1607
1616
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
@@ -1609,8 +1618,14 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1609
1618
|
logger.verbose(
|
|
1610
1619
|
`${EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
|
|
1611
1620
|
);
|
|
1621
|
+
|
|
1622
|
+
// execute the harvest
|
|
1612
1623
|
const calls: Call[] = [];
|
|
1613
|
-
|
|
1624
|
+
// do one at a time.
|
|
1625
|
+
const chosenClaim = unClaimedRewards[0];
|
|
1626
|
+
logger.info(`${EkuboCLVault.name}: harvest => doing one at a time`);
|
|
1627
|
+
logger.info(`${EkuboCLVault.name}: harvest => chosenClaim -> Claim ID: ${chosenClaim.claim.id}, Amount: ${chosenClaim.claim.amount.toString()}, actualAmount: ${chosenClaim.actualReward.toString()}, addr: ${chosenClaim.claim.claimee.toString()}`);
|
|
1628
|
+
for (let claim of [chosenClaim]) {
|
|
1614
1629
|
const fee = claim.claim.amount
|
|
1615
1630
|
.multipliedBy(this.metadata.additionalInfo.feeBps)
|
|
1616
1631
|
.dividedBy(10000);
|
|
@@ -1683,60 +1698,50 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1683
1698
|
logger.verbose(
|
|
1684
1699
|
`${
|
|
1685
1700
|
EkuboCLVault.name
|
|
1686
|
-
}: harvest => token0Amt: ${token0Amt.
|
|
1687
|
-
);
|
|
1688
|
-
|
|
1689
|
-
// THis function cannot handle swapping of non-STRK pool,
|
|
1690
|
-
// bcz atleast one of token0Amt or token1Amt are in STRK terms.
|
|
1691
|
-
const swapInfo = await this.getSwapInfoGivenAmounts(
|
|
1692
|
-
poolKey,
|
|
1693
|
-
token0Amt,
|
|
1694
|
-
token1Amt,
|
|
1695
|
-
bounds,
|
|
1696
|
-
maxIterations,
|
|
1697
|
-
priceRatioPrecision
|
|
1698
|
-
);
|
|
1699
|
-
swapInfo.token_to_address = token0Info.address.address;
|
|
1700
|
-
logger.verbose(
|
|
1701
|
-
`${EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
|
|
1701
|
+
}: harvest => token0Amt: ${token0Amt.toFixed(18)}, token1Amt: ${token1Amt.toFixed(18)}`
|
|
1702
1702
|
);
|
|
1703
1703
|
|
|
1704
1704
|
logger.verbose(
|
|
1705
1705
|
`${EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
|
|
1706
1706
|
);
|
|
1707
|
-
const
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1707
|
+
const claimTokenInfo = await Global.getTokenInfoFromAddr(claim.token);
|
|
1708
|
+
const harvestEstimateCall = async (baseSwapInfo: SwapInfo) => {
|
|
1709
|
+
// - the base swap if actual swap from claim token to non-claim token
|
|
1710
|
+
// - the other swap is just claim token to claim token (e.g. STRK to STRK)
|
|
1711
|
+
// which is just dummy
|
|
1712
|
+
let baseSwapAmount = Web3Number.fromWei(
|
|
1713
|
+
uint256.uint256ToBN(baseSwapInfo.token_from_amount).toString(),
|
|
1714
|
+
claimTokenInfo.decimals
|
|
1711
1715
|
).minimum(
|
|
1712
|
-
postFeeAmount.toFixed(
|
|
1716
|
+
postFeeAmount.toFixed(claimTokenInfo.decimals)
|
|
1713
1717
|
); // ensure we don't swap more than we have
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
+
if (baseSwapAmount.lt(0.0001)) {
|
|
1719
|
+
baseSwapAmount = new Web3Number(0, claimTokenInfo.decimals);
|
|
1720
|
+
}
|
|
1721
|
+
baseSwapInfo.token_from_amount = uint256.bnToUint256(baseSwapAmount.toWei());
|
|
1718
1722
|
|
|
1723
|
+
const isToken0ClaimToken = claim.token.eq(poolKey.token0);
|
|
1719
1724
|
logger.verbose(
|
|
1720
|
-
`${EkuboCLVault.name}: harvest =>
|
|
1725
|
+
`${EkuboCLVault.name}: harvest => isToken0ClaimToken: ${isToken0ClaimToken}, baseSwapAmount: ${baseSwapAmount}`
|
|
1721
1726
|
);
|
|
1722
1727
|
|
|
1723
|
-
const remainingAmount = postFeeAmount.minus(
|
|
1728
|
+
const remainingAmount = postFeeAmount.minus(baseSwapAmount).maximum(0);
|
|
1724
1729
|
logger.verbose(
|
|
1725
1730
|
`${EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
|
|
1726
1731
|
);
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
+
|
|
1733
|
+
// obv, same to same
|
|
1734
|
+
let dummySwapInfo = AvnuWrapper.buildZeroSwap(claim.token, this.address.address, claim.token);
|
|
1735
|
+
dummySwapInfo.token_from_amount = uint256.bnToUint256(remainingAmount.toWei());
|
|
1736
|
+
|
|
1732
1737
|
logger.verbose(
|
|
1733
|
-
`${EkuboCLVault.name}: harvest =>
|
|
1734
|
-
|
|
1738
|
+
`${EkuboCLVault.name}: harvest => dummySwapInfo: ${JSON.stringify(
|
|
1739
|
+
dummySwapInfo
|
|
1735
1740
|
)}`
|
|
1736
1741
|
);
|
|
1737
1742
|
logger.verbose(
|
|
1738
|
-
`${EkuboCLVault.name}: harvest =>
|
|
1739
|
-
|
|
1743
|
+
`${EkuboCLVault.name}: harvest => baseSwapInfo: ${JSON.stringify(
|
|
1744
|
+
baseSwapInfo
|
|
1740
1745
|
)}`
|
|
1741
1746
|
);
|
|
1742
1747
|
const calldata = [
|
|
@@ -1747,18 +1752,41 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1747
1752
|
claimee: claim.claim.claimee.address,
|
|
1748
1753
|
},
|
|
1749
1754
|
claim.proof.map((p) => num.getDecimalString(p)),
|
|
1750
|
-
|
|
1751
|
-
|
|
1755
|
+
isToken0ClaimToken ? dummySwapInfo : baseSwapInfo, // is token0 claim token, its just dummy swap
|
|
1756
|
+
isToken0ClaimToken ? baseSwapInfo : dummySwapInfo,
|
|
1752
1757
|
];
|
|
1753
|
-
logger.verbose(
|
|
1754
|
-
`${EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
|
|
1755
|
-
calldata
|
|
1756
|
-
)}`
|
|
1757
|
-
);
|
|
1758
1758
|
return [this.contract.populate("harvest", calldata)];
|
|
1759
1759
|
};
|
|
1760
|
+
|
|
1761
|
+
// if token0 == claim token, then the base swapInfo is from claim token to token1
|
|
1762
|
+
// if token1 == claim token, then the base swapInfo is from claim token to token0
|
|
1763
|
+
const isToken0ClaimToken = claim.token.eq(poolKey.token0);
|
|
1764
|
+
let baseSwapInfo = AvnuWrapper.buildZeroSwap(claim.token, this.address.address, isToken0ClaimToken ? token1Info.address : token0Info.address);
|
|
1765
|
+
baseSwapInfo.token_from_amount = uint256.bnToUint256(postFeeAmount.toWei()); // we try to swap all to start with
|
|
1766
|
+
|
|
1767
|
+
// if token0 != claim token, then we swap from claim token to token0
|
|
1768
|
+
if (postFeeAmount.greaterThan(0) && !isToken0ClaimToken) {
|
|
1769
|
+
const avnuWrapper = new AvnuWrapper();
|
|
1770
|
+
const quote = await avnuWrapper.getQuotes(
|
|
1771
|
+
claim.token.address,
|
|
1772
|
+
token0Info.address.address,
|
|
1773
|
+
postFeeAmount.toWei(),
|
|
1774
|
+
this.address.address
|
|
1775
|
+
);
|
|
1776
|
+
baseSwapInfo = await avnuWrapper.getSwapInfo(quote, this.address.address, 0, this.address.address);
|
|
1777
|
+
} else if (postFeeAmount.greaterThan(0) && isToken0ClaimToken) {
|
|
1778
|
+
// if token0 == claim token, then we swap from claim token to token1
|
|
1779
|
+
const avnuWrapper = new AvnuWrapper();
|
|
1780
|
+
const quote = await avnuWrapper.getQuotes(
|
|
1781
|
+
claim.token.address,
|
|
1782
|
+
token1Info.address.address,
|
|
1783
|
+
postFeeAmount.toWei(),
|
|
1784
|
+
this.address.address
|
|
1785
|
+
);
|
|
1786
|
+
baseSwapInfo = await avnuWrapper.getSwapInfo(quote, this.address.address, 0, this.address.address);
|
|
1787
|
+
}
|
|
1760
1788
|
const _callsFinal = await this.rebalanceIter(
|
|
1761
|
-
|
|
1789
|
+
baseSwapInfo,
|
|
1762
1790
|
acc,
|
|
1763
1791
|
harvestEstimateCall,
|
|
1764
1792
|
claim.token.eq(poolKey.token0),
|
|
@@ -1828,39 +1856,47 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1828
1856
|
}) {
|
|
1829
1857
|
const { postFeeAmount, claim, token0Info, token1Info, acc } = params;
|
|
1830
1858
|
let harvestCall: Call | null = null;
|
|
1859
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => postFeeAmount: ${postFeeAmount.toString()}`);
|
|
1831
1860
|
|
|
1861
|
+
let attempt = 0;
|
|
1862
|
+
let MAX_ATTEMPTS = 50;
|
|
1832
1863
|
const binarySearchCallbackFn = async (mid: bigint) => {
|
|
1864
|
+
attempt++;
|
|
1865
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => mid: ${mid}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
|
|
1833
1866
|
const rewardPart2 = BigInt(postFeeAmount.toWei()) - mid;
|
|
1834
1867
|
const avnuWrapper = new AvnuWrapper();
|
|
1835
1868
|
const beneficiary = this.address.address;
|
|
1836
1869
|
|
|
1837
1870
|
// get quote for 1st part
|
|
1838
|
-
const
|
|
1871
|
+
const quote1Prom = avnuWrapper.getQuotes(
|
|
1839
1872
|
claim.token.address,
|
|
1840
1873
|
token0Info.address.address,
|
|
1841
1874
|
mid.toString(),
|
|
1842
1875
|
beneficiary
|
|
1843
1876
|
);
|
|
1877
|
+
const quote2Prom = avnuWrapper.getQuotes(
|
|
1878
|
+
claim.token.address,
|
|
1879
|
+
token1Info.address.address,
|
|
1880
|
+
rewardPart2.toString(),
|
|
1881
|
+
beneficiary
|
|
1882
|
+
);
|
|
1883
|
+
const [quote1, quote2] = await Promise.all([quote1Prom, quote2Prom]);
|
|
1884
|
+
|
|
1844
1885
|
// default min amount is ok
|
|
1845
1886
|
const swapInfo1 = await avnuWrapper.getSwapInfo(
|
|
1846
1887
|
quote1,
|
|
1847
1888
|
beneficiary,
|
|
1848
|
-
0,
|
|
1889
|
+
0, // fee bps
|
|
1849
1890
|
beneficiary
|
|
1850
1891
|
);
|
|
1851
1892
|
|
|
1852
1893
|
// get quote for 2nd part
|
|
1853
|
-
|
|
1854
|
-
claim.token.address,
|
|
1855
|
-
token1Info.address.address,
|
|
1856
|
-
rewardPart2.toString(),
|
|
1857
|
-
beneficiary
|
|
1858
|
-
);
|
|
1894
|
+
|
|
1859
1895
|
// default min amount is ok
|
|
1860
1896
|
const swapInfo2 = await avnuWrapper.getSwapInfo(
|
|
1861
1897
|
quote2,
|
|
1862
1898
|
beneficiary,
|
|
1863
|
-
0,
|
|
1899
|
+
0, // fee bps
|
|
1864
1900
|
beneficiary
|
|
1865
1901
|
);
|
|
1866
1902
|
|
|
@@ -1879,15 +1915,19 @@ export class EkuboCLVault extends BaseStrategy<
|
|
|
1879
1915
|
];
|
|
1880
1916
|
harvestCall = this.contract.populate("harvest", calldata)
|
|
1881
1917
|
const gas = await acc.estimateInvokeFee(harvestCall);
|
|
1918
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => gas: ${gas.overall_fee.toString()}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
|
|
1882
1919
|
return 'found';
|
|
1883
1920
|
} catch (err: any) {
|
|
1884
1921
|
if (err.message.includes('invalid token0 amount')) {
|
|
1922
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => invalid token0 amount, attempt: ${attempt}/${MAX_ATTEMPTS}`);
|
|
1885
1923
|
// too much token0 amount left, may be swap less to token0
|
|
1886
1924
|
return 'go_low';
|
|
1887
1925
|
} else if (err.message.includes('invalid token1 amount')) {
|
|
1926
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => invalid token1 amount, attempt: ${attempt}/${MAX_ATTEMPTS}`);
|
|
1888
1927
|
// too much token1 balance left, may be swap more to token0
|
|
1889
1928
|
return 'go_high';
|
|
1890
1929
|
}
|
|
1930
|
+
logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => error: ${err.message}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
|
|
1891
1931
|
return 'retry';
|
|
1892
1932
|
}
|
|
1893
1933
|
}
|
|
@@ -427,8 +427,10 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
|
|
|
427
427
|
*/
|
|
428
428
|
async getVesuMultiplyCall(params: {
|
|
429
429
|
isDeposit: boolean,
|
|
430
|
-
leg1DepositAmount: Web3Number
|
|
430
|
+
leg1DepositAmount: Web3Number,
|
|
431
|
+
maxEkuboPriceImpact?: number
|
|
431
432
|
}) {
|
|
433
|
+
const maxEkuboPriceImpact = params.maxEkuboPriceImpact || 0.01;
|
|
432
434
|
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
433
435
|
const legLTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
434
436
|
logger.verbose(`${this.getTag()}::getVesuMultiplyCall legLTV: ${legLTV}`);
|
|
@@ -498,7 +500,8 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
|
|
|
498
500
|
marginAmount,
|
|
499
501
|
debtAmount,
|
|
500
502
|
lstDexPriceInUnderlying: dexPrice,
|
|
501
|
-
isIncrease: debtAmount.greaterThan(0)
|
|
503
|
+
isIncrease: debtAmount.greaterThan(0),
|
|
504
|
+
maxEkuboPriceImpact
|
|
502
505
|
});
|
|
503
506
|
}
|
|
504
507
|
|
|
@@ -665,7 +668,8 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
|
|
|
665
668
|
marginAmount: Web3Number, // >0 during deposit
|
|
666
669
|
debtAmount: Web3Number,
|
|
667
670
|
lstDexPriceInUnderlying: number,
|
|
668
|
-
isIncrease: boolean
|
|
671
|
+
isIncrease: boolean,
|
|
672
|
+
maxEkuboPriceImpact: number
|
|
669
673
|
}): Promise<Call[]> {
|
|
670
674
|
logger.verbose(`${this.getTag()}::getModifyLeverCall marginAmount: ${params.marginAmount}, debtAmount: ${params.debtAmount}, lstDexPriceInUnderlying: ${params.lstDexPriceInUnderlying}, isIncrease: ${params.isIncrease}`);
|
|
671
675
|
assert(!params.marginAmount.isZero() || !params.debtAmount.isZero(), 'Deposit/debt must be non-0');
|
|
@@ -714,7 +718,7 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
|
|
|
714
718
|
);
|
|
715
719
|
logger.verbose(`${this.getTag()}::getModifyLeverCall leverSwapQuote: ${JSON.stringify(leverSwapQuote)}`);
|
|
716
720
|
// Ekubo's price impact can randomly show high numbers sometimes.
|
|
717
|
-
assert(leverSwapQuote.price_impact
|
|
721
|
+
assert(leverSwapQuote.price_impact <= params.maxEkuboPriceImpact, 'getIncreaseLeverCall: Price impact is too high [Debt swap]');
|
|
718
722
|
const leverSwap = ekuboQuoter.getVesuMultiplyQuote(leverSwapQuote, fromToken, toToken);
|
|
719
723
|
logger.verbose(`${this.getTag()}::getModifyLeverCall leverSwap: ${JSON.stringify(leverSwap)}`);
|
|
720
724
|
|