code-423n4 / 2022-03-lifinance-findings

6 stars 4 forks source link

Gas Optimizations #172

Open code423n4 opened 2 years ago

code423n4 commented 2 years ago
  1. Execution functionSelector first for saving gas

https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/LiFiDiamond.sol#L12-L13

function order will also have an impact on gas consumption. Because this contract, there is a difference in order of the function so this implementation below can be using for saving more gas (±12 gas)

Tool Used

Remix

POC

        IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](1);
        bytes4[] memory functionSelectors = new bytes4[](1);
        functionSelectors[0] = IDiamondCut.diamondCut.selector;
        cut[0] = IDiamondCut.FacetCut({
            facetAddress: _diamondCutFacet,
            action: IDiamondCut.FacetCutAction.Add,
            functionSelectors: functionSelectors
        });
        LibDiamond.diamondCut(cut, address(0), "");
    }

can be changed into :

        bytes4[] memory functionSelectors = new bytes4[](1);
        IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](1);   
        functionSelectors[0] = IDiamondCut.diamondCut.selector;
        cut[0] = IDiamondCut.FacetCut({
            facetAddress: _diamondCutFacet,
            action: IDiamondCut.FacetCutAction.Add,
            functionSelectors: functionSelectors
        });
        LibDiamond.diamondCut(cut, address(0), "");
    }
  1. Using ++i instead i++ for saving more gas

Using i++ instead ++i for all the loops, the variable i is incremented using i++. It is known that implementation by using ++i costs less gas per iteration than i++.

Tools Used

Remix

Occurances

main/src/Facets/Swapper.sol#L14
main/src/Facets/HopFacet.sol#L48
main/src/Facets/DiamondLoupeFacet.sol#L24
main/src/Facets/DexManagerFacet.sol#L33
main/src/Facets/DexManagerFacet.sol#L52
main/src/Facets/DexManagerFacet.sol#L65
  1. Removing && operator can saving more gas

instead of using operator && on single require check. using additional require check can save more gas.

Tool Used

Remix

POC

require(
        ls.dexWhitelist[_swapData[i].approveTo] == true && ls.dexWhitelist[_swapData[i].callTo] == true,
        "Contract call not allowed!"
        );

can be changed to :

require(ls.dexWhitelist[_swapData[i].approveTo] == true, "Contract call not allowed!");
require(ls.dexWhitelist[_swapData[i].callTo] == true, "Contract call not allowed!");
  1. Using require instead of Assert for saving more gas

Assert-style exceptions consume all gas available to the call. on other hand, using require-style exception will not consume any gas. it would be saving more gas by using require instead of assert.

Tool Used

Remix

POC

https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/WithdrawFacet.sol#L30 https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/WithdrawFacet.sol#L34

            assert(_amount <= self.balance);
            assert(_amount <= assetBalance);

change to

        require(_amount <= self.balance);
            require(_amount <= assetBalance);
  1. Optimize order for struct declaration

https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/AnyswapFacet.sol#L20 This implementation can be used for saving more gas (24 gas)

Tool Used

Remix

POC

    struct AnyswapData {
        address token;
        address router;
        uint256 amount;
        address recipient;
        uint256 toChainId;
    }

change to :

    struct AnyswapData {
        address token;
        address router;
        address recipient;
        uint256 amount;
        uint256 toChainId;
    }
  1. Better way SafeERC20.function to saving more gas

https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/WithdrawFacet.sol#L9

this implementation can be used for another gas opt

Tool used

Remix

POC

by not declare :

using SafeERC20 for IERC20;

and change at : https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/WithdrawFacet.sol#L35

SafeERC20.safeTransfer(IERC20(_assetAddress), sendTo, _amount);
  1. Change 2**256 - 1 to type(uint).max

its cheaper to using type(uint).max instead of using 2**256-1 calculation for unlimited approval

POC : LibAsset.sol #L15

https://github.com/code-423n4/2022-03-lifinance/blob/main/src/Libraries/LibAsset.sol#L15

uint256 private constant MAX_INT = 2**256 - 1;
  1. Using short reason string can saving more gas

Every reason string takes at least 32 bytes. Use short reason strings that fits in 32 bytes or it will become more expensive.

Occurance :

LibDiamond.sol #L102
LibDiamond.sol #L187
LibDiamond.sol #L189
  1. Instead of caching calldata can be using memory for saving more gas

https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/CBridgeFacet.sol#L57 This implementation can be using for saving more gas.

Tool used

Remix

POC

    function startBridgeTokensViaCBridge(LiFiData memory _lifiData, CBridgeData calldata _cBridgeData) public payable { // ---> 2166900 deploy

can be changed to


    function startBridgeTokensViaCBridge(LiFiData memory _lifiData, CBridgeData memory _cBridgeData) public payable { // ---> 2133888 deploy 
H3xept commented 2 years ago

Re Change 2**256 - 1 to type(uint).max

Duplicate of #197

H3xept commented 2 years ago

Re Using short reason string can saving more gas

Duplicate of #100

H3xept commented 2 years ago

Re Optimize order for struct declaration

Duplicate of #178

H3xept commented 2 years ago

Re Assert is used instead of require

Duplicate of #165

H3xept commented 2 years ago

Re prefix increments

We internally decided to avoid previx increments for now.

H3xept commented 2 years ago

Re calldata instead of memory for read-only arguments

Duplicate of #152

H3xept commented 2 years ago

Re gas saving with SafeERC20.function

Duplicate of #183