LI.FI contest - IllIllI's results

Bridge & DEX Aggregation.

General Information

Platform: Code4rena

Start Date: 24/03/2022

Pot Size: $75,000 USDC

Total HM: 15

Participants: 59

Period: 7 days

Judge: gzeon

Id: 103

League: ETH

LI.FI

Findings Distribution

Researcher Performance

Rank: 38/59

Findings: 2

Award: $203.26

๐ŸŒŸ Selected for report: 0

๐Ÿš€ Solo Findings: 0

Low Risk Issues

_executeSwaps() requires a specific order of swaps if the same asset is involved

Consider the following chain of swaps <token>(<amount>): A(1)->B(2), C(1)->B(2), B(5)->D. If the specified order happens, the first two swaps will have deposited the majority of the funds needed for the third. If the swaps are shuffled, it's possible for the third swap to come first, transferring B(5) first, then getting an additional B(4) from the other two swaps. Documentation should make it clear that the order in the array is the order that things will take place in (i.e. a list of swaps and not a set of swaps), and that this functionality should not be used for batching requests from multiple users.

        if (!LibAsset.isNativeAsset(fromAssetId) && LibAsset.getOwnBalance(fromAssetId) < fromAmount) {
            LibAsset.transferFromERC20(fromAssetId, msg.sender, address(this), fromAmount);
        }

        if (!LibAsset.isNativeAsset(fromAssetId)) {
            LibAsset.approveERC20(IERC20(fromAssetId), _swapData.approveTo, fromAmount);
        }

https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Libraries/LibSwap.sol#L33-L39

Unnecessary receive()

The added capability of the contract to receive Ether, without any purpose, is incorrect state handling. Nothing is emitted, no revert stateemnts are added, and no calldata is passed.

  1. File: src/LiFiDiamond.sol (line 62)
    receive() external payable {}

require() should be used instead of assert()

  1. File: src/Facets/WithdrawFacet.sol (line 30)
            assert(_amount <= self.balance);
  1. File: src/Facets/WithdrawFacet.sol (line 34)
            assert(_amount <= assetBalance);

Slippage has no bounds checking, which could lead to excessive transaction costs

  1. File: src/Facets/CBridgeFacet.sol: (lines 149-169)
        if (LibAsset.isNativeAsset(_cBridgeData.token)) {
            ICBridge(bridge).sendNative(
                _cBridgeData.receiver,
                _cBridgeData.amount,
                _cBridgeData.dstChainId,
                _cBridgeData.nonce,
                _cBridgeData.maxSlippage
            );
        } else {
            // Give CBridge approval to bridge tokens
            LibAsset.approveERC20(IERC20(_cBridgeData.token), bridge, _cBridgeData.amount);
            // solhint-disable check-send-result
            ICBridge(bridge).send(
                _cBridgeData.receiver,
                _cBridgeData.token,
                _cBridgeData.amount,
                _cBridgeData.dstChainId,
                _cBridgeData.nonce,
                _cBridgeData.maxSlippage
            );
        }

Non-critical Issues

No two-phase ownership transfer pattern

Consider adding a two-phase transfer, where the current owner nominates the next owner, and the next owner has to call acceptOwnership() to become the new owner. This prevents passing the ownership to an account that is unable to use it.

  1. File: src/Libraries/LibDiamond.sol (lines 44-49)
    function setContractOwner(address _newOwner) internal {
        DiamondStorage storage ds = diamondStorage();
        address previousOwner = ds.contractOwner;
        ds.contractOwner = _newOwner;
        emit OwnershipTransferred(previousOwner, _newOwner);
    }

safeApprove() is deprecated

Deprecated in favor of safeIncreaseAllowance() and safeDecreaseAllowance()

  1. File: src/Libraries/LibAsset.sol (line 67)
            if (allowance > 0) SafeERC20.safeApprove(IERC20(assetId), spender, 0);
  1. File: src/Libraries/LibAsset.sol (line 68)
            SafeERC20.safeApprove(IERC20(assetId), spender, MAX_INT);

Event is missing indexed fields

Each event should use three indexed fields if there are three or more fields

  1. File: src/Libraries/LibSwap.sol (lines 19-27)
    event AssetSwapped(
        bytes32 transactionId,
        address dex,
        address fromAssetId,
        address toAssetId,
        uint256 fromAmount,
        uint256 toAmount,
        uint256 timestamp
    );
  1. File: src/Libraries/LibDiamond.sol (line 59)
    event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
  1. File: src/Interfaces/IDiamondCut.sol (line 30)
    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
  1. File: src/Interfaces/ITransactionManager.sol (line 152)
    event LiquidityAdded(address indexed router, address indexed assetId, uint256 amount, address caller);
  1. File: src/Interfaces/ITransactionManager.sol (line 154)
    event LiquidityRemoved(address indexed router, address indexed assetId, uint256 amount, address recipient);
  1. File: src/Interfaces/ILiFi.sol (lines 20-30)
    event LiFiTransferStarted(
        bytes32 indexed transactionId,
        string integrator,
        address referrer,
        address sendingAssetId,
        address receivingAssetId,
        address receiver,
        uint256 amount,
        uint256 destinationChainId,
        uint256 timestamp
    );
  1. File: src/Interfaces/ILiFi.sol (lines 32-38)
    event LiFiTransferCompleted(
        bytes32 indexed transactionId,
        address receivingAssetId,
        address receiver,
        uint256 amount,
        uint256 timestamp
    );
  1. File: src/Interfaces/ILiFi.sol (lines 40-50)
    event LiFiTransferConfirmed(
        bytes32 indexed transactionId,
        string integrator,
        address referrer,
        address sendingAssetId,
        address receivingAssetId,
        address receiver,
        uint256 amount,
        uint256 destinationChainId,
        uint256 timestamp
    );
  1. File: src/Interfaces/ILiFi.sol (lines 51-61)
    event LiFiTransferRefunded(
        bytes32 indexed transactionId,
        string integrator,
        address referrer,
        address sendingAssetId,
        address receivingAssetId,
        address receiver,
        uint256 amount,
        uint256 destinationChainId,
        uint256 timestamp
    );
  1. File: src/Interfaces/ILiFi.sol (line 62)
    event Inited(address indexed bridge, uint64 chainId);
  1. File: src/Facets/NXTPFacet.sol (lines 25-29)
    event NXTPBridgeStarted(
        bytes32 indexed lifiTransactionId,
        bytes32 nxtpTransactionId,
        ITransactionManager.TransactionData txData
    );
  1. File: src/Facets/WithdrawFacet.sol (line 12)
    event LogWithdraw(address indexed _assetAddress, address _from, uint256 amount);

public functions not called by the contract should be declared external instead

Contracts are allowed to override their parents' functions and change the visibility from external to public.

  1. File: src/Facets/NXTPFacet.sol (line 46)
    function startBridgeTokensViaNXTP(LiFiData memory _lifiData, ITransactionManager.PrepareArgs memory _nxtpData)
  1. File: src/Facets/NXTPFacet.sol (lines 85-88)
    function swapAndStartBridgeTokensViaNXTP(
        LiFiData memory _lifiData,
        LibSwap.SwapData[] calldata _swapData,
        ITransactionManager.PrepareArgs memory _nxtpData
  1. File: src/Facets/NXTPFacet.sol (lines 124-128)
    function completeBridgeTokensViaNXTP(
        LiFiData memory _lifiData,
        address assetId,
        address receiver,
        uint256 amount
  1. File: src/Facets/NXTPFacet.sol (lines 150-154)
    function swapAndCompleteBridgeTokensViaNXTP(
        LiFiData memory _lifiData,
        LibSwap.SwapData[] calldata _swapData,
        address finalAssetId,
        address receiver
  1. File: src/Facets/HopFacet.sol (line 61)
    function startBridgeTokensViaHop(LiFiData memory _lifiData, HopData calldata _hopData) public payable {
  1. File: src/Facets/HopFacet.sol (lines 95-98)
    function swapAndStartBridgeTokensViaHop(
        LiFiData memory _lifiData,
        LibSwap.SwapData[] calldata _swapData,
        HopData memory _hopData
  1. File: src/Facets/GenericSwapFacet.sol (line 22)
    function swapTokensGeneric(LiFiData memory _lifiData, LibSwap.SwapData[] calldata _swapData) public payable {
  1. File: src/Facets/WithdrawFacet.sol (lines 20-23)
    function withdraw(
        address _assetAddress,
        address _to,
        uint256 _amount
  1. File: src/Facets/AnyswapFacet.sol (line 35)
    function startBridgeTokensViaAnyswap(LiFiData memory _lifiData, AnyswapData calldata _anyswapData) public payable {
  1. File: src/Facets/AnyswapFacet.sol (lines 74-77)
    function swapAndStartBridgeTokensViaAnyswap(
        LiFiData memory _lifiData,
        LibSwap.SwapData[] calldata _swapData,
        AnyswapData memory _anyswapData
  1. File: src/Facets/CBridgeFacet.sol (line 57)
    function startBridgeTokensViaCBridge(LiFiData memory _lifiData, CBridgeData calldata _cBridgeData) public payable {
  1. File: src/Facets/CBridgeFacet.sol (lines 92-95)
    function swapAndStartBridgeTokensViaCBridge(
        LiFiData memory _lifiData,
        LibSwap.SwapData[] calldata _swapData,
        CBridgeData memory _cBridgeData

constants should be defined rather than using magic numbers

  1. File: src/Libraries/LibUtil.sol (line 11)
        if (_res.length < 68) return "Transaction reverted silently";
  1. File: src/Libraries/LibUtil.sol (line 12)
        bytes memory revertData = _res.slice(4, _res.length - 4); // Remove the selector which is the first 4 bytes
  1. File: src/Libraries/LibUtil.sol (line 12)
        bytes memory revertData = _res.slice(4, _res.length - 4); // Remove the selector which is the first 4 bytes

File is missing NatSpec

  1. File: src/Libraries/LibSwap.sol (line 0)
// SPDX-License-Identifier: MIT
  1. File: src/Libraries/LibUtil.sol (line 0)
// SPDX-License-Identifier: MIT
  1. File: src/Libraries/LibDiamond.sol (line 0)
// SPDX-License-Identifier: MIT
  1. File: src/Libraries/LibStorage.sol (line 0)
// SPDX-License-Identifier: MIT
  1. File: src/Interfaces/IAnyswapRouter.sol (line 0)
// SPDX-License-Identifier: MIT
  1. File: src/Interfaces/IHopBridge.sol (line 0)
// SPDX-License-Identifier: MIT
  1. File: src/Interfaces/IAnyswapToken.sol (line 0)
// SPDX-License-Identifier: MIT
  1. File: src/Interfaces/ILiFi.sol (line 0)
// SPDX-License-Identifier: MIT
  1. File: src/Interfaces/ICBridge.sol (line 0)
// SPDX-License-Identifier: MIT
  1. File: src/LiFiDiamond.sol (line 0)
// SPDX-License-Identifier: MIT
  1. File: src/Facets/OwnershipFacet.sol (line 0)
// SPDX-License-Identifier: MIT
  1. File: src/Facets/Swapper.sol (line 0)
// SPDX-License-Identifier: MIT

Non-library/interface files should use fixed compiler versions, not floating ones

  1. File: src/LiFiDiamond.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/DexManagerFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/NXTPFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/OwnershipFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/HopFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/Swapper.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/GenericSwapFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/DiamondCutFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/WithdrawFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/AnyswapFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/DiamondLoupeFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/CBridgeFacet.sol (line 2)
pragma solidity ^0.8.7;

2**<n> - 1 should be re-written as type(uint<n>).max

  1. File: src/Libraries/LibSwap.sol (line 8)
    uint256 private constant MAX_INT = 2**256 - 1;
  1. File: src/Libraries/LibAsset.sol (line 15)
    uint256 private constant MAX_INT = 2**256 - 1;

Typos

  1. File: src/Interfaces/ITransactionManager.sol (line 77)
     *                      the inforamtion that does change between chains

inforamtion

  1. File: src/LiFiDiamond.sol (line 11)
        // Add the diamondCut external function from the diamondCutFacet

diamondCutFacet -> _diamondCutFacet

  1. File: src/Facets/DexManagerFacet.sol (line 28)
    /// @notice Batch register the addresss of DEX contracts to be approved for swapping.

addresss

  1. File: src/Facets/HopFacet.sol (line 131)
     * @dev Conatains the business logic for the bridge via Hop Protocol

Conatains

Non-exploitable reentrancies

Code should follow the best-practice of the Checks-Effects-Interactions pattern

Reentrancy in NXTPFacet._startBridge(bytes32,ITransactionManager.PrepareArgs) (src/Facets/NXTPFacet.sol#175-188): External calls: - LibAsset.approveERC20(IERC20(sendingAssetId),address(s.nxtpTxManager),_nxtpData.amount) (src/Facets/NXTPFacet.sol#180) - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) External calls sending eth: - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) Event emitted after the call(s): - NXTPBridgeStarted(_transactionId,result.transactionId,result) (src/Facets/NXTPFacet.sol#187) Reentrancy in NXTPFacet.completeBridgeTokensViaNXTP(ILiFi.LiFiData,address,address,uint256) (src/Facets/NXTPFacet.sol#124-140): External calls: - LibAsset.transferFromERC20(assetId,msg.sender,address(this),amount) (src/Facets/NXTPFacet.sol#134) - LibAsset.transferAsset(assetId,address(receiver),amount) (src/Facets/NXTPFacet.sol#137) Event emitted after the call(s): - LiFiTransferCompleted(_lifiData.transactionId,assetId,receiver,amount,block.timestamp) (src/Facets/NXTPFacet.sol#139) Reentrancy in AnyswapFacet.startBridgeTokensViaAnyswap(ILiFi.LiFiData,AnyswapFacet.AnyswapData) (src/Facets/AnyswapFacet.sol#35-66): External calls: - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#36) - _anyswapData.token != address(0) && underlyingToken != IAnyswapRouter(_anyswapData.router).wNATIVE() (src/Facets/AnyswapFacet.sol#37) - LibAsset.transferFromERC20(underlyingToken,msg.sender,address(this),_anyswapData.amount) (src/Facets/AnyswapFacet.sol#43) - _startBridge(_anyswapData) (src/Facets/AnyswapFacet.sol#53) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#134) - underlyingToken == IAnyswapRouter(_anyswapData.router).wNATIVE() (src/Facets/AnyswapFacet.sol#136) - IAnyswapRouter(_anyswapData.router).anySwapOutNative{value: _anyswapData.amount}(_anyswapData.token,_anyswapData.recipient,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#137-141) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(underlyingToken),_anyswapData.router,_anyswapData.amount) (src/Facets/AnyswapFacet.sol#149) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - IAnyswapRouter(_anyswapData.router).anySwapOutUnderlying(_anyswapData.token,_anyswapData.recipient,_anyswapData.amount,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#151-156) - LibAsset.approveERC20(IERC20(_anyswapData.token),_anyswapData.router,_anyswapData.amount) (src/Facets/AnyswapFacet.sol#159) - IAnyswapRouter(_anyswapData.router).anySwapOut(_anyswapData.token,_anyswapData.recipient,_anyswapData.amount,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#161-166) External calls sending eth: - _startBridge(_anyswapData) (src/Facets/AnyswapFacet.sol#53) - IAnyswapRouter(_anyswapData.router).anySwapOutNative{value: _anyswapData.amount}(_anyswapData.token,_anyswapData.recipient,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#137-141) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/AnyswapFacet.sol#55-65) Reentrancy in CBridgeFacet.startBridgeTokensViaCBridge(ILiFi.LiFiData,CBridgeFacet.CBridgeData) (src/Facets/CBridgeFacet.sol#57-84): External calls: - LibAsset.transferFromERC20(_cBridgeData.token,msg.sender,address(this),_cBridgeData.amount) (src/Facets/CBridgeFacet.sol#61) - _startBridge(_cBridgeData) (src/Facets/CBridgeFacet.sol#71) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - ICBridge(bridge).sendNative(_cBridgeData.receiver,_cBridgeData.amount,_cBridgeData.dstChainId,_cBridgeData.nonce,_cBridgeData.maxSlippage) (src/Facets/CBridgeFacet.sol#150-156) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibAsset.approveERC20(IERC20(_cBridgeData.token),bridge,_cBridgeData.amount) (src/Facets/CBridgeFacet.sol#159) - ICBridge(bridge).send(_cBridgeData.receiver,_cBridgeData.token,_cBridgeData.amount,_cBridgeData.dstChainId,_cBridgeData.nonce,_cBridgeData.maxSlippage) (src/Facets/CBridgeFacet.sol#161-168) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) External calls sending eth: - _startBridge(_cBridgeData) (src/Facets/CBridgeFacet.sol#71) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/CBridgeFacet.sol#73-83) Reentrancy in HopFacet.startBridgeTokensViaHop(ILiFi.LiFiData,HopFacet.HopData) (src/Facets/HopFacet.sol#61-87): External calls: - LibAsset.transferFromERC20(sendingAssetId,msg.sender,address(this),_hopData.amount) (src/Facets/HopFacet.sol#67) - _startBridge(_hopData) (src/Facets/HopFacet.sol#74) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - LibAsset.approveERC20(IERC20(sendingAssetId),bridge,_hopData.amount) (src/Facets/HopFacet.sol#149) - IHopBridge(bridge).sendToL2{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.destinationAmountOutMin,_hopData.destinationDeadline,address(0),0) (src/Facets/HopFacet.sol#155-163) - IHopBridge(bridge).swapAndSend{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.bonderFee,_hopData.amountOutMin,_hopData.deadline,_hopData.destinationAmountOutMin,_hopData.destinationDeadline) (src/Facets/HopFacet.sol#167-176) External calls sending eth: - _startBridge(_hopData) (src/Facets/HopFacet.sol#74) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - IHopBridge(bridge).sendToL2{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.destinationAmountOutMin,_hopData.destinationDeadline,address(0),0) (src/Facets/HopFacet.sol#155-163) - IHopBridge(bridge).swapAndSend{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.bonderFee,_hopData.amountOutMin,_hopData.deadline,_hopData.destinationAmountOutMin,_hopData.destinationDeadline) (src/Facets/HopFacet.sol#167-176) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/HopFacet.sol#76-86) Reentrancy in NXTPFacet.startBridgeTokensViaNXTP(ILiFi.LiFiData,ITransactionManager.PrepareArgs) (src/Facets/NXTPFacet.sol#46-76): External calls: - LibAsset.transferFromERC20(sendingAssetId,msg.sender,address(this),_nxtpData.amount) (src/Facets/NXTPFacet.sol#55) - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#63) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.approveERC20(IERC20(sendingAssetId),address(s.nxtpTxManager),_nxtpData.amount) (src/Facets/NXTPFacet.sol#180) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) External calls sending eth: - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#63) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/NXTPFacet.sol#65-75) - NXTPBridgeStarted(_transactionId,result.transactionId,result) (src/Facets/NXTPFacet.sol#187) - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#63) Reentrancy in LibSwap.swap(bytes32,LibSwap.SwapData) (src/Libraries/LibSwap.sol#29-58): External calls: - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) External calls sending eth: - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) Event emitted after the call(s): - AssetSwapped(transactionId,_swapData.callTo,_swapData.sendingAssetId,_swapData.receivingAssetId,fromAmount,toAmount,block.timestamp) (src/Libraries/LibSwap.sol#49-57) Reentrancy in NXTPFacet.swapAndCompleteBridgeTokensViaNXTP(ILiFi.LiFiData,LibSwap.SwapData[],address,address) (src/Facets/NXTPFacet.sol#150-171): External calls: - _executeSwaps(_lifiData,_swapData) (src/Facets/NXTPFacet.sol#159) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - LibAsset.transferAsset(finalAssetId,address(receiver),finalBalance) (src/Facets/NXTPFacet.sol#167) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/NXTPFacet.sol#159) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) Event emitted after the call(s): - LiFiTransferCompleted(_lifiData.transactionId,finalAssetId,receiver,finalBalance,block.timestamp) (src/Facets/NXTPFacet.sol#170) Reentrancy in AnyswapFacet.swapAndStartBridgeTokensViaAnyswap(ILiFi.LiFiData,LibSwap.SwapData[],AnyswapFacet.AnyswapData) (src/Facets/AnyswapFacet.sol#74-123): External calls: - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#79) - _anyswapData.token != address(0) && underlyingToken != IAnyswapRouter(_anyswapData.router).wNATIVE() (src/Facets/AnyswapFacet.sol#80) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#88) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#88) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) Event emitted after the call(s): - AssetSwapped(transactionId,_swapData.callTo,_swapData.sendingAssetId,_swapData.receivingAssetId,fromAmount,toAmount,block.timestamp) (src/Libraries/LibSwap.sol#49-57) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#88) Reentrancy in AnyswapFacet.swapAndStartBridgeTokensViaAnyswap(ILiFi.LiFiData,LibSwap.SwapData[],AnyswapFacet.AnyswapData) (src/Facets/AnyswapFacet.sol#74-123): External calls: - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#79) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#99) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#99) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) Event emitted after the call(s): - AssetSwapped(transactionId,_swapData.callTo,_swapData.sendingAssetId,_swapData.receivingAssetId,fromAmount,toAmount,block.timestamp) (src/Libraries/LibSwap.sol#49-57) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#99) Reentrancy in AnyswapFacet.swapAndStartBridgeTokensViaAnyswap(ILiFi.LiFiData,LibSwap.SwapData[],AnyswapFacet.AnyswapData) (src/Facets/AnyswapFacet.sol#74-123): External calls: - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#79) - _anyswapData.token != address(0) && underlyingToken != IAnyswapRouter(_anyswapData.router).wNATIVE() (src/Facets/AnyswapFacet.sol#80) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#88) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#99) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_anyswapData) (src/Facets/AnyswapFacet.sol#110) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - underlyingToken = IAnyswapToken(_anyswapData.token).underlying() (src/Facets/AnyswapFacet.sol#134) - underlyingToken == IAnyswapRouter(_anyswapData.router).wNATIVE() (src/Facets/AnyswapFacet.sol#136) - IAnyswapRouter(_anyswapData.router).anySwapOutNative{value: _anyswapData.amount}(_anyswapData.token,_anyswapData.recipient,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#137-141) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(underlyingToken),_anyswapData.router,_anyswapData.amount) (src/Facets/AnyswapFacet.sol#149) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - IAnyswapRouter(_anyswapData.router).anySwapOutUnderlying(_anyswapData.token,_anyswapData.recipient,_anyswapData.amount,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#151-156) - LibAsset.approveERC20(IERC20(_anyswapData.token),_anyswapData.router,_anyswapData.amount) (src/Facets/AnyswapFacet.sol#159) - IAnyswapRouter(_anyswapData.router).anySwapOut(_anyswapData.token,_anyswapData.recipient,_anyswapData.amount,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#161-166) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#88) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _executeSwaps(_lifiData,_swapData) (src/Facets/AnyswapFacet.sol#99) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_anyswapData) (src/Facets/AnyswapFacet.sol#110) - IAnyswapRouter(_anyswapData.router).anySwapOutNative{value: _anyswapData.amount}(_anyswapData.token,_anyswapData.recipient,_anyswapData.toChainId) (src/Facets/AnyswapFacet.sol#137-141) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/AnyswapFacet.sol#112-122) Reentrancy in CBridgeFacet.swapAndStartBridgeTokensViaCBridge(ILiFi.LiFiData,LibSwap.SwapData[],CBridgeFacet.CBridgeData) (src/Facets/CBridgeFacet.sol#92-134): External calls: - _executeSwaps(_lifiData,_swapData) (src/Facets/CBridgeFacet.sol#101) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _executeSwaps(_lifiData,_swapData) (src/Facets/CBridgeFacet.sol#112) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_cBridgeData) (src/Facets/CBridgeFacet.sol#121) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - ICBridge(bridge).sendNative(_cBridgeData.receiver,_cBridgeData.amount,_cBridgeData.dstChainId,_cBridgeData.nonce,_cBridgeData.maxSlippage) (src/Facets/CBridgeFacet.sol#150-156) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibAsset.approveERC20(IERC20(_cBridgeData.token),bridge,_cBridgeData.amount) (src/Facets/CBridgeFacet.sol#159) - ICBridge(bridge).send(_cBridgeData.receiver,_cBridgeData.token,_cBridgeData.amount,_cBridgeData.dstChainId,_cBridgeData.nonce,_cBridgeData.maxSlippage) (src/Facets/CBridgeFacet.sol#161-168) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/CBridgeFacet.sol#101) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _executeSwaps(_lifiData,_swapData) (src/Facets/CBridgeFacet.sol#112) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_cBridgeData) (src/Facets/CBridgeFacet.sol#121) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/CBridgeFacet.sol#123-133) Reentrancy in HopFacet.swapAndStartBridgeTokensViaHop(ILiFi.LiFiData,LibSwap.SwapData[],HopFacet.HopData) (src/Facets/HopFacet.sol#95-126): External calls: - _executeSwaps(_lifiData,_swapData) (src/Facets/HopFacet.sol#105) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_hopData) (src/Facets/HopFacet.sol#113) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - LibAsset.approveERC20(IERC20(sendingAssetId),bridge,_hopData.amount) (src/Facets/HopFacet.sol#149) - IHopBridge(bridge).sendToL2{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.destinationAmountOutMin,_hopData.destinationDeadline,address(0),0) (src/Facets/HopFacet.sol#155-163) - IHopBridge(bridge).swapAndSend{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.bonderFee,_hopData.amountOutMin,_hopData.deadline,_hopData.destinationAmountOutMin,_hopData.destinationDeadline) (src/Facets/HopFacet.sol#167-176) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/HopFacet.sol#105) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_hopData) (src/Facets/HopFacet.sol#113) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - IHopBridge(bridge).sendToL2{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.destinationAmountOutMin,_hopData.destinationDeadline,address(0),0) (src/Facets/HopFacet.sol#155-163) - IHopBridge(bridge).swapAndSend{value: value}(_hopData.chainId,_hopData.recipient,_hopData.amount,_hopData.bonderFee,_hopData.amountOutMin,_hopData.deadline,_hopData.destinationAmountOutMin,_hopData.destinationDeadline) (src/Facets/HopFacet.sol#167-176) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/HopFacet.sol#115-125) Reentrancy in NXTPFacet.swapAndStartBridgeTokensViaNXTP(ILiFi.LiFiData,LibSwap.SwapData[],ITransactionManager.PrepareArgs) (src/Facets/NXTPFacet.sol#85-115): External calls: - _executeSwaps(_lifiData,_swapData) (src/Facets/NXTPFacet.sol#94) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#102) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.approveERC20(IERC20(sendingAssetId),address(s.nxtpTxManager),_nxtpData.amount) (src/Facets/NXTPFacet.sol#180) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/NXTPFacet.sol#94) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#102) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - result = s.nxtpTxManager.prepare{value: value}(_nxtpData) (src/Facets/NXTPFacet.sol#185) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/NXTPFacet.sol#104-114) - NXTPBridgeStarted(_transactionId,result.transactionId,result) (src/Facets/NXTPFacet.sol#187) - _startBridge(_lifiData.transactionId,_nxtpData) (src/Facets/NXTPFacet.sol#102) Reentrancy in GenericSwapFacet.swapTokensGeneric(ILiFi.LiFiData,LibSwap.SwapData[]) (src/Facets/GenericSwapFacet.sol#22-43): External calls: - _executeSwaps(_lifiData,_swapData) (src/Facets/GenericSwapFacet.sol#26) - SafeERC20.safeTransferFrom(IERC20(assetId),from,to,amount) (src/Libraries/LibAsset.sol#100) - returndata = address(token).functionCall(data,SafeERC20: low-level call failed) (node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol#92) - LibAsset.transferFromERC20(fromAssetId,msg.sender,address(this),fromAmount) (src/Libraries/LibSwap.sol#34) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - LibSwap.swap(_lifiData.transactionId,_swapData[i]) (src/Facets/Swapper.sol#20) - SafeERC20.safeApprove(IERC20(assetId),spender,0) (src/Libraries/LibAsset.sol#67) - LibAsset.approveERC20(IERC20(fromAssetId),_swapData.approveTo,fromAmount) (src/Libraries/LibSwap.sol#38) - SafeERC20.safeApprove(IERC20(assetId),spender,MAX_INT) (src/Libraries/LibAsset.sol#68) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) - LibAsset.transferAsset(_lifiData.receivingAssetId,address(msg.sender),postSwapBalance) (src/Facets/GenericSwapFacet.sol#30) External calls sending eth: - _executeSwaps(_lifiData,_swapData) (src/Facets/GenericSwapFacet.sol#26) - (success,returndata) = target.call{value: value}(data) (node_modules/@openzeppelin/contracts/utils/Address.sol#131) - (success,res) = _swapData.callTo.call{value: msg.value}(_swapData.callData) (src/Libraries/LibSwap.sol#42) Event emitted after the call(s): - LiFiTransferStarted(_lifiData.transactionId,_lifiData.integrator,_lifiData.referrer,_lifiData.sendingAssetId,_lifiData.receivingAssetId,_lifiData.receiver,_lifiData.amount,_lifiData.destinationChainId,block.timestamp) (src/Facets/GenericSwapFacet.sol#32-42) Reentrancy in WithdrawFacet.withdraw(address,address,uint256) (src/Facets/WithdrawFacet.sol#20-38): External calls: - IERC20(_assetAddress).safeTransfer(sendTo,_amount) (src/Facets/WithdrawFacet.sol#35) External calls sending eth: - address(sendTo).transfer(_amount) (src/Facets/WithdrawFacet.sol#31) Event emitted after the call(s): - LogWithdraw(sendTo,_assetAddress,_amount) (src/Facets/WithdrawFacet.sol#37) ```

#0 - H3xept

2022-04-01T10:11:56Z

Re: require() should be used instead of assert()

Fixed by lifinance/lifi-contracts@ae1dc0bb1d27be95910df70022b19c64acddfb7a

#1 - H3xept

2022-04-11T11:21:21Z

Re Assert is used instead of require

Duplicate of #165

#2 - H3xept

2022-04-11T11:23:24Z

Re Use of deprecated safeApprove()

Duplicate of #82

#3 - H3xept

2022-04-11T12:23:01Z

Re 2 Steps Verification before Transferring Ownership

Duplicate of #143

Awards

70.6981 USDC - $70.70

Labels

bug
G (Gas Optimization)
resolved

External Links

Code refactoring

The chain of getOwnBalance(), _executeSwaps(), getOwnBalance(), require(), assign, should be refactored to a common function https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/NXTPFacet.sol#L91-L100 https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/HopFacet.sol#L102-L111 https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/AnyswapFacet.sol#L85-L94 https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/CBridgeFacet.sol#L98-L107 The same should be done for the native versions

Don't compare boolean expressions to boolean literals

if (<x> == true) => if (<x>), if (<x> == false) => if (!<x>)

  1. File: src/Facets/DexManagerFacet.sol (line 20)
        if (s.dexWhitelist[_dex] == true) {
  1. File: src/Facets/DexManagerFacet.sol (line 34)
            if (s.dexWhitelist[_dexs[i]] == true) {
  1. File: src/Facets/DexManagerFacet.sol (line 47)
        if (s.dexWhitelist[_dex] == false) {
  1. File: src/Facets/DexManagerFacet.sol (line 66)
            if (s.dexWhitelist[_dexs[i]] == false) {
  1. File: src/Facets/Swapper.sol (line 16)
                ls.dexWhitelist[_swapData[i].approveTo] == true && ls.dexWhitelist[_swapData[i].callTo] == true,
  1. File: src/Facets/Swapper.sol (line 16)
                ls.dexWhitelist[_swapData[i].approveTo] == true && ls.dexWhitelist[_swapData[i].callTo] == true,

Expressions for constant values such as a call to keccak256(), should use immutable rather than constant

See this issue for a detail description of the issue

  1. File: src/Libraries/LibDiamond.sol (line 7)
    bytes32 internal constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
  1. File: src/Facets/NXTPFacet.sol (line 18)
    bytes32 internal constant NAMESPACE = keccak256("com.lifi.facets.nxtp");
  1. File: src/Facets/HopFacet.sol (line 18)
    bytes32 internal constant NAMESPACE = keccak256("com.lifi.facets.hop");
  1. File: src/Facets/CBridgeFacet.sol (line 18)
    bytes32 internal constant NAMESPACE = keccak256("com.lifi.facets.cbridge2");

Superfluous event fields

block.timestamp and block.number are added to event information by default so adding them manually wastes gas

  1. File: src/Libraries/LibSwap.sol (line 26)
        uint256 timestamp
  1. File: src/Interfaces/ILiFi.sol (line 29)
        uint256 timestamp
  1. File: src/Interfaces/ILiFi.sol (line 37)
        uint256 timestamp
  1. File: src/Interfaces/ILiFi.sol (line 49)
        uint256 timestamp
  1. File: src/Interfaces/ILiFi.sol (line 60)
        uint256 timestamp

++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

  1. File: src/Libraries/LibDiamond.sol (line 67)
        for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
  1. File: src/Libraries/LibDiamond.sol (line 92)
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
  1. File: src/Libraries/LibDiamond.sol (line 110)
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
  1. File: src/Libraries/LibDiamond.sol (line 125)
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
  1. File: src/Facets/DexManagerFacet.sol (line 33)
        for (uint256 i; i < _dexs.length; i++) {
  1. File: src/Facets/DexManagerFacet.sol (line 52)
        for (uint256 i; i < s.dexs.length; i++) {
  1. File: src/Facets/DexManagerFacet.sol (line 65)
        for (uint256 i; i < _dexs.length; i++) {
  1. File: src/Facets/DexManagerFacet.sol (line 70)
            for (uint256 j; j < s.dexs.length; j++) {
  1. File: src/Facets/HopFacet.sol (line 48)
        for (uint8 i; i < _tokens.length; i++) {
  1. File: src/Facets/Swapper.sol (line 14)
        for (uint8 i; i < _swapData.length; i++) {
  1. File: src/Facets/DiamondLoupeFacet.sol (line 24)
        for (uint256 i; i < numFacets; i++) {

<array>.length should not be looked up in every loop of a for-loop

Even memory arrays incur the overhead of bit tests and bit shifts to calculate the array length

  1. File: src/Libraries/LibDiamond.sol (line 67)
        for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
  1. File: src/Libraries/LibDiamond.sol (line 92)
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
  1. File: src/Libraries/LibDiamond.sol (line 110)
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
  1. File: src/Libraries/LibDiamond.sol (line 125)
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
  1. File: src/Facets/DexManagerFacet.sol (line 33)
        for (uint256 i; i < _dexs.length; i++) {
  1. File: src/Facets/DexManagerFacet.sol (line 52)
        for (uint256 i; i < s.dexs.length; i++) {
  1. File: src/Facets/DexManagerFacet.sol (line 65)
        for (uint256 i; i < _dexs.length; i++) {
  1. File: src/Facets/DexManagerFacet.sol (line 70)
            for (uint256 j; j < s.dexs.length; j++) {
  1. File: src/Facets/HopFacet.sol (line 48)
        for (uint8 i; i < _tokens.length; i++) {
  1. File: src/Facets/Swapper.sol (line 14)
        for (uint8 i; i < _swapData.length; i++) {

Using calldata instead of memory for read-only arguments in external functions saves gas

  1. File: src/Facets/HopFacet.sol (line 41)
        string[] memory _tokens,
  1. File: src/Facets/HopFacet.sol (line 42)
        IHopBridge.BridgeConfig[] memory _bridgeConfigs,

require() or revert() statements that check input arguments should be at the top of the function

  1. File: src/Libraries/LibDiamond.sol (line 86)
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
  1. File: src/Libraries/LibDiamond.sol (line 104)
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
  1. File: src/Libraries/LibDiamond.sol (line 124)
        require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");

internal functions only called once can be inlined to save gas

  1. File: src/Facets/CBridgeFacet.sol (line 176)
    function _bridge() internal view returns (address) {

++i costs less gas than ++i, especially when it's used in for-loops (--i/i-- too)

  1. File: src/Libraries/LibDiamond.sol (line 67)
        for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
  1. File: src/Libraries/LibDiamond.sol (line 92)
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
  1. File: src/Libraries/LibDiamond.sol (line 110)
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
  1. File: src/Libraries/LibDiamond.sol (line 125)
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
  1. File: src/Facets/DexManagerFacet.sol (line 33)
        for (uint256 i; i < _dexs.length; i++) {
  1. File: src/Facets/DexManagerFacet.sol (line 52)
        for (uint256 i; i < s.dexs.length; i++) {
  1. File: src/Facets/DexManagerFacet.sol (line 65)
        for (uint256 i; i < _dexs.length; i++) {
  1. File: src/Facets/DexManagerFacet.sol (line 70)
            for (uint256 j; j < s.dexs.length; j++) {
  1. File: src/Facets/HopFacet.sol (line 48)
        for (uint8 i; i < _tokens.length; i++) {
  1. File: src/Facets/Swapper.sol (line 14)
        for (uint8 i; i < _swapData.length; i++) {
  1. File: src/Facets/DiamondLoupeFacet.sol (line 24)
        for (uint256 i; i < numFacets; i++) {

Use a more recent version of solidity

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

  1. File: src/Libraries/LibSwap.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Libraries/LibUtil.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Libraries/LibDiamond.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Libraries/LibAsset.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Libraries/LibStorage.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Interfaces/IAnyswapRouter.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Interfaces/IERC165.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Interfaces/IHopBridge.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Interfaces/IDiamondCut.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Interfaces/IDiamondLoupe.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Interfaces/ITransactionManager.sol (line 2)
pragma solidity 0.8.7;
  1. File: src/Interfaces/IERC173.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Interfaces/IAnyswapToken.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Interfaces/ILiFi.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Interfaces/ICBridge.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/LiFiDiamond.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/DexManagerFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/NXTPFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/OwnershipFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/HopFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/Swapper.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/GenericSwapFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/DiamondCutFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/WithdrawFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/AnyswapFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/DiamondLoupeFacet.sol (line 2)
pragma solidity ^0.8.7;
  1. File: src/Facets/CBridgeFacet.sol (line 2)
pragma solidity ^0.8.7;

Splitting require() statements that use && saves gas

See this issue for an example

  1. File: src/Facets/Swapper.sol (lines 15-18)
            require(
                ls.dexWhitelist[_swapData[i].approveTo] == true && ls.dexWhitelist[_swapData[i].callTo] == true,
                "Contract call not allowed!"
            );

Duplicated require()/revert() checks should be refactored to a modifier or function

  1. File: src/Libraries/LibDiamond.sol (line 102)
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
  1. File: src/Libraries/LibDiamond.sol (line 104)
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
  1. File: src/Facets/AnyswapFacet.sol (line 105)
            require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
  1. File: src/Facets/CBridgeFacet.sol (line 116)
            require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");

Using > 0 costs more gas than != 0 when used on a uint in a require() statement

  1. File: src/Libraries/LibDiamond.sol (line 212)
        require(contractSize > 0, _errorMessage);
  1. File: src/Facets/NXTPFacet.sol (line 98)
        require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
  1. File: src/Facets/HopFacet.sol (line 109)
        require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
  1. File: src/Facets/AnyswapFacet.sol (line 92)
            require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
  1. File: src/Facets/AnyswapFacet.sol (line 105)
            require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
  1. File: src/Facets/CBridgeFacet.sol (line 105)
            require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");
  1. File: src/Facets/CBridgeFacet.sol (line 116)
            require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT");

require()/revert() strings longer than 32 bytes cost extra gas

  1. File: src/Libraries/LibDiamond.sol (line 56)
        require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
  1. File: src/Libraries/LibDiamond.sol (line 76)
                revert("LibDiamondCut: Incorrect FacetCutAction");
  1. File: src/Libraries/LibDiamond.sol (line 84)
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
  1. File: src/Libraries/LibDiamond.sol (line 86)
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
  1. File: src/Libraries/LibDiamond.sol (line 95)
            require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");
  1. File: src/Libraries/LibDiamond.sol (line 102)
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
  1. File: src/Libraries/LibDiamond.sol (line 104)
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
  1. File: src/Libraries/LibDiamond.sol (line 113)
            require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");
  1. File: src/Libraries/LibDiamond.sol (line 121)
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
  1. File: src/Libraries/LibDiamond.sol (line 124)
        require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
  1. File: src/Libraries/LibDiamond.sol (line 154)
        require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist");
  1. File: src/Libraries/LibDiamond.sol (line 156)
        require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function");
  1. File: src/Libraries/LibDiamond.sol (line 187)
            require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty");
  1. File: src/Libraries/LibDiamond.sol (line 189)
            require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");
  1. File: src/Libraries/LibDiamond.sol (line 200)
                    revert("LibDiamondCut: _init function reverted");
  1. File: src/Facets/HopFacet.sol (line 146)
        require(s.hopChainId != _hopData.chainId, "Cannot bridge to the same network.");
  1. File: src/Facets/AnyswapFacet.sol (line 133)
        require(block.chainid != _anyswapData.toChainId, "Cannot bridge to the same network.");
  1. File: src/Facets/CBridgeFacet.sol (line 147)
        require(s.cBridgeChainId != _cBridgeData.dstChainId, "Cannot bridge to the same network.");

State variables should be cached in stack variables rather than re-reading them from storage

The instances below point to the second access of a state variable within a function. Less obvious optimizations include having local storage variables of mappings within state variable mappings or mappings within state variable structs, having local storage variables of structs within mappings, or having local caches of state variable contracts/addresses.

  1. File: src/Facets/DexManagerFacet.sol (line 24)
        s.dexWhitelist[_dex] = true;
  1. File: src/Facets/DexManagerFacet.sol (line 37)
            s.dexWhitelist[_dexs[i]] = true;
  1. File: src/Facets/DexManagerFacet.sol (line 51)
        s.dexWhitelist[_dex] = false;
  1. File: src/Facets/DexManagerFacet.sol (line 69)
            s.dexWhitelist[_dexs[i]] = false;
  1. File: src/Facets/DexManagerFacet.sol (line 85)
        s.dexs[index] = s.dexs[s.dexs.length - 1];
  1. File: src/Facets/Swapper.sol (line 16)
                ls.dexWhitelist[_swapData[i].approveTo] == true && ls.dexWhitelist[_swapData[i].callTo] == true,

Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead

When using elements that are smaller than 32 bytes, your contractโ€™s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.

https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed

  1. File: src/Libraries/LibDiamond.sol (line 11)
        uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
  1. File: src/Libraries/LibDiamond.sol (line 87)
        uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
  1. File: src/Libraries/LibDiamond.sol (line 105)
        uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
  1. File: src/Libraries/LibDiamond.sol (line 141)
        uint96 _selectorPosition,
  1. File: src/Interfaces/ILiFi.sol (line 62)
    event Inited(address indexed bridge, uint64 chainId);
  1. File: src/Interfaces/ICBridge.sol (line 9)
        uint64 _dstChinId,
  1. File: src/Interfaces/ICBridge.sol (line 10)
        uint64 _nonce,
  1. File: src/Interfaces/ICBridge.sol (line 11)
        uint32 _maxSlippage
  1. File: src/Interfaces/ICBridge.sol (line 17)
        uint64 _dstChinId,
  1. File: src/Interfaces/ICBridge.sol (line 18)
        uint64 _nonce,
  1. File: src/Interfaces/ICBridge.sol (line 19)
        uint32 _maxSlippage
  1. File: src/Facets/HopFacet.sol (line 48)
        for (uint8 i; i < _tokens.length; i++) {
  1. File: src/Facets/Swapper.sol (line 14)
        for (uint8 i; i < _swapData.length; i++) {
  1. File: src/Facets/CBridgeFacet.sol (line 21)
        uint64 cBridgeChainId;
  1. File: src/Facets/CBridgeFacet.sol (line 30)
        uint64 dstChainId;
  1. File: src/Facets/CBridgeFacet.sol (line 31)
        uint64 nonce;
  1. File: src/Facets/CBridgeFacet.sol (line 32)
        uint32 maxSlippage;
  1. File: src/Facets/CBridgeFacet.sol (line 42)
    function initCbridge(address _cBridge, uint64 _chainId) external {

Structs can be packed into fewer storage slots

  1. File: src/Facets/CBridgeFacet.sol (lines 26-33)
    struct CBridgeData {
        address receiver;
        address token;
        uint256 amount;
        uint64 dstChainId;
        uint64 nonce;
        uint32 maxSlippage;
    }

Struct member ordering with 3 slots instead of the current 4: uint256(32):amount,address(20):receiver,uint64(8):dstChainId,uint32(4):maxSlippage,address(20):token,uint64(8):nonce

Remove unused variables

  1. File: src/Libraries/LibSwap.sol (line 8)
    uint256 private constant MAX_INT = 2**256 - 1;

Use custom error codes instead of revert strings to save gas

Various files and various locations

#0 - H3xept

2022-04-01T10:42:06Z

Re: Expressions for constant values such as a call to keccak256(), should use immutable rather than constant

Fixed by lifinance/lifi-contracts@39dd074acf47b40f9a544439427e58de0208b961

#1 - H3xept

2022-04-01T10:50:21Z

Re: ++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

We internally decided to avoid unchecked expressions for now.

#2 - H3xept

2022-04-01T10:59:41Z

Re: Splitting require() statements that use && saves gas

I found no evidence online about this. Upon testing locally, this seems to be wrong (&& saves gas!!)

#3 - H3xept

2022-04-01T11:01:12Z

Re: <array>.length should not be looked up in every loop of a for-loop

Fixed by lifinance/lifi-contracts@975f12529f2232a59def392349bf8dccf4141aa9 Duplicate of #44

#4 - H3xept

2022-04-01T11:03:56Z

Re: require()/revert() strings longer than 32 bytes cost extra gas

Fixed by lifinance/lifi-contracts@45edddfb56028db3cfd070b57990ae8a455f0109

#5 - H3xept

2022-04-01T11:07:54Z

Re: State variables should be cached in stack variables rather than re-reading them from storage

Fixed by lifinance/lifi-contracts@2b0c057fb05c62d95c0b04edd1864c184ccf9ad8

#6 - H3xept

2022-04-08T15:17:16Z

Re Unused variable MAX_INT

Duplicate of #100

#7 - H3xept

2022-04-11T10:30:30Z

Re strings longer than 32 bytes cost extra gas

Duplicate of #100

#8 - H3xept

2022-04-11T10:51:15Z

Re Structs can be packed into fewer storage slots

Duplicate of #178

#9 - H3xept

2022-04-11T11:12:02Z

Re Using > 0 costs more gas than != 0 when used on a uint in a require() statement

Duplicate of #100

#10 - H3xept

2022-04-11T12:02:00Z

Re prefix increments

We internally decided to avoid previx increments for now.

#11 - H3xept

2022-04-11T12:41:49Z

Re calldata instead of memory for read-only arguments

Duplicate of #152

#12 - H3xept

2022-04-11T12:52:46Z

Re pre-compute constant values

Duplicate of #182

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