Tranche.sol#issue, updateUnclaimedYield, collect functions which process yields are all implemented with whenNotPaused modifier.
But the whenNotPaused modifier is not applied to redeemWithYT function.
Vulnerability Detail
Tranche.sol#redeemWithYT function is as follows.
function redeemWithYT(address from, address to, uint256 pyAmount) external nonReentrant returns (uint256) {
uint256 _lscale = lscales[from];
uint256 accruedInTarget = unclaimedYields[from];
// Calculate the accrued interest in Target token
// The lscale should not be 0 because the user should have some YT balance
if (_lscale == 0) revert NoAccruedYield();
GlobalScales memory _gscales = gscales;
_updateGlobalScalesCache(_gscales);
// Compute the accrued yield from the time when the YT balance is updated last to now
// The accrued yield in units of target is computed as:
// Formula: yield = ytBalance * (1/lscale - 1/maxscale)
// Sum up the accrued yield, plus the unclaimed yield from the last time to now
accruedInTarget += _computeAccruedInterestInTarget(
_gscales.maxscale,
_lscale,
// Use yt balance instead of `pyAmount`
// because we'll update the user's lscale to the current maxscale after this line
// regardless of whether the user redeems all of their yt or not.
// Otherwise, the user will lose some accrued yield from the last time to now.
_yt.balanceOf(from)
);
// Compute shares equivalent to the amount of principal token to redeem
uint256 sharesRedeemed = pyAmount.divWadDown(_gscales.maxscale);
// Update the local scale and accrued yield of `from`
lscales[from] = _gscales.maxscale;
275 delete unclaimedYields[from];
gscales = _gscales;
// Burn PT and YT tokens from `from`
_burnFrom(from, pyAmount);
_yt.burnFrom(from, msg.sender, pyAmount);
// Withdraw underlying tokens from the adapter and transfer them to the user
283 _target.safeTransfer(address(adapter), sharesRedeemed + accruedInTarget);
284 (uint256 amountWithdrawn, ) = adapter.prefundedRedeem(to);
emit RedeemWithYT(from, to, amountWithdrawn);
return amountWithdrawn;
}
As we can see above, on L275, 283, 284, it processes yields. But whenNotPaused is not applied.
dany.armstrong90
medium
Yield can be distributed when tranche is paused.
Summary
Tranche.sol#issue, updateUnclaimedYield, collect
functions which process yields are all implemented withwhenNotPaused
modifier. But thewhenNotPaused
modifier is not applied toredeemWithYT
function.Vulnerability Detail
Tranche.sol#redeemWithYT
function is as follows.As we can see above, on L275, 283, 284, it processes yields. But
whenNotPaused
is not applied.Impact
Yield can be distributed when paused.
Code Snippet
https://github.com/sherlock-audit/2024-01-napier/blob/main/napier-v1/src/Tranche.sol#L246
Tool used
Manual Review
Recommendation
The
whenNotPaused
modifier has to be applied toTranche.sol#redeemWithYT
as follows.Tranche.sol#redeemWithYT
function has to be modified as follows.Duplicate of #75