Axelar Network - Rolezn's results

Decentralized interoperability network.

General Information

Platform: Code4rena

Start Date: 12/07/2023

Pot Size: $80,000 USDC

Total HM: 11

Participants: 47

Period: 9 days

Judge: berndartmueller

Total Solo HM: 1

Id: 260

League: ETH

Axelar Network

Findings Distribution

Researcher Performance

Rank: 16/47

Findings: 2

Award: $664.41

QA:
grade-a
Gas:
grade-a

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Labels

bug
grade-a
QA (Quality Assurance)
Q-12

Awards

474.6749 USDC - $474.67

External Links

QA Summary<a name="QA Summary">

Low Risk Issues

IssueContexts
LOW‑1Dangerous use of the burn function1
LOW‑2decimals() not part of ERC20 standard1
LOW‑3Remove unused code1
LOW‑4Unnecessary Low level calls should be avoided1

Total: 4 contexts over 4 issues

Non-critical Issues

IssueContexts
NC‑1Avoid the use of sensitive terms42
NC‑2Do not calculate constants22
NC‑3block.timestamp is already used when emitting events, no need to input timestamp1
NC‑4Generate perfect code headers for better solidity code layout and readability31
NC‑5override function arguments that are unused should have the variable name removed or commented out to avoid compiler warnings2
NC‑6Using underscore at the end of variable name16
NC‑7Use abi.encodeCall() instead of abi.encodeSignature()/abi.encodeSelector()7
NC‑8Use named function calls9
NC‑9Use SMTChecker1
NC‑10Cast to bytes or bytes32 for clearer semantic meaning4
NC‑11Utilizing delegatecall within a loop1

Total: 136 contexts over 11 issues

Low Risk Issues

<a href="#qa-summary">[LOW‑1]</a><a name="LOW&#x2011;1"> Dangerous use of the burnToken function

The function burnToken is used by users to burn an option position by minting the required liquidity and unlocking the collateral. As how the function is designed right now in order to do that, the user needs to send his shares to the contract balance. This is simply too risky, as anyone can call the function and basically burn the shares deposited by the users, before they even get the chance to call the function first.

Instead of the need to send the shares to the contract balance, the function can be refactored to check the balance of shares the user posses and to burn them in the moment of execution or on top of that to input a uint value of how many shares the user wants to burn.

<ins>Proof Of Concept</ins>
File: AxelarGateway.sol


function burnToken(bytes calldata params, bytes32) external onlySelf {
        (string memory symbol, bytes32 salt) = abi.decode(params, (string, bytes32));

        address tokenAddress = tokenAddresses(symbol);

        if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);

        if (_getTokenType(symbol) == TokenType.External) {
            address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode)));

            if (_hasCode(depositHandlerAddress)) return;

            DepositHandler depositHandler = new DepositHandler{ salt: salt }();

            (bool success, bytes memory returnData) = depositHandler.execute(
                tokenAddress,
                abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler)))
            );

            if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol);

            
            depositHandler.destroy(address(this));
        } else {
            IBurnableMintableCappedERC20(tokenAddress).burn(salt);
        }
    }

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L427

<a href="#qa-summary">[LOW‑2]</a><a name="LOW&#x2011;2"> decimals() not part of ERC20 standard

decimals() is not part of the official ERC20 standard and might fail for tokens that do not implement it. While in practice it is very unlikely, as usually most of the tokens implement it, this should still be considered as a potential issue.

<ins>Proof Of Concept</ins>
File: InterchainTokenService.sol

737: decimals = token.decimals()

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L737

<a href="#qa-summary">[LOW‑3]</a><a name="LOW&#x2011;3"> Remove unused code

This code is not used in the main project contract files, remove it or add event-emit Code that is not in use, suggests that they should not be present and could potentially contain insecure functionalities.

<ins>Proof Of Concept</ins>
File: InterchainGovernance.sol

function _executeWithToken

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/InterchainGovernance.sol#L155

<a href="#qa-summary">[LOW‑4]</a><a name="LOW&#x2011;4"> Unnecessary Low level calls should be avoided

Avoid making unnecessary low-level calls to the system whenever possible, as they function differently from contract-type calls. For instance: Using address.call(abi.encodeWithSelector("fancy(bytes32)", mybytes) does not confirm whether the target is genuinely a contract, whereas ContractInterface(address).fancy(mybytes) does.

Moreover, when invoking functions declared as view/pure, the Solidity compiler executes a staticcall, offering extra security guarantees that are absent in low-level calls. Additionally, return values must be manually decoded when making low-level calls.

Note: If a low-level call is required, consider using Contract.function.selector instead of employing a hardcoded ABI string for encoding.

<ins>Proof Of Concept</ins>
File: AxelarGateway.sol


function execute(bytes calldata input) external override {
        (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes));

        bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data));

        
        bool allowOperatorshipTransfer = IAxelarAuth(AUTH_MODULE).validateProof(messageHash, proof);

        uint256 chainId;
        bytes32[] memory commandIds;
        string[] memory commands;
        bytes[] memory params;

        (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[]));

        if (chainId != block.chainid) revert InvalidChainId();

        uint256 commandsLength = commandIds.length;

        if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();

        for (uint256 i; i < commandsLength; ++i) {
            bytes32 commandId = commandIds[i];

            if (isCommandExecuted(commandId)) continue; 

            bytes4 commandSelector;
            bytes32 commandHash = keccak256(abi.encodePacked(commands[i]));

            if (commandHash == SELECTOR_DEPLOY_TOKEN) {
                commandSelector = AxelarGateway.deployToken.selector;
            } else if (commandHash == SELECTOR_MINT_TOKEN) {
                commandSelector = AxelarGateway.mintToken.selector;
            } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
                commandSelector = AxelarGateway.approveContractCall.selector;
            } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
                commandSelector = AxelarGateway.approveContractCallWithMint.selector;
            } else if (commandHash == SELECTOR_BURN_TOKEN) {
                commandSelector = AxelarGateway.burnToken.selector;
            } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
                if (!allowOperatorshipTransfer) continue;

                allowOperatorshipTransfer = false;
                commandSelector = AxelarGateway.transferOperatorship.selector;
            } else {
                continue; 
            }

            
            _setCommandExecuted(commandId, true);

            (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId));

            if (success) emit Executed(commandId);
            else _setCommandExecuted(commandId, false);
        }
    }

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L374

<ins>Recommended Mitigation Steps</ins>

When reaching out to a known contract within the system, always opt for typed contract calls (interfaces/contracts) rather than low-level calls. This approach helps prevent mistakes, potentially unverified return values, and ensures security guarantees.

Non Critical Issues

<a href="#qa-summary">[NC‑1]</a><a name="NC&#x2011;1"> Avoid the use of sensitive terms

Use <a href="https://www.zdnet.com/article/mysql-drops-master-slave-and-blacklist-whitelist-terminology/">alternative variants</a>, e.g. allowlist/denylist instead of whitelist/blacklist

<ins>Proof Of Concept</ins>
File: InterchainProposalExecutor.sol

