Platform: Code4rena
Start Date: 07/07/2023
End Date: 14/07/2023
Period: 7 days
Status: Completed
Pot Size: $121,650 USDC
Participants: 111
Reporter: thebrittfactor
Judge: Picodes
Id: 258
League: ETH
dirk_y | 1/111 | $5,660.59 | 10 | 3 | 0 | 6 | 2 | 0 | 0 | Grade B |
rvierdiiev | 2/111 | $4,403.17 | 8 | 3 | 0 | 4 | 0 | Grade A | 0 | 0 |
0xStalin | 3/111 | $4,022.18 | 6 | 3 | 0 | 2 | 1 | 0 | 0 | Grade A |
zzzitron | 4/111 | $3,606.36 | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
KupiaSec | 5/111 | $2,710.76 | 5 | 4 | 0 | 1 | 0 | 0 | 0 | 0 |
pontifex | 6/111 | $2,465.97 | 2 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
KIntern_NA | 7/111 | $2,465.97 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
bin2chen | 8/111 | $2,311.11 | 5 | 2 | 0 | 2 | 1 | Grade A | 0 | 0 |
shaka | 9/111 | $2,027.76 | 4 | 1 | 0 | 3 | 1 | 0 | 0 | 0 |
volodya | 10/111 | $2,014.75 | 3 | 0 | 0 | 2 | 1 | Grade A | 0 | 0 |
Auditor per page
Automated findings output for the audit can be found here.
Note for C4 wardens: Anything included in the automated findings output is considered a publicly known issue and is ineligible for awards.
PoolTogether is a prize savings protocol. Yield on deposits is awarded periodically as random prizes. PoolTogether is a gamification layer that can be added to any yield-bearing asset. We like to call them prize-wrapped assets.
PoolTogether V5 is a major leap forward for the protocol. The system is:
You can read more about the protocol design in our official documentation
Here is a Loom video highlighting the major concepts in the code:
Contract | SLOC | Purpose | Libraries used |
---|---|---|---|
claimer/src/libraries/LinearVRGDALib.sol | 51 | Variable-Rate Gradual Dutch Auction Math | prb-math , solmate |
claimer/src/Claimer.sol | 86 | Incentivizes prize claims for a Prize Pool | prb-math , openzeppelin |
prize-pool/src/abstract/TieredLiquidityDistributor.sol | 753 | Distributes liquidity as tiered prizes | prb-math |
prize-pool/src/libraries/DrawAccumulatorLib.sol | 286 | Distributes liquidity over future draws using exponential smoothing | prb-math , ring-buffer-lib |
prize-pool/src/libraries/TierCalculationLib.sol | 81 | Computes tier odds, prize counts, and winners | prb-math |
prize-pool/src/libraries/UD34x4.sol | 35 | Provides an unsigned 34x4 precision fixed point decimal | prb-math |
prize-pool/src/PrizePool.sol | 528 | Distributes liquidity as tiered prizes | prb-math , openzeppelin |
twab-controller/src/libraries/ObservationLib.sol | 45 | Tracks a ring buffer of balance observations and provides a fast binary search algorithm to access them | ring-buffer-lib |
twab-controller/src/libraries/OverflowSafeComparatorLib.sol | 21 | Provides an overflow-safe means of comparing two 32-bit timestamps | |
twab-controller/src/libraries/TwabLib.sol | 442 | Provides an accounts struct and logic to mint, burn and transfer balance and measure twabs. | ring-buffer-lib |
twab-controller/src/TwabController.sol | 393 | Allows contracts to track balances and look up the time-weighted average balance of an account | |
vault/src/interfaces/IVaultHooks.sol | 20 | Provides a standard interface with which to attach hooks to vaults | |
vault/src/Vault.sol | 540 | An ERC-4626 compatible vault that uses a Twab Controller to track balances. The contract is bound to an ERC-4626 yield source and exposes yield to a liquidator. | openzeppelin , owner-manager-contracts |
vault/src/VaultFactory.sol | 43 | Provides a mean to easily create new Vaults and find them | openzeppelin |
There are a few important mathematical models used in the codebase that are important to understand:
Below we highlight protocol invariants or holistic concerns.
We want to make sure the prize pool doesn't award too much prize liquidity. The expectation is that the statistical model is tuned such that the rate of prizes being awarded matches the available prize liquidity for the draw.
The prize pool is a complex contract, and one of our biggest concerns is that it is tracking prize liquidity precisely. The balance of prize tokens held by the contract must always be equal to the sum of the available tier liquidity and the reserve. When contributing liquidity the prize pool will temporarily hold a balance greater than the accounted balance, but otherwise the two should match.
The Twab Controller should accurately measure a user's average balance held during a draw. However, we have reduced the granularity of measurements to save gas. Is it possible for a user to manipulate the twab to improve their odds of winning? For example: the user should never be able to alter their average balance in the past.
The Vaults hold user funds, so it's critical that there can be no loss of funds. The liquidator is able to liquidate the accrued yield on the vault, so it's a second possible ingress point for an attacker. We want to make sure that the liquidator can't access more than the yield, and that users can't access each other's principal.
Repositories
- How many contracts are in scope?: 14 - Total SLoC for these contracts?: 3335 - How many external imports are there?: 4 - How many separate interfaces and struct definitions are there for the contracts within scope?: ~20 - Does most of your code generally use composition or inheritance?: Composition - How many external calls?: 12 - What is the overall line coverage percentage provided by your tests?: ~99.9% - Is there a need to understand a separate part of the codebase / get context in order to audit this part of the protocol?: False - Please describe required context: N/A - Does it use an oracle?: No - Does the token conform to the ERC20 standard?: Yes - Are there any novel or unique curve logic or mathematical models?: True - Does it use a timelock function?: No - Is it an NFT?: No - Does it have an AMM?: No - Is it a fork of a popular project?: No - Does it use rollups?: - Is it multi-chain?: - Does it use a side-chain?: No
Clone using the --recurse
option or update the repository with git submodule update --init --recursive
Within each git submodule, you can run forge test
to run all tests. You can run forge coverage
to see the coverage report.
One-Liner for tests: cd claimer && forge test && cd .. && cd prize-pool && forge test && cd .. && cd twab-controller && forge test && cd .. && cd vault && forge test && cd ..
Note: the Prize Pool must be compiled with --optimize --via-ir
in order to fit within contract size limits.