Backd contest - joestakey's results

Maximize the power of your assets and start earning yield

General Information

Platform: Code4rena

Start Date: 21/04/2022

Pot Size: $100,000 USDC

Total HM: 18

Participants: 60

Period: 7 days

Judge: gzeon

Total Solo HM: 10

Id: 112

League: ETH

Backd

Findings Distribution

Researcher Performance

Rank: 14/60

Findings: 2

Award: $1,032.54

🌟 Selected for report: 1

πŸš€ Solo Findings: 0

Awards

204.213 USDC - $204.21

Labels

bug
QA (Quality Assurance)
resolved
reviewed

External Links

QA Report

Table of Contents

summary

Few vulnerabilities were found examining the contracts. The main concerns are with unchecked inputs in setter functions.

Typos

PROBLEM

There are a few typos in some comments

SEVERITY

Non-Critical

PROOF OF CONCEPT

Instances include:

CompoundHandler.sol

CompoundHandler.sol:90: bytes memory//no parameter is declared

Preparable.sol

Preparable.sol:148: _setConfig is declared twice

TOOLS USED

Manual Analysis

MITIGATION

Correct the typos.

Comment Missing function parameter

PROBLEM

Some of the function comments are missing function parameters or returns

SEVERITY

Non-Critical

PROOF OF CONCEPT

Instances include:

AaveHandler.sol

AaveHandler.sol:26: topUp() //bytes memory extra

CompoundHandler.sol

CompoundHandler.sol:26: topUp() //bytes memory extra
CompoundHandler.sol:109: topUp() //CToken ctoken

TopUpAction.sol

TopUpAction.sol:203: register() //return value missing comment TopUpAction.sol:442: addUsableToken() //return value missing comment

TOOLS USED

Manual Analysis

MITIGATION

Add a comment for these parameters

Function missing comments

PROBLEM

Some functions are missing comments.

SEVERITY

Non-Critical

PROOF OF CONCEPT

Instances include:

AaveHandler.sol

AaveHandler.sol:69: getUserFactor()

CompoundHandler.sol

CompoundHandler.sol:128: _getAccountBorrowsAndSupply()

CTokenRegistry.sol

CTokenRegistry.sol:128: _isCTokenUsable()

TopUpAction.sol

TopUpAction.sol:36: lockFunds() TopUpAction.sol:91: getSwapper() TopUpAction.sol:180: initialize() TopUpAction.sol:821: _updateTopUpHandler() TopUpAction.sol:871: _removePosition() TopUpAction.sol:884: _removeUserPosition()

TOOLS USED

Manual Analysis

MITIGATION

Add comments to all functions

Related data should be grouped in struct

PROBLEM

When there are mappings that use the same key value, having separate fields is error prone, for instance in case of deletion or with future new fields.

SEVERITY

Non-Critical

PROOF OF CONCEPT

Instances include:

BkdLocker.sol

BkdLocker.sol:26:mapping(address => uint256) public balances; BkdLocker.sol:27:mapping(address => uint256) public boostFactors; BkdLocker.sol:28:mapping(address => uint256) public lastUpdated; BkdLocker.sol:29:mapping(address => WithdrawStash[]) public stashedGovTokens; BkdLocker.sol:30:mapping(address => uint256) public totalStashed;

TOOLS USED

Manual Analysis

MITIGATION

Group the related data in a struct and use one mapping. For instance, the mitigation could be:

struct UserData { uint256 balances; uint256 boostFactors; uint256 lastUpdated; WithdrawStash[] stashedGovTokens; uint256 totalStashed; }

And it would be used as a state variable:

mapping(address => UserData) userData;

Event should be emitted in setters

PROBLEM

Setters should emit an event so that Dapps can detect important changes to storage

SEVERITY

Non-Critical

PROOF OF CONCEPT

Instances include:

ChainlinkOracleProvider.sol

ChainlinkOracleProvider.sol:40: setStalePriceDelay()

Controller.sol

Controller.sol:31: setInflationManager()

CvxCrvRewardsLocker.sol

