User can receive more rewards through a mistake in the withdrawal logic
In the `withdraw()` function of the SingleSidedLiquidityVault the contract updates the reward state. Because of a mistake in the calculation, the user is assigned more rewards than they're supposed to.\\nWhen a user withdraws their funds, the `_withdrawUpdateRewardState()` function checks how many rewards those LP shares generated. If that amount is higher than the actual amount of reward tokens that the user claimed, the difference between those values is cached and the amount the user claimed is set to 0. That way they receive the remaining shares the next time they claim.\\nBut, the contract resets the number of reward tokens the user claimed before it computes the difference. That way, the full amount of reward tokens the LP shares generated are added to the cache.\\nHere's an example:\\nAlice deposits funds and receives 1e18 shares\\nAlice receives 1e17 rewards and claims those funds immediately\\nTime passes and Alice earns 5e17 more reward tokens\\nInstead of claiming those tokens, Alice withdraws 5e17 (50% of her shares) That executes `_withdrawUpdateRewardState()` with `lpAmount_ = 5e17` and claim = false:\\n```\\n    function _withdrawUpdateRewardState(uint256 lpAmount_, bool claim_) internal {\\n        uint256 numInternalRewardTokens = internalRewardTokens.length;\\n        uint256 numExternalRewardTokens = externalRewardTokens.length;\\n\\n        // Handles accounting logic for internal and external rewards, harvests external rewards\\n        uint256[] memory accumulatedInternalRewards = _accumulateInternalRewards();\\n        uint256[] memory accumulatedExternalRewards = _accumulateExternalRewards();\\n        for (uint256 i; i < numInternalRewardTokens;) {\\n            _updateInternalRewardState(i, accumulatedInternalRewards[i]);\\n            if (claim_) _claimInternalRewards(i);\\n\\n            // Update reward debts so as to not understate the amount of rewards owed to the user, and push\\n            // any unclaimed rewards to the user's reward debt so that they can be claimed later\\n            InternalRewardToken memory rewardToken = internalRewardTokens[i];\\n            // @audit In our example, rewardDebtDiff = 3e17 (total rewards are 6e17 so 50% of shares earned 50% of reward tokens)\\n            uint256 rewardDebtDiff = lpAmount_ * rewardToken.accumulatedRewardsPerShare;\\n\\n            // @audit 3e17 > 1e17\\n            if (rewardDebtDiff > userRewardDebts[msg.sender][rewardToken.token]) {\\n\\n                // @audit userRewardDebts is set to 0 (original value was 1e17, the number of tokens that were already claimed)\\n                userRewardDebts[msg.sender][rewardToken.token] = 0;\\n                // @audit cached amount = 3e17 - 0 = 3e17.\\n                // Alice is assigned 3e17 reward tokens to be distributed the next time they claim\\n                // The remaining 3e17 LP shares are worth another 3e17 reward tokens.\\n                // Alice already claimed 1e17 before the withdrawal.\\n                // Thus, Alice receives 7e17 reward tokens instead of 6e17\\n                cachedUserRewards[msg.sender][rewardToken.token] +=\\n                    rewardDebtDiff - userRewardDebts[msg.sender][rewardToken.token];\\n            } else {\\n                userRewardDebts[msg.sender][rewardToken.token] -= rewardDebtDiff;\\n            }\\n\\n            unchecked {\\n                ++i;\\n            }\\n        }\\n```\\n
First calculate `cachedUserRewards` then reset `userRewardDebts`.
A user can receive more reward tokens than they should by abusing the withdrawal system.
```\\n    function _withdrawUpdateRewardState(uint256 lpAmount_, bool claim_) internal {\\n        uint256 numInternalRewardTokens = internalRewardTokens.length;\\n        uint256 numExternalRewardTokens = externalRewardTokens.length;\\n\\n        // Handles accounting logic for internal and external rewards, harvests external rewards\\n        uint256[] memory accumulatedInternalRewards = _accumulateInternalRewards();\\n        uint256[] memory accumulatedExternalRewards = _accumulateExternalRewards();\\n        for (uint256 i; i < numInternalRewardTokens;) {\\n            _updateInternalRewardState(i, accumulatedInternalRewards[i]);\\n            if (claim_) _claimInternalRewards(i);\\n\\n            // Update reward debts so as to not understate the amount of rewards owed to the user, and push\\n            // any unclaimed rewards to the user's reward debt so that they can be claimed later\\n            InternalRewardToken memory rewardToken = internalRewardTokens[i];\\n            // @audit In our example, rewardDebtDiff = 3e17 (total rewards are 6e17 so 50% of shares earned 50% of reward tokens)\\n            uint256 rewardDebtDiff = lpAmount_ * rewardToken.accumulatedRewardsPerShare;\\n\\n            // @audit 3e17 > 1e17\\n            if (rewardDebtDiff > userRewardDebts[msg.sender][rewardToken.token]) {\\n\\n                // @audit userRewardDebts is set to 0 (original value was 1e17, the number of tokens that were already claimed)\\n                userRewardDebts[msg.sender][rewardToken.token] = 0;\\n                // @audit cached amount = 3e17 - 0 = 3e17.\\n                // Alice is assigned 3e17 reward tokens to be distributed the next time they claim\\n                // The remaining 3e17 LP shares are worth another 3e17 reward tokens.\\n                // Alice already claimed 1e17 before the withdrawal.\\n                // Thus, Alice receives 7e17 reward tokens instead of 6e17\\n                cachedUserRewards[msg.sender][rewardToken.token] +=\\n                    rewardDebtDiff - userRewardDebts[msg.sender][rewardToken.token];\\n            } else {\\n                userRewardDebts[msg.sender][rewardToken.token] -= rewardDebtDiff;\\n            }\\n\\n            unchecked {\\n                ++i;\\n            }\\n        }\\n```\\n