Platform: Code4rena
Start Date: 14/10/2022
Pot Size: $100,000 USDC
Total HM: 12
Participants: 75
Period: 9 days
Judge: GalloDaSballo
Total Solo HM: 1
Id: 171
League: ETH
Rank: 9/75
Findings: 2
Award: $2,426.18
š Selected for report: 0
š Solo Findings: 0
2351.9735 USDC - $2,351.97
Issue | Instances | |
---|---|---|
[Lā01] | require() should be used instead of assert() | 1 |
[Lā02] | Missing checks for address(0x0) when assigning values to address state variables | 5 |
Total: 6 instances over 2 issues
Issue | Instances | |
---|---|---|
[Nā01] | Upgradeable contract is missing a __gap[50] storage variable to allow for new storage variables in later versions | 1 |
[Nā02] | Missing initializer modifier on constructor | 1 |
[Nā03] | Missing initializer modifier | 1 |
[Nā04] | Unused file | 1 |
[Nā05] | public functions not called by the contract should be declared external instead | 2 |
[Nā06] | Use bit shifts in an imutable variable rather than long bit masks of a single bit, for readability | 1 |
[Nā07] | Use a more recent version of solidity | 14 |
[Nā08] | Use a more recent version of solidity | 1 |
[Nā09] | Constant redefined elsewhere | 1 |
[Nā10] | Lines are too long | 2 |
[Nā11] | File is missing NatSpec | 1 |
[Nā12] | NatSpec is incomplete | 3 |
[Nā13] | Event is missing indexed fields | 19 |
[Nā14] | Not using the named return variables anywhere in the function is confusing | 12 |
Total: 60 instances over 14 issues
require()
should be used instead of assert()
Prior to solidity version 0.8.0, hitting an assert consumes the remainder of the transaction's available gas rather than returning it, as require()
/revert()
do. assert()
should be avoided even past solidity version 0.8.0 as its documentation states that "The assert function creates an error of type Panic(uint256). ... Properly functioning code should never create a Panic, not even on invalid external input. If this happens, then there is a bug in your contract which you should fix".
There is 1 instance of this issue:
File: src/LBFactory.sol 141: assert(_binStep == _preset.decode(type(uint16).max, _shift));
address(0x0)
when assigning values to address
state variablesThere are 5 instances of this issue:
File: src/LBQuoter.sol 45: routerV2 = _routerV2; 46: factoryV1 = _factoryV1; 47: factoryV2 = _factoryV2;
File: src/libraries/PendingOwnable.sol 93: _owner = _newOwner; 102: _pendingOwner = pendingOwner_;
__gap[50]
storage variable to allow for new storage variables in later versionsSee this link for a description of this storage variable. While some contracts may not currently be sub-classed, adding the variable now protects against forgetting to add it in the future.
There is 1 instance of this issue:
File: src/LBPair.sol 27: contract LBPair is LBToken, ReentrancyGuardUpgradeable, ILBPair {
initializer
modifier on constructorOpenZeppelin recommends that the initializer
modifier be applied to constructors in order to avoid potential griefs, social engineering, or exploits. Ensure that the modifier is applied to the implementation contract. If the default constructor is currently being used, it should be changed to be an explicit one with the modifier applied.
There is 1 instance of this issue:
File: src/LBPair.sol 90: constructor(ILBFactory _factory) LBToken() {
initializer
modifierThe contract extends Initializable
/ReentrancyGuardUpgradeable
but does not use the initializer
modifier anywhere
There is 1 instance of this issue:
File: src/LBPair.sol 27: contract LBPair is LBToken, ReentrancyGuardUpgradeable, ILBPair {
The file is never imported by any other file
There is 1 instance of this issue:
File: src/interfaces/IJoeRouter02.sol 0: // SPDX-License-Identifier: GPL-3.0
public
functions not called by the contract should be declared external
insteadContracts are allowed to override their parents' functions and change the visibility from external
to public
.
There are 2 instances of this issue:
File: src/LBQuoter.sol 54 function findBestPathFromAmountIn(address[] memory _route, uint256 _amountIn) 55 public 56 view 57: returns (Quote memory quote) 134 function findBestPathFromAmountOut(address[] memory _route, uint256 _amountOut) 135 public 136 view 137: returns (Quote memory quote)
There is 1 instance of this issue:
File: src/libraries/Math128x128.sol 108: if (absY < 0x100000) {
Use a solidity version of at least 0.8.13 to get the ability to use using for
with a list of free functions
There are 14 instances of this issue:
File: src/LBPair.sol 3: pragma solidity ^0.8.0;
File: src/LBQuoter.sol 3: pragma solidity ^0.8.0;
File: src/LBRouter.sol 3: pragma solidity ^0.8.0;
File: src/LBToken.sol 3: pragma solidity ^0.8.0;
File: src/libraries/BinHelper.sol 3: pragma solidity ^0.8.0;
File: src/libraries/FeeDistributionHelper.sol 3: pragma solidity ^0.8.0;
File: src/libraries/FeeHelper.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Math128x128.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Math512Bits.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Oracle.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Samples.sol 3: pragma solidity ^0.8.0;
File: src/libraries/SwapHelper.sol 3: pragma solidity ^0.8.0;
File: src/libraries/TokenHelper.sol 3: pragma solidity ^0.8.0;
File: src/libraries/TreeMath.sol 3: pragma solidity ^0.8.0;
Use a solidity version of at least 0.8.4 to get bytes.concat()
instead of abi.encodePacked(<bytes>,<bytes>)
Use a solidity version of at least 0.8.12 to get string.concat()
instead of abi.encodePacked(<str>,<str>)
There is 1 instance of this issue:
File: src/LBFactory.sol 3: pragma solidity ^0.8.0;
Consider defining in only one contract so that values cannot become out of sync when only one location is updated. A cheap way to store constants in a single location is to create an internal constant
in a library
. If the variable is a local cache of another contract's value, consider making the cache variable internal or private, which will require external users to query the contract with the source of truth, so that callers don't get out of sync.
There is 1 instance of this issue:
File: src/LBRouter.sol /// @audit seen in src/LBPair.sol 28: ILBFactory public immutable override factory;
Usually lines in source code are limited to 80 characters. Today's screens are much larger so it's reasonable to stretch this in some cases. Since the files will most likely reside in GitHub, and GitHub starts using a scroll bar in all cases when the length is over 164 characters, the lines below should be split when they reach that length
There are 2 instances of this issue:
File: src/libraries/Oracle.sol 69: uint256 _weightPrev = _next.timestamp() - _lookUpTimestamp; // _next.timestamp() - _sample.timestamp() - (_lookUpTimestamp - _sample.timestamp()) 70: uint256 _weightNext = _lookUpTimestamp - _sample.timestamp(); // _next.timestamp() - _sample.timestamp() - (_next.timestamp() - _lookUpTimestamp)
There is 1 instance of this issue:
File: src/LBErrors.sol
There are 3 instances of this issue:
File: src/LBFactory.sol /// @audit Missing: '@return' 531 /// @param _protocolShare The share of the fees received by the protocol 532 /// @param _maxVolatilityAccumulated The max value of volatility accumulated 533 function _getPackedFeeParameters( 534 uint16 _binStep, 535 uint16 _baseFactor, 536 uint16 _filterPeriod, 537 uint16 _decayPeriod, 538 uint16 _reductionFactor, 539 uint24 _variableFeeControl, 540 uint16 _protocolShare, 541 uint24 _maxVolatilityAccumulated 542: ) private pure returns (bytes32) {
File: src/LBRouter.sol /// @audit Missing: '@return' 739 /// @param amountX The amount of token X sent by the pair 740 /// @param amountY The amount of token Y sent by the pair 741 function _removeLiquidity( 742 ILBPair _LBPair, 743 uint256 _amountXMin, 744 uint256 _amountYMin, 745 uint256[] memory _ids, 746 uint256[] memory _amounts, 747 address _to 748: ) private returns (uint256 amountX, uint256 amountY) {
File: src/libraries/FeeDistributionHelper.sol /// @audit Missing: '@return' 47 /// @param _fees The fees received by the pair 48 /// @param _totalSupply the total supply of a specific bin 49 function getTokenPerShare(FeeHelper.FeesDistribution memory _fees, uint256 _totalSupply) 50 internal 51 pure 52: returns (uint256)
indexed
fieldsIndex event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (three fields). Each event
should use three indexed
fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three fields, all of the fields should be indexed.
There are 19 instances of this issue:
File: src/interfaces/IJoeFactory.sol 8: event PairCreated(address indexed token0, address indexed token1, address pair, uint256);
File: src/interfaces/IJoePair.sol 8: event Approval(address indexed owner, address indexed spender, uint256 value); 9: event Transfer(address indexed from, address indexed to, uint256 value); 49: event Mint(address indexed sender, uint256 amount0, uint256 amount1); 50: event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); 51 event Swap( 52 address indexed sender, 53 uint256 amount0In, 54 uint256 amount1In, 55 uint256 amount0Out, 56 uint256 amount1Out, 57 address indexed to 58: ); 59: event Sync(uint112 reserve0, uint112 reserve1);
File: src/interfaces/ILBFactory.sol 34: event FeeRecipientSet(address oldRecipient, address newRecipient); 36: event FlashLoanFeeSet(uint256 oldFlashLoanFee, uint256 newFlashLoanFee); 38 event FeeParametersSet( 39 address indexed sender, 40 ILBPair indexed LBPair, 41 uint256 binStep, 42 uint256 baseFactor, 43 uint256 filterPeriod, 44 uint256 decayPeriod, 45 uint256 reductionFactor, 46 uint256 variableFeeControl, 47 uint256 protocolShare, 48 uint256 maxVolatilityAccumulated 49: ); 51: event FactoryLockedStatusUpdated(bool unlocked); 53: event LBPairImplementationSet(address oldLBPairImplementation, address LBPairImplementation); 55: event LBPairIgnoredStateChanged(ILBPair indexed LBPair, bool ignored); 57 event PresetSet( 58 uint256 indexed binStep, 59 uint256 baseFactor, 60 uint256 filterPeriod, 61 uint256 decayPeriod, 62 uint256 reductionFactor, 63 uint256 variableFeeControl, 64 uint256 protocolShare, 65 uint256 maxVolatilityAccumulated, 66 uint256 sampleLifetime 67: );
File: src/interfaces/ILBPair.sol 111 event FlashLoan( 112 address indexed sender, 113 address indexed recipient, 114 uint256 amountX, 115 uint256 amountY, 116 uint256 feesX, 117 uint256 feesY 118: ); 148: event FeesCollected(address indexed sender, address indexed recipient, uint256 amountX, uint256 amountY); 150: event ProtocolFeesCollected(address indexed sender, address indexed recipient, uint256 amountX, uint256 amountY); 152: event OracleSizeIncreased(uint256 previousSize, uint256 newSize);
File: src/interfaces/ILBToken.sol 19: event ApprovalForAll(address indexed account, address indexed sender, bool approved);
Consider changing the variable to be an unnamed one
There are 12 instances of this issue:
File: src/LBPair.sol /// @audit reserveX /// @audit reserveY /// @audit activeId 132 function getReservesAndId() 133 external 134 view 135 override 136 returns ( 137 uint256 reserveX, 138 uint256 reserveY, 139: uint256 activeId /// @audit feesXTotal /// @audit feesYTotal /// @audit feesXProtocol /// @audit feesYProtocol 151 function getGlobalFees() 152 external 153 view 154 override 155 returns ( 156 uint256 feesXTotal, 157 uint256 feesYTotal, 158 uint256 feesXProtocol, 159: uint256 feesYProtocol /// @audit reserveX /// @audit reserveY 251: function getBin(uint24 _id) external view override returns (uint256 reserveX, uint256 reserveY) {
File: src/libraries/Math512Bits.sol /// @audit result 30 function mulDivRoundDown( 31 uint256 x, 32 uint256 y, 33 uint256 denominator 34: ) internal pure returns (uint256 result) { /// @audit result 119 function shiftDivRoundDown( 120 uint256 x, 121 uint256 offset, 122 uint256 denominator 123: ) internal pure returns (uint256 result) {
File: src/libraries/Samples.sol /// @audit packedSample 69 function pack( 70 uint256 _cumulativeBinCrossed, 71 uint256 _cumulativeVolatilityAccumulated, 72 uint256 _cumulativeId, 73 uint256 _timestamp, 74 uint256 _initialized 75: ) internal pure returns (bytes32 packedSample) {
These findings are excluded from awards calculations because there are publicly-available automated tools that find them. The valid ones appear here for completeness
There are 6 instances of this issue:
File: src/LBFactory.sol /// @audit (valid but excluded finding) 3: pragma solidity ^0.8.0;
File: src/LBPair.sol /// @audit (valid but excluded finding) 3: pragma solidity ^0.8.0;
File: src/LBQuoter.sol /// @audit (valid but excluded finding) 3: pragma solidity ^0.8.0;
File: src/LBRouter.sol /// @audit (valid but excluded finding) 3: pragma solidity ^0.8.0;
File: src/LBToken.sol /// @audit (valid but excluded finding) 3: pragma solidity ^0.8.0;
File: src/libraries/PendingOwnable.sol /// @audit (valid but excluded finding) 3: pragma solidity ^0.8.0;
#0 - GalloDaSballo
2022-11-09T19:29:10Z
[Lā01] | require()Ā should be used instead ofĀ assert() | 1 R
[Lā02] | Missing checks forĀ address(0x0)Ā when assigning values toĀ addressĀ state variables | 5 L
[Nā01] | Upgradeable contract is missing aĀ __gap[50]Ā storage variable to allow for new storage variables in later versions | 1 L
[Nā02] | MissingĀ initializerĀ modifier on constructor | 1 R
[Nā03] | MissingĀ initializerĀ modifier | 1 R
[Nā04] | Unused file | 1 NC
[Nā05] | publicĀ functions not called by the contract should be declaredĀ externalĀ instead | 2 R
[Nā06] | Use bit shifts in an imutable variable rather than long bit masks of a single bit, for readability | 1 R
[Nā07] | Use a more recent version of solidity | 14 R
[Nā08] | Use a more recent version of solidity | 1 See above
[Nā09] | Constant redefined elsewhere | 1 NC
[Nā10] | Lines are too long | 2 NC
[Nā11] | File is missing NatSpec | 1 NC
[Nā12] | NatSpec is incomplete | 3 See above
[Nā13] | Event is missingĀ indexedĀ fields | 19 Disagree
[Nā14] | Not using the named return variables anywhere in the function is confusing R
#1 - GalloDaSballo
2022-11-09T19:29:32Z
2L 7R 4NC
#2 - c4-judge
2022-11-16T21:08:44Z
GalloDaSballo marked the issue as selected for report
#3 - Shungy
2022-11-16T22:59:38Z
I want to point out some findings I believe to be invalid in this report:
N-01: LBPair is not an upgradeable contract. Finding incorrectly assumes because the function name is ReentrancyGuardUpgradeable. N-02: LBPair is not an upgradeable contract. Finding incorrectly assumes because the function name is ReentrancyGuardUpgradeable. N-03: ReentrancyGuardUpgradeable is initialized: https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/LBPair.sol#L114 . This is a custom contract, not OpenZeppelin contract.
#4 - c4-judge
2022-11-17T15:32:10Z
GalloDaSballo marked the issue as grade-a
#5 - GalloDaSballo
2022-11-17T15:40:57Z
Will re-view during QA and re-rate. Note that this report scored so high that I used the second best to rate the rest, meaning that downgrading this should have no impact on other QAs
#6 - GalloDaSballo
2022-11-21T00:09:21Z
Agree with the comment above, gap is invalid.
I think intializer can still technically be left in and is acceptable as refactoring, you can see that __ReentrancyGuard_init_unchained
, as well as the 0 check are effectively acting as the initializer
function __ReentrancyGuard_init_unchained() internal { if (_status != 0) revert ReentrancyGuardUpgradeable__AlreadyInitialized(); _status = _NOT_ENTERED; }
Will remove 1 Low from the score
1L 7R 4NC
#7 - c4-judge
2022-11-21T14:51:40Z
GalloDaSballo marked the issue as not selected for report
#8 - GalloDaSballo
2022-11-21T14:51:48Z
Removed best after post judging QA
š Selected for report: shung
Also found by: 0x4non, IllIllI, LeoS, Mathieu, MiloTruck, ReyAdmirado, Saintcode_, Shishigami, TomJ, __141345__, c3phas, m_Rassska, pfapostol
74.2126 USDC - $74.21
Issue | Instances | Total Gas Saved | |
---|---|---|---|
[Gā01] | Multiple address /ID mappings can be combined into a single mapping of an address /ID to a struct , where appropriate | 1 | - |
[Gā02] | State variables can be packed into fewer storage slots | 1 | - |
[Gā03] | Using storage instead of memory for structs/arrays saves gas | 11 | 46200 |
[Gā04] | Avoid contract existence checks by using low level calls | 28 | 2800 |
[Gā05] | Multiple accesses of a mapping/array should use a local variable cache | 1 | 42 |
[Gā06] | Add unchecked {} for subtractions where the operands cannot underflow because of a previous require() or if -statement | 5 | 425 |
[Gā07] | ++i /i++ should be unchecked{++i} /unchecked{i++} when it is not possible for them to overflow, as is the case when used in for - and while -loops | 5 | 300 |
[Gā08] | Optimize names to save gas | 11 | 242 |
[Gā09] | Use a more recent version of solidity | 37 | - |
[Gā10] | >= costs less gas than > | 1 | 3 |
[Gā11] | Functions guaranteed to revert when called by normal users can be marked payable | 20 | 420 |
Total: 121 instances over 11 issues with 50432 gas saved
Gas totals use lower bounds of ranges and count two iterations of each for
-loop. All values above are runtime, not deployment, values; deployment values are listed in the individual issue descriptions. The table above and its gas values do not include any excluded findings.
address
/ID mappings can be combined into a single mapping
of an address
/ID to a struct
, where appropriateSaves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot. Finally, if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations.
There is 1 instance of this issue:
File: src/LBPair.sol 68 mapping(address => bytes32) private _unclaimedFees; 69 /// @dev Mapping from account to id to user's accruedDebt. 70: mapping(address => mapping(uint256 => Debts)) private _accruedDebts;
If variables occupying the same slot are both written the same function or by the constructor, avoids a separate Gsset (20000 gas). Reads of the variables can also be cheaper
There is 1 instance of this issue:
File: src/LBFactory.sol /// @audit Variable ordering with 8 slots instead of the current 9: /// move bool(1):creationUnlocked to be right after address(20):feeRecipient 32: address public override LBPairImplementation;
storage
instead of memory
for structs/arrays saves gasWhen fetching data from a storage location, assigning the data to a memory
variable causes all fields of the struct/array to be read from storage, which incurs a Gcoldsload (2100 gas) for each field of the struct/array. If the fields are read from the new memory variable, they incur an additional MLOAD
rather than a cheap stack read. Instead of declearing the variable with the memory
keyword, declaring the variable with the storage
keyword and caching any fields that need to be re-read in stack variables, will be much cheaper, only incuring the Gcoldsload for the fields actually read. The only time it makes sense to read the whole struct/array into a memory
variable, is if the full struct/array is being returned by the function, is being passed to a function that requires memory
, or if the array/struct is being read from another memory
array/struct
There are 11 instances of this issue:
File: src/LBFactory.sol 197: LBPairInformation memory _LBPairInformation = _LBPairsInfo[_tokenA][_tokenB][i];
File: src/LBPair.sol 220: FeeHelper.FeeParameters memory _fp = _feeParameters; 283: Bin memory _bin = _bins[_id]; 310: PairInformation memory _pair = _pairInformation; 318: FeeHelper.FeeParameters memory _fp = _feeParameters; 327: Bin memory _bin = _bins[_pair.activeId]; 426: FeeHelper.FeeParameters memory _fp = _feeParameters; 484: PairInformation memory _pair = _pairInformation; 486: FeeHelper.FeeParameters memory _fp = _feeParameters; 498: Bin memory _bin = _bins[_mintInfo.id]; 706: Bin memory _bin = _bins[_id];
Prior to 0.8.10 the compiler inserted extra code, including EXTCODESIZE
(100 gas), to check for contract existence for external function calls. In more recent solidity versions, the compiler will not insert these checks if the external call has a return value. Similar behavior can be achieved in earlier versions by using low-level calls, since low level calls never check for contract existence
There are 28 instances of this issue:
File: src/LBFactory.sol /// @audit factory() 216: if (ILBPair(_LBPairImplementation).factory() != this)
File: src/LBQuoter.sol /// @audit getPair() 77: quote.pairs[i] = IJoeFactory(factoryV1).getPair(_route[i], _route[i + 1]); /// @audit getAllLBPairs() 94: ILBFactory.LBPairInformation[] memory LBPairsAvailable = ILBFactory(factoryV2).getAllLBPairs( /// @audit getSwapOut() 105: ILBRouter(routerV2).getSwapOut(LBPairsAvailable[j].LBPair, quote.amounts[i], swapForY) /// @audit getPair() 156: quote.pairs[i - 1] = IJoeFactory(factoryV1).getPair(_route[i - 1], _route[i]); /// @audit getAllLBPairs() 171: ILBFactory.LBPairInformation[] memory LBPairsAvailable = ILBFactory(factoryV2).getAllLBPairs( /// @audit getSwapIn() 181: ILBRouter(routerV2).getSwapIn(LBPairsAvailable[j].LBPair, quote.amounts[i], swapForY) /// @audit getReserves() 223: (uint256 reserve0, uint256 reserve1, ) = IJoePair(_pair).getReserves(); /// @audit mulShiftRoundDown() 240: quote = BinHelper.getPriceFromId(_activeId, _binStep).mulShiftRoundDown(_amount, Constants.SCALE_OFFSET);
File: src/LBRouter.sol /// @audit getReserves() 718: (uint256 _reserveIn, uint256 _reserveOut, ) = IJoePair(_pair).getReserves(); /// @audit tokenX() 727: (amountsIn[i - 1], ) = getSwapIn(ILBPair(_pair), amountsIn[i], ILBPair(_pair).tokenX() == _token); /// @audit getReserves() 788: (uint256 _reserve0, uint256 _reserve1, ) = IJoePair(_pair).getReserves(); /// @audit swap() 792: IJoePair(_pair).swap(0, amountOut, _recipient, ""); /// @audit swap() 795: IJoePair(_pair).swap(amountOut, 0, _recipient, ""); /// @audit tokenY() 798: bool _swapForY = _tokenNext == ILBPair(_pair).tokenY(); /// @audit swap() 800: (uint256 _amountXOut, uint256 _amountYOut) = ILBPair(_pair).swap(_swapForY, _recipient); /// @audit swap() 843: IJoePair(_pair).swap(0, amountOut, _recipient, ""); /// @audit swap() 845: IJoePair(_pair).swap(amountOut, 0, _recipient, ""); /// @audit tokenY() 848: bool _swapForY = _tokenNext == ILBPair(_pair).tokenY(); /// @audit swap() 850: (uint256 _amountXOut, uint256 _amountYOut) = ILBPair(_pair).swap(_swapForY, _recipient); /// @audit getReserves() 888: (uint256 _reserve0, uint256 _reserve1, ) = IJoePair(_pair).getReserves(); /// @audit swap() 893: IJoePair(_pair).swap(0, _amountOut, _recipient, ""); /// @audit swap() 898: IJoePair(_pair).swap(_amountOut, 0, _recipient, ""); /// @audit swap() /// @audit tokenY() 901: ILBPair(_pair).swap(_tokenNext == ILBPair(_pair).tokenY(), _recipient);
File: src/libraries/BinHelper.sol /// @audit power() 44: return _getBPValue(_binStep).power(_realId);
File: src/libraries/TokenHelper.sol /// @audit call() 28: (bool success, bytes memory result) = address(token).call( /// @audit call() 46: (bool success, bytes memory result) = address(token).call(
diff --git a/src/LBFactory.sol b/src/LBFactory.sol index 32ee39c..df9d1c7 100644 --- a/src/LBFactory.sol +++ b/src/LBFactory.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "openzeppelin/proxy/Clones.sol"; import "openzeppelin/utils/structs/EnumerableSet.sol"; diff --git a/src/LBQuoter.sol b/src/LBQuoter.sol index 53fdf0c..e9f9815 100644 --- a/src/LBQuoter.sol +++ b/src/LBQuoter.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "./LBErrors.sol"; import "./libraries/BinHelper.sol"; diff --git a/src/LBRouter.sol b/src/LBRouter.sol index 567c49a..532cc13 100644 --- a/src/LBRouter.sol +++ b/src/LBRouter.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "openzeppelin/token/ERC20/IERC20.sol"; diff --git a/src/libraries/BinHelper.sol b/src/libraries/BinHelper.sol index db0fef8..c6cf99c 100644 --- a/src/libraries/BinHelper.sol +++ b/src/libraries/BinHelper.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "../LBErrors.sol"; import "./Math128x128.sol"; diff --git a/src/libraries/TokenHelper.sol b/src/libraries/TokenHelper.sol index 17d8e23..3391a98 100644 --- a/src/libraries/TokenHelper.sol +++ b/src/libraries/TokenHelper.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "openzeppelin/token/ERC20/IERC20.sol"; diff --git a/test/LBPair.t.sol b/test/LBPair.t.sol index d84bb5b..550d55a 100644 --- a/test/LBPair.t.sol +++ b/test/LBPair.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.7; +pragma solidity 0.8.10; import "./TestHelper.sol"; diff --git a/test/mocks/ERC20.sol b/test/mocks/ERC20.sol index 0543ab8..4cabd37 100644 --- a/test/mocks/ERC20.sol +++ b/test/mocks/ERC20.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "openzeppelin/token/ERC20/ERC20.sol"; diff --git a/test/mocks/ERC20MockDecimals.sol b/test/mocks/ERC20MockDecimals.sol index b952b88..95d1797 100644 --- a/test/mocks/ERC20MockDecimals.sol +++ b/test/mocks/ERC20MockDecimals.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "openzeppelin/token/ERC20/ERC20.sol"; diff --git a/test/mocks/ERC20MockDecimalsOwnable.sol b/test/mocks/ERC20MockDecimalsOwnable.sol index 081940f..7ca3b95 100644 --- a/test/mocks/ERC20MockDecimalsOwnable.sol +++ b/test/mocks/ERC20MockDecimalsOwnable.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "openzeppelin/token/ERC20/ERC20.sol"; import "openzeppelin/access/Ownable.sol"; diff --git a/test/mocks/ERC20WithTransferTax.sol b/test/mocks/ERC20WithTransferTax.sol index 7a7a1f4..269616d 100644 --- a/test/mocks/ERC20WithTransferTax.sol +++ b/test/mocks/ERC20WithTransferTax.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "openzeppelin/token/ERC20/ERC20.sol"; diff --git a/test/mocks/Faucet.sol b/test/mocks/Faucet.sol index 108bde7..e00e8fd 100644 --- a/test/mocks/Faucet.sol +++ b/test/mocks/Faucet.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "../../src/libraries/PendingOwnable.sol"; import "../../src/libraries/TokenHelper.sol"; diff --git a/test/mocks/FlashloanBorrower.sol b/test/mocks/FlashloanBorrower.sol index 16817a8..2bfe335 100644 --- a/test/mocks/FlashloanBorrower.sol +++ b/test/mocks/FlashloanBorrower.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "openzeppelin/interfaces/IERC20.sol"; diff --git a/test/mocks/WAVAX.sol b/test/mocks/WAVAX.sol index fd86df0..0ff59a0 100644 --- a/test/mocks/WAVAX.sol +++ b/test/mocks/WAVAX.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.10; import "openzeppelin/token/ERC20/ERC20.sol";
diff --git a/tmp/gas_before b/tmp/gas_after index f6d4cb0..3e4d40b 100644 --- a/tmp/gas_before +++ b/tmp/gas_after @@ -5,3 +5,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠-ā 2086657 ā 10631 ā ā ā ā ā +ā 2083650 ā 10616 ā ā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠@@ -59,3 +59,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠-ā setLBPairImplementation ā 1524 ā 24536 ā 25108 ā 25108 ā 147 ā +ā setLBPairImplementation ā 1396 ā 24408 ā 24980 ā 24980 ā 147 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠@@ -68,3 +68,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠-ā 4835641 ā 24410 ā ā ā ā ā +ā 4823808 ā 24344 ā ā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠@@ -74,9 +74,9 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠-ā balanceOfBatch ā 3766 ā 7101 ā 5769 ā 11769 ā 3 ā +ā balanceOfBatch ā 3513 ā 6936 ā 5648 ā 11648 ā 3 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠-ā burn ā 11235 ā 111199 ā 107074 ā 244666 ā 14 ā +ā burn ā 11185 ā 111009 ā 106900 ā 244223 ā 14 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠-ā collectFees ā 6720 ā 27696 ā 20481 ā 44969 ā 7 ā +ā collectFees ā 6659 ā 27637 ā 20420 ā 44908 ā 7 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠-ā collectProtocolFees ā 5620 ā 8817 ā 9349 ā 10952 ā 4 ā +ā collectProtocolFees ā 5517 ā 8708 ā 9247 ā 10824 ā 4 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠@@ -88,3 +88,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠-ā flashLoan ā 24674 ā 55799 ā 24674 ā 118050 ā 3 ā +ā flashLoan ā 24546 ā 55415 ā 24546 ā 117154 ā 3 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠@@ -108,3 +108,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠-ā mint ā 6892 ā 1402686 ā 1389693 ā 14398451 ā 216 ā +ā mint ā 6889 ā 1401974 ā 1389110 ā 14394628 ā 216 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠@@ -112,5 +112,5 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠-ā pendingFees ā 4041 ā 12049 ā 12853 ā 22185 ā 8 ā +ā pendingFees ā 3980 ā 11987 ā 12792 ā 22076 ā 8 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠-ā safeBatchTransferFrom ā 3251 ā 408394 ā 319740 ā 1394600 ā 25 ā +ā safeBatchTransferFrom ā 2997 ā 408204 ā 319642 ā 1394156 ā 25 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠@@ -122,3 +122,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠-ā swap ā 22475 ā 50419 ā 30217 ā 341090 ā 318 ā +ā swap ā 22347 ā 50291 ā 30089 ā 340962 ā 318 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā⤠@@ -141,3 +141,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāā¼āāāāāāāāā⤠-ā 1899867 ā 9873 ā ā ā ā ā +ā 1862779 ā 9669 ā ā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāā¼āāāāāāāāā⤠@@ -149,5 +149,5 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāā¼āāāāāāāāā⤠-ā findBestPathFromAmountIn ā 1033 ā 45266 ā 45438 ā 88927 ā 5 ā +ā findBestPathFromAmountIn ā 1021 ā 44110 ā 44256 ā 86575 ā 5 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāā¼āāāāāāāāā⤠-ā findBestPathFromAmountOut ā 1011 ā 38128 ā 40133 ā 68750 ā 5 ā +ā findBestPathFromAmountOut ā 999 ā 37100 ā 39335 ā 66782 ā 5 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāā¼āāāāāāāāā⤠@@ -160,3 +160,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā 4591267 ā 23440 ā ā ā ā ā +ā 4464246 ā 22787 ā ā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠@@ -164,7 +164,7 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā addLiquidity ā 19672 ā 1271036 ā 1387744 ā 3343198 ā 132 ā +ā addLiquidity ā 19104 ā 1269581 ā 1386214 ā 3340492 ā 132 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā addLiquidityAVAX ā 20036 ā 1466238 ā 1443921 ā 3391536 ā 41 ā +ā addLiquidityAVAX ā 19453 ā 1464700 ā 1442391 ā 3388830 ā 41 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā createLBPair ā 279323 ā 311452 ā 317427 ā 331632 ā 4 ā +ā createLBPair ā 279195 ā 311324 ā 317299 ā 331504 ā 4 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠@@ -174,9 +174,9 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā getIdFromPrice ā 19069 ā 28334 ā 32951 ā 32983 ā 3 ā +ā getIdFromPrice ā 18941 ā 28206 ā 32823 ā 32855 ā 3 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā getPriceFromId ā 4771 ā 5491 ā 5834 ā 5868 ā 3 ā +ā getPriceFromId ā 4643 ā 5363 ā 5706 ā 5740 ā 3 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā getSwapIn ā 1980 ā 18959 ā 11151 ā 61718 ā 30 ā +ā getSwapIn ā 1852 ā 18336 ā 10767 ā 59542 ā 30 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā getSwapOut ā 12368 ā 19836 ā 21752 ā 28264 ā 20 ā +ā getSwapOut ā 11984 ā 19375 ā 21112 ā 27368 ā 20 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠@@ -184,27 +184,27 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā removeLiquidity ā 2118 ā 579712 ā 408504 ā 1623758 ā 10 ā +ā removeLiquidity ā 2068 ā 578983 ā 407904 ā 1622121 ā 10 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā removeLiquidityAVAX ā 1941 ā 976395 ā 1115696 ā 1672247 ā 4 ā +ā removeLiquidityAVAX ā 1891 ā 975385 ā 1114521 ā 1670610 ā 4 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā swapAVAXForExactTokens ā 1534 ā 28653 ā 8550 ā 166467 ā 8 ā +ā swapAVAXForExactTokens ā 1520 ā 28333 ā 8348 ā 165405 ā 8 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā swapExactAVAXForTokens ā 1578 ā 51884 ā 15354 ā 153614 ā 8 ā +ā swapExactAVAXForTokens ā 1564 ā 51591 ā 15036 ā 153064 ā 8 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā swapExactAVAXForTokensSupportingFeeOnTransferTokens ā 1556 ā 51177 ā 14867 ā 163525 ā 9 ā +ā swapExactAVAXForTokensSupportingFeeOnTransferTokens ā 1542 ā 50810 ā 14549 ā 162719 ā 9 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā swapExactTokensForAVAX ā 1630 ā 69984 ā 15522 ā 286316 ā 10 ā +ā swapExactTokensForAVAX ā 1616 ā 69659 ā 15204 ā 285230 ā 10 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā swapExactTokensForAVAXSupportingFeeOnTransferTokens ā 1610 ā 56192 ā 15502 ā 167467 ā 10 ā +ā swapExactTokensForAVAXSupportingFeeOnTransferTokens ā 1596 ā 55786 ā 15184 ā 166822 ā 10 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā swapExactTokensForTokens ā 1631 ā 105125 ā 67133 ā 538137 ā 13 ā +ā swapExactTokensForTokens ā 1617 ā 104587 ā 66693 ā 535979 ā 13 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā swapExactTokensForTokensSupportingFeeOnTransferTokens ā 1610 ā 55076 ā 45689 ā 136771 ā 10 ā +ā swapExactTokensForTokensSupportingFeeOnTransferTokens ā 1596 ā 54621 ā 45207 ā 135965 ā 10 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā swapTokensForExactAVAX ā 1588 ā 29596 ā 8610 ā 173651 ā 8 ā +ā swapTokensForExactAVAX ā 1574 ā 29302 ā 8408 ā 172801 ā 8 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā swapTokensForExactTokens ā 1632 ā 127782 ā 24140 ā 609504 ā 11 ā +ā swapTokensForExactTokens ā 1618 ā 126636 ā 23462 ā 605298 ā 11 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā sweep ā 6028 ā 26141 ā 26740 ā 36036 ā 5 ā +ā sweep ā 5900 ā 26003 ā 26535 ā 35908 ā 5 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠-ā sweepLBToken ā 3264 ā 156904 ā 156904 ā 310544 ā 2 ā +ā sweepLBToken ā 3014 ā 156630 ā 156630 ā 310247 ā 2 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāāā¼āāāāāāāāā⤠@@ -217,3 +217,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāā¼āāāāāāāāā¼āāāāāā¼āāāāāāāāā⤠-ā 19179229 ā 95589 ā ā ā ā ā +ā 18854334 ā 93969 ā ā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāā¼āāāāāāāāā¼āāāāāā¼āāāāāāāāā⤠@@ -228,3 +228,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāā¼āāāāāāāāā¼āāāāāā¼āāāāāāāāā⤠-ā 17699454 ā 88210 ā ā ā ā ā +ā 17397071 ā 86702 ā ā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāā¼āāāāāāāāā¼āāāāāā¼āāāāāāāāā⤠@@ -249,3 +249,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāā¼āāāāāāāāā⤠-ā transfer ā 2581 ā 10121 ā 3226 ā 29926 ā 527 ā +ā transfer ā 2581 ā 10093 ā 3226 ā 29926 ā 526 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāā¼āāāāāāāāā⤠@@ -258,3 +258,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāā¼āāāāāāāāā⤠-ā 693730 ā 4198 ā ā ā ā ā +ā 693718 ā 4161 ā ā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāā¼āāāāāāāāā⤠@@ -292,3 +292,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠-ā 1098332 ā 5556 ā ā ā ā ā +ā 1095325 ā 5541 ā ā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠@@ -306,5 +306,5 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠-ā request() ā 340 ā 73455 ā 101517 ā 137977 ā 12 ā +ā request() ā 340 ā 73284 ā 101261 ā 137721 ā 12 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠-ā request(address) ā 622 ā 64004 ā 58354 ā 138687 ā 4 ā +ā request(address) ā 622 ā 63876 ā 58226 ā 138431 ā 4 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠@@ -327,3 +327,3 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠-ā 413779 ā 2134 ā ā ā ā ā +ā 401767 ā 2074 ā ā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠@@ -331,7 +331,7 @@ āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠-ā LBFlashLoanCallback ā 12455 ā 12455 ā 12455 ā 12455 ā 1 ā +ā LBFlashLoanCallback ā 11943 ā 11943 ā 11943 ā 11943 ā 1 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠-ā flashBorrow ā 33471 ā 77648 ā 77648 ā 121826 ā 2 ā +ā flashBorrow ā 33343 ā 77136 ā 77136 ā 120930 ā 2 ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāā¼āāāāāāāā¼āāāāāāāāā¼āāāāāāāāā¼āāāāāāāāā⤠-ā flashBorrowWithReentrancy ā 33427 ā 33427 ā 33427 ā 33427 ā 1 ā +ā flashBorrowWithReentrancy ā 33299 ā 33299 ā 33299 ā 33299 ā 1 ā ā°āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāā“āāāāāāāā“āāāāāāāāā“āāāāāāāāā“āāāāāāāāāāÆ
testInversePriceForOppositeBins() (gas: 0 (0.000%)) testRevertOnNonEOA() (gas: 0 (0.000%)) testForInvalidReductionFactor() (gas: 0 (0.000%)) testSetFeeRecipientNotByOwnerReverts() (gas: 0 (0.000%)) testsetFactoryLockedState() (gas: 0 (0.000%)) testSelfApprovalReverts() (gas: 0 (0.000%)) testInternalApproval() (gas: 0 (0.000%)) testInternalBurn(uint256,uint256) (gas: 0 (0.000%)) testInternalBurnFrom0AddressReverts() (gas: 0 (0.000%)) testInternalExcessiveBurnAmountReverts(uint128,uint128) (gas: 0 (0.000%)) testInternalMint(uint256) (gas: 0 (0.000%)) testInternalMintTo0AddressReverts() (gas: 0 (0.000%)) testAddToken() (gas: -19 (-0.002%)) testForInvalidFeeRecipient() (gas: -7 (-0.010%)) testIncreaseOracleLength() (gas: -256 (-0.012%)) testSetFeesParametersOnPairReverts() (gas: -128 (-0.036%)) testForDoubleIgnored() (gas: -128 (-0.036%)) testForInvalidBaseFactor() (gas: -128 (-0.036%)) testForInvalidFilterPeriod() (gas: -128 (-0.036%)) testCreatePairWhenFactoryIsUnlocked() (gas: -262 (-0.070%)) testSetFeesParametersOnPair() (gas: -256 (-0.071%)) testTLowerThanTimestamp() (gas: -5524 (-0.072%)) testIfPairAlreadyExistsReverts() (gas: -256 (-0.073%)) testGetSwapOutWithMultipleChoices() (gas: -3684 (-0.090%)) testForceDecay() (gas: -8084 (-0.101%)) testFuzzingAddLiquidity(uint256) (gas: -1066 (-0.103%)) testForInvalidProtocolShare() (gas: -384 (-0.109%)) testSwapXtoYDistantBinsFromGetSwapOut() (gas: -1970 (-0.112%)) testFlashloan() (gas: -1953 (-0.113%)) testInsufficientLiquidityMinted() (gas: -1876 (-0.114%)) testSwapXtoYConsecutiveBinFromGetSwapOut() (gas: -1970 (-0.115%)) testSwapYtoXConsecutiveBinFromGetSwapOut() (gas: -1970 (-0.116%)) testBurnLiquidity() (gas: -2272 (-0.120%)) testSwapXtoYDistantBinsFromGetSwapIn() (gas: -2098 (-0.120%)) testSwapXtoYConsecutiveBinFromGetSwapIn() (gas: -2098 (-0.123%)) testSwapYtoXConsecutiveBinFromGetSwapIn() (gas: -2098 (-0.123%)) testSwapYtoXDistantBinsFromGetSwapOut() (gas: -2226 (-0.125%)) testOracleSampleFromWith100SamplesNotAllInitialized() (gas: -24340 (-0.125%)) testSwapYtoXDistantBinsFromGetSwapIn() (gas: -2354 (-0.132%)) testTaxTokenSwappedOnV1Pairs() (gas: -6516 (-0.134%)) testFailFlashloanMoreThanReserves() (gas: -128 (-0.141%)) testFailFlashlaonWithReentrancy() (gas: -128 (-0.142%)) testFlawedCompositionFactor() (gas: -2724 (-0.162%)) testLockRequest() (gas: -256 (-0.162%)) testSafeBatchTransferFrom() (gas: -2642 (-0.167%)) testSafeTransferNotApprovedReverts() (gas: -1906 (-0.182%)) testEnsureModifierLiquidity() (gas: -1549 (-0.183%)) testAddLiquidityTaxToken() (gas: -6640 (-0.185%)) testForAmountSlippageCaughtReverts() (gas: -4296 (-0.193%)) testSafeBatchTransferNotApprovedReverts() (gas: -2028 (-0.193%)) testGetIdFromPrice() (gas: -896 (-0.195%)) testSafeTransferFromReverts() (gas: -3730 (-0.196%)) testOracleSampleFromEdgeCases() (gas: -948 (-0.198%)) testDistributionOverflowReverts() (gas: -1768 (-0.204%)) testGetSwapInMoreBins() (gas: -4018 (-0.204%)) testGetSwapInWithMultipleChoices() (gas: -3684 (-0.205%)) testForIdSlippageCaughtReverts() (gas: -4570 (-0.205%)) testOracleSampleFromWith2Samples() (gas: -1076 (-0.207%)) testSwapWithDifferentBinSteps() (gas: -4380 (-0.209%)) testGetSwapInOverflowReverts() (gas: -1586 (-0.213%)) testRemoveLiquiditySlippageReverts() (gas: -13559 (-0.215%)) testModifierCheckLength() (gas: -4108 (-0.216%)) testGetSwapOutOnV2Pair() (gas: -3556 (-0.224%)) testGetSwapInOnV2Pair() (gas: -3556 (-0.224%)) testClaimFeesY() (gas: -2792 (-0.228%)) testClaimFeesX() (gas: -2792 (-0.228%)) testGetPriceFromId() (gas: -896 (-0.230%)) testAddLiquidityIgnored() (gas: -4256 (-0.231%)) testSetLBPairImplementation() (gas: -39185 (-0.234%)) testFeesOnTokenTransfer() (gas: -3298 (-0.236%)) testBalanceOfBatch() (gas: -2522 (-0.237%)) testAddLiquidityAVAXReversed() (gas: -11019 (-0.241%)) testAddLiquidityAVAX() (gas: -11922 (-0.241%)) testQuoteAssets() (gas: -1792 (-0.242%)) testConstructor(uint16,uint16,uint16,uint16,uint16,uint24,uint16,uint24) (gas: -12363 (-0.243%)) testGetSwapInOnComplexRoute() (gas: -4542 (-0.244%)) testSweepLBToken() (gas: -4475 (-0.248%)) testSafeBatchTransferFromReverts() (gas: -5060 (-0.249%)) testCreateLBPair() (gas: -896 (-0.251%)) testCreateLBPair() (gas: -1024 (-0.252%)) testSafeTransferFrom() (gas: -3058 (-0.261%)) testGetSwapOutOnComplexRoute() (gas: -4926 (-0.262%)) testAddLiquidityNoSlippage() (gas: -5707 (-0.273%)) testRemoveLiquidityReverseOrder() (gas: -5708 (-0.273%)) testOracleSampleFromWith100Samples() (gas: -69140 (-0.276%)) testSetRequestAmount() (gas: -512 (-0.280%)) testWithdrawAvax() (gas: -512 (-0.294%)) testClaimProtocolFees() (gas: -3828 (-0.307%)) testClaimFeesComplex(uint256,uint256) (gas: -4212 (-0.322%)) testGetSwapInWrongAmountsReverts() (gas: -6608 (-0.330%)) testRequestFaucetTokensByOperator() (gas: -1024 (-0.332%)) testSwapYtoXSingleBinFromGetSwapOut() (gas: -1714 (-0.344%)) testSwapXtoYSingleBinFromGetSwapOut() (gas: -1714 (-0.344%)) testSwapXtoYSingleBinFromGetSwapIn() (gas: -1714 (-0.345%)) testForLengthsMismatchReverts() (gas: -762 (-0.367%)) testFeeOnActiveBinReverse() (gas: -3274 (-0.372%)) testFeeOnActiveBin() (gas: -3274 (-0.372%)) testRequestFaucetTokens() (gas: -1024 (-0.381%)) testSwapYtoXSingleBinFromGetSwapIn() (gas: -1970 (-0.386%)) testGetSwapInOnV1Pair() (gas: -1168 (-0.405%)) testSwapExactTokensForAvaxSinglePair() (gas: -1597 (-0.415%)) testSwapExactTokensForTokensMultiplePairs() (gas: -2542 (-0.424%)) testForZeroAddressPairReverts() (gas: -256 (-0.434%)) testSweep() (gas: -512 (-0.456%)) testInvalidBinStepWhileCreatingLBPair() (gas: -128 (-0.463%)) testAddLiquidityAVAXnotAVAXReverts() (gas: -965 (-0.465%)) testGetSwapOutOnV1Pair() (gas: -1552 (-0.505%)) testWithdrawToken() (gas: -1024 (-0.524%)) testTaxTokenEqualOnlyV2Swap() (gas: -3196 (-0.525%)) testSwapExactTokensForAVAXSupportingFeeOnTransferTokens() (gas: -2007 (-0.534%)) testSetFeeRecipient() (gas: -128 (-0.539%)) testSwapExactAVAXForTokensSinglePair() (gas: -1996 (-0.544%)) testForIdDesiredOverflowReverts() (gas: -1906 (-0.556%)) testSweepMax() (gas: -640 (-0.565%)) testAvailableBinSteps() (gas: -730 (-0.585%)) testForIdenticalAddressesReverts() (gas: -128 (-0.622%)) testAddRemovePresets() (gas: -504 (-0.627%)) testSwapExactAVAXForTokensSupportingFeeOnTransferTokens() (gas: -2508 (-0.649%)) testForSettingFlashloanFee() (gas: -128 (-0.654%)) testSwapExactTokensForTokensSinglePair() (gas: -2124 (-0.672%)) testFactoryLockedReverts() (gas: -128 (-0.684%)) testWrongTokenOrderReverts() (gas: -1674 (-0.723%)) testInsufficientLiquidityBurnedReverts() (gas: -178 (-0.741%)) testSwapExactTokensForTokensMultiplePairsWithV1() (gas: -2812 (-0.749%)) testSwapTokensForExactTokensMultiplePairsWithV1() (gas: -4418 (-0.763%)) testModifieronlyFactoryOwner() (gas: -128 (-0.770%)) testFeesAboveMaxVolatilityReverts(uint8) (gas: -128 (-0.833%)) testFeesAboveMaxBaseFactorReverts(uint8) (gas: -128 (-0.837%)) testSwapInsufficientAmountReverts() (gas: -512 (-0.859%)) testSwapExactTokensForTokensSupportingFeeOnTransferTokens() (gas: -4423 (-0.862%)) testRemoveToken() (gas: -384 (-0.873%)) testPendingFeesNotIncreasingReverts() (gas: -153 (-0.877%)) testSetRequestCooldown() (gas: -1792 (-0.890%)) testSwapTokensForExactTokensMultiplePairs() (gas: -7446 (-0.926%)) testSwapTokensForExactAVAXSinglePair() (gas: -2658 (-0.945%)) testSwapAVAXForExactTokensSinglePair() (gas: -2658 (-1.066%)) testSetPresets() (gas: -384 (-1.104%)) testVerifyOracleInitialParams() (gas: -128 (-1.124%)) testCollectingFeesOnlyFeeRecipient() (gas: -256 (-1.127%)) testMintWrongLengthsReverts() (gas: -516 (-1.156%)) testSwapTokensForExactTokensSinglePair() (gas: -2786 (-1.174%)) testInvalidLength() (gas: -292 (-1.644%)) testSwappingOnNotExistingV1PairReverts() (gas: -4011 (-1.933%)) testSwappingOnNotExistingV2PairReverts() (gas: -4011 (-2.034%)) testPrivateViewFunctions() (gas: -256 (-2.037%)) testgetAllLBPairs() (gas: -128415 (-2.258%)) <------------------------------------ testConstructor() (gas: -256 (-2.340%)) testInvalidTokenPathReverts() (gas: -828 (-2.380%)) testForInvalidBinStepUnderflowReverts() (gas: -384 (-2.531%)) testForInvalidBinStepOverflowReverts() (gas: -384 (-2.539%)) testModifierEnsure() (gas: -1955 (-3.207%)) testConstructor() (gas: -384 (-3.242%)) testConstructor() (gas: -384 (-3.858%)) testModifierVerifyInputs() (gas: -3198 (-4.074%)) Overall gas change: -581485 (-81.334%) <------------------------------------
The instances below point to the second+ access of a value inside a mapping/array, within a function. Caching a mapping's value in a local storage
or calldata
variable when the value is accessed multiple times, saves ~42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations. Caching an array's struct avoids recalculating the array offsets into memory/calldata
There is 1 instance of this issue:
File: src/LBPair.sol /// @audit _bins[_id] on line 452 453: _bins[_id].accTokenYPerShare += _feesY.getTokenPerShare(_totalSupply);
unchecked {}
for subtractions where the operands cannot underflow because of a previous require()
or if
-statementrequire(a <= b); x = b - a
=> require(a <= b); unchecked { x = b - a }
There are 5 instances of this issue:
File: src/LBPair.sol /// @audit if-condition on line 219 225: uint256 _deltaT = _lookUpTimestamp - timestamp; /// @audit if-condition on line 534 536: _fp.getFeeAmountForC(_mintInfo.amountX - _receivedX) /// @audit if-condition on line 545 547: _fp.getFeeAmountForC(_mintInfo.amountY - _receivedY) /// @audit if-condition on line 597 598: tokenX.safeTransfer(_to, _mintInfo.amountXIn - _amountAddedPlusFee); /// @audit if-condition on line 602 603: tokenY.safeTransfer(_to, _mintInfo.amountYIn - _amountAddedPlusFee);
++i
/i++
should be unchecked{++i}
/unchecked{i++}
when it is not possible for them to overflow, as is the case when used in for
- and while
-loopsThe unchecked
keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas per loop
There are 5 instances of this issue:
File: src/LBQuoter.sol 75: for (uint256 i; i < swapLength; i++) { 100: for (uint256 j; j < LBPairsAvailable.length; j++) { 154: for (uint256 i = swapLength; i > 0; i--) { 177: for (uint256 j; j < LBPairsAvailable.length; j++) {
File: src/LBRouter.sol 711: for (uint256 i = _pairs.length; i != 0; i--) {
public
/external
function names and public
member variable names can be optimized to save gas. See this link for an example of how it works. Below are the interfaces/abstract contracts that can be optimized so that the most frequently-called functions use the least amount of gas possible during method lookup. Method IDs that have two leading zero bytes can save 128 gas each during deployment, and renaming functions to have lower method IDs will save 22 gas per call, per sorted position shifted
There are 11 instances of this issue:
File: src/interfaces/IJoeFactory.sol /// @audit feeTo(), feeToSetter(), migrator(), getPair(), allPairs(), allPairsLength(), createPair(), setFeeTo(), setFeeToSetter(), setMigrator() 7: interface IJoeFactory {
File: src/interfaces/IJoePair.sol /// @audit MINIMUM_LIQUIDITY(), factory(), token0(), token1(), getReserves(), price0CumulativeLast(), price1CumulativeLast(), kLast(), mint(), burn(), swap(), skim(), sync(), initialize() 7: interface IJoePair {
File: src/interfaces/IJoeRouter01.sol /// @audit factory(), WAVAX(), addLiquidity(), addLiquidityAVAX(), removeLiquidity(), removeLiquidityAVAX(), removeLiquidityWithPermit(), removeLiquidityAVAXWithPermit(), swapExactTokensForTokens(), swapTokensForExactTokens(), swapExactAVAXForTokens(), swapTokensForExactAVAX(), swapExactTokensForAVAX(), swapAVAXForExactTokens(), quote(), getAmountOut(), getAmountIn(), getAmountsOut(), getAmountsIn() 7: interface IJoeRouter01 {
File: src/interfaces/IJoeRouter02.sol /// @audit removeLiquidityAVAXSupportingFeeOnTransferTokens(), removeLiquidityAVAXWithPermitSupportingFeeOnTransferTokens(), swapExactTokensForTokensSupportingFeeOnTransferTokens(), swapExactAVAXForTokensSupportingFeeOnTransferTokens(), swapExactTokensForAVAXSupportingFeeOnTransferTokens() 9: interface IJoeRouter02 is IJoeRouter01 {
File: src/interfaces/ILBFactory.sol /// @audit MAX_FEE(), MIN_BIN_STEP(), MAX_BIN_STEP(), MAX_PROTOCOL_SHARE(), LBPairImplementation(), getNumberOfQuoteAssets(), getQuoteAsset(), isQuoteAsset(), feeRecipient(), flashLoanFee(), creationUnlocked(), allLBPairs(), getNumberOfLBPairs(), getLBPairInformation(), getPreset(), getAllBinSteps(), getAllLBPairs(), setLBPairImplementation(), createLBPair(), setLBPairIgnored(), setPreset(), removePreset(), setFeesParametersOnPair(), setFeeRecipient(), setFlashLoanFee(), setFactoryLockedState(), addQuoteAsset(), removeQuoteAsset(), forceDecay() 13: interface ILBFactory is IPendingOwnable {
File: src/interfaces/ILBFlashLoanCallback.sol /// @audit LBFlashLoanCallback() 8: interface ILBFlashLoanCallback {
File: src/interfaces/ILBPair.sol /// @audit tokenX(), tokenY(), factory(), getReservesAndId(), getGlobalFees(), getOracleParameters(), getOracleSampleFrom(), feeParameters(), findFirstNonEmptyBinId(), getBin(), pendingFees(), swap(), flashLoan(), mint(), burn(), increaseOracleLength(), collectFees(), collectProtocolFees(), setFeesParameters(), forceDecay(), initialize() 13: interface ILBPair {
File: src/interfaces/ILBRouter.sol /// @audit factory(), oldFactory(), wavax(), getIdFromPrice(), getPriceFromId(), getSwapIn(), getSwapOut(), createLBPair(), addLiquidity(), addLiquidityAVAX(), removeLiquidity(), removeLiquidityAVAX(), swapExactTokensForTokens(), swapExactTokensForAVAX(), swapExactAVAXForTokens(), swapTokensForExactTokens(), swapTokensForExactAVAX(), swapAVAXForExactTokens(), swapExactTokensForTokensSupportingFeeOnTransferTokens(), swapExactTokensForAVAXSupportingFeeOnTransferTokens(), swapExactAVAXForTokensSupportingFeeOnTransferTokens(), sweep(), sweepLBToken() 13: interface ILBRouter {
File: src/interfaces/ILBToken.sol /// @audit userPositionAtIndex(), userPositionNumber(), totalSupply(), safeTransferFrom(), safeBatchTransferFrom() 8: interface ILBToken {
File: src/interfaces/IPendingOwnable.sol /// @audit pendingOwner(), setPendingOwner(), revokePendingOwner(), becomeOwner() 8: interface IPendingOwnable {
File: src/LBQuoter.sol /// @audit findBestPathFromAmountIn(), findBestPathFromAmountOut() 17: contract LBQuoter {
Use a solidity version of at least 0.8.2 to get simple compiler automatic inlining
Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads
Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require()
strings
Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value
There are 37 instances of this issue:
File: src/interfaces/IJoeFactory.sol 3: pragma solidity ^0.8.0;
File: src/interfaces/IJoePair.sol 3: pragma solidity ^0.8.0;
File: src/interfaces/IJoeRouter01.sol 3: pragma solidity ^0.8.0;
File: src/interfaces/IJoeRouter02.sol 3: pragma solidity ^0.8.0;
File: src/interfaces/ILBFactory.sol 3: pragma solidity ^0.8.0;
File: src/interfaces/ILBFlashLoanCallback.sol 3: pragma solidity ^0.8.0;
File: src/interfaces/ILBPair.sol 3: pragma solidity ^0.8.0;
File: src/interfaces/ILBRouter.sol 3: pragma solidity ^0.8.0;
File: src/interfaces/ILBToken.sol 3: pragma solidity ^0.8.0;
File: src/interfaces/IPendingOwnable.sol 3: pragma solidity ^0.8.0;
File: src/interfaces/IWAVAX.sol 3: pragma solidity ^0.8.0;
File: src/LBErrors.sol 3: pragma solidity ^0.8.0;
File: src/LBFactory.sol 3: pragma solidity ^0.8.0;
File: src/LBPair.sol 3: pragma solidity ^0.8.0;
File: src/LBQuoter.sol 3: pragma solidity ^0.8.0;
File: src/LBRouter.sol 3: pragma solidity ^0.8.0;
File: src/LBToken.sol 3: pragma solidity ^0.8.0;
File: src/libraries/BinHelper.sol 3: pragma solidity ^0.8.0;
File: src/libraries/BitMath.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Buffer.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Constants.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Decoder.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Encoder.sol 3: pragma solidity ^0.8.0;
File: src/libraries/FeeDistributionHelper.sol 3: pragma solidity ^0.8.0;
File: src/libraries/FeeHelper.sol 3: pragma solidity ^0.8.0;
File: src/libraries/JoeLibrary.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Math128x128.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Math512Bits.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Oracle.sol 3: pragma solidity ^0.8.0;
File: src/libraries/PendingOwnable.sol 3: pragma solidity ^0.8.0;
File: src/libraries/ReentrancyGuardUpgradeable.sol 3: pragma solidity ^0.8.0;
File: src/libraries/SafeCast.sol 3: pragma solidity ^0.8.0;
File: src/libraries/SafeMath.sol 3: pragma solidity ^0.8.0;
File: src/libraries/Samples.sol 3: pragma solidity ^0.8.0;
File: src/libraries/SwapHelper.sol 3: pragma solidity ^0.8.0;
File: src/libraries/TokenHelper.sol 3: pragma solidity ^0.8.0;
File: src/libraries/TreeMath.sol 3: pragma solidity ^0.8.0;
>=
costs less gas than >
The compiler uses opcodes GT
and ISZERO
for solidity code that uses >
, but only requires LT
for >=
, which saves 3 gas
There is 1 instance of this issue:
File: src/LBRouter.sol 116: _amountOutOfBin = _amountOut > _reserve ? _reserve : _amountOut;
payable
If a function modifier such as onlyOwner
is used, the function will revert if a normal user tries to pay the function. Marking the function as payable
will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are
CALLVALUE
(2),DUP1
(3),ISZERO
(3),PUSH2
(3),JUMPI
(10),PUSH1
(3),DUP1
(3),REVERT
(0),JUMPDEST
(1),POP
(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost
There are 20 instances of this issue:
File: src/LBFactory.sol 215: function setLBPairImplementation(address _LBPairImplementation) external override onlyOwner { 312 function setLBPairIgnored( 313 IERC20 _tokenX, 314 IERC20 _tokenY, 315 uint256 _binStep, 316 bool _ignored 317: ) external override onlyOwner { 340 function setPreset( 341 uint16 _binStep, 342 uint16 _baseFactor, 343 uint16 _filterPeriod, 344 uint16 _decayPeriod, 345 uint16 _reductionFactor, 346 uint24 _variableFeeControl, 347 uint16 _protocolShare, 348 uint24 _maxVolatilityAccumulated, 349 uint16 _sampleLifetime 350: ) external override onlyOwner { 396: function removePreset(uint16 _binStep) external override onlyOwner { 423 function setFeesParametersOnPair( 424 IERC20 _tokenX, 425 IERC20 _tokenY, 426 uint16 _binStep, 427 uint16 _baseFactor, 428 uint16 _filterPeriod, 429 uint16 _decayPeriod, 430 uint16 _reductionFactor, 431 uint24 _variableFeeControl, 432 uint16 _protocolShare, 433 uint24 _maxVolatilityAccumulated 434: ) external override onlyOwner { 468: function setFeeRecipient(address _feeRecipient) external override onlyOwner { 474: function setFlashLoanFee(uint256 _flashLoanFee) external override onlyOwner { 485: function setFactoryLockedState(bool _locked) external override onlyOwner { 493: function addQuoteAsset(IERC20 _quoteAsset) external override onlyOwner { 502: function removeQuoteAsset(IERC20 _quoteAsset) external override onlyOwner { 520: function forceDecay(ILBPair _LBPair) external override onlyOwner {
File: src/LBPair.sol 104 function initialize( 105 IERC20 _tokenX, 106 IERC20 _tokenY, 107 uint24 _activeId, 108 uint16 _sampleLifetime, 109 bytes32 _packedFeeParameters 110: ) external override onlyFactory { 788: function setFeesParameters(bytes32 _packedFeeParameters) external override onlyFactory { 792: function forceDecay() external override onlyFactory {
File: src/LBRouter.sol 622 function sweep( 623 IERC20 _token, 624 address _to, 625 uint256 _amount 626: ) external override onlyFactoryOwner { 642 function sweepLBToken( 643 ILBToken _lbToken, 644 address _to, 645 uint256[] memory _ids, 646 uint256[] memory _amounts 647: ) external override onlyFactoryOwner {
File: src/libraries/PendingOwnable.sol 59: function setPendingOwner(address pendingOwner_) public override onlyOwner { 68: function revokePendingOwner() public override onlyOwner { 75: function becomeOwner() public override onlyPendingOwner { 84: function renounceOwnership() public override onlyOwner {
These findings are excluded from awards calculations because there are publicly-available automated tools that find them. The valid ones appear here for completeness
<array>.length
should not be looked up in every loop of a for
-loopThe overheads outlined below are PER LOOP, excluding the first loop
MLOAD
(3 gas)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 13 instances of this issue:
File: src/LBPair.sol /// @audit (valid but excluded finding) 274: for (uint256 i; i < _ids.length; ++i) { /// @audit (valid but excluded finding) 496: for (uint256 i; i < _ids.length; ++i) { /// @audit (valid but excluded finding) 623: for (uint256 i; i < _ids.length; ++i) { /// @audit (valid but excluded finding) 701: for (uint256 i; i < _ids.length; ++i) {
File: src/LBQuoter.sol /// @audit (valid but excluded finding) 100: for (uint256 j; j < LBPairsAvailable.length; j++) { /// @audit (valid but excluded finding) 177: for (uint256 j; j < LBPairsAvailable.length; j++) {
File: src/LBRouter.sol /// @audit (valid but excluded finding) 674: for (uint256 i; i < depositIds.length; ++i) { /// @audit (valid but excluded finding) 778: for (uint256 i; i < _pairs.length; ++i) { /// @audit (valid but excluded finding) 831: for (uint256 i; i < _pairs.length; ++i) { /// @audit (valid but excluded finding) 878: for (uint256 i; i ... See the rest this report [here](https://github.com/code-423n4/2022-10-traderjoe-findings/blob/main/data/IllIllI-G.md)
#0 - GalloDaSballo
2022-11-09T22:30:37Z
[Gā03] Using storage instead of memory for structs/arrays saves gas 1k
[Gā04] Avoid contract existence checks by using low level calls Capping it at 1k
Rest is minor
#1 - GalloDaSballo
2022-11-09T22:30:39Z
2K
#2 - c4-judge
2022-11-16T21:24:26Z
GalloDaSballo marked the issue as grade-b