CvxCrvRewardsLocker.sol:119: setWithdrawalFlag()

TOOLS USED

Manual Analysis

MITIGATION

Emit an event in all setters.

Unchecked inputs

PROBLEM

There should be a non-zero (address or integer) check in all setters

SEVERITY

Non-Critical

PROOF OF CONCEPT

Instances include:

ConvexStrategyBase.sol

ConvexStrategyBase.sol:181: setCommunityReserve() ConvexStrategyBase.sol:227: setImbalanceToleranceIn() ConvexStrategyBase.sol:243: setImbalanceToleranceOut()

CvxCrvRewardsLocker.sol

CvxCrvRewardsLocker.sol:150: setTreasury() CvxCrvRewardsLocker.sol:189: setDelegate()

TOOLS USED

Manual Analysis

MITIGATION

Add non-zero checks.

Awards

828.3304 USDC - $828.33

Labels

bug
G (Gas Optimization)
resolved
reviewed

External Links

Gas Report

Table of Contents

Caching storage variables in memory to save gas

PROBLEM

Anytime you are reading from storage more than once, it is cheaper in gas cost to cache the variable in memory: a SLOAD cost 100gas, while MLOAD and MSTORE cost 3 gas.

In particular, in for loops, when using the length of a storage array as the condition being checked after each loop, caching the array length in memory can yield significant gas savings if the array length is high.

PROOF OF CONCEPT

Instances include:

AaveHandler.sol

scope: topUp()

  • weth is read twice
AaveHandler.sol:44 AaveHandler.sol:45
  • lendingPool is read 4 times
AaveHandler.sol:50 AaveHandler.sol:53 AaveHandler.sol:60 AaveHandler.sol:65

CompoundHandler.sol

scope: _getAccountBorrowsAndSupply()

  • comptroller is read (2 + assets.length) times. Number of read depends on the length of assets as it is in a for loop
CompoundHandler.sol:132 CompoundHandler.sol:134 CompoundHandler.sol:142

CTokenRegistry.sol

scope: _isCTokenUsable()

  • comptroller is read 3 times
CTokenRegistry.sol:77 CTokenRegistry.sol:79 CTokenRegistry.sol:80

TopUpAction.sol

scope: resetPosition()

  • addressProvider is read twice
TopUpAction.sol:284 TopUpAction.sol:295

scope: execute()

  • addressProvider is read 3 times
TopUpAction.sol:562 TopUpAction.sol:604 TopUpAction.sol:632

BkdEthCvx.sol

scope: _withdraw()

  • vault is read twice
BkdEthCvx.sol:77 BkdEthCvx.sol:93

BkdTriHopCvx.sol

scope: _withdraw()

  • vault is read twice
BkdTriHopCvx.sol:175 BkdTriHopCvx.sol:201

ConvexStrategyBase.sol

scope: addRewardToken()

  • _strategySwapper is read twice
ConvexStrategyBase.sol:279 ConvexStrategyBase.sol:280

scope: harvestable()

  • crvCommunityReserveShare is read twice
ConvexStrategyBase.sol:307 ConvexStrategyBase.sol:311
  • _rewardTokens.length() is read _rewardTokens.length() times. Number of read depends on the length of _rewardsTokens as it is in a for loop
ConvexStrategyBase.sol:313

scope: _harvest()

  • _rewardTokens.length() is read _rewardTokens.length() times. Number of read depends on the length of _rewardsTokens as it is in a for loop
ConvexStrategyBase.sol:380

scope: _sendCommunityReserveShare()

  • cvxCommunityReserveShare is read twice
ConvexStrategyBase.sol:398 ConvexStrategyBase.sol:409

Vault.sol

scope: _handleExcessDebt()

  • reserve is read 3 times
Vault.sol:645 Vault.sol:648 Vault.sol:649

scope: _handleExcessDebt()

  • totalDebt is read twice
Vault.sol:657 Vault.sol:658

Vault.sol

scope: stakeFor()

  • token is read 4 times
Vault.sol:324 Vault.sol:331 Vault.sol:338 Vault.sol:339

scope: unStakeFor()

  • token is read 4 times
Vault.sol:365 Vault.sol:376 Vault.sol:382 Vault.sol:384

TOOLS USED

Manual Analysis

MITIGATION

cache these storage variables in memory

Calldata instead of memory for RO function parameters

PROBLEM

If a reference type function parameter is read-only, it is cheaper in gas to use calldata instead of memory. Calldata is a non-modifiable, non-persistent area where function arguments are stored, and behaves mostly like memory.

Try to use calldata as a data location because it will avoid copies and also makes sure that the data cannot be modified.

PROOF OF CONCEPT

Instances include:

RoleManager.sol

scope: hasAnyRole()

RoleManager.sol:73: bytes32[] memory roles

AaveHandler.sol

scope: topUp()

AaveHandler.sol:40: bytes memory extra

CompoundHandler.sol

scope: topUp()

CompoundHandler.sol:54: bytes memory extra

TopUpAction.sol

scope: getHealthFactor()

TopUpAction.sol:760: bytes memory extra

TopUpKeeperHelper.sol

scope: canExecute()

TopUpKeeperHelper.sol:108: ITopUpAction.RecordKey memory key

scope: _canExecute()

TopUpKeeperHelper.sol:131: ITopUpAction.RecordWithMeta memory position

scope: _positionToTopup()

TopUpKeeperHelper.sol:145: ITopUpAction.RecordWithMeta memory position

scope: _shortenTopups()

TopUpKeeperHelper.sol:159: TopupData[] memory topups

Erc20Pool.sol

scope: initialize()

Erc20Pool.sol:15: string memory name_

EthPool.sol

scope: initialize()

EthPool.sol:13: string memory name_

LiquidityPool.sol

scope: initialize()

LiquidityPool.sol:702: string memory name_

LpToken.sol

scope: initialize()

LpToken.sol:29: string memory name_ LpToken.sol:30: string memory symbol_

TOOLS USED

Manual Analysis

MITIGATION

Replace memory with calldata

Comparisons with zero for unsigned integers

PROBLEM

>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:

TopUpAction.sol

scope: register()

TopUpAction.sol:210

scope: execute()

TopUpAction.sol:554

TopUpActionFeeHandler.sol

scope: claimKeeperFeesForPool()

TopUpActionFeeHandler.sol:123

LiquidityPool.sol

scope: updateDepositCap()

LiquidityPool.sol:401

scope: calcRedeem()

LiquidityPool.sol:471 LiquidityPool.sol:473

scope: redeem()

LiquidityPool.sol:549

Vault.sol

scope: withdrawFromReserve()

Vault.sol:164

BkdLocker.sol

scope: depositFees()

BkdLocker.sol:90 BkdLocker.sol:91 BkdLocker.sol:136

TOOLS USED

Manual Analysis

MITIGATION

Replace > 0 with !0

Comparison Operators

PROBLEM

In the EVM, there is no opcode for >= or <=. When using greater than or equal, two operations are performed: > and =.

Using strict comparison operators hence saves gas

PROOF OF CONCEPT

Instances include:

TopUpAction.sol

TopUpAction.sol:61 TopUpAction.sol:212 TopUpAction.sol:224 TopUpAction.sol:328 TopUpAction.sol:360 TopUpAction.sol:361 TopUpAction.sol:500 TopUpAction.sol:501 TopUpAction.sol:576 TopUpAction.sol:584 TopUpAction.sol:724

TopUpActionFeeHandler.sol

TopUpActionFeeHandler.sol:54 TopUpActionFeeHandler.sol:151 TopUpActionFeeHandler.sol:163 TopUpActionFeeHandler.sol:196 TopUpActionFeeHandler.sol:208

ChainLinkOracleProvider.sol

ChainLinkOracleProvider.sol:41 ChainLinkOracleProvider.sol:57

EthPool.sol

EthPool.sol:442 EthPool.sol:208 EthPool.sol:518 EthPool.sol:525 EthPool.sol:551 EthPool.sol:562 EthPool.sol:690 EthPool.sol:811 EthPool.sol:812

BkdEthCvx.sol

BkdEthCvx.sol:76

BkdTriHopCvx.sol

BkdTriHopCvx.sol:174

ConvexStrategyBase.sol

ConvexStrategyBase.sol:197 ConvexStrategyBase.sol:214

StrategySwapper.sol

StrategySwapper.sol:110

CvxMintAmount.sol

CvxMintAmount.sol:21

Preparable.sol

Preparable.sol:29 Preparable.sol:110

Vault.sol

Vault.sol:88 Vault.sol:89 Vault.sol:90 Vault.sol:167 Vault.sol:264 Vault.sol:323 Vault.sol:392 Vault.sol:437 Vault.sol:482 Vault.sol:712 Vault.sol:763

VaultReserve.sol

VaultReserve.sol:59 VaultReserve.sol:75 VaultReserve.sol:103

BkdLocker.sol

BkdLocker.sol:119 BkdLocker.sol:140 BkdLocker.sol:281

Controller.sol

Controller:98

CvxCrvRewardsLocker.sol

CvxCrvRewardsLocker:84

GasBank.sol

GasBank:68 GasBank:76

StakerVault.sol

StakerVault:107 StakerVault:150 StakerVault:153 StakerVault:324 StakerVault:368 StakerVault:371

TOOLS USED

Manual Analysis

MITIGATION

Replace <= with <, and >= with >. Do not forget to increment/decrement the compared variable

example:

-require(maxFee >= minFee, Error.INVALID_AMOUNT); +require(maxFee > minFee - 1, Error.INVALID_AMOUNT);

When the comparison is with a constant storage variable, you can also do the increment in the storage variable declaration

example:

-require(maxFee <= _MAX_WITHDRAWAL_FEE, Error.INVALID_AMOUNT) +require(maxFee < _MAX_WITHDRAWAL_FEE_PLUS_ONE, Error.INVALID_AMOUNT)

However, when 1 is negligible compared to the variable (with is the case here as the variable is in the order of 10**16), it is not necessary to increment.

Custom Errors

PROBLEM

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:

RoleManager.sol

RoleManager.sol:44 RoleManager.sol:110 RoleManager.sol:111

AaveHandler.sol

AaveHandler.sol:51

CompoundHandler.sol

CompoundHandler.sol:74 CompoundHandler.sol:80 CompoundHandler.sol:123 CompoundHandler.sol:141 CompoundHandler.sol:148

TopUpAction.sol

TopUpAction.sol:67 TopUpAction.sol:98 TopUpAction.sol:185 TopUpAction.sol:209 TopUpAction.sol:210 TopUpAction.sol:211 TopUpAction.sol:212 TopUpAction.sol:213 TopUpAction.sol:217 TopUpAction.sol:218 TopUpAction.sol:224 TopUpAction.sol:282 TopUpAction.sol:328 TopUpAction.sol:359 TopUpAction.sol:546 TopUpAction.sol:553 TopUpAction.sol:554 TopUpAction.sol:560 TopUpAction.sol:575 TopUpAction.sol:583 TopUpAction.sol:676 TopUpAction.sol:723 TopUpAction.sol:928

TopUpActionFeeHandler.sol

TopUpActionFeeHandler.sol:67 TopUpActionFeeHandler.sol:68 TopUpActionFeeHandler.sol:87 TopUpActionFeeHandler.sol:123 TopUpActionFeeHandler.sol:151 TopUpActionFeeHandler.sol:161 TopUpActionFeeHandler.sol:196 TopUpActionFeeHandler.sol:206

ChainLinkOracleProvider.sol

ChainLinkOracleProvider.sol:31 ChainLinkOracleProvider.sol:41 ChainLinkOracleProvider.sol:53 ChainLinkOracleProvider.sol:57 ChainLinkOracleProvider.sol:58

Erc20Pool.sol

Erc20Pool.sol:20 Erc20Pool.sol:30

EthPool.sol

EthPool.sol:25 EthPool.sol:26

LiquidityPool.sol

