From 413b28ac36efbbd439fab670686d349664b977f0 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Thu, 6 Apr 2023 14:58:54 +0200 Subject: [PATCH] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/163 --- src/v2/Carousel/Carousel.sol | 19 ++++++++++++------- test/V2/Carousel/CarouselTest.t.sol | 7 +++++++ test/V2/Helper.sol | 4 ++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 74e7a81c..b96f0637 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -394,35 +394,40 @@ contract Carousel is VaultV2 { while ((index - prevIndex) < (_operations)) { // only roll over if last epoch is resolved if (epochResolved[queue[index].epochId]) { - uint256 entitledShares = previewWithdraw( + uint256 entitledAmount = previewWithdraw( queue[index].epochId, queue[index].assets ); // mint only if user won epoch he is rolling over - if (entitledShares > queue[index].assets) { + if (entitledAmount > queue[index].assets) { + uint256 diff = entitledAmount - queue[index].assets; + // get diff amount in assets + uint256 diffInAssets = diff.mulDivUp(finalTVL[queue[index].epochId], claimTVL[queue[index].epochId]); // skip the rollover for the user if the assets cannot cover the relayer fee instead of revert. if (queue[index].assets < relayerFee) { index++; continue; } + + uint256 originalDepositValue = queue[index].assets - diffInAssets; // @note we know shares were locked up to this point _burn( queue[index].receiver, queue[index].epochId, - queue[index].assets + originalDepositValue ); // transfer emission tokens out of contract otherwise user could not access them as vault shares are burned _burnEmissions( queue[index].receiver, queue[index].epochId, - queue[index].assets + originalDepositValue ); // @note emission token is a known token which has no before transfer hooks which makes transfer safer emissionsToken.safeTransfer( queue[index].receiver, previewEmissionsWithdraw( queue[index].epochId, - queue[index].assets + originalDepositValue ) ); @@ -431,8 +436,8 @@ contract Carousel is VaultV2 { queue[index].receiver, queue[index].receiver, _epochId, - queue[index].assets, - entitledShares + originalDepositValue, + entitledAmount ); uint256 assetsToMint = queue[index].assets - relayerFee; _mintShares(queue[index].receiver, _epochId, assetsToMint); diff --git a/test/V2/Carousel/CarouselTest.t.sol b/test/V2/Carousel/CarouselTest.t.sol index 6bdc1695..6915347a 100644 --- a/test/V2/Carousel/CarouselTest.t.sol +++ b/test/V2/Carousel/CarouselTest.t.sol @@ -320,6 +320,9 @@ contract CarouselTest is Helper { console.log("rollover queue length", vault.getRolloverQueueLenght()); + // get value of prev epoch sahres for user + uint256 prevEpochShareValue = vault.previewWithdraw(prevEpoch, vault.balanceOf(USER, prevEpoch)); + // mint rollovers again // this should mint shares as prev epoch is in profit // should only mint as many positions as there are in queue (6) @@ -333,6 +336,10 @@ contract CarouselTest is Helper { uint256 _relayerFee = (balanceAfter - balanceBefore) / 6; assertEq(_relayerFee, relayerFee); + //@note after rollover, prev value of shares should subtract by original deposit value + uint256 prevEpochSharesValueAfterRollover = vault.previewWithdraw(prevEpoch, vault.balanceOf(USER, prevEpoch)); + assertEq(((prevEpochSharesValueAfterRollover >> 1) << 1) , ((prevEpochShareValue - prevEpochUserBalance) >> 1) << 1); // zero out last bit to avoid rounding errors + // check balances assertEq(vault.balanceOf(USER, _epochId), prevEpochUserBalance - relayerFee); assertEq(vault.balanceOfEmissions(USER, _epochId), prevEpochUserBalance - relayerFee); diff --git a/test/V2/Helper.sol b/test/V2/Helper.sol index feb1f88f..db1d8153 100644 --- a/test/V2/Helper.sol +++ b/test/V2/Helper.sol @@ -10,8 +10,8 @@ contract Helper is Test { uint256 public constant COLLATERAL_MINUS_FEES = 21989999998407999999; uint256 public constant COLLATERAL_MINUS_FEES_DIV10 = 2198999999840799999; uint256 public constant NEXT_COLLATERAL_MINUS_FEES = 21827317001456829250; - uint256 public constant USER1_EMISSIONS_AFTER_WITHDRAW = 1099999999999999999749; - uint256 public constant USER2_EMISSIONS_AFTER_WITHDRAW = 99999999999999999749; + uint256 public constant USER1_EMISSIONS_AFTER_WITHDRAW = 1096380172807730660741; + uint256 public constant USER2_EMISSIONS_AFTER_WITHDRAW = 96380172807730660741; uint256 public constant USER_AMOUNT_AFTER_WITHDRAW = 13112658495641799945; address public constant ADMIN = address(0x1); address public constant WETH = address(0x888);