Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gas Optimizations #122

Open
code423n4 opened this issue Aug 3, 2022 · 2 comments
Open

Gas Optimizations #122

code423n4 opened this issue Aug 3, 2022 · 2 comments

Comments

@code423n4
Copy link
Contributor

Summary

Gas Optimizations

Issue Instances
[G‑01] Using calldata instead of memory for read-only arguments in external functions saves gas 7
[G‑02] Avoid contract existence checks by using solidity version 0.8.10 or later 25
[G‑03] internal functions only called once can be inlined to save gas 7
[G‑04] <array>.length should not be looked up in every loop of a for-loop 7
[G‑05] ++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 12
[G‑06] keccak256() should only need to be called on a specific string literal once 4
[G‑07] Optimize names to save gas 10
[G‑08] ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too) 5
[G‑09] Empty blocks should be removed or emit something 2
[G‑10] Functions guaranteed to revert when called by normal users can be marked payable 11

Total: 90 instances over 10 issues

Gas Optimizations

[G‑01] Using calldata instead of memory for read-only arguments in external functions saves gas

When a function with a memory array is called externally, the abi.decode() step has to use a for-loop to copy each index of the calldata to the memory index. Each iteration of this for-loop costs at least 60 gas (i.e. 60 * <mem_array>.length). Using calldata directly, obliviates the need for such a loop in the contract code and runtime execution. Note that even if an interface defines a function as having memory arguments, it's still valid for implementation contracs to use calldata arguments instead.

If the array is passed to an internal function which passes the array to another internal function where the array is modified and therefore memory is used in the external call, it's still more gass-efficient to use calldata when the external function uses modifiers, since the modifiers may prevent the internal functions from being called. Structs have the same overhead as an array of length one

Note that I've also flagged instances where the function is public but can be marked as external since it's not called by the contract, and cases where a constructor is involved

There are 7 instances of this issue:

File: contracts/auth/AxelarAuthWeighted.sol

/// @audit recentOperators
16:       constructor(bytes[] memory recentOperators) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/auth/AxelarAuthWeighted.sol#L16

File: contracts/AxelarGateway.sol

172:      function tokenFrozen(string memory) external pure override returns (bool) {

/// @audit executeData
447       function _unpackLegacyCommands(bytes memory executeData)
448           external
449           pure
450           returns (
451               uint256 chainId,
452               bytes32[] memory commandIds,
453               string[] memory commands,
454:              bytes[] memory params

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/AxelarGateway.sol#L172

File: contracts/deposit-service/AxelarDepositService.sol

/// @audit wrappedSymbol
18:       constructor(address gateway, string memory wrappedSymbol) DepositBase(gateway, wrappedSymbol) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/AxelarDepositService.sol#L18

File: contracts/deposit-service/DepositReceiver.sol

/// @audit delegateData
8:        constructor(bytes memory delegateData) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/DepositReceiver.sol#L8

File: contracts/deposit-service/ReceiverImplementation.sol

/// @audit wrappedSymbol
12:       constructor(address gateway, string memory wrappedSymbol) DepositBase(gateway, wrappedSymbol) {}

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/ReceiverImplementation.sol#L12

File: contracts/gas-service/AxelarGasService.sol

/// @audit symbol
35        function payGasForContractCallWithToken(
36            address sender,
37            string calldata destinationChain,
38            string calldata destinationAddress,
39            bytes calldata payload,
40            string memory symbol,
41            uint256 amount,
42            address gasToken,
43            uint256 gasFeeAmount,
44:           address refundAddress

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/gas-service/AxelarGasService.sol#L35-L44

[G‑02] Avoid contract existence checks by using solidity version 0.8.10 or later

Prior to 0.8.10 the compiler inserted extra code, including EXTCODESIZE (100 gas), to check for contract existence for external calls. In more recent solidity versions, the compiler will not insert these checks if the external call has a return value

There are 25 instances of this issue:

File: contracts/AxelarGateway.sol

/// @audit validateProof()
268:          bool currentOperators = IAxelarAuth(AUTH_MODULE).validateProof(messageHash, proof);

/// @audit _unpackLegacyCommands()
275:          try AxelarGateway(this)._unpackLegacyCommands(data) returns (

/// @audit call()
320:              (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId));

/// @audit balanceOf()
385:                  abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler)))

