code-423n4 / 2022-07-axelar-findings

0 stars 0 forks source link

Gas Optimizations #223

Open code423n4 opened 2 years ago

code423n4 commented 2 years ago

Gas Optimizations Report

Table of Contents

  1. Don't Initialize Variables with Default Value
  2. Cache Array Length Outside of Loop
  3. Use != 0 instead of > 0 for Unsigned Integer Comparison
  4. Use Shift Right/Left instead of Division/Multiplication if possible

1. Don't Initialize Variables with Default Value

Impact

Uninitialized variables are assigned with the types default value. Explicitly initializing a variable with it's default value costs unnecesary gas.

Example

Bad:

uint256 x = 0;
bool y = false;

Good:

uint256 x;
bool y;

Background Information

2. Cache Array Length Outside of Loop

Impact

Caching the array length outside a loop saves reading it on each iteration, as long as the array's length is not changed during the loop.

Example

Bad:

for (uint256 i = 0; i < array.length; i++) {
    // invariant: array's length is not changed
}

Good:

uint256 len = array.length
for (uint256 i = 0; i < len; i++) {
    // invariant: array's length is not changed
}

Background Information

POC

  2022-07-axelar/contracts/AdminMultisigBase.sol::149 => uint256 adminLength = accounts.length;
  2022-07-axelar/contracts/AxelarGateway.sol::49 => if (authModule.code.length == 0) revert InvalidAuthModule();
  2022-07-axelar/contracts/AxelarGateway.sol::50 => if (tokenDeployerImplementation.code.length == 0) revert InvalidTokenDeployer();
  2022-07-axelar/contracts/AxelarGateway.sol::205 => if (symbols.length != limits.length) revert InvalidSetDailyMintLimitsParams();
  2022-07-axelar/contracts/AxelarGateway.sol::207 => for (uint256 i = 0; i < symbols.length; i++) {
  2022-07-axelar/contracts/AxelarGateway.sol::228 => if (setupParams.length != 0) {
  2022-07-axelar/contracts/AxelarGateway.sol::255 => if (newOperatorsData.length > 0) {
  2022-07-axelar/contracts/AxelarGateway.sol::288 => uint256 commandsLength = commandIds.length;
  2022-07-axelar/contracts/AxelarGateway.sol::290 => if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();
  2022-07-axelar/contracts/AxelarGateway.sol::355 => if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress);
  2022-07-axelar/contracts/AxelarGateway.sol::388 => if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol);
  2022-07-axelar/contracts/AxelarGateway.sol::462 => return success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
  2022-07-axelar/contracts/AxelarGatewayProxy.sol::19 => if (gatewayImplementation.code.length == 0) revert InvalidImplementation();
  2022-07-axelar/contracts/DepositHandler.sol::23 => if (callee.code.length == 0) revert NotContract();
  2022-07-axelar/contracts/ECDSA.sol::32 => // Check the signature length
  2022-07-axelar/contracts/ECDSA.sol::33 => if (signature.length != 65) revert InvalidSignatureLength();
  2022-07-axelar/contracts/ECDSA.sol::75 => // 32 is the length in bytes of hash, 

3. Use != 0 instead of > 0 for Unsigned Integer Comparison

Impact

When dealing with unsigned integer types, comparisons with != 0 are cheaper then with > 0.

Example

Bad:

// `a` being of type unsigned integer
require(a > 0, "!a > 0");

Good:

// `a` being of type unsigned integer
require(a != 0, "!a > 0");

POC

  2022-07-axelar/contracts/AxelarGateway.sol::255 => if (newOperatorsData.length > 0) {
  2022-07-axelar/contracts/AxelarGateway.sol::613 => if (limit > 0 && amount > limit) revert ExceedDailyMintLimit(symbol);
  2022-07-axelar/contracts/ECDSA.sol::58 => if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidS();
  2022-07-axelar/contracts/ERC20Permit.sol::45 => if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidS();
  2022-07-axelar/contracts/auth/AxelarAuthWeighted.sol::76 => if (epochForHash[newOperatorsHash] > 0) revert SameOperators();
  2022-07-axelar/contracts/deposit-service/AxelarDepositService.sol::165 => if (addressForNativeDeposit(salt, refundAddress, destinationChain, destinationAddress).balance > 0 && msg.sender != refundAddress)
  2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::23 => if (address(this).balance > 0) refundAddress.transfer(address(this).balance);
  2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::51 => if (address(this).balance > 0) refundAddress.transfer(address(this).balance);
  2022-07-axelar/contracts/deposit-service/ReceiverImplementation.sol::71 => if (address(this).balance > 0) refundAddress.transfer(address(this).balance);
  2022-07-axelar/contracts/gas-service/AxelarGasService.sol::128 => if (amount > 0) receiver.transfer(amount);
  2022-07-axelar/contracts/gas-service/AxelarGasService.sol::131 => if (amount > 0) _safeTransfer(token, receiver, amount);
  2022-07-axelar/contracts/util/Upgradable.sol::50 => if (params.length > 0) {
  2022-07-axelar/xc20/contracts/ERC20Permit.sol::45 => if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidS(); 

4. Use Shift Right/Left instead of Division/Multiplication if possible

Description

A division/multiplication by any number x being a power of 2 can be calculated by shifting log2(x) to the right/left.

While the DIV opcode uses 5 gas, the SHR opcode only uses 3 gas. Furthermore, Solidity's division operation also includes a division-by-0 prevention which is bypassed using shifting.

Impact

Bad:

uint256 b = a / 2;
uint256 c = a / 4;
uint256 d = a * 8;

Good:

uint256 b = a >> 1;
uint256 c = a >> 2;
uint256 d = a << 3;

Background Information

POC

  2022-07-axelar/contracts/ECDSA.sol::56 => // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
  2022-07-axelar/contracts/ERC20.sol::15 => * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
  2022-07-axelar/contracts/interfaces/IERC20.sol::49 => * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
  2022-07-axelar/contracts/test/gmp/DestinationChainTokenSwapper.sol::29 => convertedAmount = amount * 2;
  2022-07-axelar/contracts/test/gmp/DestinationChainTokenSwapper.sol::33 => convertedAmount = amount / 2;
  2022-07-axelar/xc20/contracts/ERC20.sol::15 => * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
  2022-07-axelar/xc20/contracts/interfaces/IERC20.sol::63 => * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
GalloDaSballo commented 2 years ago

Less than 100 gas saved