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: 38/120
Findings: 2
Award: $69.44
๐ Selected for report: 0
๐ Solo Findings: 0
๐ Selected for report: 0x1f8b
Also found by: 0x52, 0xA5DF, 0xDjango, 0xNazgul, 0xNineDec, 0xSmartContract, 0xmatt, 0xsolstars, Aymen0909, Bnke0x0, CertoraInc, Chom, CodingNameKiki, Deivitto, Dravee, ElKu, EthLedger, Funen, IllIllI, JC, Junnon, Lambda, LeoS, MiloTruck, Noah3o6, PaludoX0, ReyAdmirado, Rohan16, RoiEvenHaim, Rolezn, SaharAP, Sm4rty, SooYa, The_GUILD, TomJ, Waze, Yiko, _Adam, __141345__, a12jmx, ak1, asutorufos, auditor0517, ayeslick, ballx, beelzebufo, berndartmueller, bin2chen, brgltd, c3phas, cRat1st0s, cccz, cryptonue, cryptphi, d3e4, delfin454000, dipp, djxploit, durianSausage, dy, erictee, fatherOfBlocks, gogo, gzeon, hyh, ignacio, kyteg, ladboy233, medikko, mics, minhquanym, oyc_109, pfapostol, rbserver, reassor, ret2basic, robee, sach1r0, simon135, sryysryy, tabish, yac, yash90, zzzitron
47.0406 USDC - $47.04
return
statement when the function defines a named return variable, is redundantThere is 1 instance of this issue:
File: src/contracts/FraxlendPairDeployer.sol 191: function _deployFirst( 201: ) private returns (address _pairAddress) { 233: return _pairAddress;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairDeployer.sol
Emmiting events is recommended each time when a state variable's value is being changed or just some critical event for the contract has occurred. It also helps off-chain monitoring of the contract's state.
There are 2 instances of this issue:
File: src/contracts/FraxlendPairCore.sol 245: function initialize(
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
File: src/contracts/FraxlendPairDeployer.sol 170: function setCreationCode(bytes calldata _creationCode) external onlyOwner {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairDeployer.sol
public
functions not called by the contract should be declared external
insteadThere are 5 instances of this issue:
File: src/contracts/FraxlendPair.sol 74: function name() public view override(ERC20, IERC20Metadata) returns (string memory) { 78: function symbol() public view override(ERC20, IERC20Metadata) returns (string memory) { 84: function decimals() public pure override(ERC20, IERC20Metadata) returns (uint8) { 89: function totalSupply() public view override(ERC20, IERC20) returns (uint256) { 100: function totalAssets() public view virtual returns (uint256) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPair.sol
There are 7 instances of this issue:
File: src/contracts/FraxlendPair.sol 2: pragma solidity ^0.8.15;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPair.sol
File: src/contracts/FraxlendPairConstants.sol 2: pragma solidity ^0.8.15;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairConstants.sol
File: src/contracts/FraxlendPairCore.sol 2: pragma solidity ^0.8.15;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
File: src/contracts/FraxlendPairDeployer.sol 2: pragma solidity ^0.8.15;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairDeployer.sol
File: src/contracts/FraxlendWhitelist.sol 2: pragma solidity ^0.8.15;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendWhitelist.sol
File: src/contracts/LinearInterestRate.sol 2: pragma solidity ^0.8.15;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/LinearInterestRate.sol
File: src/contracts/VariableInterestRate.sol 2: pragma solidity ^0.8.15;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/VariableInterestRate.sol
indexed
fieldsEach event that contains more than 2 fields should have 3 fields marked as indexed
There are 4 instances of this issue:
File: src/contracts/FraxlendPair.sol event WithdrawFees(uint128 _shares, address _recipient, uint256 _amountToTransfer)
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPair.sol
File: src/contracts/FraxlendPairCore.sol event UpdateRate(uint256 _ratePerSec, uint256 _deltaTime, uint256 _utilizationRate, uint256 _newRatePerSec) event AddCollateral(address indexed _sender, address indexed _borrower, uint256 _collateralAmount) event RepayAsset(address indexed _sender, address indexed _borrower, uint256 _amountToRepay, uint256 _shares)
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
There are 6 instances of this issue:
File: src/contracts/FraxlendPair.sol 30: import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 31: import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; 36: import "./interfaces/IERC4626.sol"; 37: import "./interfaces/IFraxlendWhitelist.sol"; 38: import "./interfaces/IRateCalculator.sol"; 39: import "./interfaces/ISwapper.sol";
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPair.sol
๐ 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
22.4004 USDC - $22.40
++i
will cost less gas than i++
. The same change can be applied to i--
as well.This change would save up to 6 gas per instance/loop.
There are 9 instances of this issue:
File: src/contracts/FraxlendPair.sol 289: for (uint256 i = 0; i < _lenders.length; i++) { 308: for (uint256 i = 0; i < _borrowers.length; i++) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPair.sol
File: src/contracts/FraxlendPairDeployer.sol 130: i++; 158: i++;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairDeployer.sol
File: src/contracts/FraxlendWhitelist.sol 51: for (uint256 i = 0; i < _addresses.length; i++) { 66: for (uint256 i = 0; i < _addresses.length; i++) { 81: for (uint256 i = 0; i < _addresses.length; i++) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendWhitelist.sol
File: src/contracts/libraries/SafeERC20.sol 24: i++; 27: for (i = 0; i < 32 && data[i] != 0; i++) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/libraries/SafeERC20.sol
The instances below point to the second+ access of a state variable within a function. Caching of a state variable replace each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
There are 5 instances of this issue:
File: src/contracts/FraxlendPairCore.sol /// @audit Cache `oracleMultiply`. Used 3 times in `_updateExchangeRate` 523: if (oracleMultiply != address(0)) { 524: (, int256 _answer, , , ) = AggregatorV3Interface(oracleMultiply).latestRoundData(); 526: revert OracleLTEZero(oracleMultiply); /// @audit Cache `oracleDivide`. Used 3 times in `_updateExchangeRate` 531: if (oracleDivide != address(0)) { 532: (, int256 _answer, , , ) = AggregatorV3Interface(oracleDivide).latestRoundData(); 534: revert OracleLTEZero(oracleDivide);
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
File: src/contracts/LinearInterestRate.sol /// @audit Cache `UTIL_PREC`. Used 4 times in `getNewRate` 84: uint256 _slope = ((_vertexInterest - _minInterest) * UTIL_PREC) / _vertexUtilization; 85: _newRatePerSec = uint64(_minInterest + ((_utilization * _slope) / UTIL_PREC)); 87: uint256 _slope = (((_maxInterest - _vertexInterest) * UTIL_PREC) / (UTIL_PREC - _vertexUtilization)); 88: _newRatePerSec = uint64(_vertexInterest + (((_utilization - _vertexUtilization) * _slope) / UTIL_PREC));
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/LinearInterestRate.sol
File: src/contracts/VariableInterestRate.sol /// @audit Cache `INT_HALF_LIFE`. Used 4 times in `requireValidInitData` 70: uint256 _decayGrowth = INT_HALF_LIFE + (_deltaUtilization * _deltaUtilization * _deltaTime); 71: _newRatePerSec = uint64((_currentRatePerSec * INT_HALF_LIFE) / _decayGrowth); 77: uint256 _decayGrowth = INT_HALF_LIFE + (_deltaUtilization * _deltaUtilization * _deltaTime); 78: _newRatePerSec = uint64((_currentRatePerSec * _decayGrowth) / INT_HALF_LIFE); /// @audit Cache `INT_HALF_LIFE`. Used 4 times in `getNewRate` 70: uint256 _decayGrowth = INT_HALF_LIFE + (_deltaUtilization * _deltaUtilization * _deltaTime); 71: _newRatePerSec = uint64((_currentRatePerSec * INT_HALF_LIFE) / _decayGrowth); 77: uint256 _decayGrowth = INT_HALF_LIFE + (_deltaUtilization * _deltaUtilization * _deltaTime); 78: _newRatePerSec = uint64((_currentRatePerSec * _decayGrowth) / INT_HALF_LIFE);
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/VariableInterestRate.sol
!= 0
on uints
costs less gas than > 0
.This change saves 3 gas per instance/loop
There are 6 instances of this issue:
File: src/contracts/FraxlendPairCore.sol 477: if (_currentRateInfo.feeToProtocolRate > 0) { 754: if (_collateralAmount > 0) { 1002: if (_leftoverBorrowShares > 0) { 1094: if (_initialCollateralAmount > 0) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
File: src/contracts/LinearInterestRate.sol 66: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0, 67: "LinearInterestRate: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0"
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/LinearInterestRate.sol
constant
/non-immutable
variables to zero than to let the default of zero be appliedNot overwriting the default for stack variables saves 8 gas. Storage and memory variables have larger savings
There are 9 instances of this issue:
File: src/contracts/FraxlendPair.sol 289: for (uint256 i = 0; i < _lenders.length; i++) { 308: for (uint256 i = 0; i < _borrowers.length; i++) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPair.sol
File: src/contracts/FraxlendPairCore.sol 265: for (uint256 i = 0; i < _approvedBorrowers.length; ++i) { 270: for (uint256 i = 0; i < _approvedLenders.length; ++i) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
File: src/contracts/FraxlendPairDeployer.sol 402: for (uint256 i = 0; i < _lengthOfArray; ) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairDeployer.sol
File: src/contracts/FraxlendWhitelist.sol 51: for (uint256 i = 0; i < _addresses.length; i++) { 66: for (uint256 i = 0; i < _addresses.length; i++) { 81: for (uint256 i = 0; i < _addresses.length; i++) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendWhitelist.sol
File: src/contracts/libraries/SafeERC20.sol 22: uint8 i = 0;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/libraries/SafeERC20.sol
payable
Marking a function as payable
reduces gas cost since the compiler does not have to check whether a payment was provided or not. This change will save around 21 gas per function call.
There are 8 instances of this issue:
File: src/contracts/FraxlendPair.sol 204: function setTimeLock(address _newAddress) external onlyOwner { 234: function withdrawFees(uint128 _shares, address _recipient) external onlyOwner returns (uint256 _amountToTransfer) { 274: function setSwapper(address _swapper, bool _approval) external onlyOwner {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPair.sol
File: src/contracts/FraxlendPairDeployer.sol 170: function setCreationCode(bytes calldata _creationCode) external onlyOwner { 398: function globalPause(address[] memory _addresses) external returns (address[] memory _updatedAddresses) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairDeployer.sol
File: src/contracts/FraxlendWhitelist.sol 50: function setOracleContractWhitelist(address[] calldata _addresses, bool _bool) external onlyOwner { 65: function setRateContractWhitelist(address[] calldata _addresses, bool _bool) external onlyOwner { 80: function setFraxlendDeployerWhitelist(address[] calldata _addresses, bool _bool) external onlyOwner {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendWhitelist.sol
<array>.length
should not be looked up in every loop of a for
-loopThe overheads outlined below are PER LOOP, excluding the first loop \ - storage arrays incur a Gwarmaccess (100 gas) \ - memory arrays use MLOAD
(3 gas) \ - calldata arrays use CALLDATALOAD
(3 gas) \ \ Caching the length changes each of these to a DUP<N> (3 gas), and gets rid of the extra DUP<N> needed to store the stack offset
There are 7 instances of this issue:
File: src/contracts/FraxlendPair.sol 289: for (uint256 i = 0; i < _lenders.length; i++) { 308: for (uint256 i = 0; i < _borrowers.length; i++) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPair.sol
File: src/contracts/FraxlendPairCore.sol 265: for (uint256 i = 0; i < _approvedBorrowers.length; ++i) { 270: for (uint256 i = 0; i < _approvedLenders.length; ++i) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
File: src/contracts/FraxlendWhitelist.sol 51: for (uint256 i = 0; i < _addresses.length; i++) { 66: for (uint256 i = 0; i < _addresses.length; i++) { 81: for (uint256 i = 0; i < _addresses.length; i++) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendWhitelist.sol
++i
/i++
should be unchecked{++I}
/unchecked{I++}
in for
-loopsWhen an increment or any arithmetic operation is not possible to overflow it should be placed in unchecked{}
block. \This is because of the default compiler overflow and underflow safety checks since Solidity version 0.8.0. \In for-loops it saves around 30-40 gas per loop
There are 8 instances of this issue:
File: src/contracts/FraxlendPair.sol 289: for (uint256 i = 0; i < _lenders.length; i++) { 308: for (uint256 i = 0; i < _borrowers.length; i++) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPair.sol
File: src/contracts/FraxlendPairCore.sol 265: for (uint256 i = 0; i < _approvedBorrowers.length; ++i) { 270: for (uint256 i = 0; i < _approvedLenders.length; ++i) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
File: src/contracts/FraxlendWhitelist.sol 51: for (uint256 i = 0; i < _addresses.length; i++) { 66: for (uint256 i = 0; i < _addresses.length; i++) { 81: for (uint256 i = 0; i < _addresses.length; i++) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendWhitelist.sol
File: src/contracts/libraries/SafeERC20.sol 27: for (i = 0; i < 32 && data[i] != 0; i++) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/libraries/SafeERC20.sol
<x> += <y>
costs more gas than <x> = <x> + <y>
for state variablesThere are 6 instances of this issue:
File: src/contracts/FraxlendPairCore.sol 773: totalCollateral += _collateralAmount; 815: totalCollateral -= _collateralAmount; 772: userCollateralBalance[_borrower] += _collateralAmount; 813: userCollateralBalance[_borrower] -= _collateralAmount; 724: userBorrowShares[msg.sender] += _sharesAdded; 867: userBorrowShares[_borrower] -= _shares;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
uint
s/int
s smaller than 32 bytes (256 bits) incurs overhead'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.' \ https://docs.soliditylang.org/en/v0.8.15/internals/layout_in_storage.html \ Use a larger size then downcast where needed
There are 39 instances of this issue:
File: src/contracts/FraxlendPair.sol 165: uint64 _DEFAULT_INT, 166: uint16 _DEFAULT_PROTOCOL_FEE, 211: event ChangeFee(uint32 _newFee); 215: function changeFee(uint32 _newFee) external whenNotPaused { 228: event WithdrawFees(uint128 _shares, address _recipient, uint256 _amountToTransfer); 234: function withdrawFees(uint128 _shares, address _recipient) external onlyOwner returns (uint256 _amountToTransfer) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPair.sol
File: src/contracts/FraxlendPairConstants.sol 41: uint64 internal constant DEFAULT_INT = 158247046; 47: uint16 internal constant DEFAULT_PROTOCOL_FEE = 0;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairConstants.sol
File: src/contracts/FraxlendPairCore.sol 106: uint64 lastBlock; 107: uint64 feeToProtocolRate; 108: uint64 lastTimestamp; 109: uint64 ratePerSec; 116: uint32 lastTimestamp; 400: uint64 _newRate 415: uint64 _newRate 561: uint128 _amount, 562: uint128 _shares, 625: uint128 _amountToReturn, 626: uint128 _shares, 707: function _borrowAsset(uint128 _borrowAmount, address _receiver) internal returns (uint256 _sharesAdded) { 857: uint128 _amountToRepay, 858: uint128 _shares, 951: uint128 _sharesToLiquidate, 967: uint128 _borrowerShares = userBorrowShares[_borrower].toUint128(); 993: uint128 _amountLiquidatorToRepay = (_totalBorrow.toAmount(_sharesToLiquidate, true)).toUint128(); 997: uint128 _sharesToAdjust; 998: uint128 _amountToAdjust; 1001: uint128 _leftoverBorrowShares = _borrowerShares - _sharesToLiquidate;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
File: src/contracts/libraries/SafeERC20.sol 22: uint8 i = 0;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/libraries/SafeERC20.sol
File: src/contracts/libraries/VaultAccount.sol 5: uint128 amount; 6: uint128 shares;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/libraries/VaultAccount.sol
File: src/contracts/LinearInterestRate.sol 76: function getNewRate(bytes calldata _data, bytes calldata _initData) external pure returns (uint64 _newRatePerSec) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/LinearInterestRate.sol
File: src/contracts/VariableInterestRate.sol 35: uint32 private constant MIN_UTIL = 75000; 36: uint32 private constant MAX_UTIL = 85000; 37: uint32 private constant UTIL_PREC = 1e5; 40: uint64 private constant MIN_INT = 79123523; 41: uint64 private constant MAX_INT = 146248508681; 63: function getNewRate(bytes calldata _data, bytes calldata _initData) external pure returns (uint64 _newRatePerSec) { 64: (uint64 _currentRatePerSec, uint256 _deltaTime, uint256 _utilization, ) = abi.decode(
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/VariableInterestRate.sol
require()
statements that use &&
saves gasInstead of using &&
on single require
check using two require
checks can save gas
There are 3 instances of this issue:
File: src/contracts/LinearInterestRate.sol 57: require( 58: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT, 59: "LinearInterestRate: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT" 60: ); 61: require( 62: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT, 63: "LinearInterestRate: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT" 64: ); 65: require( 66: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0, 67: "LinearInterestRate: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0" 68: );
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/LinearInterestRate.sol
calldata
instead of memory
for function parametersIf 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.
There are 23 instances of this issue:
File: src/contracts/FraxlendPairCore.sol /// @audit Store `_totalAsset` in calldata. 295: function _totalAssetAvailable(VaultAccount memory _totalAsset, VaultAccount memory _totalBorrow) /// @audit Store `_totalBorrow` in calldata. 295: function _totalAssetAvailable(VaultAccount memory _totalAsset, VaultAccount memory _totalBorrow) 560: VaultAccount memory _totalAsset, 624: VaultAccount memory _totalAsset, 856: VaultAccount memory _totalBorrow, 1067: address[] memory _path
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
File: src/contracts/FraxlendPairDeployer.sol 193: bytes memory _configData, 194: bytes memory _immutables, 243: string memory _name, 245: bytes memory _configData, 246: address[] memory _approvedBorrowers, 247: address[] memory _approvedLenders 273: string memory _name, 275: bytes memory _configData, 310: function deploy(bytes memory _configData) external returns (address _pairAddress) { 356: string memory _name, 357: bytes memory _configData, 362: address[] memory _approvedBorrowers, 363: address[] memory _approvedLenders 398: function globalPause(address[] memory _addresses) external returns (address[] memory _updatedAddresses) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairDeployer.sol
File: src/contracts/libraries/SafeERC20.sol 18: function returnDataToString(bytes memory data) internal pure returns (string memory) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/libraries/SafeERC20.sol
File: src/contracts/libraries/VaultAccount.sol 17: VaultAccount memory total, 34: VaultAccount memory total,
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/libraries/VaultAccount.sol
x <= y
with x < y + 1
, and x >= y
with x > y - 1
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
There are 12 instances of this issue:
File: src/contracts/FraxlendPairCore.sol 196: if (_maxLTV >= LTV_PRECISION && !_isBorrowerWhitelistActive) revert BorrowerWhitelistRequired(); 315: return _ltv <= maxLTV; 472: _interestEarned + _totalBorrow.amount <= type(uint128).max && 473: _interestEarned + _totalAsset.amount <= type(uint128).max 525: if (_answer <= 0) { 533: if (_answer <= 0) { 988: _collateralForLiquidator = _leftoverCollateral <= 0 1000: if (_leftoverCollateral <= 0) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
File: src/contracts/FraxlendPairDeployer.sol 365: require(_maxLTV <= GLOBAL_MAX_LTV, "FraxlendPairDeployer: _maxLTV is too large");
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairDeployer.sol
File: src/contracts/libraries/SafeERC20.sol 19: if (data.length >= 64) {
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/libraries/SafeERC20.sol
File: src/contracts/LinearInterestRate.sol 58: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT, 62: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT,
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/LinearInterestRate.sol
immutable
& constant
for state variables that do not change their valueThere are 5 instances of this issue:
File: src/contracts/FraxlendPairCore.sol 86: address public TIME_LOCK_ADDRESS; 92: string internal nameOfContract;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol
File: src/contracts/FraxlendPairDeployer.sol 57: address public CIRCUIT_BREAKER_ADDRESS; 58: address public COMPTROLLER_ADDRESS; 59: address public TIME_LOCK_ADDRESS;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairDeployer.sol
require()/revert()
strings longer than 32 bytes cost extra gasEach extra memory word of bytes past the original 32 incurs an MSTORE which costs 3 gas
There are 8 instances of this issue:
File: src/contracts/FraxlendPairDeployer.sol 205: require(deployedPairsBySalt[salt] == address(0), "FraxlendPairDeployer: Pair already deployed"); 228: require(_pairAddress != address(0), "FraxlendPairDeployer: create2 failed"); 253: require(deployedPairsByName[_name] == address(0), "FraxlendPairDeployer: Pair name must be unique"); 365: require(_maxLTV <= GLOBAL_MAX_LTV, "FraxlendPairDeployer: _maxLTV is too large"); 366: require( 367: IFraxlendWhitelist(FRAXLEND_WHITELIST_ADDRESS).fraxlendDeployerWhitelist(msg.sender), 368: "FraxlendPairDeployer: Only whitelisted addresses" 369: );
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairDeployer.sol
File: src/contracts/LinearInterestRate.sol 57: require( 58: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT, 59: "LinearInterestRate: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT" 60: ); 61: require( 62: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT, 63: "LinearInterestRate: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT" 64: ); 65: require( 66: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0, 67: "LinearInterestRate: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0" 68: );
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/LinearInterestRate.sol
revert()
/require()
strings to save gasCustom errors are available from solidity version 0.8.4. Custom errors save ~50 gas each time they're hitby avoiding having to allocate and store the revert string. Not defining the strings also save deployment gas
There are 9 instances of this issue:
File: src/contracts/FraxlendPairDeployer.sol 205: require(deployedPairsBySalt[salt] == address(0), "FraxlendPairDeployer: Pair already deployed"); 228: require(_pairAddress != address(0), "FraxlendPairDeployer: create2 failed"); 253: require(deployedPairsByName[_name] == address(0), "FraxlendPairDeployer: Pair name must be unique"); 365: require(_maxLTV <= GLOBAL_MAX_LTV, "FraxlendPairDeployer: _maxLTV is too large"); 366: require( 367: IFraxlendWhitelist(FRAXLEND_WHITELIST_ADDRESS).fraxlendDeployerWhitelist(msg.sender), 368: "FraxlendPairDeployer: Only whitelisted addresses" 369: ); 399: require(msg.sender == CIRCUIT_BREAKER_ADDRESS, "Circuit Breaker only");
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairDeployer.sol
File: src/contracts/LinearInterestRate.sol 57: require( 58: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT, 59: "LinearInterestRate: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT" 60: ); 61: require( 62: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT, 63: "LinearInterestRate: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT" 64: ); 65: require( 66: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0, 67: "LinearInterestRate: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0" 68: );
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/LinearInterestRate.sol
Use uint256(1)
and uint256(2)
for true
/false
to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing from 'false' to 'true', after having been 'true' in the past
There are 2 instances of this issue:
File: src/contracts/FraxlendPairCore.sol 133: bool public immutable borrowerWhitelistActive; 136: bool public immutable lenderWhitelistActive;
https://github.com/code-423n4/2022-08-frax/blob/main/src/contracts/FraxlendPairCore.sol