/// @audit burn()
393:              IBurnableMintableCappedERC20(tokenAddress).burn(salt);

/// @audit mint()
481:              IBurnableMintableCappedERC20(tokenAddress).mint(account, amount);

/// @audit depositAddress()
525:                  IBurnableMintableCappedERC20(tokenAddress).depositAddress(bytes32(0)),

/// @audit burn()
532:          IBurnableMintableCappedERC20(tokenAddress).burn(bytes32(0));

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/AxelarGateway.sol#L268

File: contracts/deposit-service/AxelarDepositService.sol

/// @audit approve()
30:           IERC20(wrappedTokenAddress).approve(gateway, amount);

/// @audit tokenAddresses()
115:              address gatewayToken = IAxelarGateway(gateway).tokenAddresses(tokenSymbol);

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/AxelarDepositService.sol#L30

File: contracts/deposit-service/DepositReceiver.sol

/// @audit delegatecall()
/// @audit receiverImplementation()
12:           (bool success, ) = IAxelarDepositService(msg.sender).receiverImplementation().delegatecall(delegateData);

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/DepositReceiver.sol#L12

File: contracts/deposit-service/ReceiverImplementation.sol

/// @audit tokenAddresses()
25:           address tokenAddress = IAxelarGateway(gateway).tokenAddresses(symbol);

/// @audit refundToken()
27:           address refund = DepositBase(msg.sender).refundToken();

/// @audit balanceOf()
29:               _safeTransfer(refund, refundAddress, IERC20(refund).balanceOf(address(this)));

/// @audit balanceOf()
33:           uint256 amount = IERC20(tokenAddress).balanceOf(address(this));

/// @audit approve()
38:           IERC20(tokenAddress).approve(gateway, amount);

/// @audit refundToken()
49:           address refund = DepositBase(msg.sender).refundToken();

/// @audit balanceOf()
53:               _safeTransfer(refund, refundAddress, IERC20(refund).balanceOf(address(this)));

/// @audit approve()
64:           IERC20(wrappedTokenAddress).approve(gateway, amount);

/// @audit refundToken()
74:           address refund = DepositBase(msg.sender).refundToken();

/// @audit balanceOf()
76:               _safeTransfer(refund, refundAddress, IERC20(refund).balanceOf(address(this)));

/// @audit balanceOf()
80:           uint256 amount = IERC20(wrappedTokenAddress).balanceOf(address(this));

/// @audit withdraw()
85:           IWETH9(wrappedTokenAddress).withdraw(amount);

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/ReceiverImplementation.sol#L25

File: contracts/gas-service/AxelarGasService.sol

/// @audit balanceOf()
130:                  uint256 amount = IERC20(token).balanceOf(address(this));

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/gas-service/AxelarGasService.sol#L130

[G‑03] internal functions only called once can be inlined to save gas

Not inlining costs 20 to 40 gas because of two extra JUMP instructions and additional stack operations needed for function calls.

There are 7 instances of this issue:

File: contracts/auth/AxelarAuthWeighted.sol

86        function _validateSignatures(
87            bytes32 messageHash,
88            address[] memory operators,
89            uint256[] memory weights,
90            uint256 threshold,
91:           bytes[] memory signatures

115:      function _isSortedAscAndContainsNoDuplicate(address[] memory accounts) internal pure returns (bool) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/auth/AxelarAuthWeighted.sol#L86-L91

File: contracts/AxelarGateway.sol

611:      function _setTokenDailyMintAmount(string memory symbol, uint256 amount) internal {

622:      function _setTokenAddress(string memory symbol, address tokenAddress) internal {

630       function _setContractCallApproved(
631           bytes32 commandId,
632           string memory sourceChain,
633           string memory sourceAddress,
634           address contractAddress,
635:          bytes32 payloadHash

640       function _setContractCallApprovedWithMint(
641           bytes32 commandId,
642           string memory sourceChain,
643           string memory sourceAddress,
644           address contractAddress,
645           bytes32 payloadHash,
646           string memory symbol,
647:          uint256 amount

655:      function _setImplementation(address newImplementation) internal {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/AxelarGateway.sol#L611

[G‑04] <array>.length should not be looked up in every loop of a for-loop

The overheads outlined below are PER LOOP, excluding the first loop

  • storage arrays incur a Gwarmaccess (100 gas)
  • memory arrays use MLOAD (3 gas)
  • calldata arrays use CALLDATALOAD (3 gas)

Caching the length changes each of these to a DUP<N> (3 gas), and gets rid of the extra DUP<N> needed to store the stack offset

There are 7 instances of this issue:

File: contracts/auth/AxelarAuthWeighted.sol

17:           for (uint256 i; i < recentOperators.length; ++i) {

98:           for (uint256 i = 0; i < signatures.length; ++i) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/auth/AxelarAuthWeighted.sol#L17

File: contracts/AxelarGateway.sol

207:          for (uint256 i = 0; i < symbols.length; i++) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/AxelarGateway.sol#L207

File: contracts/deposit-service/AxelarDepositService.sol

114:          for (uint256 i; i < refundTokens.length; i++) {

168:          for (uint256 i; i < refundTokens.length; i++) {

204:          for (uint256 i; i < refundTokens.length; i++) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/AxelarDepositService.sol#L114

File: contracts/gas-service/AxelarGasService.sol

123:          for (uint256 i; i < tokens.length; i++) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/gas-service/AxelarGasService.sol#L123

[G‑05] ++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

The unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas per loop

There are 12 instances of this issue:

File: contracts/auth/AxelarAuthWeighted.sol

17:           for (uint256 i; i < recentOperators.length; ++i) {

69:           for (uint256 i = 0; i < weightsLength; ++i) {

98:           for (uint256 i = 0; i < signatures.length; ++i) {

101:              for (; operatorIndex < operatorsLength && signer != operators[operatorIndex]; ++operatorIndex) {}

116:          for (uint256 i; i < accounts.length - 1; ++i) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/auth/AxelarAuthWeighted.sol#L17

File: contracts/AxelarGateway.sol

195:          for (uint256 i; i < adminCount; ++i) {

207:          for (uint256 i = 0; i < symbols.length; i++) {

292:          for (uint256 i; i < commandsLength; ++i) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/AxelarGateway.sol#L195

File: contracts/deposit-service/AxelarDepositService.sol

114:          for (uint256 i; i < refundTokens.length; i++) {

168:          for (uint256 i; i < refundTokens.length; i++) {

204:          for (uint256 i; i < refundTokens.length; i++) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/AxelarDepositService.sol#L114

File: contracts/gas-service/AxelarGasService.sol

123:          for (uint256 i; i < tokens.length; i++) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/gas-service/AxelarGasService.sol#L123

[G‑06] keccak256() should only need to be called on a specific string literal once

It should be saved to an immutable variable, and the variable used instead. If the hash is being used as a part of a function selector, the cast to bytes4 should also only be done once

There are 4 instances of this issue:

File: contracts/deposit-service/AxelarDepositServiceProxy.sol

9:            return keccak256('axelar-deposit-service');

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/AxelarDepositServiceProxy.sol#L9

File: contracts/deposit-service/AxelarDepositService.sol

242:          return keccak256('axelar-deposit-service');

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/AxelarDepositService.sol#L242

File: contracts/gas-service/AxelarGasServiceProxy.sol

10:           return keccak256('axelar-gas-service');

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/gas-service/AxelarGasServiceProxy.sol#L10

File: contracts/gas-service/AxelarGasService.sol

181:          return keccak256('axelar-gas-service');

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/gas-service/AxelarGasService.sol#L181

[G‑07] Optimize names to save gas

public/external function names and public member variable names can be optimized to save gas. See this link for an example of how it works. Below are the interfaces/abstract contracts that can be optimized so that the most frequently-called functions use the least amount of gas possible during method lookup. Method IDs that have two leading zero bytes can save 128 gas each during deployment, and renaming functions to have lower method IDs will save 22 gas per call, per sorted position shifted

There are 10 instances of this issue:

File: contracts/auth/AxelarAuthWeighted.sol

/// @audit validateProof(), transferOperatorship()
9:    contract AxelarAuthWeighted is Ownable, IAxelarAuthWeighted {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/auth/AxelarAuthWeighted.sol#L9

File: contracts/AxelarGateway.sol

/// @audit sendToken(), callContract(), callContractWithToken(), deployToken(), mintToken(), burnToken(), approveContractCall(), approveContractCallWithMint(), transferOperatorship(), _unpackLegacyCommands()
15:   contract AxelarGateway is IAxelarGateway, AdminMultisigBase {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/AxelarGateway.sol#L15

File: contracts/deposit-service/AxelarDepositService.sol

/// @audit sendNative(), addressForTokenDeposit(), addressForNativeDeposit(), addressForNativeUnwrap(), sendTokenDeposit(), refundTokenDeposit(), sendNativeDeposit(), refundNativeDeposit(), nativeUnwrap(), refundNativeUnwrap(), contractId()
15:   contract AxelarDepositService is Upgradable, DepositBase, IAxelarDepositService {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/AxelarDepositService.sol#L15

File: contracts/deposit-service/ReceiverImplementation.sol

/// @audit receiveAndSendToken(), receiveAndSendNative(), receiveAndUnwrapNative()
11:   contract ReceiverImplementation is DepositBase {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/ReceiverImplementation.sol#L11

File: contracts/gas-service/AxelarGasService.sol

/// @audit collectFees(), refund(), contractId()
10:   contract AxelarGasService is Upgradable, IAxelarGasService {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/gas-service/AxelarGasService.sol#L10

File: contracts/interfaces/IAxelarAuth.sol

/// @audit validateProof(), transferOperatorship()
7:    interface IAxelarAuth is IOwnable {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/interfaces/IAxelarAuth.sol#L7

File: contracts/interfaces/IAxelarAuthWeighted.sol

/// @audit currentEpoch(), hashForEpoch(), epochForHash()
7:    interface IAxelarAuthWeighted is IAxelarAuth {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/interfaces/IAxelarAuthWeighted.sol#L7

File: contracts/interfaces/IAxelarDepositService.sol

/// @audit sendNative(), addressForTokenDeposit(), addressForNativeDeposit(), addressForNativeUnwrap(), sendTokenDeposit(), refundTokenDeposit(), sendNativeDeposit(), refundNativeDeposit(), nativeUnwrap(), refundNativeUnwrap(), receiverImplementation()
9:    interface IAxelarDepositService is IUpgradable, IDepositBase {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/interfaces/IAxelarDepositService.sol#L9

File: contracts/interfaces/IAxelarExecutable.sol

/// @audit execute(), executeWithToken()
7:    abstract contract IAxelarExecutable {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/interfaces/IAxelarExecutable.sol#L7

File: contracts/interfaces/IAxelarGasService.sol

/// @audit payGasForContractCall(), payGasForContractCallWithToken(), payNativeGasForContractCall(), payNativeGasForContractCallWithToken(), addGas(), addNativeGas(), collectFees(), refund()
8:    interface IAxelarGasService is IUpgradable {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/interfaces/IAxelarGasService.sol#L8

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

Saves 5 gas per loop

There are 5 instances of this issue:

File: contracts/AxelarGateway.sol

207:          for (uint256 i = 0; i < symbols.length; i++) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/AxelarGateway.sol#L207

File: contracts/deposit-service/AxelarDepositService.sol

114:          for (uint256 i; i < refundTokens.length; i++) {

168:          for (uint256 i; i < refundTokens.length; i++) {

204:          for (uint256 i; i < refundTokens.length; i++) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/deposit-service/AxelarDepositService.sol#L114

File: contracts/gas-service/AxelarGasService.sol

123:          for (uint256 i; i < tokens.length; i++) {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/gas-service/AxelarGasService.sol#L123

[G‑09] Empty blocks should be removed or emit something

The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the contract is meant to be extended, the contract should be abstract and the function signatures be added without any default implementation. If the block is an empty if-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...} => if(!x){if(y){...}else{...}}). Empty receive()/fallback() payable functions that are not used, can be removed to save deployment gas.

There are 2 instances of this issue:

File: contracts/interfaces/IAxelarExecutable.sol

46:       ) internal virtual {}

54:       ) internal virtual {}

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/interfaces/IAxelarExecutable.sol#L46

[G‑10] Functions guaranteed to revert when called by normal users can be marked payable

If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are
CALLVALUE(2),DUP1(3),ISZERO(3),PUSH2(3),JUMPI(10),PUSH1(3),DUP1(3),REVERT(0),JUMPDEST(1),POP(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost

There are 11 instances of this issue:

File: contracts/auth/AxelarAuthWeighted.sol

47:       function transferOperatorship(bytes calldata params) external onlyOwner {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/auth/AxelarAuthWeighted.sol#L47

File: contracts/AxelarGateway.sol

204:      function setTokenDailyMintLimits(string[] calldata symbols, uint256[] calldata limits) external override onlyAdmin {

217       function upgrade(
218           address newImplementation,
219           bytes32 newImplementationCodeHash,
220           bytes calldata setupParams
221:      ) external override onlyAdmin {

331:      function deployToken(bytes calldata params, bytes32) external onlySelf {

367:      function mintToken(bytes calldata params, bytes32) external onlySelf {

373:      function burnToken(bytes calldata params, bytes32) external onlySelf {

397:      function approveContractCall(bytes calldata params, bytes32 commandId) external onlySelf {

411:      function approveContractCallWithMint(bytes calldata params, bytes32 commandId) external onlySelf {

437:      function transferOperatorship(bytes calldata newOperatorsData, bytes32) external onlySelf {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/AxelarGateway.sol#L204

File: contracts/gas-service/AxelarGasService.sol

120:      function collectFees(address payable receiver, address[] calldata tokens) external onlyOwner {

136       function refund(
137           address payable receiver,
138           address token,
139           uint256 amount
140:      ) external onlyOwner {

https://github.com/code-423n4/2022-07-axelar/blob/9c4c44b94cddbd48b9baae30051a4e13cbe39539/contracts/gas-service/AxelarGasService.sol#L120

code423n4 added a commit that referenced this issue Aug 3, 2022
@re1ro
Copy link
Member

re1ro commented Aug 5, 2022

Dup #2 #3

@GalloDaSballo
Copy link
Collaborator

[G‑01] Using calldata instead of memory for read-only arguments in external functions saves gas

60 for the array of bytes

[G‑02] Avoid contract existence checks by using solidity version 0.8.10 or later

100 gas per instance
2500

[G‑03] internal functions only called once can be inlined to save gas

20 per instance
140

[G‑04] .length should not be looked up in every loop of a for-loop + G-05

Giving 300 consistently with rest of submissions

[G‑06] keccak256() should only need to be called on a specific string literal once

30 gas per instance
120

Rest is too opinionated for me :P

Great report as usual, would love to see a couple customized suggestion (packing or similar) and benchmarks, but still really good

3120 gas saved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants