Submitted by dirk_y, also found by Jeiwan, 0xStalin, and seeques (1, 2)
https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L498-L502
https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L743-L746
https://github.com/GenerationSoftware/pt-v5-prize-pool/blob/4bc8a12b857856828c018510b5500d722b79ca3a/src/PrizePool.sol#L312
When anyone calls the increaseReserve method in PrizePool.sol the accounted balance in the prize pool isnt properly updated. This allows a vault to effectively steal the prize token contribution and this contribution gets distributed during draws; effectively double counting the initial injection into the reserves. The actual prize token balance of the prize pool will be below the accounted balance of the prize pool as time goes on.
As mentioned in the audit README:
Unfortunately, this is broken when anyone contributes directly to the reserve by calling increaseReserve.
In the normal audit flow, the reserve is increased when a draw is closed by the draw manager. During calls to closeDraw, the next draw is started with a given number of tiers and the contributions for the round are calculated and split across the tiers and the reserve:
Under the hood, this calls _computeNewDistributions which calculates the amount to increase the reserves, based on the number of reserve shares and the new prize token liquidity being contributed in this round. During this flow, the actual balance of reward tokens held in the prize pool are equal to the accounted balance.
The break in accounting occurs when calling increaseReserve:
As you can see, the prize tokens are transferred into the pool and the reserve increased. But the accounted balance is unchanged:
Because the accounted balance is unchanged, any vault can now call contributePrizeTokens to effectively steal the funds meant for the reserve:
This increases the relevant vault accumulator and the total accumulator; thereby, effectively double counting the same prize tokens, since weve already increased _reserve.
The accounted balance of the prize pool should be updated when increaseReserve is called. I think the easiest way of achieving this is having a tracker for reserve injections:
Math
asselstine (PoolTogether) confirmed and commented via duplicate issue #200:
PoolTogether mitigated:
Status: Mitigation confirmed. Full details in reports from dirk_y, rvierdiiev and 0xStalin.