15: * The contract maintains whitelists for proposal senders and proposal callers. Proposal senders
23: // Whitelisted proposal callers. The proposal caller is the contract that calls the `InterchainProposalSender` at the source chain.
24: mapping(string => mapping(address => bool)) public whitelistedCallers;
26: // Whitelisted proposal senders. The proposal sender is the `InterchainProposalSender` contract address at the source chain.
27: mapping(string => mapping(address => bool)) public whitelistedSenders;
34: * @dev Executes the proposal. The source address must be a whitelisted sender.
48: // Check that the source address is whitelisted
49: if (!whitelistedSenders[sourceChain][StringToAddress.toAddress(sourceAddress)]) {
50: revert NotWhitelistedSourceAddress();
56: // Check that the caller is whitelisted
57: if (!whitelistedCallers[sourceChain][interchainProposalCaller]) {
58: revert NotWhitelistedCaller();
87: * @dev Set the proposal caller whitelist status
90: * @param whitelisted The whitelist status
105: * @param whitelisted The whitelist status
92: function setWhitelistedProposalCaller(
95: bool whitelisted
110: bool whitelisted
97: whitelistedCallers[sourceChain][sourceCaller] = whitelisted;
98: emit WhitelistedProposalCallerSet(sourceChain, sourceCaller, whitelisted);
102: * @dev Set the proposal sender whitelist status
107: function setWhitelistedProposalSender(
110: bool whitelisted
112: whitelistedSenders[sourceChain][sourceSender] = whitelisted;
113: emit WhitelistedProposalSenderSet(sourceChain, sourceSender, whitelisted);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L15

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L23

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L24

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L26

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L27

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L34

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L48

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L49

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L50

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L56

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L57

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L58

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L87

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L90

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L105

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L92

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L95

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L110

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L97

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L98

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L102

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L107

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L112

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L113

File: IInterchainProposalExecutor.sol

6: // An event emitted when the proposal caller is whitelisted
7: event WhitelistedProposalCallerSet(string indexed sourceChain, address indexed sourceCaller, bool whitelisted);
9: // An event emitted when the proposal sender is whitelisted
10: event WhitelistedProposalSenderSet(string indexed sourceChain, address indexed sourceSender, bool whitelisted);
17: // An error emitted when the proposal caller is not whitelisted
18: error NotWhitelistedCaller();
20: // An error emitted when the proposal sender is not whitelisted
21: error NotWhitelistedSourceAddress();
24: * @notice set the whitelisted status of a proposal sender which is the `InterchainProposalSender` contract address on the source chain
27: * @param whitelisted The whitelisted status
39: * @param whitelisted The whitelisted status
29: function setWhitelistedProposalSender(
32: bool whitelisted
44: bool whitelisted
36: * @notice set the whitelisted status of a proposal caller which normally set to the `Timelock` contract address on the source chain
41: function setWhitelistedProposalCaller(
44: bool whitelisted

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L6

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L7

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L9

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L10

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L17

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L18

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L20

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L21

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L24

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L27

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L39

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L29

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L32

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L44

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L36

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/interfaces/IInterchainProposalExecutor.sol#L41

<a href="#qa-summary">[NC‑2]</a><a name="NC&#x2011;2"> Do not calculate constants

Due to how constant variables are implemented (replacements at compile-time), an expression assigned to a constant variable is recomputed each time that the variable is used, which wastes some gas.

<ins>Proof Of Concept</ins>
<details>
File: AxelarGateway.sol

31: // bytes32 internal constant KEY_ALL_TOKENS_FROZEN = keccak256('all-tokens-frozen');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L31

File: AxelarGateway.sol

32: // bytes32 internal constant PREFIX_TOKEN_FROZEN = keccak256('token-frozen');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L32

File: AxelarGateway.sol

44: bytes32 internal constant PREFIX_COMMAND_EXECUTED = keccak256('command-executed');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L44

File: AxelarGateway.sol

45: bytes32 internal constant PREFIX_TOKEN_ADDRESS = keccak256('token-address');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L45

File: AxelarGateway.sol

46: bytes32 internal constant PREFIX_TOKEN_TYPE = keccak256('token-type');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L46

File: AxelarGateway.sol

47: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED = keccak256('contract-call-approved');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L47

File: AxelarGateway.sol

48: bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT = keccak256('contract-call-approved-with-mint');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L48

File: AxelarGateway.sol

49: bytes32 internal constant PREFIX_TOKEN_MINT_LIMIT = keccak256('token-mint-limit');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L49

File: AxelarGateway.sol

50: bytes32 internal constant PREFIX_TOKEN_MINT_AMOUNT = keccak256('token-mint-amount');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L50

File: FinalProxy.sol

18: bytes32 internal constant FINAL_IMPLEMENTATION_SALT = keccak256('final-implementation');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/FinalProxy.sol#L18

File: TimeLock.sol

13: bytes32 internal constant PREFIX_TIME_LOCK = keccak256('time-lock');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L13

File: InterchainTokenService.sol

62: bytes32 internal constant PREFIX_CUSTOM_TOKEN_ID = keccak256('its-custom-token-id');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L62

File: InterchainTokenService.sol

63: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_ID = keccak256('its-standardized-token-id');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L63

File: InterchainTokenService.sol

64: bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_SALT = keccak256('its-standardized-token-salt');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L64

File: InterchainTokenService.sol

71: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L71

File: InterchainTokenServiceProxy.sol

12: bytes32 private constant CONTRACT_ID = keccak256('interchain-token-service');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/proxies/InterchainTokenServiceProxy.sol#L12

File: RemoteAddressValidatorProxy.sol

12: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/proxies/RemoteAddressValidatorProxy.sol#L12

File: StandardizedTokenProxy.sol

14: bytes32 private constant CONTRACT_ID = keccak256('standardized-token');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/proxies/StandardizedTokenProxy.sol#L14

File: RemoteAddressValidator.sol

21: bytes32 private constant CONTRACT_ID = keccak256('remote-address-validator');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L21

File: StandardizedToken.sol

27: bytes32 private constant CONTRACT_ID = keccak256('standardized-token');

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-implementations/StandardizedToken.sol#L27

File: FlowLimit.sol

15: uint256 internal constant PREFIX_FLOW_OUT_AMOUNT = uint256(keccak256('prefix-flow-out-amount'));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L15

File: FlowLimit.sol

16: uint256 internal constant PREFIX_FLOW_IN_AMOUNT = uint256(keccak256('prefix-flow-in-amount'));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L16

</details>

<a href="#qa-summary">[NC‑3]</a><a name="NC&#x2011;3"> block.timestamp is already used when emitting events, no need to input timestamp

<ins>Proof Of Concept</ins>
File: InterchainGovernance.sol

78: emit ProposalExecuted(proposalHash, target, callData, nativeValue, block.timestamp);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/InterchainGovernance.sol#L78

<a href="#qa-summary">[NC‑4]</a><a name="NC&#x2011;4"> Generate perfect code headers for better solidity code layout and readability

It is recommended to use pre-made headers for Solidity code layout and readability: https://github.com/transmissions11/headers

/*//////////////////////////////////////////////////////////////
                           TESTING 123
//////////////////////////////////////////////////////////////*/
<ins>Proof Of Concept</ins>
<details>
File: AxelarGateway.sol

7: AxelarGateway.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L7

File: MultisigBase.sol

5: MultisigBase.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L5

File: AxelarServiceGovernance.sol

5: AxelarServiceGovernance.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L5

File: InterchainGovernance.sol

7: InterchainGovernance.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/InterchainGovernance.sol#L7

File: Multisig.sol

5: Multisig.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/Multisig.sol#L5

File: Caller.sol

5: Caller.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Caller.sol#L5

File: Upgradable.sol

5: Upgradable.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Upgradable.sol#L5

File: FinalProxy.sol

6: FinalProxy.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/FinalProxy.sol#L6

File: InitProxy.sol

5: InitProxy.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/InitProxy.sol#L5

File: Proxy.sol

5: Proxy.sol
7: Proxy.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/Proxy.sol#L5

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/Proxy.sol#L7

File: Upgradable.sol

5: Upgradable.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/Upgradable.sol#L5

File: TimeLock.sol

5: TimeLock.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L5

File: InterchainProposalExecutor.sol

7: InterchainProposalExecutor.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L7

File: InterchainProposalSender.sol

7: InterchainProposalSender.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalSender.sol#L7

File: InterchainToken.sol

5: InterchainToken.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token/InterchainToken.sol#L5

File: InterchainTokenService.sol

11: InterchainTokenService.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L11

File: StandardizedTokenProxy.sol

7: StandardizedTokenProxy.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/proxies/StandardizedTokenProxy.sol#L7

File: TokenManagerProxy.sol

6: TokenManagerProxy.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/proxies/TokenManagerProxy.sol#L6

File: RemoteAddressValidator.sol

4: RemoteAddressValidator.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L4

File: Pausable.sol

5: Pausable.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/test/utils/Pausable.sol#L5

File: TokenManager.sol

5: TokenManager.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-manager/TokenManager.sol#L5

File: Distributable.sol

5: Distributable.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L5

File: ExpressCallHandler.sol

5: ExpressCallHandler.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/ExpressCallHandler.sol#L5

File: FlowLimit.sol

5: FlowLimit.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L5

File: Implementation.sol

5: Implementation.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Implementation.sol#L5

File: Multicall.sol

5: Multicall.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L5

File: Operatable.sol

5: Operatable.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L5

File: Pausable.sol

5: Pausable.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L5

File: StandardizedTokenDeployer.sol

7: StandardizedTokenDeployer.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/StandardizedTokenDeployer.sol#L7

File: TokenManagerDeployer.sol

7: TokenManagerDeployer.sol

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/TokenManagerDeployer.sol#L7

</details>

<a href="#qa-summary">[NC‑5]</a><a name="NC&#x2011;5"> override function arguments that are unused should have the variable name removed or commented out to avoid compiler warnings

<ins>Proof Of Concept</ins>
File: AxelarGateway.sol

224: function admins : uint256

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L224

File: AxelarGateway.sol

238: function tokenFrozen : string memory

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L238

<a href="#qa-summary">[NC‑6]</a><a name="NC&#x2011;6"> Using underscore at the end of variable name

The use of underscore at the end of the variable name is uncommon and also suggests that the variable name was not completely changed. Consider refactoring variableName_ to variableName.

<ins>Proof Of Concept</ins>
<details>
File: AxelarGateway.sol

68: authModule_;
69: tokenDeployerImplementation_;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L68-L69

File: InterchainGovernance.sol

39: governanceChain_;
40: governanceAddress_;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/InterchainGovernance.sol#L39-L40

File: InterchainTokenService.sol

100: tokenManagerDeployer_;
101: standardizedTokenDeployer_;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L100-L101

File: TokenManagerProxy.sol

32: implementationType_;
33: tokenId_;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/proxies/TokenManagerProxy.sol#L32-L33

File: StandardizedToken.sol

51: distributor_;
52: tokenManager_;
56: tokenManager_;
52: tokenManager_;
56: tokenManager_;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-implementations/StandardizedToken.sol#L51

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-implementations/StandardizedToken.sol#L52

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-implementations/StandardizedToken.sol#L56

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-implementations/StandardizedToken.sol#L52

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-implementations/StandardizedToken.sol#L56

File: TokenManager.sol

63: operator_;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-manager/TokenManager.sol#L63

File: StandardizedTokenDeployer.sol

34: implementationLockUnlockAddress_;
35: implementationMintBurnAddress_;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/StandardizedTokenDeployer.sol#L34-L35

</details>

<a href="#qa-summary">[NC‑7]</a><a name="NC&#x2011;7"> Use abi.encodeCall() instead of abi.encodeSignature()/abi.encodeSelector()

abi.encodeCall() has compiler <a href="https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3693">type safety</a>, whereas the other two functions do not

<ins>Proof Of Concept</ins>
<details>
File: AxelarGateway.sol

294: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(IAxelarGateway.setup.selector, setupParams));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L294

File: AxelarGateway.sol

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

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L374

File: AxelarGateway.sol

399: abi.encodeWithSelector(ITokenDeployer.deployToken.selector, name, symbol, decimals, cap, salt)

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L399

File: AxelarGateway.sol

443: abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler)))

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L443

File: Upgradable.sol

49: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(this.setup.selector, params));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Upgradable.sol#L49

File: InitProxy.sol

58: (bool success, ) = implementationAddress.delegatecall(abi.encodeWithSelector(IUpgradable.setup.selector, params));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/InitProxy.sol#L58

File: Upgradable.sol

61: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(this.setup.selector, params));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/Upgradable.sol#L61

