Trader Joe v2 contest - pfapostol's results

One-stop-shop decentralized trading on Avalanche.

General Information

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

Trader Joe

Findings Distribution

Researcher Performance

Rank: 19/75

Findings: 1

Award: $613.77

Gas:
grade-a

๐ŸŒŸ Selected for report: 0

๐Ÿš€ Solo Findings: 0

Findings Information

Labels

bug
G (Gas Optimization)
grade-a
G-11

Awards

613.7687 USDC - $613.77

External Links

Gas Optimizations

Gas savings are estimated using the gas report of existing forge test --gas-report tests (the sum of all deployment costs and the sum of the costs of calling methods) and may vary depending on the implementation of the fix.

IssueInstancesEstimated gas(deployments)Estimated gas(min method call)Estimated gas(avg method call)Estimated gas(max method call)
1Use functions instead of modifiers81 065 143-974-1 557-2 027
2Use a more recent version of solidity37821 2584 61216 39337 384
3Duplicated require()/revert() checks should be refactored to a modifier or function38566 224-424-1 473-2 818
4Unchecking arithmetics operations that can't underflow/overflow258 52406511 104
5Use of the memory keyword when storage pointer should be used453 5235513 58015 945
6Using calldata instead of memory for read-only arguments in external functions saves gas139 0862 2561 199-2 165
7Do not cache msg.sender113 8430-14035
8Unnecessary else statement47 2170-88338
9++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too)52 80003269
Overall Gas Saving1002 623 2835 38128 75548 090

Total: 100 instances over 9 issues


1. Use functions instead of modifiers (8 instances)

Deployment. Gas Saved: 1 065 143

Minimum Method Call. Gas Saved: -974

Average Method Call. Gas Saved: -1 557

Maximum Method Call. Gas Saved: -2 027

Overall gas change: -477 008 (-0.302%)

- src/LBPair.sol:43, 110, 788, 792,
diff --git a/src/LBPair.sol b/src/LBPair.sol
index 717270e..edb50ac 100644
--- a/src/LBPair.sol
+++ b/src/LBPair.sol
@@ -40,9 +40,8 @@ contract LBPair is LBToken, ReentrancyGuardUpgradeable, ILBPair {
   40,  40: 
   41,  41:     /** Modifiers **/
   42,  42: 
-  43     :-    modifier onlyFactory() {
+       43:+    function onlyFactory() private {
   44,  44:         if (msg.sender != address(factory)) revert LBPair__OnlyFactory();
-  45     :-        _;
   46,  45:     }
   47,  46: 
   48,  47:     /** Public immutable variables **/
@@ -107,7 +106,8 @@ contract LBPair is LBToken, ReentrancyGuardUpgradeable, ILBPair {
  107, 106:         uint24 _activeId,
  108, 107:         uint16 _sampleLifetime,
  109, 108:         bytes32 _packedFeeParameters
- 110     :-    ) external override onlyFactory {
+      109:+    ) external override {
+      110:+        onlyFactory();
  111, 111:         if (address(_tokenX) == address(0) || address(_tokenY) == address(0)) revert LBPair__AddressZero();
  112, 112:         if (address(tokenX) != address(0)) revert LBPair__AlreadyInitialized();
  113, 113: 
@@ -785,11 +785,13 @@ contract LBPair is LBToken, ReentrancyGuardUpgradeable, ILBPair {
  785, 785:     /// The bin step will not change
  786, 786:     /// Only callable by the factory
  787, 787:     /// @param _packedFeeParameters The packed fee parameters
- 788     :-    function setFeesParameters(bytes32 _packedFeeParameters) external override onlyFactory {
+      788:+    function setFeesParameters(bytes32 _packedFeeParameters) external override {
+      789:+        onlyFactory();
  789, 790:         _setFeesParameters(_packedFeeParameters);
  790, 791:     }
  791, 792: 
- 792     :-    function forceDecay() external override onlyFactory {
+      793:+    function forceDecay() external override {
+      794:+        onlyFactory();
  793, 795:         unchecked {
  794, 796:             _feeParameters.volatilityReference = uint24(
  795, 797:                 (uint256(_feeParameters.reductionFactor) * _feeParameters.volatilityReference) /
- src/LBRouter.sol:32, 626, 647
diff --git a/src/LBRouter.sol b/src/LBRouter.sol
index 567c49a..2cf7514 100644
--- a/src/LBRouter.sol
+++ b/src/LBRouter.sol
@@ -29,9 +29,8 @@ contract LBRouter is ILBRouter {
   29,  29:     IJoeFactory public immutable override oldFactory;
   30,  30:     IWAVAX public immutable override wavax;
   31,  31: 
-  32     :-    modifier onlyFactoryOwner() {
+       32:+    function onlyFactoryOwner() private {
   33,  33:         if (msg.sender != factory.owner()) revert LBRouter__NotFactoryOwner();
-  34     :-        _;
   35,  34:     }
   36,  35: 
   37,  36:     modifier ensure(uint256 _deadline) {
@@ -623,7 +622,8 @@ contract LBRouter is ILBRouter {
  623, 622:         IERC20 _token,
  624, 623:         address _to,
  625, 624:         uint256 _amount
- 626     :-    ) external override onlyFactoryOwner {
+      625:+    ) external override {
+      626:+        onlyFactoryOwner();
  627, 627:         if (address(_token) == address(0)) {
  628, 628:             if (_amount == type(uint256).max) _amount = address(this).balance;
  629, 629:             _safeTransferAVAX(_to, _amount);
@@ -644,7 +644,8 @@ contract LBRouter is ILBRouter {
  644, 644:         address _to,
  645, 645:         uint256[] memory _ids,
  646, 646:         uint256[] memory _amounts
- 647     :-    ) external override onlyFactoryOwner {
+      647:+    ) external override {
+      648:+        onlyFactoryOwner();
  648, 649:         _lbToken.safeBatchTransferFrom(address(this), _to, _ids, _amounts);
  649, 650:     }
  650, 651: 
- src/LBRouter.sol:36, 41
diff --git a/src/LBRouter.sol b/src/LBRouter.sol
index 2cf7514..200c7e2 100644
--- a/src/LBRouter.sol
+++ b/src/LBRouter.sol
@@ -33,15 +33,13 @@ contract LBRouter is ILBRouter {
   33,  33:         if (msg.sender != factory.owner()) revert LBRouter__NotFactoryOwner();
   34,  34:     }
   35,  35: 
-  36     :-    modifier ensure(uint256 _deadline) {
+       36:+    function ensure(uint256 _deadline) private {
   37,  37:         if (block.timestamp > _deadline) revert LBRouter__DeadlineExceeded(_deadline, block.timestamp);
-  38     :-        _;
   39,  38:     }
   40,  39: 
-  41     :-    modifier verifyInputs(uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath) {
+       40:+    function verifyInputs(uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath) private {
   42,  41:         if (_pairBinSteps.length == 0 || _pairBinSteps.length + 1 != _tokenPath.length)
   43,  42:             revert LBRouter__LengthsMismatch();
-  44     :-        _;
   45,  43:     }
   46,  44: 
   47,  45:     /// @notice Constructor
@@ -280,7 +278,8 @@ contract LBRouter is ILBRouter {
  280, 278:         uint256[] memory _amounts,
  281, 279:         address _to,
  282, 280:         uint256 _deadline
- 283     :-    ) external override ensure(_deadline) returns (uint256 amountX, uint256 amountY) {
+      281:+    ) external override returns (uint256 amountX, uint256 amountY) {
+      282:+        ensure(_deadline);
  284, 283:         ILBPair _LBPair = _getLBPairInformation(_tokenX, _tokenY, _binStep);
  285, 284:         if (_tokenX != _LBPair.tokenX()) {
  286, 285:             (_tokenX, _tokenY) = (_tokenY, _tokenX);
@@ -313,7 +312,8 @@ contract LBRouter is ILBRouter {
  313, 312:         uint256[] memory _amounts,
  314, 313:         address payable _to,
  315, 314:         uint256 _deadline
- 316     :-    ) external override ensure(_deadline) returns (uint256 amountToken, uint256 amountAVAX) {
+      315:+    ) external override returns (uint256 amountToken, uint256 amountAVAX) {
+      316:+        ensure(_deadline);
  317, 317:         ILBPair _LBPair = _getLBPairInformation(_token, IERC20(wavax), _binStep);
  318, 318: 
  319, 319:         bool _isAVAXTokenY = IERC20(wavax) == _LBPair.tokenY();
@@ -355,7 +355,9 @@ contract LBRouter is ILBRouter {
  355, 355:         IERC20[] memory _tokenPath,
  356, 356:         address _to,
  357, 357:         uint256 _deadline
- 358     :-    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
+      358:+    ) external override returns (uint256 amountOut) {
+      359:+        ensure(_deadline);
+      360:+        verifyInputs(_pairBinSteps, _tokenPath);
  359, 361:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
  360, 362: 
  361, 363:         _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn);
@@ -380,7 +382,9 @@ contract LBRouter is ILBRouter {
  380, 382:         IERC20[] memory _tokenPath,
  381, 383:         address payable _to,
  382, 384:         uint256 _deadline
- 383     :-    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
+      385:+    ) external override returns (uint256 amountOut) {
+      386:+        ensure(_deadline);
+      387:+        verifyInputs(_pairBinSteps, _tokenPath);
  384, 388:         if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
  385, 389:             revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));
  386, 390: 
@@ -409,7 +413,9 @@ contract LBRouter is ILBRouter {
  409, 413:         IERC20[] memory _tokenPath,
  410, 414:         address _to,
  411, 415:         uint256 _deadline
- 412     :-    ) external payable override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
+      416:+    ) external payable override returns (uint256 amountOut) {
+      417:+        ensure(_deadline);
+      418:+        verifyInputs(_pairBinSteps, _tokenPath);
  413, 419:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
  414, 420: 
  415, 421:         _wavaxDepositAndTransfer(_pairs[0], msg.value);
@@ -434,7 +440,9 @@ contract LBRouter is ILBRouter {
  434, 440:         IERC20[] memory _tokenPath,
  435, 441:         address _to,
  436, 442:         uint256 _deadline
- 437     :-    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256[] memory amountsIn) {
+      443:+    ) external override returns (uint256[] memory amountsIn) {
+      444:+        ensure(_deadline);
+      445:+        verifyInputs(_pairBinSteps, _tokenPath);
  438, 446:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
  439, 447:         amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountOut);
  440, 448: 
@@ -462,7 +470,9 @@ contract LBRouter is ILBRouter {
  462, 470:         IERC20[] memory _tokenPath,
  463, 471:         address payable _to,
  464, 472:         uint256 _deadline
- 465     :-    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256[] memory amountsIn) {
+      473:+    ) external override returns (uint256[] memory amountsIn) {
+      474:+        ensure(_deadline);
+      475:+        verifyInputs(_pairBinSteps, _tokenPath);
  466, 476:         if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
  467, 477:             revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));
  468, 478: 
@@ -499,10 +509,10 @@ contract LBRouter is ILBRouter {
  499, 509:         external
  500, 510:         payable
  501, 511:         override
- 502     :-        ensure(_deadline)
- 503     :-        verifyInputs(_pairBinSteps, _tokenPath)
  504, 512:         returns (uint256[] memory amountsIn)
  505, 513:     {
+      514:+        ensure(_deadline);
+      515:+        verifyInputs(_pairBinSteps, _tokenPath);
  506, 516:         if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0]));
  507, 517: 
  508, 518:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
@@ -534,7 +544,9 @@ contract LBRouter is ILBRouter {
  534, 544:         IERC20[] memory _tokenPath,
  535, 545:         address _to,
  536, 546:         uint256 _deadline
- 537     :-    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
+      547:+    ) external override returns (uint256 amountOut) {
+      548:+        ensure(_deadline);
+      549:+        verifyInputs(_pairBinSteps, _tokenPath);
  538, 550:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
  539, 551: 
  540, 552:         IERC20 _targetToken = _tokenPath[_pairs.length];
@@ -564,7 +576,9 @@ contract LBRouter is ILBRouter {
  564, 576:         IERC20[] memory _tokenPath,
  565, 577:         address payable _to,
  566, 578:         uint256 _deadline
- 567     :-    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
+      579:+    ) external override returns (uint256 amountOut) {
+      580:+        ensure(_deadline);
+      581:+        verifyInputs(_pairBinSteps, _tokenPath);
  568, 582:         if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
  569, 583:             revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));
  570, 584: 
@@ -596,7 +610,9 @@ contract LBRouter is ILBRouter {
  596, 610:         IERC20[] memory _tokenPath,
  597, 611:         address _to,
  598, 612:         uint256 _deadline
- 599     :-    ) external payable override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
+      613:+    ) external payable override returns (uint256 amountOut) {
+      614:+        ensure(_deadline);
+      615:+        verifyInputs(_pairBinSteps, _tokenPath);
  600, 616:         if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0]));
  601, 617: 
  602, 618:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
@@ -656,9 +672,10 @@ contract LBRouter is ILBRouter {
  656, 672:     /// @return liquidityMinted Amounts of LBToken minted for each bin
  657, 673:     function _addLiquidity(LiquidityParameters memory _liq, ILBPair _LBPair)
  658, 674:         private
- 659     :-        ensure(_liq.deadline)
+      675:+        
  660, 676:         returns (uint256[] memory depositIds, uint256[] memory liquidityMinted)
  661, 677:     {
+      678:+        ensure(_liq.deadline);
  662, 679:         unchecked {
  663, 680:             if (_liq.deltaIds.length != _liq.distributionX.length && _liq.deltaIds.length != _liq.distributionY.length)
  664, 681:                 revert LBRouter__LengthsMismatch();
- src/LBToken.sol:32, 37, 42
diff --git a/src/LBToken.sol b/src/LBToken.sol
index 47aa528..8a184be 100644
--- a/src/LBToken.sol
+++ b/src/LBToken.sol
@@ -29,19 +29,16 @@ contract LBToken is ILBToken {
   29,  29:     string private constant _name = "Liquidity Book Token";
   30,  30:     string private constant _symbol = "LBT";
   31,  31: 
-  32     :-    modifier checkApproval(address _from, address _spender) {
+       32:+    function checkApproval(address _from, address _spender) private view {
   33,  33:         if (!_isApprovedForAll(_from, _spender)) revert LBToken__SpenderNotApproved(_from, _spender);
-  34     :-        _;
   35,  34:     }
   36,  35: 
-  37     :-    modifier checkAddresses(address _from, address _to) {
+       36:+    function checkAddresses(address _from, address _to) private pure {
   38,  37:         if (_from == address(0) || _to == address(0)) revert LBToken__TransferFromOrToAddress0();
-  39     :-        _;
   40,  38:     }
   41,  39: 
-  42     :-    modifier checkLength(uint256 _lengthA, uint256 _lengthB) {
+       40:+    function checkLength(uint256 _lengthA, uint256 _lengthB) private pure {
   43,  41:         if (_lengthA != _lengthB) revert LBToken__LengthMismatch(_lengthA, _lengthB);
-  44     :-        _;
   45,  42:     }
   46,  43: 
   47,  44:     /// @notice Returns the name of the token
@@ -81,9 +78,9 @@ contract LBToken is ILBToken {
   81,  78:         view
   82,  79:         virtual
   83,  80:         override
-  84     :-        checkLength(_accounts.length, _ids.length)
   85,  81:         returns (uint256[] memory batchBalances)
   86,  82:     {
+       83:+        checkLength(_accounts.length, _ids.length);
   87,  84:         batchBalances = new uint256[](_accounts.length);
   88,  85: 
   89,  86:         unchecked {
@@ -133,7 +130,9 @@ contract LBToken is ILBToken {
  133, 130:         address _to,
  134, 131:         uint256 _id,
  135, 132:         uint256 _amount
- 136     :-    ) public virtual override checkAddresses(_from, _to) checkApproval(_from, msg.sender) {
+      133:+    ) public virtual override {
+      134:+        checkAddresses(_from, _to);
+      135:+        checkApproval(_from, msg.sender);
  137, 136:         address _spender = msg.sender;
  138, 137: 
  139, 138:         _transfer(_from, _to, _id, _amount);
@@ -154,11 +153,11 @@ contract LBToken is ILBToken {
  154, 153:     )
  155, 154:         public
  156, 155:         virtual
- 157     :-        override
- 158     :-        checkLength(_ids.length, _amounts.length)
- 159     :-        checkAddresses(_from, _to)
- 160     :-        checkApproval(_from, msg.sender)
+      156:+        override   
  161, 157:     {
+      158:+        checkLength(_ids.length, _amounts.length);
+      159:+        checkAddresses(_from, _to);
+      160:+        checkApproval(_from, msg.sender);
  162, 161:         unchecked {
  163, 162:             for (uint256 i; i < _ids.length; ++i) {
  164, 163:                 _transfer(_from, _to, _ids[i], _amounts[i]);
- src/LBFactory.sol:215, 317, 350, 396, 434, 468, 474, 485, 493, 502, 520
diff --git a/src/LBFactory.sol b/src/LBFactory.sol
index 32ee39c..6b6a58f 100644
--- a/src/LBFactory.sol
+++ b/src/LBFactory.sol
@@ -212,7 +212,8 @@ contract LBFactory is PendingOwnable, ILBFactory {
  212, 212:     /// @notice Set the LBPair implementation address
  213, 213:     /// @dev Needs to be called by the owner
  214, 214:     /// @param _LBPairImplementation The address of the implementation
- 215     :-    function setLBPairImplementation(address _LBPairImplementation) external override onlyOwner {
+      215:+    function setLBPairImplementation(address _LBPairImplementation) external override {
+      216:+        onlyOwner();
  216, 217:         if (ILBPair(_LBPairImplementation).factory() != this)
  217, 218:             revert LBFactory__LBPairSafetyCheckFailed(_LBPairImplementation);
  218, 219: 
@@ -314,7 +315,8 @@ contract LBFactory is PendingOwnable, ILBFactory {
  314, 315:         IERC20 _tokenY,
  315, 316:         uint256 _binStep,
  316, 317:         bool _ignored
- 317     :-    ) external override onlyOwner {
+      318:+    ) external override {
+      319:+        onlyOwner();
  318, 320:         (IERC20 _tokenA, IERC20 _tokenB) = _sortTokens(_tokenX, _tokenY);
  319, 321: 
  320, 322:         LBPairInformation memory _LBPairInformation = _LBPairsInfo[_tokenA][_tokenB][_binStep];
@@ -347,7 +349,8 @@ contract LBFactory is PendingOwnable, ILBFactory {
  347, 349:         uint16 _protocolShare,
  348, 350:         uint24 _maxVolatilityAccumulated,
  349, 351:         uint16 _sampleLifetime
- 350     :-    ) external override onlyOwner {
+      352:+    ) external override {
+      353:+        onlyOwner();
  351, 354:         bytes32 _packedFeeParameters = _getPackedFeeParameters(
  352, 355:             _binStep,
  353, 356:             _baseFactor,
@@ -393,7 +396,8 @@ contract LBFactory is PendingOwnable, ILBFactory {
  393, 396: 
  394, 397:     /// @notice Remove the preset linked to a binStep
  395, 398:     /// @param _binStep The bin step to remove
- 396     :-    function removePreset(uint16 _binStep) external override onlyOwner {
+      399:+    function removePreset(uint16 _binStep) external override {
+      400:+        onlyOwner();
  397, 401:         if (_presets[_binStep] == bytes32(0)) revert LBFactory__BinStepHasNoPreset(_binStep);
  398, 402: 
  399, 403:         // Set the bit `_binStep` to 0
@@ -431,7 +435,8 @@ contract LBFactory is PendingOwnable, ILBFactory {
  431, 435:         uint24 _variableFeeControl,
  432, 436:         uint16 _protocolShare,
  433, 437:         uint24 _maxVolatilityAccumulated
- 434     :-    ) external override onlyOwner {
+      438:+    ) external override {
+      439:+        onlyOwner();
  435, 440:         ILBPair _LBPair = _getLBPairInformation(_tokenX, _tokenY, _binStep).LBPair;
  436, 441: 
  437, 442:         if (address(_LBPair) == address(0)) revert LBFactory__LBPairNotCreated(_tokenX, _tokenY, _binStep);
@@ -465,13 +470,15 @@ contract LBFactory is PendingOwnable, ILBFactory {
  465, 470: 
  466, 471:     /// @notice Function to set the recipient of the fees. This address needs to be able to receive ERC20s
  467, 472:     /// @param _feeRecipient The address of the recipient
- 468     :-    function setFeeRecipient(address _feeRecipient) external override onlyOwner {
+      473:+    function setFeeRecipient(address _feeRecipient) external override {
+      474:+        onlyOwner();
  469, 475:         _setFeeRecipient(_feeRecipient);
  470, 476:     }
  471, 477: 
  472, 478:     /// @notice Function to set the flash loan fee
  473, 479:     /// @param _flashLoanFee The value of the fee for flash loan
- 474     :-    function setFlashLoanFee(uint256 _flashLoanFee) external override onlyOwner {
+      480:+    function setFlashLoanFee(uint256 _flashLoanFee) external override {
+      481:+        onlyOwner();
  475, 482:         uint256 _oldFlashLoanFee = flashLoanFee;
  476, 483: 
  477, 484:         if (_oldFlashLoanFee == _flashLoanFee) revert LBFactory__SameFlashLoanFee(_flashLoanFee);
@@ -482,7 +489,8 @@ contract LBFactory is PendingOwnable, ILBFactory {
  482, 489: 
  483, 490:     /// @notice Function to set the creation restriction of the Factory
  484, 491:     /// @param _locked If the creation is restricted (true) or not (false)
- 485     :-    function setFactoryLockedState(bool _locked) external override onlyOwner {
+      492:+    function setFactoryLockedState(bool _locked) external override {
+      493:+        onlyOwner();
  486, 494:         if (creationUnlocked != _locked) revert LBFactory__FactoryLockIsAlreadyInTheSameState();
  487, 495:         creationUnlocked = !_locked;
  488, 496:         emit FactoryLockedStatusUpdated(_locked);
@@ -490,7 +498,8 @@ contract LBFactory is PendingOwnable, ILBFactory {
  490, 498: 
  491, 499:     /// @notice Function to add an asset to the whitelist of quote assets
  492, 500:     /// @param _quoteAsset The quote asset (e.g: AVAX, USDC...)
- 493     :-    function addQuoteAsset(IERC20 _quoteAsset) external override onlyOwner {
+      501:+    function addQuoteAsset(IERC20 _quoteAsset) external override {
+      502:+        onlyOwner();
  494, 503:         if (!_quoteAssetWhitelist.add(address(_quoteAsset)))
  495, 504:             revert LBFactory__QuoteAssetAlreadyWhitelisted(_quoteAsset);
  496, 505: 
@@ -499,7 +508,8 @@ contract LBFactory is PendingOwnable, ILBFactory {
  499, 508: 
  500, 509:     /// @notice Function to remove an asset to the whitelist of quote assets
  501, 510:     /// @param _quoteAsset The quote asset (e.g: AVAX, USDC...)
- 502     :-    function removeQuoteAsset(IERC20 _quoteAsset) external override onlyOwner {
+      511:+    function removeQuoteAsset(IERC20 _quoteAsset) external override {
+      512:+        onlyOwner();
  503, 513:         if (!_quoteAssetWhitelist.remove(address(_quoteAsset))) revert LBFactory__QuoteAssetNotWhitelisted(_quoteAsset);
  504, 514: 
  505, 515:         emit QuoteAssetRemoved(_quoteAsset);
@@ -517,7 +527,8 @@ contract LBFactory is PendingOwnable, ILBFactory {
  517, 527:         emit FeeRecipientSet(_oldFeeRecipient, _feeRecipient);
  518, 528:     }
  519, 529: 
- 520     :-    function forceDecay(ILBPair _LBPair) external override onlyOwner {
+      530:+    function forceDecay(ILBPair _LBPair) external override {
+      531:+        onlyOwner();
  521, 532:         _LBPair.forceDecay();
  522, 533:     }
  523, 534: 
- src/libraries/PendingOwnable.sol:29
diff --git a/src/libraries/PendingOwnable.sol b/src/libraries/PendingOwnable.sol
index f745362..bb29ec8 100644
--- a/src/libraries/PendingOwnable.sol
+++ b/src/libraries/PendingOwnable.sol
@@ -26,9 +26,8 @@ contract PendingOwnable is IPendingOwnable {
   26,  26:     address private _pendingOwner;
   27,  27: 
   28,  28:     /// @notice Throws if called by any account other than the owner.
-  29     :-    modifier onlyOwner() {
+       29:+    function onlyOwner() internal view {
   30,  30:         if (msg.sender != _owner) revert PendingOwnable__NotOwner();
-  31     :-        _;
   32,  31:     }
   33,  32: 
   34,  33:     /// @notice Throws if called by any account other than the pending owner.
@@ -56,7 +55,8 @@ contract PendingOwnable is IPendingOwnable {
   56,  55: 
   57,  56:     /// @notice Sets the pending owner address. This address will be able to become
   58,  57:     /// the owner of this contract by calling {becomeOwner}
-  59     :-    function setPendingOwner(address pendingOwner_) public override onlyOwner {
+       58:+    function setPendingOwner(address pendingOwner_) public override {
+       59:+        onlyOwner();
   60,  60:         if (pendingOwner_ == address(0)) revert PendingOwnable__AddressZero();
   61,  61:         if (_pendingOwner != address(0)) revert PendingOwnable__PendingOwnerAlreadySet();
   62,  62:         _setPendingOwner(pendingOwner_);
@@ -65,7 +65,8 @@ contract PendingOwnable is IPendingOwnable {
   65,  65:     /// @notice Revoke the pending owner address. This address will not be able to
   66,  66:     /// call {becomeOwner} to become the owner anymore.
   67,  67:     /// Can only be called by the owner
-  68     :-    function revokePendingOwner() public override onlyOwner {
+       68:+    function revokePendingOwner() public override {
+       69:+        onlyOwner();
   69,  70:         if (_pendingOwner == address(0)) revert PendingOwnable__NoPendingOwner();
   70,  71:         _setPendingOwner(address(0));
   71,  72:     }
@@ -81,7 +82,8 @@ contract PendingOwnable is IPendingOwnable {
   81,  82:     ///
   82,  83:     /// NOTE: Renouncing ownership will leave the contract without an owner,
   83,  84:     /// thereby removing any functionality that is only available to the owner.
-  84     :-    function renounceOwnership() public override onlyOwner {
+       85:+    function renounceOwnership() public override {
+       86:+        onlyOwner();
   85,  87:         _transferOwnership(address(0));
   86,  88:     }
   87,  89: 
diff --git a/test/mocks/Faucet.sol b/test/mocks/Faucet.sol
index 108bde7..da1835f 100644
--- a/test/mocks/Faucet.sol
+++ b/test/mocks/Faucet.sol
@@ -93,14 +93,16 @@ contract Faucet is PendingOwnable {
   93,  93:     /// @dev Tokens need to be owned by the faucet, and only mintable by the owner
   94,  94:     /// @param _token The address of the token
   95,  95:     /// @param _amountPerRequest The amount per request
-  96     :-    function addFaucetToken(IERC20 _token, uint96 _amountPerRequest) external onlyOwner {
+       96:+    function addFaucetToken(IERC20 _token, uint96 _amountPerRequest) external {
+       97:+        onlyOwner();
   97,  98:         _addFaucetToken(FaucetToken({ERC20: _token, amountPerRequest: _amountPerRequest}));
   98,  99:     }
   99, 100: 
  100, 101:     /// @notice Remove a token from the faucet
  101, 102:     /// @dev Token needs to be in the set, and AVAX can't be removed
  102, 103:     /// @param _token The address of the token
- 103     :-    function removeFaucetToken(IERC20 _token) external onlyOwner {
+      104:+    function removeFaucetToken(IERC20 _token) external {
+      105:+        onlyOwner();
  104, 106:         uint256 index = tokenToIndices[_token];
  105, 107: 
  106, 108:         require(index >= 2, "Not a faucet token");
@@ -115,7 +117,8 @@ contract Faucet is PendingOwnable {
  115, 117:     /// @notice Set the request cooldown for every users
  116, 118:     /// @dev This function needs to be called by the owner
  117, 119:     /// @param _requestCooldown The new cooldown
- 118     :-    function setRequestCooldown(uint256 _requestCooldown) external onlyOwner {
+      120:+    function setRequestCooldown(uint256 _requestCooldown) external {
+      121:+        onlyOwner();
  119, 122:         _setRequestCooldown(_requestCooldown);
  120, 123:     }
  121, 124: 
@@ -123,7 +126,8 @@ contract Faucet is PendingOwnable {
  123, 126:     /// @dev This function needs to be called by the owner
  124, 127:     /// @param _token The address of the token
  125, 128:     /// @param _amountPerRequest The new amount per request
- 126     :-    function setAmountPerRequest(IERC20 _token, uint96 _amountPerRequest) external onlyOwner {
+      129:+    function setAmountPerRequest(IERC20 _token, uint96 _amountPerRequest) external {
+      130:+        onlyOwner();
  127, 131:         _setAmountPerRequest(_token, _amountPerRequest);
  128, 132:     }
  129, 133: 
@@ -136,20 +140,23 @@ contract Faucet is PendingOwnable {
  136, 140:         IERC20 _token,
  137, 141:         address _to,
  138, 142:         uint256 _amount
- 139     :-    ) external onlyOwner {
+      143:+    ) external {
+      144:+        onlyOwner();
  140, 145:         if (address(_token) == address(0)) _sendAvax(_to, _amount);
  141, 146:         else _token.safeTransfer(_to, _amount);
  142, 147:     }
  143, 148: 
  144, 149:     /// @notice Set the address of the operator
  145, 150:     /// @param _newOperator The address of the new operator
- 146     :-    function setOperator(address _newOperator) external onlyOwner {
+      151:+    function setOperator(address _newOperator) external {
+      152:+        onlyOwner();
  147, 153:         operator = _newOperator;
  148, 154:     }
  149, 155: 
  150, 156:     /// @notice Set whether the direct request is unlocked or not
  151, 157:     /// @param _unlockedRequest The address of the new operator
- 152     :-    function setUnlockedRequest(bool _unlockedRequest) external onlyOwner {
+      158:+    function setUnlockedRequest(bool _unlockedRequest) external {
+      159:+        onlyOwner();
  153, 160:         unlockedRequest = _unlockedRequest;
  154, 161:     }
  155, 162: 

2. Use a more recent version of solidity (37 instances)

Use a solidity version of at least 0.8.0 to get overflow protection without SafeMath 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

NOTE: compared to 0.8.7 which the project uses by default

Deployment. Gas Saved: 821 258

Minimum Method Call. Gas Saved: 4 612

Average Method Call. Gas Saved: 16 393

Maximum Method Call. Gas Saved: 37 384

Overall gas change: -581 263 (-81.312%)

2022-10-traderjoe/src/interfaces/IJoeFactory.sol 2022-10-traderjoe/src/interfaces/IJoePair.sol 2022-10-traderjoe/src/interfaces/IJoeRouter01.sol 2022-10-traderjoe/src/interfaces/IJoeRouter02.sol 2022-10-traderjoe/src/interfaces/ILBFactory.sol 2022-10-traderjoe/src/interfaces/ILBFlashLoanCallback.sol 2022-10-traderjoe/src/interfaces/ILBPair.sol 2022-10-traderjoe/src/interfaces/ILBRouter.sol 2022-10-traderjoe/src/interfaces/ILBToken.sol 2022-10-traderjoe/src/interfaces/IPendingOwnable.sol 2022-10-traderjoe/src/interfaces/IWAVAX.sol 2022-10-traderjoe/src/libraries/BinHelper.sol 2022-10-traderjoe/src/libraries/BitMath.sol 2022-10-traderjoe/src/libraries/Buffer.sol 2022-10-traderjoe/src/libraries/Constants.sol 2022-10-traderjoe/src/libraries/Decoder.sol 2022-10-traderjoe/src/libraries/Encoder.sol 2022-10-traderjoe/src/libraries/FeeDistributionHelper.sol 2022-10-traderjoe/src/libraries/FeeHelper.sol 2022-10-traderjoe/src/libraries/JoeLibrary.sol 2022-10-traderjoe/src/libraries/Math128x128.sol 2022-10-traderjoe/src/libraries/Math512Bits.sol 2022-10-traderjoe/src/libraries/Oracle.sol 2022-10-traderjoe/src/libraries/PendingOwnable.sol 2022-10-traderjoe/src/libraries/ReentrancyGuardUpgradeable.sol 2022-10-traderjoe/src/libraries/SafeCast.sol 2022-10-traderjoe/src/libraries/SafeMath.sol 2022-10-traderjoe/src/libraries/Samples.sol 2022-10-traderjoe/src/libraries/SwapHelper.sol 2022-10-traderjoe/src/libraries/TokenHelper.sol 2022-10-traderjoe/src/libraries/TreeMath.sol 2022-10-traderjoe/src/LBErrors.sol 2022-10-traderjoe/src/LBFactory.sol 2022-10-traderjoe/src/LBPair.sol 2022-10-traderjoe/src/LBQuoter.sol 2022-10-traderjoe/src/LBRouter.sol 2022-10-traderjoe/src/LBToken.sol

  3,1: pragma solidity ^0.8.0;

3. Duplicated require()/revert() checks should be refactored to a modifier or function (38 instances)

Deployment. Gas Saved: 566 224

Minimum Method Call. Gas Saved: -424

Average Method Call. Gas Saved: -1 473

Maximum Method Call. Gas Saved: -2 818

Overall gas change: -174 947 (-0.950%)

- src/LBErrors.sol:link
diff --git a/src/LBErrors.sol b/src/LBErrors.sol
index 092ede5..d8e5ddd 100644
--- a/src/LBErrors.sol
+++ b/src/LBErrors.sol
@@ -4,6 +4,12 @@ pragma solidity ^0.8.0;
    4,   4: 
    5,   5: import "./interfaces/ILBPair.sol";
    6,   6: 
+        7:+/** Common errors */
+        8:+
+        9:+error IdOverflows(int256 id);
+       10:+error AddressZero();
+       11:+error InsufficientLiquidity();
+       12:+
    7,  13: /** LBRouter errors */
    8,  14: 
    9,  15: error LBRouter__SenderIsNotWAVAX();
@@ -14,7 +20,6 @@ error LBRouter__BrokenSwapSafetyCheck();
   14,  20: error LBRouter__NotFactoryOwner();
   15,  21: error LBRouter__TooMuchTokensIn(uint256 excess);
   16,  22: error LBRouter__BinReserveOverflows(uint256 id);
-  17     :-error LBRouter__IdOverflows(int256 id);
   18,  23: error LBRouter__LengthsMismatch();
   19,  24: error LBRouter__WrongTokenOrder();
   20,  25: error LBRouter__IdSlippageCaught(uint256 activeIdDesired, uint256 idSlippage, uint256 activeId);
@@ -51,7 +56,6 @@ error LBToken__TransferExceedsBalance(address from, uint256 id, uint256 amount);
   51,  56: error LBFactory__IdenticalAddresses(IERC20 token);
   52,  57: error LBFactory__QuoteAssetNotWhitelisted(IERC20 quoteAsset);
   53,  58: error LBFactory__QuoteAssetAlreadyWhitelisted(IERC20 quoteAsset);
-  54     :-error LBFactory__AddressZero();
   55,  59: error LBFactory__LBPairAlreadyExists(IERC20 tokenX, IERC20 tokenY, uint256 _binStep);
   56,  60: error LBFactory__LBPairNotCreated(IERC20 tokenX, IERC20 tokenY, uint256 binStep);
   57,  61: error LBFactory__DecreasingPeriods(uint16 filterPeriod, uint16 decayPeriod);
@@ -75,7 +79,6 @@ error LBFactory__ImplementationNotSet();
   75,  79: /** LBPair errors */
   76,  80: 
   77,  81: error LBPair__InsufficientAmounts();
-  78     :-error LBPair__AddressZero();
   79,  82: error LBPair__BrokenSwapSafetyCheck();
   80,  83: error LBPair__CompositionFactorFlawed(uint256 id);
   81,  84: error LBPair__InsufficientLiquidityMinted(uint256 id);
@@ -93,7 +96,6 @@ error LBPair__NewSizeTooSmall(uint256 newSize, uint256 oracleSize);
   93,  96: /** BinHelper errors */
   94,  97: 
   95,  98: error BinHelper__BinStepOverflows(uint256 bp);
-  96     :-error BinHelper__IdOverflows(int256 id);
   97,  99: error BinHelper__IntOverflows(uint256 id);
   98, 100: 
   99, 101: /** FeeDistributionHelper errors */
@@ -124,7 +126,6 @@ error PendingOwnable__NotOwner();
  124, 126: error PendingOwnable__NotPendingOwner();
  125, 127: error PendingOwnable__PendingOwnerAlreadySet();
  126, 128: error PendingOwnable__NoPendingOwner();
- 127     :-error PendingOwnable__AddressZero();
  128, 129: 
  129, 130: /** ReentrancyGuardUpgradeable errors */
  130, 131: 
@@ -173,9 +174,7 @@ error TreeMath__ErrorDepthSearch();
  173, 174: /** JoeLibrary errors */
  174, 175: 
  175, 176: error JoeLibrary__IdenticalAddresses();
- 176     :-error JoeLibrary__AddressZero();
  177, 177: error JoeLibrary__InsufficientAmount();
- 178     :-error JoeLibrary__InsufficientLiquidity();
  179, 178: 
  180, 179: /** TokenHelper errors */
  181, 180: 
@@ -184,3 +183,49 @@ error TokenHelper__TransferFailed(IERC20 token, address recipient, uint256 amoun
  184, 183: /** LBQuoter errors */
  185, 184: 
  186, 185: error LBQuoter_InvalidLength();
+      186:+
+      187:+library Validation {
+      188:+    function valid_id(int256 _id) pure internal {
+      189:+        if (_id < 0 || uint256(_id) > type(uint24).max) revert IdOverflows(_id);
+      190:+    }
+      191:+
+      192:+    function is_address_zero(address a) pure internal {
+      193:+        if (a == address(0)) revert AddressZero();
+      194:+    }
+      195:+
+      196:+    function valid_liquidity(uint256 a, uint256 b) pure internal {
+      197:+        if (a == 0 || b == 0) revert InsufficientLiquidity();
+      198:+    }
+      199:+
+      200:+    function bin_step_has_no_preset(bytes32 preset, uint16 binStep) pure internal {
+      201:+        if (preset == bytes32(0)) revert LBFactory__BinStepHasNoPreset(binStep);
+      202:+    }
+      203:+
+      204:+    function is_valid_length(uint256 length) pure internal {
+      205:+        if (length < 2) {
+      206:+            revert LBQuoter_InvalidLength();
+      207:+        }
+      208:+    }
+      209:+
+      210:+    function is_valid_tokens(IERC20 a, IERC20 b) pure internal {
+      211:+        if (a != b) revert LBRouter__WrongTokenOrder();
+      212:+    }
+      213:+
+      214:+    function amount_out_is_sufficient(uint256 min, uint256 out) pure internal {
+      215:+        if (min > out) revert LBRouter__InsufficientAmountOut(min, out);
+      216:+    }
+      217:+
+      218:+    function is_valid_token_path(IERC20 pl, IERC20 pr) pure internal {
+      219:+        if (pl != pr)
+      220:+            revert LBRouter__InvalidTokenPath(address(pl));
+      221:+    }
+      222:+
+      223:+    function is_max_amount_exceeded(uint256 _in, uint256 max) pure internal {
+      224:+        if (_in > max) revert LBRouter__MaxAmountInExceeded(max, _in);
+      225:+    }
+      226:+
+      227:+    function caugth_amount_slippage(uint256 xAdded, uint256 minXAdded, uint256 yAdded, uint256 minYAdded) pure internal {
+      228:+        if (xAdded < minXAdded || yAdded < minYAdded)
+      229:+                revert LBRouter__AmountSlippageCaught(minXAdded, xAdded, minYAdded, yAdded);
+      230:+    }
+      231:+}
\ No newline at end of file
- src/LBFactory.sol:136, 254, 259, 321, 397, 511
diff --git a/src/LBFactory.sol b/src/LBFactory.sol
index 32ee39c..b00b22a 100644
--- a/src/LBFactory.sol
+++ b/src/LBFactory.sol
@@ -133,7 +133,7 @@ contract LBFactory is PendingOwnable, ILBFactory {
  133, 133:         )
  134, 134:     {
  135, 135:         bytes32 _preset = _presets[_binStep];
- 136     :-        if (_preset == bytes32(0)) revert LBFactory__BinStepHasNoPreset(_binStep);
+      136:+        Validation.bin_step_has_no_preset(_preset, _binStep);
  137, 137: 
  138, 138:         uint256 _shift;
  139, 139: 
@@ -251,12 +251,12 @@ contract LBFactory is PendingOwnable, ILBFactory {
  251, 251:         // We sort token for storage efficiency, only one input needs to be stored
  252, 252:         (IERC20 _tokenA, IERC20 _tokenB) = _sortTokens(_tokenX, _tokenY);
  253, 253:         // single check is sufficient
- 254     :-        if (address(_tokenA) == address(0)) revert LBFactory__AddressZero();
+      254:+        Validation.is_address_zero(address(_tokenA));
  255, 255:         if (address(_LBPairsInfo[_tokenA][_tokenB][_binStep].LBPair) != address(0))
  256, 256:             revert LBFactory__LBPairAlreadyExists(_tokenX, _tokenY, _binStep);
  257, 257: 
  258, 258:         bytes32 _preset = _presets[_binStep];
- 259     :-        if (_preset == bytes32(0)) revert LBFactory__BinStepHasNoPreset(_binStep);
+      259:+        Validation.bin_step_has_no_preset(_preset, _binStep);
  260, 260: 
  261, 261:         uint256 _sampleLifetime = _preset.decode(type(uint16).max, 240);
  262, 262:         // We remove the bits that are not part of the feeParameters
@@ -318,7 +318,7 @@ contract LBFactory is PendingOwnable, ILBFactory {
  318, 318:         (IERC20 _tokenA, IERC20 _tokenB) = _sortTokens(_tokenX, _tokenY);
  319, 319: 
  320, 320:         LBPairInformation memory _LBPairInformation = _LBPairsInfo[_tokenA][_tokenB][_binStep];
- 321     :-        if (address(_LBPairInformation.LBPair) == address(0)) revert LBFactory__AddressZero();
+      321:+        Validation.is_address_zero(address(_LBPairInformation.LBPair));
  322, 322: 
  323, 323:         if (_LBPairInformation.ignoredForRouting == _ignored) revert LBFactory__LBPairIgnoredIsAlreadyInTheSameState();
  324, 324: 
@@ -394,7 +394,7 @@ contract LBFactory is PendingOwnable, ILBFactory {
  394, 394:     /// @notice Remove the preset linked to a binStep
  395, 395:     /// @param _binStep The bin step to remove
  396, 396:     function removePreset(uint16 _binStep) external override onlyOwner {
- 397     :-        if (_presets[_binStep] == bytes32(0)) revert LBFactory__BinStepHasNoPreset(_binStep);
+      397:+        Validation.bin_step_has_no_preset(_presets[_binStep], _binStep);
  398, 398: 
  399, 399:         // Set the bit `_binStep` to 0
  400, 400:         bytes32 _avPresets = _availablePresets;
@@ -508,7 +508,7 @@ contract LBFactory is PendingOwnable, ILBFactory {
  508, 508:     /// @notice Internal function to set the recipient of the fee
  509, 509:     /// @param _feeRecipient The address of the recipient
  510, 510:     function _setFeeRecipient(address _feeRecipient) internal {
- 511     :-        if (_feeRecipient == address(0)) revert LBFactory__AddressZero();
+      511:+        Validation.is_address_zero(_feeRecipient);
  512, 512: 
  513, 513:         address _oldFeeRecipient = feeRecipient;
  514, 514:         if (_oldFeeRecipient == _feeRecipient) revert LBFactory__SameFeeRecipient(_feeRecipient);
- src/LBPair.sol:91, 111
diff --git a/src/LBPair.sol b/src/LBPair.sol
index 717270e..cad9f06 100644
--- a/src/LBPair.sol
+++ b/src/LBPair.sol
@@ -88,7 +88,7 @@ contract LBPair is LBToken, ReentrancyGuardUpgradeable, ILBPair {
   88,  88:     /// @notice Set the factory address
   89,  89:     /// @param _factory The address of the factory
   90,  90:     constructor(ILBFactory _factory) LBToken() {
-  91     :-        if (address(_factory) == address(0)) revert LBPair__AddressZero();
+       91:+        Validation.is_address_zero(address(_factory));
   92,  92:         factory = _factory;
   93,  93:     }
   94,  94: 
@@ -108,7 +108,8 @@ contract LBPair is LBToken, ReentrancyGuardUpgradeable, ILBPair {
  108, 108:         uint16 _sampleLifetime,
  109, 109:         bytes32 _packedFeeParameters
  110, 110:     ) external override onlyFactory {
- 111     :-        if (address(_tokenX) == address(0) || address(_tokenY) == address(0)) revert LBPair__AddressZero();
+      111:+        Validation.is_address_zero(address(_tokenX));
+      112:+        Validation.is_address_zero(address(_tokenY));
  112, 113:         if (address(tokenX) != address(0)) revert LBPair__AlreadyInitialized();
  113, 114: 
  114, 115:         __ReentrancyGuard_init();
- src/LBQuoter.sol:59-61, 139-141
diff --git a/src/LBQuoter.sol b/src/LBQuoter.sol
index 53fdf0c..342ef5c 100644
--- a/src/LBQuoter.sol
+++ b/src/LBQuoter.sol
@@ -56,9 +56,7 @@ contract LBQuoter {
   56,  56:         view
   57,  57:         returns (Quote memory quote)
   58,  58:     {
-  59     :-        if (_route.length < 2) {
-  60     :-            revert LBQuoter_InvalidLength();
-  61     :-        }
+       59:+        Validation.is_valid_length(_route.length);
   62,  60: 
   63,  61:         quote.route = _route;
   64,  62: 
@@ -136,9 +134,7 @@ contract LBQuoter {
  136, 134:         view
  137, 135:         returns (Quote memory quote)
  138, 136:     {
- 139     :-        if (_route.length < 2) {
- 140     :-            revert LBQuoter_InvalidLength();
- 141     :-        }
+      137:+        Validation.is_valid_length(_route.length);
  142, 138:         quote.route = _route;
  143, 139: 
  144, 140:         uint256 swapLength = _route.length - 1;
- src/LBRouter.sol:217, 241, 366, 385-386, 394, 420, 442, 448, 467-468, 473, 479, 507, 512, 518, 550, 569-570, 581, 601, 614, 676, 690-691, 751-752
diff --git a/src/LBRouter.sol b/src/LBRouter.sol
index 567c49a..64c34d0 100644
--- a/src/LBRouter.sol
+++ b/src/LBRouter.sol
@@ -214,7 +214,7 @@ contract LBRouter is ILBRouter {
  214, 214:             _liquidityParameters.tokenY,
  215, 215:             _liquidityParameters.binStep
  216, 216:         );
- 217     :-        if (_liquidityParameters.tokenX != _LBPair.tokenX()) revert LBRouter__WrongTokenOrder();
+      217:+        Validation.is_valid_tokens(_liquidityParameters.tokenX, _LBPair.tokenX());
  218, 218: 
  219, 219:         _liquidityParameters.tokenX.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountX);
  220, 220:         _liquidityParameters.tokenY.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountY);
@@ -238,7 +238,7 @@ contract LBRouter is ILBRouter {
  238, 238:             _liquidityParameters.tokenY,
  239, 239:             _liquidityParameters.binStep
  240, 240:         );
- 241     :-        if (_liquidityParameters.tokenX != _LBPair.tokenX()) revert LBRouter__WrongTokenOrder();
+      241:+        Validation.is_valid_tokens(_liquidityParameters.tokenX, _LBPair.tokenX());
  242, 242: 
  243, 243:         if (_liquidityParameters.tokenX == wavax && _liquidityParameters.amountX == msg.value) {
  244, 244:             _wavaxDepositAndTransfer(address(_LBPair), msg.value);
@@ -363,7 +363,7 @@ contract LBRouter is ILBRouter {
  363, 363: 
  364, 364:         amountOut = _swapExactTokensForTokens(_amountIn, _pairs, _pairBinSteps, _tokenPath, _to);
  365, 365: 
- 366     :-        if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut);
+      366:+        Validation.amount_out_is_sufficient(_amountOutMin, amountOut);
  367, 367:     }
  368, 368: 
  369, 369:     /// @notice Swaps exact tokens for AVAX while performing safety checks
@@ -382,8 +382,7 @@ contract LBRouter is ILBRouter {
  382, 382:         address payable _to,
  383, 383:         uint256 _deadline
  384, 384:     ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
- 385     :-        if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
- 386     :-            revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));
+      385:+        Validation.is_valid_token_path(_tokenPath[_pairBinSteps.length], IERC20(wavax));
  387, 386: 
  388, 387:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
  389, 388: 
@@ -391,7 +390,7 @@ contract LBRouter is ILBRouter {
  391, 390: 
  392, 391:         amountOut = _swapExactTokensForTokens(_amountIn, _pairs, _pairBinSteps, _tokenPath, address(this));
  393, 392: 
- 394     :-        if (_amountOutMinAVAX > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMinAVAX, amountOut);
+      393:+        Validation.amount_out_is_sufficient(_amountOutMinAVAX, amountOut);
  395, 394: 
  396, 395:         wavax.withdraw(amountOut);
  397, 396:         _safeTransferAVAX(_to, amountOut);
@@ -417,7 +416,7 @@ contract LBRouter is ILBRouter {
  417, 416: 
  418, 417:         amountOut = _swapExactTokensForTokens(msg.value, _pairs, _pairBinSteps, _tokenPath, _to);
  419, 418: 
- 420     :-        if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut);
+      419:+        Validation.amount_out_is_sufficient(_amountOutMin, amountOut);
  421, 420:     }
  422, 421: 
  423, 422:     /// @notice Swaps tokens for exact tokens while performing safety checks
@@ -439,13 +438,13 @@ contract LBRouter is ILBRouter {
  439, 438:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
  440, 439:         amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountOut);
  441, 440: 
- 442     :-        if (amountsIn[0] > _amountInMax) revert LBRouter__MaxAmountInExceeded(_amountInMax, amountsIn[0]);
+      441:+        Validation.is_max_amount_exceeded(amountsIn[0], _amountInMax);
  443, 442: 
  444, 443:         _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], amountsIn[0]);
  445, 444: 
  446, 445:         uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, _to);
  447, 446: 
- 448     :-        if (_amountOutReal < _amountOut) revert LBRouter__InsufficientAmountOut(_amountOut, _amountOutReal);
+      447:+        Validation.amount_out_is_sufficient(_amountOut, _amountOutReal);
  449, 448:     }
  450, 449: 
  451, 450:     /// @notice Swaps tokens for exact AVAX while performing safety checks
@@ -464,19 +463,18 @@ contract LBRouter is ILBRouter {
  464, 463:         address payable _to,
  465, 464:         uint256 _deadline
  466, 465:     ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256[] memory amountsIn) {
- 467     :-        if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
- 468     :-            revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));
+      466:+        Validation.is_valid_token_path(_tokenPath[_pairBinSteps.length], IERC20(wavax));
  469, 467: 
  470, 468:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
  471, 469:         amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountAVAXOut);
  472, 470: 
- 473     :-        if (amountsIn[0] > _amountInMax) revert LBRouter__MaxAmountInExceeded(_amountInMax, amountsIn[0]);
+      471:+        Validation.is_max_amount_exceeded(amountsIn[0], _amountInMax);
  474, 472: 
  475, 473:         _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], amountsIn[0]);
  476, 474: 
  477, 475:         uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, address(this));
  478, 476: 
- 479     :-        if (_amountOutReal < _amountAVAXOut) revert LBRouter__InsufficientAmountOut(_amountAVAXOut, _amountOutReal);
+      477:+        Validation.amount_out_is_sufficient(_amountAVAXOut, _amountOutReal);
  480, 478: 
  481, 479:         wavax.withdraw(_amountOutReal);
  482, 480:         _safeTransferAVAX(_to, _amountOutReal);
@@ -504,18 +502,18 @@ contract LBRouter is ILBRouter {
  504, 502:         verifyInputs(_pairBinSteps, _tokenPath)
  505, 503:         returns (uint256[] memory amountsIn)
  506, 504:     {
- 507     :-        if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0]));
+      505:+        Validation.is_valid_token_path(_tokenPath[0], IERC20(wavax));
  508, 506: 
  509, 507:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
  510, 508:         amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountOut);
  511, 509: 
- 512     :-        if (amountsIn[0] > msg.value) revert LBRouter__MaxAmountInExceeded(msg.value, amountsIn[0]);
+      510:+        Validation.is_max_amount_exceeded(amountsIn[0], msg.value);
  513, 511: 
  514, 512:         _wavaxDepositAndTransfer(_pairs[0], amountsIn[0]);
  515, 513: 
  516, 514:         uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, _to);
  517, 515: 
- 518     :-        if (_amountOutReal < _amountOut) revert LBRouter__InsufficientAmountOut(_amountOut, _amountOutReal);
+      516:+        Validation.amount_out_is_sufficient(_amountOut, _amountOutReal);
  519, 517: 
  520, 518:         if (msg.value > amountsIn[0]) _safeTransferAVAX(_to, amountsIn[0] - msg.value);
  521, 519:     }
@@ -547,7 +545,7 @@ contract LBRouter is ILBRouter {
  547, 545:         _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _tokenPath, _to);
  548, 546: 
  549, 547:         amountOut = _targetToken.balanceOf(_to) - _balanceBefore;
- 550     :-        if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut);
+      548:+        Validation.amount_out_is_sufficient(_amountOutMin, amountOut);
  551, 549:     }
  552, 550: 
  553, 551:     /// @notice Swaps exact tokens for AVAX while performing safety checks supporting for fee on transfer tokens
@@ -566,8 +564,7 @@ contract LBRouter is ILBRouter {
  566, 564:         address payable _to,
  567, 565:         uint256 _deadline
  568, 566:     ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
- 569     :-        if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
- 570     :-            revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));
+      567:+        Validation.is_valid_token_path(_tokenPath[_pairBinSteps.length], IERC20(wavax));
  571, 568: 
  572, 569:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
  573, 570: 
@@ -578,7 +575,7 @@ contract LBRouter is ILBRouter {
  578, 575:         _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _tokenPath, address(this));
  579, 576: 
  580, 577:         amountOut = wavax.balanceOf(address(this)) - _balanceBefore;
- 581     :-        if (_amountOutMinAVAX > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMinAVAX, amountOut);
+      578:+        Validation.amount_out_is_sufficient(_amountOutMinAVAX, amountOut);
  582, 579: 
  583, 580:         wavax.withdraw(amountOut);
  584, 581:         _safeTransferAVAX(_to, amountOut);
@@ -598,7 +595,7 @@ contract LBRouter is ILBRouter {
  598, 595:         address _to,
  599, 596:         uint256 _deadline
  600, 597:     ) external payable override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
- 601     :-        if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0]));
+      598:+        Validation.is_valid_token_path(_tokenPath[0], IERC20(wavax));
  602, 599: 
  603, 600:         address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
  604, 601: 
@@ -611,7 +608,7 @@ contract LBRouter is ILBRouter {
  611, 608:         _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _tokenPath, _to);
  612, 609: 
  613, 610:         amountOut = _targetToken.balanceOf(_to) - _balanceBefore;
- 614     :-        if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut);
+      611:+        Validation.amount_out_is_sufficient(_amountOutMin, amountOut);
  615, 612:     }
  616, 613: 
  617, 614:     /// @notice Unstuck tokens that are sent to this contract by mistake
@@ -673,7 +670,7 @@ contract LBRouter is ILBRouter {
  673, 670:             depositIds = new uint256[](_liq.deltaIds.length);
  674, 671:             for (uint256 i; i < depositIds.length; ++i) {
  675, 672:                 int256 _id = int256(_activeId) + _liq.deltaIds[i];
- 676     :-                if (_id < 0 || uint256(_id) > type(uint24).max) revert LBRouter__IdOverflows(_id);
+      673:+                Validation.valid_id(_id);
  677, 674:                 depositIds[i] = uint256(_id);
  678, 675:             }
  679, 676: 
@@ -687,8 +684,7 @@ contract LBRouter is ILBRouter {
  687, 684:                 _liq.to
  688, 685:             );
  689, 686: 
- 690     :-            if (_amountXAdded < _liq.amountXMin || _amountYAdded < _liq.amountYMin)
- 691     :-                revert LBRouter__AmountSlippageCaught(_liq.amountXMin, _amountXAdded, _liq.amountYMin, _amountYAdded);
+      687:+            Validation.caugth_amount_slippage(_amountXAdded, _liq.amountXMin, _amountYAdded, _liq.amountYMin);
  692, 688:         }
  693, 689:     }
  694, 690: 
@@ -748,8 +744,7 @@ contract LBRouter is ILBRouter {
  748, 744:     ) private returns (uint256 amountX, uint256 amountY) {
  749, 745:         ILBToken(address(_LBPair)).safeBatchTransferFrom(msg.sender, address(_LBPair), _ids, _amounts);
  750, 746:         (amountX, amountY) = _LBPair.burn(_ids, _amounts, _to
... See the rest this report [here](https://github.com/code-423n4/2022-10-traderjoe-findings/blob/main/data/pfapostol-G.md)

#0 - GalloDaSballo

2022-11-09T23:39:37Z

##ย Inline Modifier Will award 1k

Solidity

1k

5. Use of the memory keyword when storage pointer should be used (4 instances)

1k

6. Using calldata instead of memory for read-only arguments in external functions saves gas (1 instance)

1k

Else 88

Very good submission!

4088

#1 - c4-judge

2022-11-16T21:25:37Z

GalloDaSballo marked the issue as grade-a

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax ยฉ 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter