Platform: Code4rena
Start Date: 23/02/2024
Pot Size: $36,500 USDC
Total HM: 2
Participants: 39
Period: 7 days
Judge: Dravee
Id: 338
League: ETH
Rank: 21/39
Findings: 1
Award: $80.57
🌟 Selected for report: 0
🚀 Solo Findings: 0
80.5733 USDC - $80.57
https://github.com/code-423n4/2024-02-spectra/blob/25603ac27c3488423a0739b66e784c01a3db7d75/src/tokens/PrincipalToken.sol#L484-L486 https://github.com/code-423n4/2024-02-spectra/blob/25603ac27c3488423a0739b66e784c01a3db7d75/src/tokens/PrincipalToken.sol#L867-L875
The principalToken.sol
contract claims to be ERC5095 comliant. The EIP 5095 standard wants the maxRedeem()
function to return 0 if redemption are paused. But this is not the current case .
The contract fails to be ERC5095 compliant, which is a requirement stated in the contest page.
function maxRedeem(address owner) public view override returns (uint256) { return _maxBurnable(owner); }
We can see that the redeem function makes an internal call to the _maxBurnable internal function
function _maxBurnable(address _user) internal view returns (uint256 maxBurnable) { if (block.timestamp >= expiry) { maxBurnable = balanceOf(_user); } else { uint256 ptBalance = balanceOf(_user); uint256 ytBalance = IYieldToken(yt).balanceOf(_user); maxBurnable = (ptBalance > ytBalance) ? ytBalance : ptBalance; } }
It is here flagrant that the results won't be altered if the redemptions are paused.
MUST return the maximum amount of principal tokens that could be transferred from holder through redeem and not cause a revert
return 0 if the redemption are paused. As such:
function maxRedeem(address owner) public view override returns (uint256 result) { if(paused()) result = 0; result = _maxBurnable(owner); }
Other
#0 - c4-pre-sort
2024-03-03T13:07:19Z
gzeon-c4 marked the issue as duplicate of #33
#1 - c4-pre-sort
2024-03-03T13:07:22Z
gzeon-c4 marked the issue as sufficient quality report
#2 - c4-judge
2024-03-11T00:26:44Z
JustDravee marked the issue as satisfactory
#3 - c4-judge
2024-03-11T00:26:56Z
JustDravee marked the issue as partial-75
80.5733 USDC - $80.57
According to the almighty EIP-5095, the maxWithdraw()
function "MUST return the maximum amount of underlying tokens that could be redeemed from holder through withdraw and not cause a revert". However instead of this the cheeky maxWithdraw()
function in the contract will revert when paused because of the whenNotPaused
modifier
The function reverts when the redemptions are paused, which is not in line with the requirements of the EIP-5095.
function maxWithdraw(address owner) public view override whenNotPaused returns (uint256) { return convertToUnderlying(_maxBurnable(owner)); //@note inclusive of fees }
reverts when the DAO decides to paused the contract. If the function is called while paused the function reverts.
function _requireNotPaused() internal view virtual { if (paused()) { @> revert EnforcedPause(); } }
EIP-5095 docs
If the contract happens to be paused, return 0 instead of revertin'.
-- function maxWithdraw(address owner) public view override whenNotPaused returns (uint256) { ++ function maxWithdraw(address owner) public view override returns (uint256) { ++ if(paused()) return 0; return convertToUnderlying(_maxBurnable(owner)); //@note inclusive of fees }
Other
#0 - c4-pre-sort
2024-03-03T13:07:12Z
gzeon-c4 marked the issue as duplicate of #33
#1 - c4-pre-sort
2024-03-03T13:07:24Z
gzeon-c4 marked the issue as sufficient quality report
#2 - c4-judge
2024-03-11T00:27:09Z
JustDravee marked the issue as partial-75
#3 - c4-judge
2024-03-11T00:27:12Z
JustDravee marked the issue as satisfactory
#4 - c4-judge
2024-03-14T06:23:59Z
JustDravee marked the issue as partial-75