</details>

<a href="#qa-summary">[NC‑8]</a><a name="NC&#x2011;8"> Use named function calls

Code base has an extensive use of named function calls, but it somehow missed one instance where this would be appropriate.

It should use named function calls on function call, as such:

    library.exampleFunction{value: _data.amount.value}({
        _id: _data.id,
        _amount: _data.amount.value,
        _token: _data.token,
        _example: "",
        _metadata: _data.metadata
    });
<ins>Proof Of Concept</ins>
<details>
File: Caller.sol

18: (bool success, ) = target.call{ value: nativeValue }(callData);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Caller.sol#L18

File: InterchainProposalExecutor.sol

76: (bool success, bytes memory result) = call.target.call{ value: call.value }(call.callData);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L76

File: InterchainProposalSender.sol

92: gasService.payNativeGasForContractCall{ value: interchainCall.gas }(
                address(this),
                interchainCall.destinationChain,
                interchainCall.destinationContract,
                payload,
                msg.sender
            );

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalSender.sol#L92

File: InterchainToken.sol

66: tokenManager.transmitInterchainTransfer{ value: msg.value }(sender, destinationChain, recipient, amount, metadata);
104: tokenManager.transmitInterchainTransfer{ value: msg.value }(sender, destinationChain, recipient, amount, metadata);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token/InterchainToken.sol#L66

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token/InterchainToken.sol#L104

File: InterchainTokenService.sol

715: gasService.payNativeGasForContractCall{ value: gasValue }(
                address(this),
                destinationChain,
                destinationAddress,
                payload,
                refundTo
            );

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L715

File: TokenManager.sol

92: interchainTokenService.transmitSendToken{ value: msg.value }(
            _getTokenId(),
            sender,
            destinationChain,
            destinationAddress,
            amount,
            metadata
        );
145: interchainTokenService.transmitSendToken{ value: msg.value }(
            _getTokenId(),
            sender,
            destinationChain,
            destinationAddress,
            amount,
            metadata
        );

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-manager/TokenManager.sol#L92

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-manager/TokenManager.sol#L145

File: TokenManager.sol

119: interchainTokenService.transmitSendToken{ value: msg.value }(
            _getTokenId(),
            sender,
            destinationChain,
            destinationAddress,
            amount,
            abi.encodePacked(version, data)
        );

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-manager/TokenManager.sol#L119

</details>

