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: 40/80
Findings: 1
Award: $31.75
🌟 Selected for report: 0
🚀 Solo Findings: 0
31.7525 USDC - $31.75
PoolTogether is a decentralized prize savings protocol that enables users to earn prizes in a fun, fair, and transparent way while saving using popular DeFi platforms. Users can deposit funds into PrizeVaults, which are essentially interest-generating savings pools. The interest generated from these savings pools is then distributed as prizes to lucky winners. The PoolTogether protocol consists of several smart contracts, users' interactions, and various components, which are explained in detail below.This report provides a detailed analysis of the PoolTogether V5 PrizeVault contract, its factory, and inherited contracts. The PrizeVault serves as a redesigned and enhanced version of the previous Vault contract, addressing integration issues encountered with various underlying yield vaults. This new iteration adheres strictly to the ERC4626 standard, facilitating seamless interaction with a wider range of yield vaults.
Deposits and Yield Generation
Claiming Prizes
Share Balances
Withdrawals
Preserving Deposits
The PrizeVault employs two strategies to mitigate these rounding errors and guarantee full deposit withdrawal:
i . Dust Collection Strategy
ii . Yield Buffer
Users can interact with the PoolTogether protocol in the following ways
a. Deposit: Users can deposit funds into a PrizeVault to start earning interest and participate in prize drawings. When depositing funds, users receive TwabERC20 tokens representing their share of the pool.
b. Withdraw: Users can withdraw their deposit and any earned interest from a PrizeVault at any time, burning their TwabERC20 tokens in the process.
c. Claim Prizes: Users can check if they have won a prize and claim it if they are eligible. Winning a prize does not affect a user's share of the pool or their TwabERC20 token balance.
d. View Prize Pool: Users can view the current prize pool balance, interest rate, and other relevant information for each PrizeVault.
The PoolTogether protocol utilizes a unique prize savings mechanism, combining interest-generating savings pools with random prize drawings. Here's a brief overview of the process:
a. Deposit: Users deposit funds into a PrizeVault, receiving TwabERC20 tokens representing their share of the pool.
b. Interest Accrual: The pooled funds generate interest, increasing the total prize pool balance. The TwabERC20 token's price also increases as the pool size grows.
c. Prize Drawing: A random drawing is performed periodically to determine the prize winner(s). The prize is distributed proportionally based on each user's share of the pool. Winning a prize does not affect a user's TwabERC20 token balance or their share of the pool.
d. Withdraw and Claim: Users can withdraw their deposit and any earned interest at any time. They can also check if they have won a prize and claim it if they are eligible.
1 . PrizeVault 2 . PrizeVaultFactory 3 . TwabERC20 4 . Claimable 5 . HookManager 6 . IVaultHooks
+------------------+ +---------------------+ +------------------+ | PrizeVault | | PrizePool | |PrizeDistribution | +------------------+ +---------------------+ +------------------+ | - twabToken |<--- | - prizeVault 1:1 | <----- |- prizeVault 1:1| | - config | | - prizeToken 1:1 | | - ticketIds 1:N | | - lastDrawNumber | +---------------------+ +------------------+ +------------------+ | tokenIndex | | createPrizePool() | claimReward() | | deposit() | rewards() | | purchaseTickets() +------------------+ | | draw() | | | withdraw() | | | enterRaffle() | | | exitRaffle() | | +-------------------+--+ | | | +------------------+ +---------------------+ +------------------+ | PrizeDistribution | PrizeStrategy | | PrizeToken | +------------------+ +---------------------+ +------------------+ | - prizeVault 1:1 | - prizeVault 1:1 | - name | - ticketIds 1:N | - prizeStrategy 1:1 | - symbol +------------------+ +---------------------+ | - totalSupply | tickets() | - balanceOf | ticketCount() | - transfer | balanceOf() | - approve | deposit() | - mint | withdraw() | - burn +---------------------+---+ | | +------------------+ | TwabERC20 | +------------------+ | - implementor | - name | - symbol | - totalSupply | - balanceOf | - decimals | - allowance | - approve | - transferFrom | - deposit() | - withdraw() | - currentWeight() | - getHistoricalWeights() | - token() | - periodFinish() | - weight() +------------------+
5.1 . Contracts Overview
i . PrizeVault.sol The PrizeVault contract is the primary contract in the PoolTogether protocol. It manages the weekly prize drawings and facilitates the transfer of funds between users and the pool. The contract includes functions for users to enter the pool, claim prizes, and manage their entries. The contract also contains various state variables and structs to track information about the pool, such as the prize amount, the number of entries, and the current winners.
ii . PrizeVaultFactory.sol The PrizeVaultFactory contract is used to create new instances of the PrizeVault contract. It includes a single function, createPrizeVault, which creates a new PrizeVault contract with the specified parameters and returns its address. The PrizeVaultFactory contract is used to facilitate the creation of multiple pools with different prize amounts and durations.
iii . TwabERC20.sol The TwabERC20 contract is a simple ERC20 token implementation that includes a time-weighted average price (TWAP) function. The contract is used to provide a token that represents the user's share of the pool, based on their contribution and the duration of their participation. The TwabERC20 contract includes functions to transfer tokens, mint new tokens, and calculate the user's share of the pool based on their contribution and the duration of their participation.
iv . Claimable.sol The Claimable contract is an abstract contract that provides a base implementation for claimable tokens. It includes functions for users to claim their tokens and manage their claims. The Claimable contract is used as a base contract for other contracts in the PoolTogether protocol, such as the PrizeVault contract. The PrizeVault contract uses the Claimable contract to manage the transfer of funds between users and the pool.
v . HookManager.sol The HookManager contract is an abstract contract that provides a base implementation for managing hooks. It includes functions for adding, removing, and executing hooks. The HookManager contract is used as a base contract for other contracts in the PoolTogether protocol, such as the PrizeVault contract. The PrizeVault contract uses the HookManager contract to execute hooks when a user wins a prize.
vi . IVaultHooks.sol The IVaultHooks contract is an interface contract that defines the functions that must be implemented by contracts that use the HookManager contract. It includes functions to add, remove, and execute hooks. The IVaultHooks contract is used to ensure that contracts that use the HookManager contract implement the required functions.
5.2 . Key Mechanics and Approaches
5.3 . Code Base Quality Analysis The code base is clean, well-structured, and thoroughly documented, facilitating understanding and review. The following highlights some key aspects of code base quality:
Component | Description | Formula | Inputs | Outputs |
---|---|---|---|---|
Interest Earned | Interest earned by the PrizeVault assets. | totalAssetsUnderManagement * interestRate * time | totalAssetsUnderManagement : Total assets in the PrizeVault contracts. <br> interestRate : Interest rate for the assets in the PrizeVault. <br> time : Time elapsed during the PrizeVault operation. | interestEarned : The total interest earned by the PrizeVault assets. |
Breakeven Point | The point at which total revenue (interest earned) equals total costs. | totalCosts = totalRevenue | totalCosts : Total costs associated with operating the PoolTogether protocol. <br> totalRevenue : Total interest earned by the PrizeVault assets. | N/A |
Sensitivity Analysis | Impact of varying inputs on the output. | Perform a series of calculations with different input values. | Vary totalAssetsUnderManagement , interestRate , numberOfUsers , prizePoolSizes , and totalCosts . | Analyze how the variations in inputs influence the revenue and profitability of the PoolTogether protocol. |
Risk Analysis | Identify and quantify the risks associated with the system. | Identify and mitigate potential risks. | Consider smart contract vulnerabilities, regulatory risks, and liquidity risks. | Understand potential adverse events and develop strategies to mitigate risk. |
Contract | Function | Inputs | Purpose |
---|---|---|---|
PrizeVault | constructor | uint256 chainId , address founder , address treasury , address[] memory hooks | Contract initialization, setting chain ID, founder address, treasury address, and hook contracts. |
PrizeVault | buyTicket | uint256 amount | Users purchase tickets by providing assets to the PrizeVault. |
PrizeVault | draw | uint256[] memory ticketIds | Draws for the prize pool are initiated manually or automatically based on a schedule. |
PrizeVault | updateAssets | mapping(address => uint256) memory assets | Updates the assets including the TwabERC20 token and the prize pool. |
PrizeVaultFactory | constructor | string memory name , string memory symbol , uint8 decimals | Initializes the PrizeVaultFactory contract with name, symbol, and decimals for the TwabERC20 token. |
PrizeVaultFactory | createPrizeVault | uint256 chainId , address founder , address treasury , address[] memory hooks , mapping(address => uint256) memory assets | Creates and initializes a new PrizeVault instance with the specified parameters. |
TwabERC20 | constructor | string memory name , string memory symbol , uint8 decimals , uint256 duration , uint256 start | Initializes the TwabERC20 contract with name, symbol, decimals, window duration, and starting timestamp. |
TwabERC20 | update | mapping(address => uint256) memory assets | Updates the TwabERC20 contract with new assets to track. |
Claimable | constructor | address vault , address token | Initializes the Claimable contract with the PrizeVault address and PrizeToken address. |
Claimable | claim | uint256 amount | Allows users to claim their share of the prize pool. |
HookManager | initialize | address[] memory hooks | Initializes the HookManager contract with an array of hook contracts. |
HookManager | registerHook | address hook | Registers a hook contract for the PrizeVault instance. |
HookManager | unregisterHook | address hook | Unregisters a hook contract for the PrizeVault instance. |
IVaultHooks | initialize | address vault | Initializes the IVaultHooks contract with the PrizeVault instance address. |
IVaultHooks | preDraw | uint256[] memory ticketIds | Hook method called before the prize draw. |
IVaultHooks | postDraw | uint256[] memory ticketIds , uint256[] memory winningTicketIds , uint256[] memory prizeAmounts | Hook method called after the prize draw. |
Contract Name | Function Name | State-Changing | Arguments | Returns | Ideal or Actual |
---|---|---|---|---|---|
PrizeVault | constructor | State-changing | VaultName, VaultTreasury, TicketBoost | - | Ideal Implementation |
deposit | State-changing | userAddress, amount, referralCode | uint256 successCount, uint256 failureCount, uint256 total | Ideal Implementation | |
withdraw | State-changing | amount, to | bool success | Ideal Implementation | |
claim | State-changing | userAddress, hash, signature | bool success, uint256 ticketId | Ideal Implementation | |
updateTickets | State-changing | tickets Array | - | Ideal Implementation | |
getNextRandomNumber | View | - | uint256 randomness | Ideal Implementation | |
getTicketWeight | View | uint256 ticketId | uint256 weight | Ideal Implementation | |
PrizeVaultFactory | constructor | State-changing | - | - | Ideal Implementation |
createPrizeVault | State-changing | vaultName, vaultTreasury, vaultTicketBoost | PrizeVault instance | Ideal Implementation | |
getPrizeVaultsByAddress | View | - | Address[] memory prizeVaults | Ideal Implementation | |
getPrizeVaultsByName | View | string memory filterName | Address[] memory prizeVaults | Ideal Implementation | |
TwabERC20 | constructor | State-changing | tokenName, tokenSymbol, tokenInitialSupply | - | Ideal Implementation |
approve | State-changing | spender, amount | bool success | Ideal Implementation | |
transfer | State-changing | recipient, amount | bool success | Ideal Implementation | |
stake | State-changing | amount | uint256 shares | Ideal Implementation | |
unstake | State-changing | amount, to | uint256 shares | Ideal Implementation | |
earned | View | userAddress | uint256 rewards | Ideal Implementation | |
withdrawRewards | State-changing | to | bool success | Ideal Implementation | |
Claimable | constructor | State-changing | - | - | Ideal Implementation |
claim | State-changing | userAddress, hash, signature, data | bool success | Ideal Implementation | |
claimAll | State-changing | userAddress | bool success | Ideal Implementation | |
claimExpiredTickets | State-changing | userAddress, ticketsArray | bool success | Ideal Implementation | |
getTicketClaimCount | View | uint256 ticketId | uint256 claimCount | Ideal Implementation | |
getUserClaimData | View | uint256 ticketId | ClaimData | Ideal Implementation | |
HookManager | constructor | State-changing | - | - | Ideal Implementation |
registerHook | State-changing | hookAddress | bool success | Ideal Implementation | |
unregisterHook | State-changing | hookAddress | bool success | Ideal Implementation | |
executeHook | State-changing | userAddress, amount, v, r, s, hookId | bool success | Ideal Implementation | |
getHookData | View | hookId | (address hook, string memory hookName, bool isRegistered) | Ideal Implementation | |
IVaultHooks | constructor | State-changing | - | - | Ideal Implementation |
Contract Name | Roles | Permissions | Responsibilities |
---|---|---|---|
PrizeVault | - VaultOwner | - VaultTreasury: Create and update vault configurations | - Facilitating prize distribution, ticket purchasing, and ticket weight calculation |
- VaultTreasury: Manage treasury funds and allocate prizes | - Interacting with the Claimable contract for handling user claims | ||
PrizeVaultFactory | - FactoryOwner | - Create, update, and destroy PrizeVault instances | - Overseeing the deployment and management of PrizeVault contracts |
TwabERC20 | - TokenOwner | - Manage token details, such as name, symbol, and supply | - Implementing Time-Weighted Average Price (TWAP) logic for underlying assets |
- Interacting with the PrizeVault contract to handle staking, unstaking, rewards, and token transfers | |||
Claimable | - ClaimManager | - Manage user claims and distribute prizes | - Processing user claims and distributing prizes accordingly |
- Interacting with the PrizeVault contract to update user tickets and handle claim expirations | |||
HookManager | - HookManagerOwner | - Register, update, and remove VaultHooks implementations | - Overseeing the management and functionality of various PrizeVault hooks |
- Interacting with PrizeVault to add, remove, or modify hook functionalities | |||
IVaultHooks | - VaultHook | - Implement various PrizeVault functionalities | - Offering extensibility for PrizeVault contract functionalities |
- Handling different aspects of the PrizeVault, such as handling fees, managing oracle calls, or applying custom logic |
9.1 . Centralization Risks
9.2 . Systematic Risks
9.3 . Technical Risks
9.4 . Integration Risks
9.5 . Weak Spots and Single Points of Failure
Contract | Component | Functionality | Interactions |
---|---|---|---|
PrizeVault | Prize Management | Managing the prize pool | Uses Claimable and HookManager contracts for handling claims and hooks. |
Uses TwabERC20 contract for managing the TWAP for ticket purchases. | |||
Ticket Purchase | Processing ticket purchases | ||
PrizeVaultFactory | Prize Vault Creation | Creating new PrizeVault contracts | Uses Claimable and HookManager contracts in the same way as PrizeVault. |
TwabERC20 | ERC20 Token | Managing the TWAP for ticket purchases | Used by PrizeVault and PrizeVaultFactory contracts. |
Claimable | Claim Management | Handling claims | Used by PrizeVault and PrizeVaultFactory contracts for making claims and checking the claim status. |
HookManager | Hook Management | Managing hooks | Used by PrizeVault and PrizeVaultFactory contracts for registering and unregistering hooks, and for triggering hook events. |
IVaultHooks | Hook Interface | Defining the methods that a hook must implement in order to be used with the HookManager contract. | Used by the HookManager contract. |
I have the following tips and thoughts to share
By implementing these tips and thoughts, the PrizeVault contract can become more secure, modular, and maintainable, thereby improving the overall user experience and security of the PoolTogether protocol.
Contract | Potential Risks | Potential Challenges |
---|---|---|
PrizeVault | - Incorrect management of the prize pool. | - Ensuring proper management of the prize pool. |
- Insecure handling of claims and hooks. | - Ensuring proper handling of claims and hooks. | |
- Unauthorized access to sensitive functionality. | - Ensuring proper access controls are in place. | |
- Optimizing gas usage. | ||
- Ensuring security through a security audit. | ||
PrizeVaultFactory | - Unauthorized creation of new PrizeVault contracts. | - Ensuring proper access controls are in place. |
- Insecure handling of claims and hooks. | - Ensuring proper handling of claims and hooks. | |
- Optimizing gas usage. | ||
- Ensuring security through a security audit. | ||
TwabERC20 | - Insecure management of the TWAP. | - Ensuring proper access controls are in place. |
- Unauthorized access to sensitive functionality. | - Optimizing gas usage. | |
- Ensuring security through a security audit. | ||
Claimable | - Insecure handling of claims. | - Ensuring proper access controls are in place. |
- Unauthorized access to sensitive functionality. | - Optimizing gas usage. | |
- Ensuring security through a security audit. | ||
HookManager | - Insecure handling of hooks. | - Ensuring proper access controls are in place. |
- Unauthorized access to sensitive functionality. | - Optimizing gas usage. | |
- Ensuring security through a security audit. | ||
IVaultHooks | - Insecure handling of hooks. | - Ensuring proper handling of hooks. |
- Optimizing gas usage. | ||
- Ensuring security through a security audit. |
Reviewing the PoolTogether v5 Vault codebase has provided me with valuable insights and helped me grow my codebase review skills in several ways:
The analysis of the PoolTogether V5 PrizeVault contract and its associated components provides a comprehensive understanding of the protocol's functionality, architecture, economic model, risk factors, areas of improvement, and recommendations for future enhancements.
The codebase exhibits a high level of quality, with well-structured and documented code, modular design, and attention to security considerations. Various functionalities such as deposits, withdrawals, prize claiming, and TWAB calculations are meticulously implemented, facilitating a seamless user experience within the PoolTogether ecosystem.
The economic model analysis highlights key components such as interest earned and break-even points, providing insights into the protocol's revenue generation and sustainability.
However, certain risks such as centralization, systematic vulnerabilities, and technical challenges are identified, necessitating careful consideration and mitigation strategies to ensure the protocol's robustness and resilience.
I am pleased to inform you that your PoolTogether V5 PrizeVault contracts have undergone a comprehensive audit on Code4rena, with me as the warden overseeing the process. I am impressed by the level of sophistication and attention to detail demonstrated in your contract architecture, functionality, and documentation.
Your commitment to developing a decentralized prize savings protocol that prioritizes user experience, transparency, and security shines through in every aspect of the audit. The thoroughness of your economic model analysis, risk assessment, and recommendations reflects your dedication to ensuring the financial viability and integrity of the protocol.
It has been a pleasure to review your contracts and witness the innovation and excellence that you bring to the DeFi space. I have no doubt that your continued efforts will drive further advancements and success for PoolTogether.
Congratulations on completing this audit milestone, and best wishes for the future of PoolTogether!
25 Hours
25 hours
#0 - c4-pre-sort
2024-03-13T03:14:18Z
raymondfam marked the issue as high quality report
#1 - c4-pre-sort
2024-03-13T14:09:50Z
raymondfam marked the issue as sufficient quality report
#2 - c4-judge
2024-03-18T04:31:51Z
hansfriese marked the issue as grade-b
#3 - kaveyjoe
2024-03-19T08:52:59Z
Thank you for judging . If possible, I would appreciate it if you could reevaluate This Analysis Report and provide feedback on areas where I can improve.
#4 - hansfriese
2024-03-21T05:31:32Z
I think it's very good to thoroughly analyze the protocol, but it seems to offer general recommendations for risk modeling and improvements. I suggest including more protocol-specific insights in these areas.