PoolTogether - Afriauditor's results

General Information

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

PoolTogether

Findings Distribution

Researcher Performance

Rank: 5/80

Findings: 2

Award: $915.44

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

1.4652 USDC - $1.47

Labels

bug
3 (High Risk)
insufficient quality report
satisfactory
edited-by-warden
:robot:_10_group
duplicate-59

External Links

Lines of code

https://github.com/code-423n4/2024-03-pooltogether/blob/480d58b9e8611c13587f28811864aea138a0021a/pt-v5-vault/src/PrizeVault.sol#L611

Vulnerability details

Impact

In scenario where totaldebt > totalasset. such as when where is loss of asset in the underlying yieldvault. The conversion from underlying token to prize vault shares changes from 1:1 with more prize vault share required to be exchanged for underlying token. In the function Implementation

function claimYieldFeeShares(uint256 _shares) external onlyYieldFeeRecipient { if (_shares == 0) revert MintZeroShares(); uint256 _yieldFeeBalance = yieldFeeBalance; >>>> if (_shares > _yieldFeeBalance) revert SharesExceedsYieldFeeBalance(_shares, _yieldFeeBalance); yieldFeeBalance -= _yieldFeeBalance; _mint(msg.sender, _shares); emit ClaimYieldFeeShares(msg.sender, _shares); }

the function takes in number of shares as parameter and also has a logic causing a revert when if (_shares > _yieldFeeBalance) revert This assumes conversion rate will always be 1:1. The implication here is yield fee recipient will be force to convert just a portion of their Yield fee balance to avoid a revert. leaving behind the rest of the yeild fee balance.

also there is a poor implementation here yieldFeeBalance -= _yieldFeeBalance; causing the yeildfee recipient to loose all balance regardless of the number of shares he decides to mint loosing his entire fees either the tokens are minted or not

Proof of Concept

https://github.com/code-423n4/2024-03-pooltogether/blob/480d58b9e8611c13587f28811864aea138a0021a/pt-v5-vault/src/PrizeVault.sol#L611

Tools Used

manual

++ function claimYieldFeeShares(uint256 _Yieldfeebalancetowithdraw) external onlyYieldFeeRecipient { if (_shares == 0) revert MintZeroShares(); uint256 _yieldFeeBalance = yieldFeeBalance; + uint256 Yieldfeeshare = convertToshare(_Yieldfeebalancetowithdraw) + yieldFeeBalance -= _Yieldfeebalancetowithdraw + _mint(msg.sender, Yieldfeeshare); emit ClaimYieldFeeShares(msg.sender, Yieldfeeshare); }

Assessed type

Other

#0 - c4-pre-sort

2024-03-11T22:17:16Z

raymondfam marked the issue as sufficient quality report

#1 - c4-pre-sort

2024-03-11T22:17:27Z

raymondfam marked the issue as duplicate of #10

#2 - raymondfam

2024-03-11T22:22:45Z

convertToshare() in your mitigation step is unnecessary because the input parameter is already treated as shares. The shares are minted 1:1 regardless of normal or lossy state. It only incurs a loss if the shares minted are withdrawn in a lossy state. Treated as insufficient as the assumption leading to loss of remainder yield is incorrect.

#3 - c4-pre-sort

2024-03-11T22:31:22Z

raymondfam marked the issue as insufficient quality report

#4 - c4-pre-sort

2024-03-13T04:38:41Z

raymondfam marked the issue as duplicate of #59

#5 - c4-judge

2024-03-15T07:38:16Z

hansfriese marked the issue as satisfactory

Findings Information

🌟 Selected for report: pa6kuda

Also found by: 0xhunter20, Afriauditor

Labels

bug
2 (Med Risk)
insufficient quality report
satisfactory
edited-by-warden
:robot:_188_group
duplicate-91

Awards

913.9683 USDC - $913.97

External Links

Lines of code

https://github.com/code-423n4/2024-03-pooltogether/blob/480d58b9e8611c13587f28811864aea138a0021a/pt-v5-vault/src/PrizeVault.sol#L798

Vulnerability details

Impact

While not yet minted, the accrued yieldFeeBalance is an inherent part of PrizeVault's shares(totalsupply), impacting the overall totalsupply. This is because minting the yieldFeeBalance as prizevault shares is inevitable (as long as yield fee recipient desires his fees) and really the only way to withdraw YieldFeeBalance. This poses a potential issue as the _twabSupplyLimit function, vital for calculating maxdeposits and maxamountout in liquidatableBalanceOf, omits consideration of minting yieldFeeBalance by yield fee recipient. In extreme scenarios, this oversight could render withdrawals unfeasible by yield fee recipient upon reaching the maximum total supply because it would mean minting prizevault shares exceeding TWAB limits. Which was what the Prizevault:_twabSupplyLimit was implemented to prevent.

Proof of Concept

https://github.com/code-423n4/2024-03-pooltogether/blob/480d58b9e8611c13587f28811864aea138a0021a/pt-v5-vault/src/PrizeVault.sol#L380

https://github.com/code-423n4/2024-03-pooltogether/blob/480d58b9e8611c13587f28811864aea138a0021a/pt-v5-vault/src/PrizeVault.sol#L636

function maxDeposit(address) public view returns (uint256) { uint256 _totalSupply = _maxDeposit(); uint256 totalDebt_ = _totalDebt(_totalSupply); if (totalAssets() < totalDebt_) return 0; // the vault will never mint more than 1 share per asset, so no need to convert supply limit to assets >>> uint256 twabSupplyLimit_ = _twabSupplyLimit(_totalSupply); uint256 _maxDeposit; uint256 _latentBalance = _asset.balanceOf(address(this)); uint256 _maxYieldVaultDeposit = yieldVault.maxDeposit(address(this)); if (_latentBalance >= _maxYieldVaultDeposit) { return 0; } else { unchecked { _maxDeposit = _maxYieldVaultDeposit - _latentBalance; } // @audit would return invalid number number return twabSupplyLimit_ < _maxDeposit ? twabSupplyLimit_ : _maxDeposit; } }

If this is implemented and a user hypothetically decides to use the twabSupplyLimit_ to make a deposit. It would mean TWAB controller's share supply limit is reached. So even when a yield fee recipient wants to claim Yield fee he would be unable to do so. Similar issue will arise from using maxamountout in liquidatableBalanceOf function in the link above.

Tools Used

Manual

function _twabSupplyLimit(uint256 _totalSupply) internal pure returns (uint256) { unchecked { return type(uint96).max - _totalSupply - YieldFeebalance } }

Assessed type

DoS

#0 - c4-pre-sort

2024-03-13T01:48:08Z

raymondfam marked the issue as insufficient quality report

#1 - c4-pre-sort

2024-03-13T01:48:56Z

raymondfam marked the issue as duplicate of #64

#2 - c4-judge

2024-03-18T01:56:18Z

hansfriese marked the issue as not a duplicate

#3 - c4-judge

2024-03-18T01:57:38Z

hansfriese marked the issue as duplicate of #91

#4 - c4-judge

2024-03-18T01:58:25Z

hansfriese marked the issue as unsatisfactory: Invalid

#5 - c4-judge

2024-03-18T14:34:18Z

hansfriese marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter