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
Rank: 52/60
Findings: 1
Award: $89.35
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: joestakey
Also found by: 0v3rf10w, 0x1f8b, 0x4non, 0xDjango, 0xNazgul, 0xkatana, 0xmint, Dravee, Funen, IllIllI, MaratCerby, NoamYakov, Tadashi, TerrierLover, Tomio, WatchPug, catchup, defsec, fatherOfBlocks, hake, horsefacts, kenta, oyc_109, pauliax, rayn, rfa, robee, saian, securerodd, simon135, slywaters, sorrynotsorry, tin537, z3s
89.3504 USDC - $89.35
gas
1.
Title: Unnecessary lockAmount
MSTORE
https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L43
Chacing 'lockAmount' into amountLeft
is unnecessary since loading parameter var cost same gas fee as reading from memory and parameter value can be rewritten. Remove L43 and replace all LockAmount
in the function:
function lockFunds( address stakerVaultAddress, address payer, address token, uint256 lockAmount, uint256 depositAmount ) external { IStakerVault stakerVault = IStakerVault(stakerVaultAddress); // stake deposit amount if (depositAmount > 0) { depositAmount = depositAmount > lockAmount ? lockAmount : depositAmount; IERC20(token).safeTransferFrom(payer, address(this), depositAmount); IERC20(token).safeApprove(stakerVaultAddress, depositAmount); stakerVault.stake(depositAmount); stakerVault.increaseActionLockedBalance(payer, depositAmount); lockAmount -= depositAmount; } // use stake vault allowance if available and required if (lockAmount > 0) { uint256 balance = stakerVault.balanceOf(payer); uint256 allowance = stakerVault.allowance(payer, address(this)); uint256 availableFunds = balance < allowance ? balance : allowance; if (availableFunds >= lockAmount) { stakerVault.transferFrom(payer, address(this), lockAmount); lockAmount = 0; } } require(lockAmount == 0, Error.INSUFFICIENT_UPDATE_BALANCE); }
Title: Tight variable packing in ExecuteLocalVars
struct
https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L116-L140
By placing bool success
near address underlying
() can save 1 slot
Change to:
struct ExecuteLocalVars { uint256 minActionAmountToTopUp; uint256 actionTokenAmount; uint256 depositTotalFeesAmount; uint256 actionAmountWithFees; uint256 userFactor; uint256 rate; uint256 depositAmountWithFees; uint256 depositAmountWithoutFees; uint256 actionFee; uint256 totalActionTokenAmount; uint128 totalTopUpAmount; bytes topupResult; uint256 gasBankBalance; uint256 initialGas; uint256 gasConsumed; uint256 userGasPrice; uint256 estimatedRequiredGas; uint256 estimatedRequiredWeiForGas; uint256 requiredWeiForGas; uint256 reimbursedWeiForGas; address underlying; bool removePosition; bool success; }
Title: Using unchecked and prefix increment on i in for()
Occurence: https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L188 https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L456 https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L479 https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L891
Using unchecked and prefix increment is more effective for gas saving:
for (uint256 i = 0; i < protocols.length;) { bytes32 protocolKey = _getProtocolKey(protocols[i]); _setConfig(protocolKey, handlers[i]); _updateTopUpHandler(protocols[i], address(0), handlers[i]); unchecked{++i;} }
Title: Using != is more efficient than >
https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L210 Using =! To validate that value is not zero is gas saving than >
require(record.singleTopUpAmount != 0, Error.INVALID_AMOUNT);
Title: Using && in require() isn't effective
Occurrences: https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L359-L363 https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L676 Using multiple require instead of using && is cheaper for execution gas cost Change to:
require( newSwapperSlippage >= _MIN_SWAPPER_SLIPPAGE &&, Error.INVALID_AMOUNT ); require( newSwapperSlippage <= _MAX_SWAPPER_SLIPPAGE, Error.INVALID_AMOUNT );
Title: Initializing var with default value is gas consuming
Occurence: https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L452 https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L452 https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L188 https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L456 https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L479 https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/actions/topup/TopUpAction.sol#L891 https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/vault/Vault.sol#L135
By just declaring the var without set the value to 0 is gas effective
Title: Set function to external
https://github.com/code-423n4/2022-04-backd/blob/main/backd/contracts/strategies/BkdTriHopCvx.sol#L136-L142 Some function can be set to external to be more effective for gas opt. Those function are not called inside the contract.