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: 43/80
Findings: 1
Award: $19.37
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: slvDev
Also found by: 0x11singh99, 0xhacksmithh, SAQ, SY_S, albahaca, dharma09, hunter_w3b, shamsulhaq123, unique
19.3678 USDC - $19.37
_shares == 0
& _assets == 0
inside _depositAndMint()
and _burnAndWithdraw()
As we hcan see
_shares = previewDeposit(_assets);
and
_assets = previewMint(_shares);
where they are 1:1
as per code comment
so basically if _shares != 0 so that also same for _assets
So check for only one of them will sufficient.
file: PrizeVault.sol
function _depositAndMint(address _caller, address _receiver, uint256 _assets, uint256 _shares) internal { if (_shares == 0) revert MintZeroShares(); if (_assets == 0) revert DepositZeroAssets();
function _burnAndWithdraw( address _caller, address _receiver, address _owner, uint256 _shares, uint256 _assets ) internal { if (_assets == 0) revert WithdrawZeroAssets(); // @audit gas if (_shares == 0) revert BurnZeroShares(); if (_caller != _owner) { _spendAllowance(_owner, _caller, _shares);
https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/PrizeVault.sol#L843-L845 https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/PrizeVault.sol#L894-L895
immutable
As variable only set once.
file: Claimable.sol
- address public claimer; + address public immutable claimer;
https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/abstract/Claimable.sol#L27
claimer
an cached in memoryfile: Claimable.sol
modifier onlyClaimer() { + address _claimer = claimer; - if (msg.sender != claimer) revert CallerNotClaimer(msg.sender, claimer); + if (msg.sender != _claimer) revert CallerNotClaimer(msg.sender, _claimer); _; }
https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/abstract/Claimable.sol#L53
liquidationPair
and yieldFeeRecipient
could be cached in memoryfile: PrizeVault.sol
modifier onlyLiquidationPair() { if (msg.sender != liquidationPair) { // @audit dual state read revert CallerNotLP(msg.sender, liquidationPair); } _; } /// @notice Requires the caller to be the yield fee recipient. modifier onlyYieldFeeRecipient() { if (msg.sender != yieldFeeRecipient) { // @audit dual state read revert CallerNotYieldFeeRecipient(msg.sender, yieldFeeRecipient); } _; }
https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/PrizeVault.sol#L260-L273
_hooks[_winner]
could be stored in memoryfile: Claimable.sol
if (_hooks[_winner].useBeforeClaimPrize) { // @audit _hooks[_winner] recipient = _hooks[_winner].implementation.beforeClaimPrize{ gas: HOOK_GAS }( _winner, _tier, _prizeIndex, _reward, _rewardRecipient ); } else { recipient = _winner; } if (recipient == address(0)) revert ClaimRecipientZeroAddress(); uint256 prizeTotal = prizePool.claimPrize( _winner, _tier, _prizeIndex, recipient, _reward, _rewardRecipient ); if (_hooks[_winner].useAfterClaimPrize) { _hooks[_winner].implementation.afterClaimPrize{ gas: HOOK_GAS }( _winner, _tier, _prizeIndex, prizeTotal, recipient );
https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/abstract/Claimable.sol#L85-L115
_setClaimer()
is a inernal function which only called once in constructor, and never sed further could be inlined
file: Claimable.sol
function _setClaimer(address _claimer) internal { // @audit inlined if (_claimer == address(0)) revert ClaimerZeroAddress(); claimer = _claimer; emit ClaimerSet(_claimer); }
https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/abstract/Claimable.sol#L128-L132
file: PrizeVaultFactory.sol
PrizeVault _vault = new PrizeVault{ salt: keccak256(abi.encode(msg.sender, deployerNonces[msg.sender]++)) }(
https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/PrizeVaultFactory.sol#L103
revert
, first local cache memory varible could usedfile: PrizeVault.sol
modifier onlyLiquidationPair() { if (msg.sender != liquidationPair) { // @audit dual state read revert CallerNotLP(msg.sender, liquidationPair); } _; } /// @notice Requires the caller to be the yield fee recipient. modifier onlyYieldFeeRecipient() { if (msg.sender != yieldFeeRecipient) { // @audit dual state read revert CallerNotYieldFeeRecipient(msg.sender, yieldFeeRecipient); } _; }
https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/PrizeVault.sol#L260-L273
file: PrizeVault.sol
yieldVault
could be cached in memoryfunction totalAssets() public view returns (uint256) { // @audit yieldVault return yieldVault.convertToAssets(yieldVault.balanceOf(address(this))) + _asset.balanceOf(address(this)); }
https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/PrizeVault.sol#L336-L338
prizePool
could cached in memory rather than recalling it again and again) external onlyLiquidationPair { address _prizeToken = address(prizePool.prizeToken()); // @audit prizePool if (_tokenIn != _prizeToken) { revert LiquidationTokenInNotPrizeToken(_tokenIn, _prizeToken); } prizePool.contributePrizeTokens(address(this), _amountIn); }
https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/PrizeVault.sol#L708
#0 - raymondfam
2024-03-13T03:22:25Z
False positives: G2, G5 (Both need to be changed by the owner when need be from PraizeVault.sol)
6G
#1 - c4-pre-sort
2024-03-13T03:22:29Z
raymondfam marked the issue as sufficient quality report
#2 - c4-judge
2024-03-18T02:56:16Z
hansfriese marked the issue as grade-b