<a href="#qa-summary">[NC‑9]</a><a name="NC&#x2011;9"> Use SMTChecker

The highest tier of smart contract behavior assurance is formal mathematical verification. All assertions that are made are guaranteed to be true across all inputs → The quality of your asserts is the quality of your verification

https://twitter.com/0xOwenThurm/status/1614359896350425088?t=dbG9gHFigBX85Rv29lOjIQ&s=19

<a href="#qa-summary">[NC‑10]</a><a name="NC&#x2011;10"> Cast to bytes or bytes32 for clearer semantic meaning

Using a <a href="https://ethereum.stackexchange.com/questions/30912/how-to-compare-strings-in-solidity#answer-82739">cast</a> on a single argument, rather than abi.encodePacked() makes the intended operation more clear, leading to less reviewer confusion.

<ins>Proof Of Concept</ins>
File: AxelarGateway.sol

350: bytes32 commandHash = keccak256(abi.encodePacked(commands[i]));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L350

File: AxelarGateway.sol

396: bytes32 salt = keccak256(abi.encodePacked(symbol));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L396

File: AxelarGateway.sol

435: address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode)));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L435

File: TokenManagerDeployer.sol

39: bytes memory bytecode = abi.encodePacked(type(TokenManagerProxy).creationCode, args);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/TokenManagerDeployer.sol#L39

<a href="#qa-summary">[NC‑11]</a><a name="NC&#x2011;11"> Utilizing delegatecall within a loop

Using delegatecall in a for loop can lead to high gas costs, as delegatecall is an expensive operation and its costs compound when used in a loop. Additionally, it can pose security risks including reentrancy attacks, as it executes code in the calling contract's context. The function selector collisions can also lead to unpredictable behaviour. To mitigate these risks, control the loop's iterations, apply a reentrancy guard, strictly audit contracts called via delegatecall, and consider alternatives like call or proxy patterns if the use case allows. Always thoroughly vet contracts involved in delegatecall operations.

<ins>Proof Of Concept</ins>
File: Multicall.sol

25: (bool success, bytes memory result) = address(this).delegatecall(data[i]);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L25

#0 - c4-judge

2023-09-08T11:49:25Z

berndartmueller marked the issue as grade-a

Awards

189.7433 USDC - $189.74

Labels

bug
G (Gas Optimization)
grade-a
high quality report
G-18

External Links

GAS Summary<a name="GAS Summary">

Gas Optimizations

IssueContextsEstimated Gas Saved
GAS‑1abi.encode() is less efficient than abi.encodepacked()281484
GAS‑2Use assembly in place of abi.decode to extract calldata values more efficiently2224
GAS‑3Use assembly to emit events491862
GAS‑4Counting down in for statements is more gas efficient133341
GAS‑5Use assembly to write address storage values174
GAS‑6Multiple accesses of a mapping/array should use a local variable cache6480
GAS‑7The result of a function call should be cached rather than re-calling the function261300
GAS‑8Superfluous event fields268
GAS‑9Use nested if and avoid multiple check combinations424
GAS‑10Using XOR (^) and AND (&) bitwise equivalents57741
GAS‑11Using this.<fn>() wastes gas2200

Total: 196 contexts over 11 issues

Gas Optimizations

<a href="#gas-summary">[GAS‑1]</a><a name="GAS&#x2011;1"> abi.encode() is less efficient than abi.encodepacked()

See for more information: https://github.com/ConnorBlockchain/Solidity-Encode-Gas-Comparison

<ins>Proof Of Concept</ins>
<details>
File: AxelarGateway.sol

562: return keccak256(abi.encode(PREFIX_TOKEN_MINT_AMOUNT, symbol, day));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L562

File: AxelarGateway.sol

584: return keccak256(abi.encode(PREFIX_CONTRACT_CALL_APPROVED, commandId, sourceChain, sourceAddress, contractAddress, payloadHash));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L584

File: AxelarGateway.sol

598: abi.encode(

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L598

File: ConstAddressDeployer.sol

25: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt)));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/ConstAddressDeployer.sol#L25

File: ConstAddressDeployer.sol

47: deployedAddress_ = _deploy(bytecode, keccak256(abi.encode(msg.sender, salt)));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/ConstAddressDeployer.sol#L47

File: ConstAddressDeployer.sol

63: bytes32 newSalt = keccak256(abi.encode(sender, salt));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/ConstAddressDeployer.sol#L63

File: InterchainProposalExecutor.sol

66: emit ProposalExecuted(keccak256(abi.encode(sourceChain, sourceAddress, interchainProposalCaller, payload)));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L66

File: InterchainProposalSender.sol

89: bytes memory payload = abi.encode(msg.sender, interchainCall.calls);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalSender.sol#L89

File: InterchainTokenService.sol

203: tokenId = keccak256(abi.encode(PREFIX_STANDARDIZED_TOKEN_ID, chainNameHash, tokenAddress));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L203

File: InterchainTokenService.sol

214: tokenId = keccak256(abi.encode(PREFIX_CUSTOM_TOKEN_ID, sender, salt));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L214

File: InterchainTokenService.sol

242: params = abi.encode(operator, tokenAddress);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L242

File: InterchainTokenService.sol

252: params = abi.encode(operator, tokenAddress);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L252

File: InterchainTokenService.sol

267: params = abi.encode(operator, tokenAddress, liquidityPoolAddress);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L267

File: InterchainTokenService.sol

313: _deployTokenManager(tokenId, TokenManagerType.LOCK_UNLOCK, abi.encode(address(this).toBytes(), tokenAddress));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L313

File: InterchainTokenService.sol

401: _deployTokenManager(tokenId, tokenManagerType, abi.encode(msg.sender.toBytes(), tokenAddress));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L401

File: InterchainTokenService.sol

512: payload = abi.encode(SELECTOR_SEND_TOKEN, tokenId, destinationAddress, amount);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L512

File: InterchainTokenService.sol

520: payload = abi.encode(SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destinationAddress, amount, sourceAddress.toBytes(), metadata);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L520

File: InterchainTokenService.sol

696: abi.encode(operatorBytes.length == 0 ? address(this).toBytes() : operatorBytes, tokenAddress)

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L696

File: InterchainTokenService.sol

755: bytes memory payload = abi.encode(SELECTOR_DEPLOY_TOKEN_MANAGER, tokenId, tokenManagerType, params);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L755

File: InterchainTokenService.sol

