Platform: Code4rena
Start Date: 04/03/2024
Pot Size: $36,500 USDC
Total HM: 9
Participants: 80
Period: 7 days
Judge: hansfriese
Total Solo HM: 2
Id: 332
League: ETH
Rank: 30/80
Findings: 1
Award: $131.14
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Aymen0909
Also found by: 0xmystery, Abdessamed, FastChecker, Giorgio, Tripathi, btk, cheatc0d3, trachev, turvy_fuzz
131.1445 USDC - $131.14
https://github.com/code-423n4/2024-03-pooltogether/blob/480d58b9e8611c13587f28811864aea138a0021a/pt-v5-vault/src/PrizeVault.sol#L489-L497 https://github.com/code-423n4/2024-03-pooltogether/blob/480d58b9e8611c13587f28811864aea138a0021a/pt-v5-vault/src/PrizeVault.sol#L464-L465
When debt accrues, the PrizeVault share will be worth less assets, consequently this could lead users withdrawing less assets than expected
Users will withdraw less assets or redeem more shares than expected.
When a user want to withdraw assets, the amount of shares needed are calculated through the previewWithdraw()
function.
function withdraw( uint256 _assets, address _receiver, address _owner ) external returns (uint256) { @> uint256 _shares = previewWithdraw(_assets); _burnAndWithdraw(msg.sender, _receiver, _owner, _shares, _assets); return _shares; }
The previewWithdraw will return a less favorable rate for the users if
(_totalAssets >= totalDebt_)
, normally to shares to asset ratio is 1:1, but in this case more shares will be needed:
return _assets.mulDiv(totalDebt_, _totalAssets, Math.Rounding.Up);
.
Which means that if the debt momentarily increases the value of a PrizeVault share will decrease and thus the user will withdraw less assets, which results in a loss for him.
Manual review
In order to mitigate any slippage issues, add a check for both the withdraw()
and redeem()
functions.
-- function withdraw( uint256 _assets, address _receiver, address _owner) ++ function withdraw( uint256 _assets, address _receiver, address _owner, uint256 maxShares) external returns (uint256) { uint256 _shares = previewWithdraw(_assets); ++ require(_shares <= maxShares, "slippage error"); _burnAndWithdraw(msg.sender, _receiver, _owner, _shares, _assets); return _shares; }
function redeem( -- uint256 _shares, address _receiver, address _owner ++ uint256 _shares, address _receiver, address _owner, uint256 minAssets ) external returns (uint256) { uint256 _assets = previewRedeem(_shares); ++ require(_assets >= minAssets, "slippage err"); _burnAndWithdraw(msg.sender, _receiver, _owner, _shares, _assets); return _assets; }
Other
#0 - c4-pre-sort
2024-03-11T23:26:24Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-03-11T23:26:27Z
raymondfam marked the issue as primary issue
#2 - raymondfam
2024-03-11T23:27:30Z
Slippage protection is indeed beneficial to circumvent unfavorably unexpected timing.
#3 - c4-pre-sort
2024-03-13T05:09:57Z
raymondfam marked the issue as duplicate of #274
#4 - c4-judge
2024-03-15T08:09:44Z
hansfriese marked the issue as satisfactory