Platform: Code4rena
Start Date: 12/08/2022
Pot Size: $50,000 USDC
Total HM: 15
Participants: 120
Period: 5 days
Judge: Justin Goro
Total Solo HM: 6
Id: 153
League: ETH
Rank: 92/120
Findings: 1
Award: $23.13
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0xA5DF, 0xDjango, 0xNazgul, 0xSmartContract, 0xackermann, 0xbepresent, 0xc0ffEE, 0xkatana, 2997ms, Amithuddar, Aymen0909, Bnke0x0, Chinmay, Chom, CodingNameKiki, Deivitto, Diraco, Dravee, ElKu, EthLedger, Fitraldys, Funen, IgnacioB, JC, Junnon, Lambda, LeoS, Metatron, MiloTruck, Noah3o6, NoamYakov, PaludoX0, Randyyy, ReyAdmirado, Rohan16, Rolezn, Ruhum, SaharAP, Sm4rty, SooYa, TomJ, Tomio, Waze, Yiko, _Adam, __141345__, a12jmx, ajtra, ak1, asutorufos, ballx, brgltd, c3phas, cRat1st0s, carlitox477, chrisdior4, d3e4, delfin454000, dharma09, djxploit, durianSausage, erictee, fatherOfBlocks, find_a_bug, flyx, francoHacker, gerdusx, gogo, gzeon, hakerbaya, ignacio, jag, kyteg, ladboy233, ltyu, m_Rassska, medikko, mics, mrpathfindr, newfork01, nxrblsrpr, oyc_109, pfapostol, rbserver, reassor, ret2basic, robee, sach1r0, saian, simon135, sryysryy, zeesaw
23.127 USDC - $23.13
Solidity does not recognize null as a value, so uint variables are initialized to zero. Setting a uint variable to zero is redundant and can waste gas.
Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/LinearInterestRate.sol#L33 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairConstants.sol#L47 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L402 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L265 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L270 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L51 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L66 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L81 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L289 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L308 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/libraries/SafeERC20.sol#L22
Remove the redundant zero initialization
uint256 i;
instead of uint256 i = 0;
Combining require statement conditions with && logic uses unnecessary gas. It is better to split up each part of the logical statement into a separate require statements
One example is
require( _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT, "LinearInterestRate: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT" );
This can be improved to
require(_minInterest < MAX_INT); require(_minInterest <= _vertexInterest); require(_minInterest >= MIN_INT, "LinearInterestRate: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT" );
One part of code had require statements with many logical "and"s. Instead, split into two to save gas https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/LinearInterestRate.sol#L58-L67
Use separate require statements instead of concatenating with &&
Using calldata instead of memory for function arguments saves gas sometimes. This can happen when a function is called externally and the memory array values are kept in calldata
and copied to memory
during ABI decoding (using the opcode calldataload
and mstore
). If the array is used in a for loop, arr[i]
accesses the value in memory using a mload
. If calldata is used instead, then instead of going via memory, the value is directly read from calldata
using calldataload
. That is, there are no intermediate memory operations that carries this value.
Many cases of function arguments using memory instead of calldata can use this improvement to save gas https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L362 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L363 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L398
Change function arguments from memory to calldata
Using > 0
uses slightly more gas than using != 0
. Use != 0
when comparing uint variables to zero, which cannot hold values below zero
Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/LinearInterestRate.sol#L66 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/LinearInterestRate.sol#L67 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L379 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L380 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairHelper.sol#L235 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairHelper.sol#L292 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L440 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L477 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L754 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L835 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L1002 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L1094
Replace > 0
with != 0
to save gas
Strings in solidity are handled in 32 byte chunks. A require string longer than 32 bytes uses more gas. Shortening these strings will save gas.
Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/LinearInterestRate.sol#L59 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/LinearInterestRate.sol#L63 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/LinearInterestRate.sol#L67 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L205 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L228 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L253 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L365 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L368
Shorten all require strings to less than 32 characters
Using a prefix increment (++i) instead of a postfix increment (i++) saves gas for each loop cycle and so can have a big gas impact when the loop executes on a large number of elements.
Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L130 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L158 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L265 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L270 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L51 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L66 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L81 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L289 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L308 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/libraries/SafeERC20.sol#L24 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/libraries/SafeERC20.sol#L27
Use prefix not postfix to increment in a loop
For loops that use i++ do not need to use safemath for this operation because the loop would run out of gas long before this point. Making this addition operation unsafe using unchecked saves gas.
Sample code to make the for loop increment unsafe
for (uint i = 0; i < length; i = unchecked_inc(i)) { // do something that doesn't change the value of i } function unchecked_inc(uint i) returns (uint) { unchecked { return i + 1; } }
Idea borrowed from https://gist.github.com/hrkrshnn/ee8fabd532058307229d65dcd5836ddc#the-increment-in-for-loop-post-condition-can-be-made-unchecked
Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L130 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L158 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L265 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L270 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L51 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L66 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L81 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L289 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L308 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/libraries/SafeERC20.sol#L24 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/libraries/SafeERC20.sol#L27
Make the increment in for loops unsafe to save gas
Comparing a value to zero can be done using the iszero
EVM opcode. This can save gas
Source from t11s https://twitter.com/transmissions11/status/1474465495243898885
Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairHelper.sol#L187 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L254 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L308 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L310 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L312 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L430 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L240 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/libraries/VaultAccount.sol#L21 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/libraries/VaultAccount.sol#L38
Use the assembly iszero
evm opcode to compare values to zero
Use unchecked math when there is no overflow risk to save gas. Solidity 0.8.X adds Safemath by default, and there are cases where Safemath provides no benefit and uses extra gas.
Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L441 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L454
Add unchecked around math that can't overflow for gas savings. In Solidity before 0.8.0, use the normal math operators instead of safe math functions.
Identifying a function as payable saves gas. Functions that have a modifier like onlyOwner or auth cannot be called by normal users and will not mistakenly receive ETH. These functions can be payable to save gas.
There are many functions that have the auth modifier in the contracts/. Some examples are https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L170 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L50 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L65 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L80 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L204 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L234 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L274
Add payable to these functions for gas savings
Identifying a constructor as payable saves gas. Constructors should only be called by the admin or deployer and should not mistakenly receive ETH. Constructors can be payable to save gas.
Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L98 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L151 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L40 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L45
Add payable to these functions for gas savings
An internal function can save gas vs. a modifier. A modifier inlines the code of the original function but an internal function does not.
Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L330 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L342 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L351 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L359
Use internal functions in place of modifiers to save gas.
Booleans are more expensive than uint256 or any type that takes up a full word because each write operation emits an extra SLOAD to first read the slot's contents, replace the bits taken up by the boolean, and then write back. This is the compiler's defense against contract upgrades and pointer aliasing, and it cannot be disabled.
Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L138 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L199 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L200 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairHelper.sol#L33 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairHelper.sol#L34 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L133 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L136 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L158 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L159 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L50 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L65 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendWhitelist.sol#L80 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L52 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L53 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L183 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L190 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L274 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L288 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPair.sol#L307 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/libraries/VaultAccount.sol#L19 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/libraries/VaultAccount.sol#L36
Replace bool variables with uints
From the solidity docs
When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.
Locations where this was found include https://github.com/code-423n4/2022-06-nibbl/tree/main/contracts/NibblVaultFactory.sol#L71 https://github.com/code-423n4/2022-06-nibbl/tree/main/contracts/NibblVaultFactory.sol#L73 https://github.com/code-423n4/2022-06-nibbl/tree/main/contracts/NibblVaultFactory.sol#L90 https://github.com/code-423n4/2022-06-nibbl/tree/main/contracts/NibblVaultFactory.sol#L92
Replace smaller int or uint variables with uint256 variables
Solidity errors introduced in version 0.8.4 can save gas on revert conditions https://blog.soliditylang.org/2021/04/21/custom-errors/ https://twitter.com/PatrickAlphaC/status/1505197417884528640
Errors are already used in many places, but not all. Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/LinearInterestRate.sol#L57 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/LinearInterestRate.sol#L61 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/LinearInterestRate.sol#L65 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L205 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L228 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L253 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L365 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L366 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairDeployer.sol#L399
Replace require blocks with new solidity errors described in https://blog.soliditylang.org/2021/04/21/custom-errors/
The comparison operators >= and <= use more gas than >, <, or ==. Replacing the >= and ≤ operators with a comparison operator that has an opcode in the EVM saves gas
The existing code is https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairHelper.sol#L365
_collateralForLiquidator = _leftoverCollateral <= 0 ? _userCollateralBalance : (_liquidationAmountInCollateralUnits * (_LIQ_PRECISION + _fraxlendPair.dirtyLiquidationFee())) / _LIQ_PRECISION;
A simple comparison can be used for gas savings by reversing the logic
_collateralForLiquidator = _leftoverCollateral > 0 ? (_liquidationAmountInCollateralUnits * (_LIQ_PRECISION + _fraxlendPair.dirtyLiquidationFee())) / _LIQ_PRECISION : _userCollateralBalance;
Replace the comparison operator and reverse the logic to save gas using the suggestions above
The comparison operators >= and <= use more gas than >, <, or ==. Replacing the >= and ≤ operators with a comparison operator that has an opcode in the EVM saves gas
The existing code is https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L525
if (_answer <= 0) { revert OracleLTEZero(oracleMultiply); } _price = _price * uint256(_answer);
A simple comparison can be used for gas savings by reversing the logic
if (_answer > 0) { _price = _price * uint256(_answer); } else { revert OracleLTEZero(oracleMultiply); }
Replace the comparison operator and reverse the logic to save gas using the suggestions above
Many constant variables are public, but changing the visibility of these variables to private or internal can save gas.
Locations where this was found include https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L59 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L62 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L63 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L64 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L67 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L70 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L71 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L74 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L81 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L84 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L85 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L89 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L95 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L96 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L133 https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/FraxlendPairCore.sol#L136
Declare some public variables as private or internal to save gas
The contracts are all written entirely in solidity. Writing contracts with vyper instead of solidity can save gas.
Source https://twitter.com/eiber_david/status/1515737811881807876 doggo demonstrates https://twitter.com/fubuloubu/status/1528179581974417414?t=-hcq_26JFDaHdAQZ-wYxCA&s=19
Write some or all of the contracts in vyper to save gas
abi.encodePacked()
not abi.encode()
Changing abi.encode
to abi.encodePacked
can save gas. abi.encode
pads extra null bytes at the end of the call data which is normally unnecessary. In general, abi.encodePacked
is more gas-efficient.
There was at least one place where this change can be made: https://github.com/code-423n4/2022-08-frax/tree/main/src/contracts/VariableInterestRate.sol#L53
Change abi.encode
to abi.encodePacked
#0 - gititGoro
2022-10-09T12:18:15Z
The vyper deployment savings was interesting.