780: bytes memory payload = abi.encode(

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L780

File: InterchainTokenService.sol

828: return keccak256(abi.encode(PREFIX_STANDARDIZED_TOKEN_SALT, tokenId));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L828

File: ExpressCallHandler.sol

32: slot = uint256(keccak256(abi.encode(PREFIX_EXPRESS_RECEIVE_TOKEN, tokenId, destinationAddress, amount, commandId)));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/ExpressCallHandler.sol#L32

File: ExpressCallHandler.sol

57: abi.encode(

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/ExpressCallHandler.sol#L57

File: FlowLimit.sol

47: slot = uint256(keccak256(abi.encode(PREFIX_FLOW_OUT_AMOUNT, epoch)));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L47

File: FlowLimit.sol

56: slot = uint256(keccak256(abi.encode(PREFIX_FLOW_IN_AMOUNT, epoch)));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L56

File: StandardizedTokenDeployer.sol

62: bytes memory params = abi.encode(tokenManager, distributor, name, symbol, decimals, mintAmount, mintTo);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/StandardizedTokenDeployer.sol#L62

File: StandardizedTokenDeployer.sol

63: bytecode = abi.encodePacked(type(StandardizedTokenProxy).creationCode, abi.encode(implementationAddress, params));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/StandardizedTokenDeployer.sol#L63

File: TokenManagerDeployer.sol

38: bytes memory args = abi.encode(address(this), implementationType, tokenId, params);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/TokenManagerDeployer.sol#L38

</details>
Test Code
contract GasTest is DSTest { Contract0 c0; Contract1 c1; function setUp() public { c0 = new Contract0(); c1 = new Contract1(); } function testGas() public { c0.not_optimized(); c1.optimized(); } } contract Contract0 { string a = "Code4rena"; function not_optimized() public returns(bytes32){ return keccak256(abi.encode(a)); } } contract Contract1 { string a = "Code4rena"; function optimized() public returns(bytes32){ return keccak256(abi.encodePacked(a)); } }
Gas Test Report
Contract0 contract
Deployment CostDeployment Size
101871683
Function Nameminavgmedianmax# calls
not_optimized26612661266126611
Contract1 contract
Deployment CostDeployment Size
99465671
Function Nameminavgmedianmax# calls
optimized26082608260826081

<a href="#gas-summary">[GAS‑2]</a><a name="GAS&#x2011;2"> Use assembly in place of abi.decode to extract calldata values more efficiently

Instead of using abi.decode, we can use assembly to decode our desired calldata values directly. This will allow us to avoid decoding calldata values that we will not use.

For example, for a generic abi.decode call:

(bytes32 varA, bytes32 varB, uint256 varC, uint256 varD) = abi.decode(metadata, (bytes32, bytes32, uint256, uint256));

We can use the following assembly call to extract the relevant metadata:

        bytes32 varA;
        bytes32 varB;
        uint256 varC;
        uint256 varD;
        { // used to discard `data` variable and avoid extra stack manipulation
            bytes calldata data = metadata;
            assembly {
                varA := calldataload(add(data.offset, 0x00))
                varB := calldataload(add(data.offset, 0x20))
                varC := calldataload(add(data.offset, 0x40))
                varD := calldataload(add(data.offset, 0x60))
            }
        }
<ins>Proof Of Concept</ins>
File: AxelarGateway.sol

422: (string memory symbol, address account, uint256 amount) = abi.decode(params, (string, address, uint256));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L422

File: InterchainTokenService.sol

600: (, bytes32 tokenId, bytes memory destinationAddressBytes, uint256 amount) = abi.decode(payload, (uint256, bytes32, bytes, uint256));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L600

<a href="#gas-summary">[GAS‑3]</a><a name="GAS&#x2011;3"> Use assembly to emit events

We can use assembly to emit events efficiently by utilizing scratch space and the free memory pointer. This will allow us to potentially avoid memory expansion costs. Note: In order to do this optimization safely, we will need to cache and restore the free memory pointer.

For example, for a generic emit event for eventSentAmountExample:

// uint256 id, uint256 value, uint256 amount
emit eventSentAmountExample(id, value, amount);

We can use the following assembly emit events:

        assembly {
            let memptr := mload(0x40)
            mstore(0x00, calldataload(0x44))
            mstore(0x20, calldataload(0xa4))
            mstore(0x40, amount)
            log1(
                0x00,
                0x60,
                // keccak256("eventSentAmountExample(uint256,uint256,uint256)")
                0xa622cf392588fbf2cd020ff96b2f4ebd9c76d7a4bc7f3e6b2f18012312e76bc3
            )
            mstore(0x40, memptr)
        }
<ins>Proof Of Concept</ins>
<details>
File: AxelarGateway.sol

104: emit TokenSent(msg.sender, destinationChain, destinationAddress, symbol, amount);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L104

File: AxelarGateway.sol

112: emit ContractCall(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L112

File: AxelarGateway.sol

123: emit ContractCallWithToken(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload, symbol, amount);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L123

File: AxelarGateway.sol

289: emit Upgraded(newImplementation);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L289

File: AxelarGateway.sol

319: emit OperatorshipTransferred(newOperatorsData);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L319

File: AxelarGateway.sol

376: if (success) emit Executed(commandId);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L376

File: AxelarGateway.sol

418: emit TokenDeployed(symbol, tokenAddress);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L418

File: AxelarGateway.sol

466: emit ContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, sourceTxHash, sourceEventIndex);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L466

File: AxelarGateway.sol

498: emit OperatorshipTransferred(newOperatorsData);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L498

File: AxelarGateway.sol

630: emit TokenMintLimitUpdated(symbol, limit);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L630

File: AxelarGateway.sol

682: emit GovernanceTransferred(getAddress(KEY_GOVERNANCE), newGovernance);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L682

File: AxelarGateway.sol

688: emit MintLimiterTransferred(getAddress(KEY_MINT_LIMITER), newMintLimiter);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L688

File: MultisigBase.sol

178: emit SignersRotated(newAccounts, newThreshold);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L178

File: AxelarServiceGovernance.sol

61: emit MultisigExecuted(proposalHash, target, callData, nativeValue);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L61

File: AxelarServiceGovernance.sol

89: emit ProposalScheduled(proposalHash, target, callData, nativeValue, eta);
94: emit ProposalCancelled(proposalHash, target, callData, nativeValue, eta);
99: emit MultisigApproved(proposalHash, target, callData, nativeValue);
104: emit MultisigCancelled(proposalHash, target, callData, nativeValue);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L89

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L94

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L99

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L104

File: InterchainGovernance.sol

78: emit ProposalExecuted(proposalHash, target, callData, nativeValue, block.timestamp);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/InterchainGovernance.sol#L78

File: InterchainGovernance.sol

130: emit ProposalScheduled(proposalHash, target, callData, nativeValue, eta);
135: emit ProposalCancelled(proposalHash, target, callData, nativeValue, eta);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/InterchainGovernance.sol#L130

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/InterchainGovernance.sol#L135

File: Upgradable.sol

27: emit OwnershipTransferred(newOwner);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Upgradable.sol#L27

File: Upgradable.sol

54: emit Upgraded(newImplementation);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Upgradable.sol#L54

File: ConstAddressDeployer.sol

90: emit Deployed(keccak256(bytecode), salt, deployedAddress_);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/ConstAddressDeployer.sol#L90

File: Upgradable.sol

66: emit Upgraded(newImplementation);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/Upgradable.sol#L66

File: InterchainProposalExecutor.sol

66: emit ProposalExecuted(keccak256(abi.encode(sourceChain, sourceAddress, interchainProposalCaller, payload)));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L66

File: InterchainProposalExecutor.sol

98: emit WhitelistedProposalCallerSet(sourceChain, sourceCaller, whitelisted);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L98

File: InterchainProposalExecutor.sol

113: emit WhitelistedProposalSenderSet(sourceChain, sourceSender, whitelisted);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L113

File: InterchainTokenService.sol

351: emit CustomTokenIdClaimed(tokenId, deployer_, salt);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L351

File: InterchainTokenService.sol

375: emit CustomTokenIdClaimed(tokenId, deployer_, salt);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L375

File: InterchainTokenService.sol

514: emit TokenSent(tokenId, destinationChain, destinationAddress, amount);
522: emit TokenSentWithData(tokenId, destinationChain, destinationAddress, amount, sourceAddress, metadata);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L514

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L522

File: InterchainTokenService.sol

611: emit TokenReceived(tokenId, sourceChain, destinationAddress, amount);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L611

File: InterchainTokenService.sol

659: emit TokenReceivedWithData(tokenId, sourceChain, destinationAddress, amount, sourceAddress, data);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L659

File: InterchainTokenService.sol

757: emit RemoteTokenManagerDeploymentInitialized(tokenId, destinationChain, gasValue, tokenManagerType, params);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L757

File: InterchainTokenService.sol

819: emit TokenManagerDeployed(tokenId, tokenManagerType, params);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L819

File: InterchainTokenService.sol

869: emit StandardizedTokenDeployed(tokenId, name, symbol, decimals, mintAmount, mintTo);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L869

File: RemoteAddressValidator.sol

88: emit TrustedAddressAdded(chain, addr);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L88

File: RemoteAddressValidator.sol

99: emit TrustedAddressRemoved(chain);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L99

File: RemoteAddressValidator.sol

111: emit GatewaySupportedChainAdded(chainName);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L111

File: RemoteAddressValidator.sol

124: emit GatewaySupportedChainRemoved(chainName);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L124

File: Pausable.sol

15: emit TestEvent();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/test/utils/Pausable.sol#L15

File: Distributable.sol

43: emit DistributorChanged(distributor_);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Distributable.sol#L43

File: ExpressCallHandler.sol

95: emit ExpressReceive(tokenId, destinationAddress, amount, commandId, expressCaller);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/ExpressCallHandler.sol#L95

File: ExpressCallHandler.sol

137: emit ExpressReceiveWithData(tokenId, sourceChain, sourceAddress, destinationAddress, amount, data, commandId, expressCaller);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/ExpressCallHandler.sol#L137

File: ExpressCallHandler.sol

216: emit ExpressExecutionFulfilled(tokenId, destinationAddress, amount, commandId, expressCaller);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/ExpressCallHandler.sol#L216

File: FlowLimit.sol

38: emit FlowLimitSet(flowLimit);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L38

File: Operatable.sol

43: emit OperatorChanged(operator_);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Operatable.sol#L43

File: Pausable.sol

46: emit PausedSet(paused);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Pausable.sol#L46

</details>

<a href="#gas-summary">[GAS‑4]</a><a name="GAS&#x2011;4"> Counting down in for statements is more gas efficient

Counting down is more gas efficient than counting up because neither we are making zero variable to non-zero variable and also we will get gas refund in the last transaction when making non-zero to zero variable.

<ins>Proof Of Concept</ins>
<details>
File: AxelarGateway.sol

270: for (uint256 i; i < length; ++i) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L270

File: AxelarGateway.sol

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

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L344

File: MultisigBase.sol

122: for (uint256 i; i < length; ++i) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L122

File: MultisigBase.sol

153: for (uint256 i; i < length; ++i) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L153

File: InterchainProposalExecutor.sol

74: for (uint256 i = 0; i < calls.length; i++) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L74

File: InterchainProposalSender.sol

63: for (uint256 i = 0; i < interchainCalls.length; ) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalSender.sol#L63

File: InterchainProposalSender.sol

106: for (uint256 i = 0; i < interchainCalls.length; ) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalSender.sol#L106

File: InterchainTokenService.sol

537: for (uint256 i; i < length; ++i) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L537

File: RemoteAddressValidator.sol

44: for (uint256 i; i < length; ++i) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L44

File: RemoteAddressValidator.sol

56: for (uint256 i; i < length; i++) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L56

File: RemoteAddressValidator.sol

108: for (uint256 i; i < length; ++i) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L108

File: RemoteAddressValidator.sol

121: for (uint256 i; i < length; ++i) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L121

File: Multicall.sol

24: for (uint256 i = 0; i < data.length; ++i) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/Multicall.sol#L24

</details>
Test Code
contract GasTest is DSTest { Contract0 c0; Contract1 c1; function setUp() public { c0 = new Contract0(); c1 = new Contract1(); } function testGas() public { c0.AddNum(); c1.AddNum(); } } contract Contract0 { uint256 num = 3; function AddNum() public { uint256 _num = num; for(uint i=0;i<=9;i++){ _num = _num +1; } num = _num; } } contract Contract1 { uint256 num = 3; function AddNum() public { uint256 _num = num; for(uint i=9;i>=0;i--){ _num = _num +1; } num = _num; } }
Gas Test Report
Contract0 contract
Deployment CostDeployment Size
77011311
Function Nameminavgmedianmax# calls
AddNum70407040704070401
Contract1 contract
Deployment CostDeployment Size
73811295
Function Nameminavgmedianmax# calls
AddNum38193819381938191

<a href="#gas-summary">[GAS‑5]</a><a name="GAS&#x2011;5"> Use assembly to write address storage values

<ins>Proof Of Concept</ins>
File: TimeLock.sol

22: _minimumTimeLockDelay = minimumTimeDelay;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L22

<a href="#gas-summary">[GAS‑6]</a><a name="GAS&#x2011;6"> Multiple accesses of a mapping/array should use a local variable cache

Caching a mapping's value in a local storage or calldata variable when the value is accessed multiple times saves ~42 gas per access due to not having to perform the same offset calculation every time. Help the Optimizer by saving a storage variable's reference instead of repeatedly fetching it

To help the optimizer,declare a storage type variable and use it instead of repeatedly fetching the reference in a map or an array. As an example, instead of repeatedly calling someMap[someIndex], save its reference like this: SomeStruct storage someStruct = someMap[someIndex] and use it.

<ins>Proof Of Concept</ins>
File: MultisigBase.sol

172: if (signers.isSigner[account]) revert DuplicateSigner(account);
175: signers.isSigner[account] = true;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L172

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L175

File: AxelarServiceGovernance.sol

55: if (!multisigApprovals[proposalHash]) revert NotApproved();
57: multisigApprovals[proposalHash] = false;
102: multisigApprovals[proposalHash] = false;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L55

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L57

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L102

File: AxelarServiceGovernance.sol

97: multisigApprovals[proposalHash] = true;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L97

<a href="#gas-summary">[GAS‑16]</a><a name="GAS&#x2011;16"> Multiple Address Mappings Can Be Combined Into A Single Mapping Of An Address To A Struct, Where Appropriate

Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot.

<ins>Proof Of Concept</ins>
File: MultisigBase.sol

15: mapping(address => bool) hasVoted;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L15

File: MultisigBase.sol

21: mapping(address => bool) isSigner;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L21

File: InterchainProposalExecutor.sol

24: mapping(string => mapping(address => bool)) public whitelistedCallers;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L24

File: InterchainProposalExecutor.sol

27: mapping(string => mapping(address => bool)) public whitelistedSenders;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L27

<a href="#gas-summary">[GAS‑17]</a><a name="GAS&#x2011;17"> Optimize names to save gas

Contracts most called functions could simply save gas by function ordering via Method ID. Calling a function at runtime will be cheaper if the function is positioned earlier in the order (has a relatively lower Method ID) because 22 gas are added to the cost of a function for every position that came before it. The caller can save on gas if you prioritize most called functions.

See more <a href="https://medium.com/joyso/solidity-how-does-function-name-affect-gas-consumption-in-smart-contract-47d270d8ac92">here</a>

<ins>Proof Of Concept</ins>

All in-scope contracts

<ins>Recommended Mitigation Steps</ins>

Find a lower method ID name for the most called functions for example Call() vs. Call1() is cheaper by 22 gas For example, the function IDs in the Gauge.sol contract will be the most used; A lower method ID may be given.

<a href="#gas-summary">[GAS‑18]</a><a name="GAS&#x2011;18"> <x> += <y> Costs More Gas Than <x> = <x> + <y> For State Variables

<ins>Proof Of Concept</ins>
File: InterchainProposalSender.sol

107: totalGas += interchainCalls[i].gas;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/interchain-governance-executor/InterchainProposalSender.sol#L107

<a href="#gas-summary">[GAS‑7]</a><a name="GAS&#x2011;7"> The result of a function call should be cached rather than re-calling the function

External calls are expensive. Results of external function calls should be cached rather than call them multiple times. Consider caching the following:

<ins>Proof Of Concept</ins>
<details>
File: AxelarGateway.sol

287: if (AxelarGateway(newImplementation).contractId() != contractId()) revert InvalidImplementation();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L287

File: Upgradable.sol

45: if (IUpgradable(newImplementation).contractId() != IUpgradable(this).contractId()) revert InvalidImplementation();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Upgradable.sol#L45

File: BaseProxy.sol

49: calldatacopy(0, 0, calldatasize())
51: let result := delegatecall(gas(), implementation_, 0, calldatasize(), 0, 0)
52: returndatacopy(0, 0, returndatasize())
56: revert(0, returndatasize())
59: return(0, returndatasize())

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/BaseProxy.sol#L49

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/BaseProxy.sol#L51

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/BaseProxy.sol#L52

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/BaseProxy.sol#L56

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/BaseProxy.sol#L59

File: FixedProxy.sol

41: calldatacopy(0, 0, calldatasize())
43: let result := delegatecall(gas(), implementation_, 0, calldatasize(), 0, 0)
44: returndatacopy(0, 0, returndatasize())
48: revert(0, returndatasize())
51: return(0, returndatasize())

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/FixedProxy.sol#L41

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/FixedProxy.sol#L43

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/FixedProxy.sol#L44

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/FixedProxy.sol#L48

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/FixedProxy.sol#L51

File: InitProxy.sol

49: bytes32 id = contractId();
50: if (id != bytes32(0) && IUpgradable(implementationAddress).contractId() != id) revert InvalidImplementation();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/InitProxy.sol#L49-L50

File: Upgradable.sol

57: if (IUpgradable(newImplementation).contractId() != IUpgradable(this).contractId()) revert InvalidImplementation();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/Upgradable.sol#L57

File: InterchainToken.sol

21: function getTokenManager() public view virtual returns (ITokenManager tokenManager);
32: function tokenManagerRequiresApproval() public view virtual returns (bool);
50: ITokenManager tokenManager = getTokenManager();
92: ITokenManager tokenManager = getTokenManager();
54: if (tokenManagerRequiresApproval()) {
93: if (tokenManagerRequiresApproval()) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token/InterchainToken.sol#L21

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token/InterchainToken.sol#L32

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token/InterchainToken.sol#L50

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token/InterchainToken.sol#L92

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token/InterchainToken.sol#L54

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token/InterchainToken.sol#L93

File: TokenManagerProxy.sol

76: calldatacopy(0, 0, calldatasize())
78: let result := delegatecall(gas(), implementaion_, 0, calldatasize(), 0, 0)
79: returndatacopy(0, 0, returndatasize())
83: revert(0, returndatasize())
86: return(0, returndatasize())

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/proxies/TokenManagerProxy.sol#L76

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/proxies/TokenManagerProxy.sol#L78

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/proxies/TokenManagerProxy.sol#L79

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/proxies/TokenManagerProxy.sol#L83

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/proxies/TokenManagerProxy.sol#L86

</details>

<a href="#gas-summary">[GAS‑8]</a><a name="GAS&#x2011;8"> Superfluous event fields

block.number and block.timestamp are added to the event information by default, so adding them manually will waste additional gas.

<ins>Proof Of Concept</ins>
File: IInterchainGovernance.sol

20: event ProposalExecuted(bytes32 indexed proposalHash, address indexed target, bytes callData, uint256 value, uint256 indexed timestamp);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/interfaces/IInterchainGovernance.sol#L20

File: IMultisigBase.sol

22: event SignersRotated(address[] newAccounts, uint256 newThreshold);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/interfaces/IMultisigBase.sol#L22

<a href="#gas-summary">[GAS‑9]</a><a name="GAS&#x2011;9"> Use nested if and avoid multiple check combinations

Using nested if, is cheaper than using && multiple check combinations. There are more advantages, such as easier to read code and better coverage reports.

<ins>Proof Of Concept</ins>
File: AxelarGateway.sol

446: if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L446

File: AxelarGateway.sol

635: if (limit > 0 && amount > limit) revert ExceedMintLimit(symbol);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L635

File: InitProxy.sol

50: if (id != bytes32(0) && IUpgradable(implementationAddress).contractId() != id) revert InvalidImplementation();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/InitProxy.sol#L50

File: RemoteAddressValidator.sol

58: if ((b >= 65) && (b <= 70)) bytes(s)[i] = bytes1(b + uint8(32));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L58

Test Code
contract GasTest is DSTest { Contract0 c0; Contract1 c1; function setUp() public { c0 = new Contract0(); c1 = new Contract1(); } function testGas() public { c0.checkAge(19); c1.checkAgeOptimized(19); } } contract Contract0 { function checkAge(uint8 _age) public returns(string memory){ if(_age>18 && _age<22){ return "Eligible"; } } } contract Contract1 { function checkAgeOptimized(uint8 _age) public returns(string memory){ if(_age>18){ if(_age<22){ return "Eligible"; } } } }
Gas Test Report
Contract0 contract
Deployment CostDeployment Size
76923416
Function Nameminavgmedianmax# calls
checkAge6516516516511
Contract1 contract
Deployment CostDeployment Size
76323413
Function Nameminavgmedianmax# calls
checkAgeOptimized6456456456451

<a href="#gas-summary">[GAS‑10]</a><a name="GAS&#x2011;10"> Using XOR (^) and AND (&) bitwise equivalents

Given 4 variables a, b, c and d represented as such:

0 0 0 0 0 1 1 0 <- a 0 1 1 0 0 1 1 0 <- b 0 0 0 0 0 0 0 0 <- c 1 1 1 1 1 1 1 1 <- d

To have a == b means that every 0 and 1 match on both variables. Meaning that a XOR (operator ^) would evaluate to 0 ((a ^ b) == 0), as it excludes by definition any equalities.Now, if a != b, this means that there’s at least somewhere a 1 and a 0 not matching between a and b, making (a ^ b) != 0.Both formulas are logically equivalent and using the XOR bitwise operator costs actually the same amount of gas.However, it is much cheaper to use the bitwise OR operator (|) than comparing the truthy or falsy values.These are logically equivalent too, as the OR bitwise operator (|) would result in a 1 somewhere if any value is not 0 between the XOR (^) statements, meaning if any XOR (^) statement verifies that its arguments are different.

<ins>Proof Of Concept</ins>
<details>
File: AxelarGateway.sol

255: if (newGovernance == address(0)) revert InvalidGovernance();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L255

File: AxelarGateway.sol

261: if (newMintLimiter == address(0)) revert InvalidMintLimiter();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L261

File: AxelarGateway.sol

342: if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();
352: if (commandHash == SELECTOR_DEPLOY_TOKEN) {
354: } else if (commandHash == SELECTOR_MINT_TOKEN) {
356: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
358: } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
360: } else if (commandHash == SELECTOR_BURN_TOKEN) {
362: } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L342

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L352

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L354

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L356

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L358

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L360

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L362

File: AxelarGateway.sol

394: if (tokenAddress == address(0)) {
409: if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L394

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L409

File: AxelarGateway.sol

432: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L432

File: AxelarGateway.sol

519: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L519

File: AxelarGateway.sol

537: if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
538: if (amount == 0) revert InvalidAmount();
542: if (tokenType == TokenType.External) {
544: } else if (tokenType == TokenType.InternalBurnableFrom) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L537

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L538

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L542

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/AxelarGateway.sol#L544

File: MultisigBase.sol

161: if (newThreshold == 0) revert InvalidSignerThreshold();
173: if (account == address(0)) revert InvalidSigners();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L161

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/auth/MultisigBase.sol#L173

File: AxelarServiceGovernance.sol

86: if (command == ServiceGovernanceCommand.ScheduleTimeLockProposal) {
91: } else if (command == ServiceGovernanceCommand.CancelTimeLockProposal) {
96: } else if (command == ServiceGovernanceCommand.ApproveMultisigProposal) {
101: } else if (command == ServiceGovernanceCommand.CancelMultisigApproval) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L86

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L91

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L96

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L101

File: InterchainGovernance.sol

92: if (keccak256(bytes(sourceChain)) != governanceChainHash || keccak256(bytes(sourceAddress)) != governanceAddressHash)
100: if (target == address(0)) revert InvalidTarget();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/InterchainGovernance.sol#L92

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/InterchainGovernance.sol#L100

File: InterchainGovernance.sol

127: if (command == GovernanceCommand.ScheduleTimeLockProposal) {
132: } else if (command == GovernanceCommand.CancelTimeLockProposal) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/InterchainGovernance.sol#L127

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/InterchainGovernance.sol#L132

File: Upgradable.sol

25: if (newOwner == address(0)) revert InvalidOwner();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Upgradable.sol#L25

File: ConstAddressDeployer.sol

81: if (bytecode.length == 0) revert EmptyBytecode();
88: if (deployedAddress_ == address(0)) revert FailedDeploy();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/ConstAddressDeployer.sol#L81

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/deploy/ConstAddressDeployer.sol#L88

File: FinalProxy.sol

39: if (implementation_ == address(0)) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/FinalProxy.sol#L39

File: FinalProxy.sol

63: if (implementation_.code.length == 0) implementation_ = address(0);

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/FinalProxy.sol#L63

File: Bytes32String.sol

13: if (stringBytes.length == 0 || stringBytes.length > 31) revert InvalidStringLength();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/Bytes32String.sol#L13

File: TimeLock.sol

51: if (hash == 0) revert InvalidTimeLockHash();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L51

File: TimeLock.sol

68: if (hash == 0) revert InvalidTimeLockHash();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L68

File: TimeLock.sol

82: if (hash == 0 || eta == 0) revert InvalidTimeLockHash();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/util/TimeLock.sol#L82

File: InterchainTokenService.sol

399: TokenManagerType tokenManagerType = distributor == tokenManagerAddress ? TokenManagerType.MINT_BURN : TokenManagerType.LOCK_UNLOCK;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L399

File: InterchainTokenService.sol

565: if (implementation == address(0)) revert ZeroAddress();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L565

File: InterchainTokenService.sol

581: if (selector == SELECTOR_SEND_TOKEN) {
583: } else if (selector == SELECTOR_SEND_TOKEN_WITH_DATA) {
585: } else if (selector == SELECTOR_DEPLOY_TOKEN_MANAGER) {
587: } else if (selector == SELECTOR_DEPLOY_AND_REGISTER_STANDARDIZED_TOKEN) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L581

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L583

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L585

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L587

File: InterchainTokenService.sol

609: if (expressCaller == address(0)) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L609

File: InterchainTokenService.sol

692: TokenManagerType tokenManagerType = distributor == tokenManagerAddress ? TokenManagerType.MINT_BURN : TokenManagerType.LOCK_UNLOCK;
696: abi.encode(operatorBytes.length == 0 ? address(this).toBytes() : operatorBytes, tokenAddress)

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L692

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L696

File: RemoteAddressValidator.sol

72: if (sourceAddressHash == interchainTokenServiceAddressHash) {
75: return sourceAddressHash == remoteAddressHashes[sourceChain];

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L72

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L75

File: RemoteAddressValidator.sol

84: if (bytes(chain).length == 0) revert ZeroStringLength();
85: if (bytes(addr).length == 0) revert ZeroStringLength();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L84-L85

File: RemoteAddressValidator.sol

96: if (bytes(chain).length == 0) revert ZeroStringLength();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L96

File: RemoteAddressValidator.sol

135: if (bytes(remoteAddress).length == 0) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L135

File: TokenManager.sol

68: if (operatorBytes.length == 0) {

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/token-manager/TokenManager.sol#L68

File: FlowLimit.sol

113: if (flowLimit == 0) return;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L113

File: FlowLimit.sol

126: if (flowLimit == 0) return;

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/FlowLimit.sol#L126

File: StandardizedTokenDeployer.sol

60: address implementationAddress = distributor == tokenManager ? implementationMintBurnAddress : implementationLockUnlockAddress;
66: if (tokenAddress.code.length == 0) revert TokenDeploymentFailed();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/StandardizedTokenDeployer.sol#L60

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/StandardizedTokenDeployer.sol#L66

File: TokenManagerDeployer.sol

41: if (tokenManagerAddress.code.length == 0) revert TokenManagerDeploymentFailed();

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/its/utils/TokenManagerDeployer.sol#L41

</details>
Test Code
contract GasTest is DSTest { Contract0 c0; Contract1 c1; function setUp() public { c0 = new Contract0(); c1 = new Contract1(); } function testGas() public { c0.not_optimized(1,2); c1.optimized(1,2); } } contract Contract0 { function not_optimized(uint8 a,uint8 b) public returns(bool){ return ((a==1) || (b==1)); } } contract Contract1 { function optimized(uint8 a,uint8 b) public returns(bool){ return ((a ^ 1) & (b ^ 1)) == 0; } }
Gas Test Report
Contract0 contract
Deployment CostDeployment Size
46099261
Function Nameminavgmedianmax# calls
not_optimized4564564564561
Contract1 contract
Deployment CostDeployment Size
42493243
Function Nameminavgmedianmax# calls
optimized4304304304301

<a href="#gas-summary">[GAS‑11]</a><a name="GAS&#x2011;11"> Using this.<fn>() wastes gas

Calling an external function internally, through the use of this wastes the gas overhead of calling an external function (100 gas).

<ins>Proof Of Concept</ins>
File: Upgradable.sol

49: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(this.setup.selector, params));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/util/Upgradable.sol#L49

File: Upgradable.sol

61: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(this.setup.selector, params));

https://github.com/code-423n4/2023-07-axelar/tree/main/contracts/gmp-sdk/upgradable/Upgradable.sol#L61

#0 - c4-pre-sort

2023-07-29T01:14:38Z

0xSorryNotSorry marked the issue as high quality report

#1 - c4-judge

2023-09-04T19:37:45Z

berndartmueller marked the issue as grade-a

AuditHub

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

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter