PoolTogether V5: Part Deux - K42's results

A protocol for no-loss prize savings.

General Information

Platform: Code4rena

Start Date: 02/08/2023

Pot Size: $42,000 USDC

Total HM: 13

Participants: 45

Period: 5 days

Judge: hickuphh3

Total Solo HM: 5

Id: 271

League: ETH

PoolTogether

Findings Distribution

Researcher Performance

Rank: 20/45

Findings: 2

Award: $129.80

Gas:
grade-b
Analysis:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Rolezn

Also found by: 0xhex, 0xta, JCK, K42, Rageur, Raihan, ReyAdmirado, SAQ, SY_S, dharma09, hunter_w3b, petrichor, shamsulhaq123, wahedtalash77

Labels

bug
G (Gas Optimization)
grade-b
G-15

Awards

30.6063 USDC - $30.61

External Links

Gas Optimization Report for PoolTogether-v5 by K42

Possible Optimization in LiquidationPair.sol

Possible Optimization =

  • Reducing the number of SSTORE operations by packing multiple smaller variables into a single storage slot.

Before:

// Before
uint112 _lastNonZeroAmountIn;
uint112 _lastNonZeroAmountOut;
uint96 _amountInForPeriod;
uint96 _amountOutForPeriod;
uint16 _period;
uint48 _lastAuctionTime;

After Optimization:

// After
struct AuctionState {
    uint112 lastNonZeroAmountIn;
    uint112 lastNonZeroAmountOut;
    uint96 amountInForPeriod;
    uint96 amountOutForPeriod;
    uint16 period;
    uint48 lastAuctionTime;
}

AuctionState public auctionState;
  • Estimated gas saved = This optimization doesn't directly save gas on execution, but it does reduce the amount of storage used, which can lead to gas savings when updating these variables. Each ``SSTORE` operation costs 5,000 gas, so if we can reduce the number of these operations, we can save gas.

Possible Optimizations in RngRelayAuction.sol

Possible Optimization 1 =

  • Reducing the number of SSTORE operations by packing multiple smaller variables into a single storage slot.

Before:

uint64 internal _auctionDurationSeconds;
UD2x18 internal _auctionTargetTimeFraction;

After Optimization:

struct AuctionParameters {
    uint64 auctionDurationSeconds;
    UD2x18 auctionTargetTimeFraction;
}

AuctionParameters internal auctionParameters;

Estimated gas saved = This optimization doesn't directly save gas on execution, but it does reduce the amount of storage used, which can lead to gas savings when updating these variables. Each SSTORE operation costs 5,000 gas, so if we can reduce the number of these operations, we can save gas.

Possible Optimization 2 =

  • Reducing the number of state variable updates in the rngComplete function.

After Optimization:

function rngComplete(
    uint256 _randomNumber,
    uint256 _rngCompletedAt,
    address _rewardRecipient,
    uint32 _sequenceId,
    AuctionResult calldata _rngAuctionResult
) external returns (bytes32) {
    if (_sequenceHasCompleted(_sequenceId)) revert SequenceAlreadyCompleted();
    uint64 _auctionElapsedSeconds = uint64(block.timestamp < _rngCompletedAt ? 0 : block.timestamp - _rngCompletedAt);
    if (_auctionElapsedSeconds > (_auctionDurationSeconds-1)) revert AuctionExpired();
    // Calculate the reward fraction and set the draw auction results
    UD2x18 rewardFraction = _fractionalReward(_auctionElapsedSeconds);
    _auctionResults = AuctionResult({
      rewardFraction: rewardFraction,
      recipient: _rewardRecipient
    });
    _lastSequenceId = _sequenceId;

    AuctionResult[] memory auctionResults = new AuctionResult[](2);
    auctionResults[0] = _rngAuctionResult;
    auctionResults[1] = _auctionResults;

    uint32 drawId = prizePool.closeDraw(_randomNumber);

    uint256 futureReserve = prizePool.reserve() + prizePool.reserveForOpenDraw();
    uint256[] memory _rewards = RewardLib.rewards(auctionResults, futureReserve);

    emit RngSequenceCompleted(
      _sequenceId,
      drawId,
      _rewardRecipient,
      _auctionElapsedSeconds,
      rewardFraction
    );

    for (uint8 i = 0; i < _rewards.length; i++) {
      uint104 _reward = uint104(_rewards[i]);
      if (_reward > 0) {
        prizePool.withdrawReserve(auctionResults[i].recipient, _reward);
        emit AuctionRewardDistributed(_sequenceId, auctionResults[i].recipient, i, _reward);
      }
    }

    return bytes32(uint(drawId));
}
  • Estimated gas saved = This optimization could save around 5,000 gas per transaction due to the reduction in the number of SSTORE operations.

#0 - c4-judge

2023-08-14T11:09:06Z

HickupHH3 marked the issue as grade-b

Findings Information

🌟 Selected for report: 3agle

Also found by: 0xSmartContract, 0xmystery, DedOhWale, K42, cholakov, hunter_w3b

Labels

analysis-advanced
grade-b
A-07

Awards

99.192 USDC - $99.19

External Links

Advanced Analysis Report for PoolTogether-v5 by K42

