- 50k USDC main award pot
- 10K USDC gas optimization award pot
- Read our guidelines for more details
- Starts June 16, 2021
- Ends June 23, 2021
PoolTogether is a protocol that gamifies interest. Users deposit funds into a "Prize Pool". The Prize Pool uses a Yield Source to generate interest. The interest is then exposed to a Prize Strategy, which distributes the interest as prizes. For a thorough introduction to the protocol, please refer to the Protocol Overview developer documentation.
The scope of this contest includes the PoolTogether Protocol contracts that escrow funds. We want wardens to focus exclusively on the security of user deposits. The PoolTogether Protocol architecture is shown below and the aspect under audit is outlined in red.
User deposits are held by the core Prize Pool, Yield Source implementations, and the corresponding tokens.
The PrizePool contract is the primary point of entry for users: deposits and withdrawals occur here. The contract is abstract, and has two subclasses that handle escrowed funds differently: StakePrizePool and YieldSourcePrizePool.
- 1130 Lines of Code, including natspec.
- Source file in containing project: PrizePool.sol
- External calls:
- Controlled Tokens (tickets, sponsorship)
- Reserve Registry (to lookup reserve)
- Reserve Contract (to calculate reserve)
- Prize Strategy (token listener)
- Libraries:
- SafeMath
- SafeCast
- SafeERC20
- ERC165Checker
- MappedSinglyLinkedList
- FixedPoint
This subclass of the PrizePool ferries deposits into an external Yield Source contract.
- 82 Lines of code, including natspec
- Source file in containing project: YieldSourcePrizePool.sol
- External calls (in addition to Prize Pool externals):
- Yield Source
- No additional libraries
The StakePrizePool is a subclass of the PrizePool that simply holds the deposited tokens. No yield is generated, so prizes must be added manually.
- 72 Lines of code, including natspec
- Source file in containing project: StakePrizePool.sol
- No external calls on top of Prize Pool
- No additional libraries
The ControlledToken extends the standard ERC20 token (OpenZeppelin flavour) and adds a "token controller" is that able to burn and mint tokens. The controller can also "listen" to token transfers and is called anytime a transfer occurs. The token additionally extends the (at the time) experimental ERC20Permit contract provided by OpenZeppelin.
When a Prize Pool is created an array of Controlled Tokens is passed to it. These tokens serve as receipts for the deposited collateral. The controller for all of the Controlled Tokens for a prize pool must be the prize pool itself.
- 82 Lines of code, including natspec
- Source file in containing project: ControlledToken.sol
- External calls:
- TokenController (the prize pool)
- No additional libraries
The Ticket extends the above Controlled Token and adds a special data structure that organizes the token holders into contiguous blocks. Visualizations can be found in this article.
- 85 Lines of code, including natspec
- Source file in containing project: Ticket.sol
- No additional external calls
- Libraries:
The ATokenYieldSource is an adapter for Aave V2 Lending Pools that implements the IYieldSource.sol interface.
- 263 Lines of code, including natspec
- Source file in containing project: ATokenYieldSource.sol
- External calls:
- Aave V2 LendingPoolAddressesProviderRegistry
- Aave V2 LendingPoolAddressesProvider
- Aave V2 LendingPool
- Aave V2 aToken
- ERC20 token used to deposit
- Libraries:
- SafeMath (OpenZeppelin)
- SafeERC20 (OpenZeppelin)
The YearnV2YieldSource is an adapter for Yearn V2 Vaults that implements the IYieldSource.sol interface.
- 276 Lines of code
- Source file in containing project: YearnV2YieldSource.sol
- External calls:
- Yearn V2 Vault
- ERC20 token used to deposit
- Libraries:
- SafeERC20 (OpenZeppelin)
- SafeMath (OpenZeppelin)
The SushiYieldSource is an adapter for SushiBar that implements the IYieldSource.sol interface.
- 276 Lines of code
- Source file in containing project: SushiYieldSource.sol
- External calls:
- Yearn V2 Vault
- ERC20 token used to deposit
- Libraries:
- SafeERC20 (OpenZeppelin)
- SafeMath (OpenZeppelin)
The IdleYieldSource is an adapter for Idle's Idle Token that implements the IYieldSource.sol interface.
- 160 Lines of code
- Source file in containing project: IdleYieldSource.sol
- External calls:
- Idle Token
- Underlying asset ERC20 token
- No libraries
The Badger Yield Source is an adapter for Badger Sett Vaults.
- 82 Lines of code
- Source file in containing project: BadgerYieldSource.sol.
- External calls:
- Badger Sett Vault
- Badger token
- SafeMath library
Here are some thing we're guessing may be problematic, so want to point out for efficiency's sake.
These contracts make use of floating point math. Underflow and overflow are always a concern, especially when packing token amounts into uint128. Rounding has also been known to be challenging, as numbers can behave unexpectedly.
As a consequence of the yield source interface, there is a common pattern among yield sources to exchange the tokens to shares then burn the shares.
Notice in this code from the YearnV2YieldSource.sol#L140:
function redeemToken(uint256 amount) external override returns (uint256) {
uint256 shares = _tokenToShares(amount);
uint256 withdrawnAmount = _withdrawFromVault(amount);
_burn(msg.sender, shares);
token.safeTransfer(msg.sender, withdrawnAmount);
emit RedeemedToken(msg.sender, shares, amount);
return withdrawnAmount;
}
The user is attempting to redeem say, 10 Dai, but the actual burned number of shares is calculated using the exchange rate. Are there boundary conditions in this math that could be problematic? Will it be impossible to withdraw everything and so dust will accrue? Will this contract ever lock up indefinitely?
We've been careful to prevent the addition of malicious Controlled Tokens after a prize pool has been created, so that users can't be rugged by a manipulated token supply. Are there any other ways that deposits can be compromised?
The token listener pattern used throughout the code could potentially lock tokens and grief users if exposed to the world. We've locked them down as best we can, but are there any exploits that could grief users?
There could easily be things I have missed. This is why we need your keen eyes!