LiquidityPool.sol:76 LiquidityPool.sol:136 LiquidityPool.sol:137 LiquidityPool.sol:155 LiquidityPool.sol:179 LiquidityPool.sol:208 LiquidityPool.sol:331 LiquidityPool.sol:333 LiquidityPool.sol:387 LiquidityPool.sol:399 LiquidityPool.sol:400 LiquidityPool.sol:401 LiquidityPool.sol:441 LiquidityPool.sol:471 LiquidityPool.sol:473 LiquidityPool.sol:517 LiquidityPool.sol:525 LiquidityPool.sol:549 LiquidityPool.sol:551 LiquidityPool.sol:562 LiquidityPool.sol:811 LiquidityPool.sol:812

PoolFactory.sol

PoolFactory.sol:159 PoolFactory.sol:162 PoolFactory.sol:165 PoolFactory.sol:170 PoolFactory.sol:180 PoolFactory.sol:184

BkdTriHopCvx.sol

BkdTriHopCvx.sol:133 BkdTriHopCvx.sol:147

ConvexStrategyBase.sol

ConvexStrategyBase.sol:117 ConvexStrategyBase.sol:144 ConvexStrategyBase.sol:197 ConvexStrategyBase.sol:198 ConvexStrategyBase.sol:214 ConvexStrategyBase.sol:215 ConvexStrategyBase.sol:260 ConvexStrategyBase.sol:273

StrategySwapper.sol

StrategySwapper.sol:69 StrategySwapper.sol:110 StrategySwapper.sol:111 StrategySwapper.sol:123 StrategySwapper.sol:124 StrategySwapper.sol:139

Preparable.sol

Preparable.sol:28 Preparable.sol:29 Preparable.sol:86 Preparable.sol:98 Preparable.sol:110 Preparable.sol:111

Erc20Vault.sol

Erc20Vault.sol:20

Vault.sol

Vault.sol:88 Vault.sol:89 Vault.sol:90 Vault.sol:164 Vault.sol:165 Vault.sol:167 Vault.sol:194 Vault.sol:195 Vault.sol:198 Vault.sol:264 Vault.sol:392 Vault.sol:429 Vault.sol:762

VaultReserve.sol

VaultReserve.sol:51 VaultReserve.sol:59 VaultReserve.sol:73 VaultReserve.sol:75

AddressProvider.sol

AddressProvider.sol:64 AddressProvider.sol:70 AddressProvider.sol:96 AddressProvider.sol:100 AddressProvider.sol:170 AddressProvider.sol:179 AddressProvider.sol:188 AddressProvider.sol:230 AddressProvider.sol:231 AddressProvider.sol:249 AddressProvider.sol:259 AddressProvider.sol:284 AddressProvider.sol:285 AddressProvider.sol:314 AddressProvider.sol:417 AddressProvider.sol:423

BkdLocker.sol

BkdLocker.sol:58 BkdLocker.sol:90 BkdLocker.sol:91 BkdLocker.sol:118 BkdLocker.sol:136 BkdLocker.sol:207

Controller.sol

Controller:32 Controller:33 Controller:80

CvxCrvRewardsLocker.sol

CvxCrvRewardsLocker:83 CvxCrvRewardsLocker:135

GasBank.sol

GasBank:42 GasBank:68 GasBank:69 GasBank:76 GasBank:91

LpToken.sol

LpToken:34

StakerVault.sol

StakerVault:70 StakerVault:93 StakerVault:106 StakerVault:107 StakerVault:139 StakerVault:150 StakerVault:153 StakerVault:203 StakerVault:224 StakerVault:324 StakerVault:340 StakerVault:367 StakerVault:371

SwapperRegistry.sol

SwapperRegistry:35

TOOLS USED

Manual Analysis

MITIGATION

Replace require statements with custom errors.

Default value initialization

PROBLEM

If a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type). Explicitly initializing it with its default value is an anti-pattern and wastes gas.

PROOF OF CONCEPT

Instances include:

RoleManager.sol

RoleManager.sol:80 RoleManager.sol:110 RoleManager.sol:111

CompoundHandler.sol

CompoundHandler.sol:135

CTokenRegistry.sol

CTokenRegistry.sol:61

TopUpAction.sol

TopUpAction.sol:188 TopUpAction.sol:452 TopUpAction.sol:456 TopUpAction.sol:479 TopUpAction.sol:506 TopUpAction.sol:891

TopUpActionKeeperHandler.sol

TopUpActionKeeperHandler.sol:43 TopUpActionKeeperHandler.sol:46 TopUpActionKeeperHandler.sol:72 TopUpActionKeeperHandler.sol:93 TopUpActionKeeperHandler.sol:165

LiquidityPool.sol

LiquidityPool.sol:483

ConvexStrategyBase.sol

ConvexStrategyBase.sol:313 ConvexStrategyBase.sol:380

Vault.sol

Vault.sol:42 Vault.sol:135 Vault.sol:583

BkdLocker.sol

BkdLocker.sol:133 BkdLocker.sol:310

Controller.sol

Controller:114 Controller:117

CvxCrvRewardsLocker.sol

CvxCrvRewardsLocker:43

StakerVault.sol

StakerVault:144 StakerVault:260

TOOLS USED

Manual Analysis

MITIGATION

Remove explicit initialization for default values.

Prefix increments

PROBLEM

Prefix increments are cheaper than postfix increments.

PROOF OF CONCEPT

Instances include:

RoleManager.sol

RoleManager.sol:80

CompoundHandler.sol

CompoundHandler.sol:135

CTokenRegistry.sol

CTokenRegistry.sol:61

TopUpAction.sol

TopUpAction.sol:188 TopUpAction.sol:456 TopUpAction.sol:479 TopUpAction.sol:506 TopUpAction.sol:891

TopUpActionKeeperHandler.sol

TopUpActionKeeperHandler.sol:43 TopUpActionKeeperHandler.sol:46 TopUpActionKeeperHandler.sol:50 TopUpActionKeeperHandler.sol:72 TopUpActionKeeperHandler.sol:93 TopUpActionKeeperHandler.sol:165

ConvexStrategyBase.sol

ConvexStrategyBase.sol:313 ConvexStrategyBase.sol:380

BkdLocker.sol

BkdLocker.sol:310

Controller.sol

Controller:117

StakerVault.sol

StakerVault:260

TOOLS USED

Manual Analysis

MITIGATION

change variable++ to ++variable

Redundant code

IMPACT

Redundant code should be avoided as it costs unnecessary gas

PROOF OF CONCEPT

Instances include:

Preparable.sol

Preparable.sol:140: address oldValue = currentAddresses[key]; currentAddresses[key] = value; pendingAddresses[key] = address(0); deadlines[key] = 0; emit ConfigUpdatedAddress(key, oldValue, value); return value;

We can update currentAddresses[key] after emitting the event to save the gas of the declaration of oldValue:

+emit ConfigUpdatedAddress(key, currentAddresses[key], value); pendingAddresses[key] = address(0); deadlines[key] = 0; currentAddresses[key] = value; return value;

TOOLS USED

Manual Analysis

MITIGATION

see Proof of Concept for mitigation steps.

Require instead of &&

IMPACT

Require statements including conditions with the && operator can be broken down in multiple require statements to save gas.

PROOF OF CONCEPT

Instances include:

TopUpAction.sol

TopUpAction:360: require( newSwapperSlippage >= _MIN_SWAPPER_SLIPPAGE && newSwapperSlippage <= _MAX_SWAPPER_SLIPPAGE, Error.INVALID_AMOUNT );

ConvexStrategyBase.sol

ConvexStrategyBase:274: require( token_ != address(_CVX) && token_ != address(underlying) && token_ != address(_CRV), Error.INVALID_TOKEN_TO_ADD );

SwapperRegistry.sol

SwapperRegistry:35: require( fromToken != toToken && fromToken != address(0) && toToken != address(0) && newSwapper != address(0), Error.INVALID_TOKEN_PAIR );

TOOLS USED

Manual Analysis

MITIGATION

Breakdown each condition in a separate require statement (though require statements should be replaced with custom errors)

require( newSwapperSlippage >=_MIN_SWAPPER_SLIPPAGE); require(newSwapperSlippage <= _MAX_SWAPPER_SLIPPAGE, Error.INVALID_AMOUNT)

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.

address type variables are each of 20 bytes size (way less than 32 bytes). However, they here take up a whole 32 bytes slot (they are contiguous).

As bool type variables are of size 1 byte, there's a slot here that can get saved by moving them closer to an address

PROOF OF CONCEPT

Instances include:

VaultStorage.sol

VaultStorage.sol:11: address public pool; uint256 public totalDebt; bool public strategyActive;

TOOLS USED

Manual Analysis

MITIGATION

Place strategyActive after pool to save one storage slot

address public pool; +bool public strategyActive; uint256 public totalDebt;

Unchecked arithmetic

PROBLEM

The default "checked" behavior costs more gas when adding/diving/multiplying, because under-the-hood those checks are implemented as a series of opcodes that, prior to performing the actual arithmetic, check for under/overflow and revert if it is detected.

if it can statically be determined there is no possible way for your arithmetic to under/overflow (such as a condition in an if statement), surrounding the arithmetic in an unchecked block will save gas

PROOF OF CONCEPT

Instances include:

LiquidityPool.sol

LiquidityPool.sol:751: underlyingBalance - underlyingToWithdraw; //because of the condition line 745, the underflow check is unnecessary

BkdEthCvx.sol

BkdEthCvx.sol:83: uint256 requiredUnderlyingAmount = amount - underlyingBalance; //because of the condition line 76, the underflow check is unnecessary

BkdTriHopCvx.sol

BkdTriHopCvx.sol:181: uint256 requiredUnderlyingAmount = amount - underlyingBalance; //because of the condition line 174, the underflow check is unnecessary

CvxMintAmount.sol

CvxMintAmount.sol:24: uint256 remaining = _CLIFF_COUNT - currentCliff; //because of the condition line 21, the underflow check is unnecessary

Vault.sol

Vault.sol:24: uint256 remaining = _CLIFF_COUNT - currentCliff; //because of the condition line 21, the underflow check is unnecessary Vault.sol:125: uint256 requiredWithdrawal = amount - availableUnderlying_; //because of the condition line 122, the underflow check is unnecessary Vault.sol:130: uint256 newTarget = (allocated - requiredWithdrawal) //because of the condition line 127, the underflow check is unnecessary Vault.sol:141: uint256 totalUnderlyingAfterWithdraw = totalUnderlying - amount; //because of the condition line 122, the underflow check is unnecessary Vault.sol:440: waitingForRemovalAllocated = _waitingForRemovalAllocated - withdrawn; //because of the condition line 437, the underflow check is unnecessary Vault.sol:444: uint256 profit = withdrawn - allocated; //because of the condition line 443, the underflow check is unnecessary Vault.sol:452: allocated -= withdrawn; //because of the condition line 443, the underflow check is unnecessary Vault.sol:591: uint256 profit = allocatedUnderlying - amountAllocated; //because of the condition line 589, the underflow check is unnecessary Vault.sol:595: profit -= currentDebt; //because of the condition line 593, the underflow check is unnecessary Vault.sol:600: currentDebt -= profit; //because of the condition line 593, the underflow check is unnecessary Vault.sol:605: uint256 loss = amountAllocated - allocatedUnderlying; //because of the condition line 603, the underflow check is unnecessary Vault.sol:784: uint256 withdrawAmount = allocatedUnderlying - target; //because of the condition line 782, the underflow check is unnecessary Vault.sol:790: uint256 depositAmount = target - allocatedUnderlying; //because of the condition line 788, the underflow check is unnecessary

StakerVault.sol

StakerVault.sol:164: uint256 srcTokensNew = srcTokens - amount; //because of the condition line 153, the underflow check is unnecessary

TOOLS USED

Manual Analysis

MITIGATION

Place the arithmetic operations in an unchecked block

#0 - chase-manning

2022-04-28T09:39:53Z

I consider this report to be of particularly high quality

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