PoolTogether Aave v3 contest - joestakey's results

A protocol for no loss prize savings on Ethereum.

General Information

Platform: Code4rena

Start Date: 29/04/2022

Pot Size: $22,000 USDC

Total HM: 6

Participants: 40

Period: 3 days

Judge: Justin Goro

Total Solo HM: 2

Id: 114

League: ETH

PoolTogether

Findings Distribution

Researcher Performance

Rank: 30/40

Findings: 1

Award: $31.86

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

31.859 USDC - $31.86

Labels

bug
G (Gas Optimization)

External Links

Gas Report

Table of Contents

Comparisons with zero for unsigned integers

IMPACT

> 0 is less gas efficient than != 0 if you enable the optimizer at 10k AND you’re in a require statement. Detailed explanation with the opcodes here

PROOF OF CONCEPT

Instances include:

AaveV3YieldSource.sol

AaveV3YieldSource.sol:179: require(decimals_ > 0, "AaveV3YS/decimals-gt-zero"); AaveV3YieldSource.sol:233: require(_shares > 0, "AaveV3YS/shares-gt-zero");

TOOLS USED

Manual Analysis

MITIGATION

Replace > 0 with != 0

Constructor parameters should be avoided when possible

IMPACT

Constructor parameters are expensive. The contract deployment will be cheaper in gas if they are hard coded instead of using constructor parameters.

PROOF OF CONCEPT

Instances include:

AaveV3YieldSource.sol

AaveV3YieldSource.sol:160 IAToken _aToken AaveV3YieldSource.sol:161 IRewardsController _rewardsController AaveV3YieldSource.sol:162 IPoolAddressesProviderRegistry _poolAddressesProviderRegistry AaveV3YieldSource.sol:165 uint8 decimals_

TOOLS USED

Manual Analysis

MITIGATION

Hardcode aToken, rewardsController, poolAddressesProviderRegistry and _decimals with their values instead of writing them during contract deployment with constructor parameters.

Custom Errors

IMPACT

Custom errors from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met) while providing the same amount of information, as explained here

Custom errors are defined using the error statement

PROOF OF CONCEPT

Instances include:

AaveV3YieldSource.sol

AaveV3YieldSource.sol:168: require(address(_aToken) != address(0), "AaveV3YS/aToken-not-zero-address"); AaveV3YieldSource.sol:171: require(address(_rewardsController) != address(0), "AaveV3YS/RC-not-zero-address"); AaveV3YieldSource.sol:174: require(address(_poolAddressesProviderRegistry) != address(0), "AaveV3YS/PR-not-zero-address"); AaveV3YieldSource.sol:177: require(_owner != address(0), "AaveV3YS/owner-not-zero-address"); AaveV3YieldSource.sol:179: require(decimals_ > 0, "AaveV3YS/decimals-gt-zero"); AaveV3YieldSource.sol:233: require(_shares > 0, "AaveV3YS/shares-gt-zero"); AaveV3YieldSource.sol:276: require(_to != address(0), "AaveV3YS/payee-not-zero-address"); AaveV3YieldSource.sol:337: require(address(_token) != address(aToken), "AaveV3YS/forbid-aToken-transfer"); AaveV3YieldSource.sol:349: require(_token != address(aToken), "AaveV3YS/forbid-aToken-allowance");

TOOLS USED

Manual Analysis

MITIGATION

Replace require and revert statements with custom errors.

For instance:

Replace

require(decimals_ > 0, "AaveV3YS/decimals-gt-zero");

with

if (decimals_ == 0) { revert ErrorDecimalNull(decimals_); }

and define the custom error in the contract

error ErrorDecimalNull(uint8 decimals_);

Inline functions

PROBLEM

When we define internal functions to perform computation:

  • The contract’s code size gets bigger
  • the function call consumes more gas than executing it as an inlined function (part of the code, without the function call)

When it does not affect readability, it is recommended to inline functions in order to save gas

PROOF OF CONCEPT

Instances include:

AaveV3YieldSource.sol

AaveV3YieldSource.sol: 348: function _requireNotAToken(address _token) AaveV3YieldSource.sol: 380: function _tokenAddress()

TOOLS USED

Manual Analysis

MITIGATION

Inline these functions where they are called:

AaveV3YieldSource.sol:183 AaveV3YieldSource.sol:212 AaveV3YieldSource.sol:235 AaveV3YieldSource.sol:252 AaveV3YieldSource.sol:301 AaveV3YieldSource.sol:320

Safemath library redundant

PROBLEM

As of Solidity 0.8.0, overflow and underflow checks are performed automatically. Using the SafeMath library methods for subtractions and additions is hence superfluous and cost additional gas upon deployment and function calls

PROOF OF CONCEPT

Instances include:

AaveV3YieldSource.sol

AaveV3YieldSource.sol:262: uint256 _balanceDiff = _afterBalance.sub(_beforeBalance);

TOOLS USED

Manual Analysis

MITIGATION

Replace the sub() call with the regular - operation

Tight Variable Packing

PROBLEM

Solidity contracts have contiguous 32 bytes (256 bits) slots used in storage. By arranging the variables, it is possible to minimize the number of slots used within a contract's storage and therefore reduce deployment costs.

uint8 variables are each of 1 byte size (way less than 32 bytes). However, here it takes up a whole 32 bytes slot, as it is followed in storage by a uint256 variable.

By rearranging the storage variables, we can save one slot

PROOF OF CONCEPT

Instances include:

Funding.sol

AaveV3YieldSource.sol:136-145 uint8 private immutable _decimals; /** * @dev Aave genesis market PoolAddressesProvider's ID. * @dev This variable could evolve in the future if we decide to support other markets. */ uint256 private constant ADDRESSES_PROVIDER_ID = uint256(0); /// @dev PoolTogether's Aave Referral Code uint16 private constant REFERRAL_CODE = uint16(188);

TOOLS USED

Manual Analysis

MITIGATION

Place REFERRAL_CODE after _decimals to save one storage slot

uint8 private immutable _decimals; +uint16 private constant REFERRAL_CODE = uint16(188); /** * @dev Aave genesis market PoolAddressesProvider's ID. * @dev This variable could evolve in the future if we decide to support other markets. */ uint256 private constant ADDRESSES_PROVIDER_ID = uint256(0);

#0 - PierrickGT

2022-05-03T23:42:18Z

Comparisons with zero for unsigned integers Safemath library redundant

Duplicate of https://github.com/code-423n4/2022-04-pooltogether-findings/issues/11

Constructor parameters should be avoided when possible

This parameters need to be passed to the initialized function.

Custom Errors

Duplicate of https://github.com/code-423n4/2022-04-pooltogether-findings/issues/13

Inline functions

Duplicate of https://github.com/code-423n4/2022-04-pooltogether-findings/issues/19

Tight Variable Packing

The compiler is smart enough to properly allocate memory. I didn't notice any gas saving when testing the change proposed by the warden.

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