xanoutas/solidity-security-findings huggingface dataset:
Excess Token sent when deploying a new interchain token is not refunded
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/interchain-token-service/contracts/InterchainTokenService.sol#L327-L349


# Vulnerability details

## Impact
Excess ETH send to pay for gas when deploying a new interchain token is not refunded to caller.
https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/interchain-token-service/contracts/InterchainTokenService.sol#L327

## Proof of Concept
Consider the following scenario
1. Alice wants to deploy a new interchain Token so she calls InterchainTokenService.deployInterchainToken() with the appropriate args. Now she sent a gasValue of 0.1 ether ( using this for the sake of our scenario).
https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/interchain-token-service/contracts/InterchainTokenService.sol#L334
2. Token gets deployed and consume less than 0.1 ether
3. Remaining ether is not refunded to Alice.
4. Alice funds have been effectively locked inside the contract

```solidity
function deployInterchainToken(
        bytes32 salt,
        string calldata destinationChain,
        string memory name,
        string memory symbol,
        uint8 decimals,
        bytes memory minter,
        uint256 gasValue
    ) external payable whenNotPaused returns (bytes32 tokenId) {
        address deployer = msg.sender;

        if (deployer == interchainTokenFactory) deployer = TOKEN_FACTORY_DEPLOYER;

        tokenId = interchainTokenId(deployer, salt);

        if (bytes(destinationChain).length == 0) {
            address tokenAddress = _deployInterchainToken(tokenId, minter, name, symbol, decimals);

            _deployTokenManager(tokenId, TokenManagerType.NATIVE_INTERCHAIN_TOKEN, abi.encode(minter, tokenAddress));
        } else {
            _deployRemoteInterchainToken(tokenId, name, symbol, decimals, minter, destinationChain, gasValue);
        }
    }
```

## Tools Used
Manual review

## Recommended Mitigation Steps
Refund remaining gasValue after token deployment to the caller.


## Assessed type

ETH-Transfer
The registerCanonicalInterchainToken function might assign an incorrect TokenManagerType
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/interchain-token-service/contracts/InterchainTokenFactory.sol#L244-L256


# Vulnerability details

### Description 
When a user wants to register a canonical token as an interchain token, they can do so by calling the `registerCanonicalInterchainToken` function and providing the `tokenAddress`. As per the [Axelar Docs](https://docs.axelar.dev/dev/send-tokens/interchain-tokens/upgrade-tokens#canonical-tokens-simple-wrappers): This will deploy a [Lock/Release](https://docs.axelar.dev/dev/glossary#lockunlock) - [Token Manager](https://docs.axelar.dev/dev/glossary#token-manager) on the source chain. 

Note that the [Lock/Release](https://docs.axelar.dev/dev/send-tokens/glossary#lockunlock) section does not make any distinction between `LOCK_UNLOCK` & `LOCK_UNLOCK_FEE`, the code however is clear in its difference. The latter is simply used for tokens that have a FOT behaviour. 

```javascript
        LOCK_UNLOCK_FEE, // The token will be locked/unlocked at the token manager, which will account for any fee-on-transfer behaviour.
```

If we now look at the `registerCanonicalInterchainToken` function we can see that the passed `TokenManagerType` will always be set to `LOCK_UNLOCK`:

```javascript
    function registerCanonicalInterchainToken(address tokenAddress) external payable returns (bytes32 tokenId) {
        bytes memory params = abi.encode('', tokenAddress);

        if (_isGatewayToken(tokenAddress)) revert GatewayToken(tokenAddress);

        bytes32 salt = canonicalInterchainTokenSalt(chainNameHash, tokenAddress);
        tokenId = interchainTokenService.deployTokenManager(salt, '', =>TokenManagerType.LOCK_UNLOCK, params, 0);
    }
```

This behaviour is intentional because, as previously mentioned, only lock/release tokens can be registered as canonical interchain tokens.

However, there's an issue: users have no way of knowing that this function only accepts `LOCK_UNLOCK` tokens and do not support `LOCK_UNLOCK_FEE` tokens. The documentation does not clarify this, and as we analyse the function's flow, it has no check to ensure only `LOCK_UNLOCK` tokens are being used. Instead, it always sets the `tokenManagerType` to `LOCK_UNLOCK`, assuming this is the only type that will be used

This can lead to the following scenario:

- Bob calls `registerCanonicalInterchainToken` with a token of the `LOCK_UNLOCK_FEE` type.
- Bob expects the function to work, assuming that since the token is of a Lock/Release type, it should be supported. There’s no indication or check suggesting otherwise; on the contrary, the documentation states that Lock/Release tokens are supported.
- Due to the hardcoded parameter, the token will be deployed as `LOCK_UNLOCK` instead of `LOCK_UNLOCK_FEE`.
- Bob ends up with a deployed FOT token of the `LOCK_UNLOCK` type, contrary to his expectations.

The token logic will now cause for issues, for example, whenever tra
Implementation contract (TokenManager) :: setup can be called more than once by it Proxy  contract ( TokenManagerProxy) 
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/4572617124bed39add9025317d2c326acfef29f1/interchain-token-service/contracts/proxies/TokenManagerProxy.sol#L42


# Vulnerability details

## Description
The `TokenManagerProxy` contract, designed to delegate calls to the `TokenManager` implementation contract, includes a setup function intended for one-time initialization during the proxy's construction. However, due to the absence of a robust mechanism to prevent multiple invocations, this function can potentially be called more than once.
 
The TokenManagerProxy employs a proxy pattern to delegate execution to the TokenManager implementation contract. During the proxy's construction, the setup function within the implementation is called via delegatecall to initialize critical contract parameters, including operator roles and flow limiter settings. The setup function is explicitly marked with an `onlyProxy` modifier, ensuring that only the proxy can invoke this function. Despite this restriction, the design lacks a mechanism to enforce single-time invocation, which presents a significant vulnerability.

## Proof of Concept
***Upon deployment, `TokenManagerProxy` calls the setup function in the implementation contract using delegatecall. This function sets up the operator roles and other essential configurations.
The setup function is meant to be executed only once, safeguarding the initialization integrity of the contract.***
```solidity

    /**
     * @notice Constructs the TokenManagerProxy contract.
     * @param interchainTokenService_ The address of the interchain token service.
     * @param implementationType_ The token manager type.
     * @param tokenId The identifier for the token.
     * @param params The initialization parameters for the token manager contract.
     */
    constructor(address interchainTokenService_, uint256 implementationType_, bytes32 tokenId, bytes memory params) {
        if (interchainTokenService_ == address(0)) revert ZeroAddress();

        interchainTokenService = interchainTokenService_;
        implementationType = implementationType_;
        interchainTokenId = tokenId;

        address implementation_ = _tokenManagerImplementation(interchainTokenService_, implementationType_);
        if (implementation_ == address(0)) revert InvalidImplementation();

        (bool success, ) = implementation_.delegatecall(abi.encodeWithSelector(IProxy.setup.selector, params));  <---------
        if (!success) revert SetupFailed();

        tokenAddress = IBaseTokenManager(implementation_).getTokenAddressFromParams(params);
    }
```
***The current implementation does not utilize a state flag (e.g., initialized) to prevent multiple calls to the setup function.
Without this safeguard, if the proxy or any external actor manages to trigger setup again, the contract's state could be reset or reconfigured, leading to catastrophic failures in contract operations.***
```solidity
function setup(bytes c
Gas refunds will be lost when using smart contract wallets
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/4572617124bed39add9025317d2c326acfef29f1/interchain-token-service/contracts/utils/GatewayCaller.sol#L61


# Vulnerability details

## Summary
Due to the usage of `tx.origin`, gas refunds will be lost when using a smart contract wallet.
## Description
When a contract is called on a destination chain, the following internal function is called:
```javascript
    function _callContract(
        string memory destinationChain,
        bytes memory payload,
        IGatewayCaller.MetadataVersion metadataVersion,
        uint256 gasValue
    ) internal {
        string memory destinationAddress;

        (destinationChain, destinationAddress, payload) = _getCallParams(destinationChain, payload);

        (bool success, bytes memory returnData) = gatewayCaller.delegatecall(
            abi.encodeWithSelector(
                IGatewayCaller.callContract.selector,
                destinationChain,
                destinationAddress,
                payload,
                metadataVersion,
                gasValue
            )
        );

        if (!success) revert GatewayCallFailed(returnData);
    }
```

This contract makes a `delegatecall` to `GatewayCaller.callContract`:
```javascript
    function callContract(
        string calldata destinationChain,
        string calldata destinationAddress,
        bytes calldata payload,
        MetadataVersion metadataVersion,
        uint256 gasValue
    ) external payable override {
        if (gasValue > 0) {
            if (metadataVersion == MetadataVersion.CONTRACT_CALL) {
                // slither-disable-next-line arbitrary-send-eth
                gasService.payNativeGasForContractCall{ value: gasValue }(
                    address(this),
                    destinationChain,
                    destinationAddress,
                    payload,
                    // solhint-disable-next-line avoid-tx-origin
->                  tx.origin
                );
            } else if (metadataVersion == MetadataVersion.EXPRESS_CALL) {
                // slither-disable-next-line arbitrary-send-eth
                gasService.payNativeGasForExpressCall{ value: gasValue }(
                    address(this),
                    destinationChain,
                    destinationAddress,
                    payload,
                    // solhint-disable-next-line avoid-tx-origin
->                  tx.origin
                );
            } else {
                revert InvalidMetadataVersion(uint32(metadataVersion));
            }
        }

        gateway.callContract(destinationChain, destinationAddress, payload);
    }
```

`tx.origin` is used here as the address where refunds are meant to be sent to. However, the very nature of a smart contract wallet is that it is called by another entity. This means that the gas-refund will not go to the smart contract wallet that is being used by the user, but to the other entity, whom the user
Rebasing tokens are not supported, causing inaccuracies in accounting of assets
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/4572617124bed39add9025317d2c326acfef29f1/interchain-token-service/contracts/InterchainTokenService.sol#L34


# Vulnerability details

## Vulnerability details
It is stated on the competition's page that rebasing/deflationary/inflationary tokens should be supported and are [In scope](https://code4rena.com/audits/2024-08-axelar-network#top:~:text=Balance%20changes%20outside,In%20scope). However, the transfer of such tokens through ITS will be dangerous and will cause errors in the protocols accounting balance, causing users to get more funds than intended or some users being unable to claim their transferred tokens of the destination chain.

## Impact
Loss of funds for users of the protocol and accounting errors in the ITS.

## Proof of Concept
If rebasing tokens are transferred through the ITS the following issue is likely to arise:
1/ User transfers 1000 of a rebasing token from chain A to chain B, so 1000 tokens are locked in the `TokenManager` for the token on chain A
2/ Before the transfer is executed on chain B the token rebases, decreasing balances by 10%
3/ The user finishes the bridging on chain B and receives 1000 tokens, even though they should have only received 900
4/ The 100 tokens that are added to the user are taken out of other users' locked tokens, causing further accounting issues

## Tools Used
Manual review

## Recommended Mitigation Steps
One long-term solution would be to implement a special `TokenManager` contract designed for handling rebasing tokens.


## Assessed type

ERC20
No access control on `AxelarAmplifierGateway::validateProof` and `AxelarAmplifierGateway::approveMessages` can cause DoS attack by malicios user
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/main/axelar-gmp-sdk-solidity/contracts/gateway/AxelarAmplifierGateway.sol#L75-L86
https://github.com/code-423n4/2024-08-axelar-network/blob/main/axelar-gmp-sdk-solidity/contracts/gateway/AxelarAmplifierGateway.sol#L109-L117


# Vulnerability details

## Impact
As anyone can call the `validateProof` and `approveMessages` functions, a malicious user can see the proof provided the first time these functions are called with a valid data hash and then call them multiple times causing a DoS attack as both of these functions are very gas expensive. 

## Proof of Concept
 
 Place the following code in `AxelarAmplifierGateway.js` test file for the `validateProof` and similar test in the comment for `approveMessages`. These tests can show how much time it will cost to execute them multiple times. 

```javascript
it('validateProof can be called multiple times', async () => {
            const messageId = '1';
            const payload = defaultAbiCoder.encode(['address'], [owner.address]);
            const payloadHash = keccak256(payload);
            const sourceChain = 'Source';
            const sourceAddress = 'address0x123';

            const messages = [
                {
                    sourceChain,
                    messageId,
                    sourceAddress,
                    contractAddress: owner.address,
                    payloadHash,
                },
            ];

            const proof = await getProof(APPROVE_MESSAGES, messages, weightedSigners, signers.slice(0, threshold));

            for(let i=0;i<10000;i++) {
                // await gateway.approveMessages(messages, proof);
                // or
                // await gateway.validateProof(keccak256(getApproveMessageData(messages)), proof);
                await expect(gateway.approveMessages(messages, proof)).to.not.be.reverted;
            }
        });
```


## Tools Used
Manual review.

## Recommended Mitigation Steps
1. Add a onlyRole modifier
2. Check if the provided hash has been already approved/validated by the current signers


## Assessed type

DoS
Current design do not support ERC20 rebasing token
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/main/interchain-token-service/contracts/utils/GatewayCaller.sol#L71-#L121


# Vulnerability details

## Vulnerability details
From contest page, it can be seen that rebasing token is supported. But there is no mechanism that can update rebasing amount in real time. Function `callContractWithToken()` will only update balance on destination chain with amount at the time it is called:

    /**
     * @dev Calls a contract on a specific destination chain with the given payload and token
     * @param destinationChain The target chain where the contract will be called
     * @param destinationAddress The address of the contract to be called on the destination chain
     * @param payload The data payload for the transaction
     * @param symbol The symbol of the token to be sent
     * @param amount The amount of tokens to be sent              // <--
     * @param metadataVersion The version of metadata to be used
     * @param gasValue The amount of gas to be paid for the cross-chain message. If this is 0, then gas payment is skipped. `msg.value` must be at least gasValue.
     */
    function callContractWithToken(
        string calldata destinationChain,
        string calldata destinationAddress,
        bytes calldata payload,
        string calldata symbol,
        uint256 amount,
        MetadataVersion metadataVersion,
        uint256 gasValue
    ) external payable override {
       .   .   .   .   .   .
    }

## Impact
Total balance of `Non-Canonical Interchain Token` will be different from `Canonical Interchain Token` balance. In worst scenario, when `Canonical Interchain Token` rebasing down, there wont be enough them to unlock `Non-canoical Interchain Token`

## Tools Used
Manual review

## Recommended Mitigation Steps
New design should be applied to make protocol able to work with rebasing token


## Assessed type

ERC20
Not compatible with rebasing tokens
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/main/interchain-token-service/contracts/TokenHandler.sol#L108-L109


# Vulnerability details

## Impact
The protocol is not compatible with rebasing tokens, leading to two major impacts:
- Users lose potential token yields.
- Rebasing tokens become stuck in the tokan manager contract.

## Proof of Concept
Per to doc rebasing token is in scope
>Balance changes outside of transfers In scope

Let's take aave as example:
>Aave enables users to supply and borrow digital assets through liquidity pools. Suppliers receive protocol-issued aTokens, holding the user’s supplied assets and accrued yield. 

`aTokens` can be register via [registerCanonicalInterchainToken]() function. The default manager type is `TokenManagerType.LOCK_UNLOCK`. Which means `aTokens` can be unlocked on source chain and minted on other chains if it's transfered.

[https://github.com/code-423n4/2024-08-axelar-network/blob/main/interchain-token-service/contracts/InterchainTokenFactory.sol#L249-L256](https://github.com/code-423n4/2024-08-axelar-network/blob/main/interchain-token-service/contracts/InterchainTokenFactory.sol#L249-L256)
```solidity
function registerCanonicalInterchainToken(address tokenAddress) external payable returns (bytes32 tokenId) {
    bytes memory params = abi.encode('', tokenAddress);

    if (_isGatewayToken(tokenAddress)) revert GatewayToken(tokenAddress);

    bytes32 salt = canonicalInterchainTokenSalt(chainNameHash, tokenAddress);
    tokenId = interchainTokenService.deployTokenManager(salt, '', TokenManagerType.LOCK_UNLOCK, params, 0);
}
```

Per to aave's features,`aTokens` holders can receive yield which comes from:
- Lending Interes
- Flash Loan Fees
- Protocol Incentives
- Liquidation Fees

However when user makes a interchain transfer,convert interchain token back to `aTokens` those yiled is ignored,result in user lost token yield and those yiled get stuck in contract.
[https://github.com/code-423n4/2024-08-axelar-network/blob/main/interchain-token-service/contracts/TokenHandler.sol#L108-L109](https://github.com/code-423n4/2024-08-axelar-network/blob/main/interchain-token-service/contracts/TokenHandler.sol#L108-L109)
```solidity
if (tokenManagerType == uint256(TokenManagerType.NATIVE_INTERCHAIN_TOKEN)) {
    _takeInterchainToken(tokenAddress, from, amount);
} else if (tokenManagerType == uint256(TokenManagerType.MINT_BURN)) {
    _burnToken(tokenManager, tokenAddress, from, amount);
} else if (tokenManagerType == uint256(TokenManagerType.MINT_BURN_FROM)) {
    _burnTokenFrom(tokenAddress, from, amount);
} else if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK)) {
    _transferTokenFrom(tokenAddress, from, tokenManager, amount);    <@
} else if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK_FEE)) {
    amount = _transferTokenFromWithFee(tokenAddress, from, tokenManager, amount);
} else if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) {
    symbol
Improper implementation of `isCommandExecuted` will cause approved messages to not be express executable
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/c383cc0e51805357bca8741ec5d1568cacbff6cc/axelar-gmp-sdk-solidity/contracts/gateway/BaseAmplifierGateway.sol#L115-L117
https://github.com/code-423n4/2024-08-axelar-network/blob/c383cc0e51805357bca8741ec5d1568cacbff6cc/interchain-token-service/contracts/InterchainTokenService.sol#L676-L688
https://github.com/code-423n4/2024-08-axelar-network/blob/c383cc0e51805357bca8741ec5d1568cacbff6cc/interchain-token-service/contracts/InterchainTokenService.sol#L375


# Vulnerability details

### Impact

`isCommandExecuted` in Gateway only checks if a message is non existent, as a result, attempting to express execute an approved message will be impossible.

### Proof of Concept

Looking at the `expressExecute`, it attempts to check if the command is executed in the gateway.

```solidity
    function expressExecute(
        bytes32 commandId,
        string calldata sourceChain,
        string calldata sourceAddress,
        bytes calldata payload
    ) public payable whenNotPaused {
        uint256 messageType = abi.decode(payload, (uint256));
        if (messageType != MESSAGE_TYPE_INTERCHAIN_TRANSFER) {
            revert InvalidExpressMessageType(messageType);
        }

        if (gateway.isCommandExecuted(commandId)) revert AlreadyExecuted();
//...
    }
```

In the BaseAmplifierGateway, the `isCommandExecuted` function is set like this.

```solidity
    function isCommandExecuted(bytes32 commandId) public view override returns (bool) {
        return _baseAmplifierGatewayStorage().messages[commandId] != MESSAGE_NONEXISTENT;
    }
```

As can be seen, a message can be of three types, non existent, approved and executed. So when the command is to be express executed, the check to see if the command is already executed, will always revert for approved messages, even if they had not been executed. This is because the `isCommandExecuted` returns true if message is not non-existent, rather than returning true if the message has been executed. As a result, approved messages cannot be express executed.


`expressExecute` is also called in `expressExecuteWithToken` and such, the function also experiences the same issue.
```solidity
    function expressExecuteWithToken(
        bytes32 commandId,
        string calldata sourceChain,
        string calldata sourceAddress,
        bytes calldata payload,
        string calldata tokenSymbol,
        uint256 amount
    ) external payable {
        _checkPayloadAgainstGatewayData(payload, tokenSymbol, amount);
        // It should be ok to ignore the symbol and amount since this info exists on the payload.
        expressExecute(commandId, sourceChain, sourceAddress, payload);
    }
```

### Tools Used
Manual code review

### Recommended Mitigation Steps

Recommend fixing the check.
```diff
    function isCommandExecuted(bytes32 commandId) public view override returns (bool) {
-        return _baseAmplifierGatewayStorage().messages[commandId] !=