Overview

  • PoolTogether-v5 is a protocol that allows users to participate in a no-loss lottery system. Users deposit funds into a Prize Pool, which earns interest. The interest is then distributed as prizes to randomly selected users, while the original deposits remain intact. The v5 version introduces several new features and improvements over the previous versions, including the introduction of Vaults, Draw Auctions, and a new TWAB (Time-Weighted Average Balance) Controller.

Understanding the Ecosystem:

The PoolTogether-v5 ecosystem is composed of several key components:

  • Vaults: Vaults are the primary storage mechanism for user deposits. They also handle the distribution of prizes. Each vault is associated with a specific ERC20 token.

  • Prize Pools: Prize pools are the pools of funds that users contribute to. The interest earned on these funds is used to provide the prizes for the pool.

  • Draw Auction: The Draw Auction is a mechanism that selects winners for the prizes in a fair and transparent manner.

  • Liquidation Pairs: Liquidation pairs are used to facilitate the conversion of one token into another. This is used for the liquidation of yield.

  • Claimer: The Claimer is a contract that handles the claiming of prizes by winners.

  • TWAB Controller: The TWAB (Time-Weighted Average Balance) Controller is a contract that tracks the balances of users over time. This is used to calculate a user's chance of winning a prize.

Codebase Quality Analysis:

  • The codebase of PoolTogether-v5 is well-structured and modular, with clear separation of concerns among different contracts. The contracts are well-documented with comments explaining the purpose and functionality of each function and variable. The use of libraries and interfaces further enhances the modularity and reusability of the code.

Architecture Recommendations:

The architecture of PoolTogether-v5 is robust and well-designed. However, there are a few areas where improvements could be made:

  • Gas Optimizations: As discussed in my gas report, there are a few areas in the contracts where gas optimizations could be implemented. These include reducing the number of SLOAD operations and using events to emit less frequently used data instead of storing them in contract storage.

  • Upgradeability: The contracts do not appear to have any upgradeability mechanisms in place. This could potentially limit the ability of the protocol to adapt and evolve over time.

Centralization Risks:

The PoolTogether-v5 protocol is designed to be decentralized, with no single point of failure. However, there are some centralization risks:

  • Admin Privileges: Some contracts in the codebase have functions that can only be called by the contract owner. This could potentially be a centralization risk if the owner account is compromised.

  • External Dependencies: The protocol relies on external contracts for some of its functionality, such as the ERC20 token contracts and the Uniswap contracts used for liquidation. If these external contracts were to fail or be compromised, it could impact the functioning of the PoolTogether-v5 protocol.

Mechanism Review:

  • The mechanisms used in PoolTogether-v5 are complex but well-designed. The use of a draw auction to select winners ensures fairness and transparency. The TWAB Controller provides a fair and accurate way to calculate a user's chance of winning based on their balance over time.

Systemic Risks:

  • The primary systemic risk in PoolTogether-v5 is smart contract risk. As with any decentralized protocol, there is a risk that bugs or vulnerabilities in the smart contracts could lead to loss of funds. However, the codebase appears to be well-tested and audited, which mitigates this risk.

Areas of Concern

  • Gas efficiency: As discussed earlier, there are several areas in the contracts where gas optimizations could be implemented.
  • Upgradeability: The lack of upgradeability mechanisms could limit the protocol's ability to adapt and evolve over time.
  • Centralization: The use of the Ownable pattern in some contracts introduces a degree of centralization.

Codebase Analysis

  • The codebase of PoolTogether-v5 is well-structured and modular, with clear separation of concerns among different contracts. The contracts are well-documented with comments explaining the purpose and functionality of each function and variable. The use of libraries and interfaces further enhances the modularity and reusability of the code.

Recommendations

  • Consider adding upgradeability mechanisms to the contracts.
  • Consider implementing a multi-signature scheme or a decentralized governance system to mitigate centralization risks.
  • Continue to regularly monitor and audit external contracts that the protocol relies on.

Contract Details

  • Vaults: Vaults are the primary storage mechanism for user deposits. They also handle the distribution of prizes. Each vault is associated with a specific ERC20 token.
  • Prize Pools: Prize pools are the pools of funds that users contribute to. The interest earned on these funds is used to provide the prizes for the pool.
  • Draw Auction: The Draw Auction is a mechanism that selects winners for the prizes in a fair and transparent manner.
  • Liquidation Pairs: Liquidation pairs are used to facilitate the conversion of one token into another. This is used for the liquidation of yield.
  • Claimer: The Claimer is a contract that handles the claiming of prizes by winners.
  • TWAB Controller: The TWAB (Time-Weighted Average Balance) Controller is a contract that tracks the balances of users over time. This is used to calculate a user's chance of winning a prize.

Conclusion

  • PoolTogether-v5 is a robust and well-designed protocol that provides a decentralized and transparent way for users to pool their funds and earn interest. The codebase is well-structured and modular, and the mechanisms used are fair and transparent. However, there are areas where improvements could be made, particularly in terms of gas efficiency and upgradeability.

Time spent:

16 hours

#0 - c4-judge

2023-08-14T10:56:59Z

HickupHH3 marked the issue as grade-b

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