xanoutas/solidity-security-findings huggingface dataset:
[M] Unused gasValue is not refunded when calling deployRemoteCanonicalToken to the destination chain
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/interchain-token-service/InterchainTokenService.sol#L325


# Vulnerability details

## Impact
In InterchainTokenService, its used to deploy multiple ```tokenManagers``` on different chains.

According to the dev comments:     
* @dev `gasValue` exists because this function can be part of a multicall involving 
multiple functions that could make remote contract calls.

However, when ```deployRemoteCanonicalToken``` is called, the ```gasValue``` sent could exceed the required gas fee for the function to execute successfully on the destination chain. 
## Proof of Concept

Occasionally, transactions can get "stuck" in the pipeline from a source to destination chain 
(e.g. due to one-off issues that arise with relayers that operate on top of the network).

Transactions have typically gotten "stuck" in the pipeline due to: 
1. The transaction failing to relay from the source chain into the Axelar network for processing. 
2. The transaction failing to get executed on the destination chain.


This will lead to in some instances excess gas being sent and not used. 
Therefore, the excess gas will not be refunded to the user.

This is existential across a few functions in InterchainTokenService.

Including ```deployAndRegisterRemoteStandardizedToken``` and ```deployRemoteCustomTokenManager```.

## Tools Used
Manual Review

## Recommended Mitigation Steps

I would suggest to use a gas refund mechanism to refund the unused gas to the user or 
provide a cancel option if the transaction failed, from the source chain or destination chain, 
and allow the user to get the gas refund. 


## Assessed type

Other
Proxy contract will revert when called for the first time
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/gmp-sdk/upgradable/Proxy.sol#L33
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/gmp-sdk/upgradable/BaseProxy.sol#L39-L41


# Vulnerability details

## Impact
Proxy contract will revert when called for the first time due to a check which will always result in false because of the value passed into it. Hence the proxy contract won't be deployed.

## Proof of Concept
The `Proxy` contract implements `BaseProxy` contract. The BaseProxy contract returns the value of `contractId` as `bytes32(0)`.

```solidity
File: BaseProxy.sol

39:      function contractId() internal pure virtual returns (bytes32) {
40:             return bytes32(0);
41:      }
```
When calling the `Proxy` contract for the 1st time, the value of `id` is set by calling `contractId()` in the BaseProxy. In the very next line, there is a check to see if `id != bytes32(0)`. But this will result in `false` since the value of `id` is set to `bytes32(0)`, thus resulting in a revert.

```solidity
File: Proxy.sol

constructor(
        address implementationAddress,
        address owner,
        bytes memory setupParams
    ) {
        if (owner == address(0)) revert InvalidOwner();

        bytes32 id = contractId();
        if (id != bytes32(0) && IUpgradable(implementationAddress).contractId() != id) revert InvalidImplementation();       /// @audit

        .......................................
    }
}
```

## Tools Used
Manual Review


## Assessed type

Invalid Validation
USER CAN EXECUTE THE TRANSACTION WITHOUT PROVIDING THE REQUIRED AMOUNT OF GAS FEES 
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L325-L335
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L714-L722
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L365-L376


# Vulnerability details

## Impact
The `InterchainTokenService.deployRemoteCanonicalToken` function is used to deploy remote TokenManagers and standardized tokens for a canonical token. This is a `payable` function. `gasValue` is an input parameter to this function which denotes the amount of native tokens to be used to pay for gas for the remote deployment.

In the `Natspec` comment the following is mentioned.

     * At least the amount specified needs to be passed to the call

In the documentation of the protocol the following is mentioned.

    Who the deployer is does not matter for this, they just need to pay for the deployment gas, 

But the function implementation does not check whether the passed in amount to the call is enough to cover the `gasValue`. This amount of `gasValue` is transferred in the `InterchainTokenService._callContract` as shown below:

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

So it is clear from the above code snippet (`value: gasValue`) this gasValue is taken from the contract balance. There are 6 more payable function in this contract that can transfer native tokens to `InterchainTokenService` contract.

On the other hand for the users who provide more native token `msg.value > gasVlaue` will have the excess token amount locked in the contract since there is no refund mechanism. Only the `gas refund` is given from the `gasValue` during the execution of the `InterchainTokenService._callContract` function. Hence this could be loss of funds to the users.

Hence if there is an `excessive` amount of `native tokens` in the contract balance a malicious user could use that `balance` to execute the `InterchainTokenService.deployRemoteCanonicalToken` transaction without passing the specified amount of `gasValue` to the call as required. This is not the expected behaviour of the protocol and this can be thought of as loss of funds to the protocol or other users whose excessive funds are deposited into the contract.

## Proof of Concept

```solidity
    function deployRemoteCanonicalToken(
        bytes32 tokenId,
        string calldata destinationChain,
        uint256 gasValue
    ) public payable notPaused {
        address tokenAddress = getValidTokenManagerAddress(tokenId);
        tokenAddress = ITokenManager(tokenAddress).tokenAddress();
        if (getCanonicalTokenId(tokenAddress) != tokenId) revert NotCanonicalTokenManag
Possible Unauthorized Redemption of Collateral ERC20 Tokens due to Lack of Proper Check in `redeem()` Function
Audit: 2023-01-reserve-findings
Severity: HIGH

# Lines of code

https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/p1/RToken.sol#L439-L514
https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/p1/RToken.sol#L446


# Vulnerability details

## Impact

An attacker who is not authorized by the smart contract could potentially redeem more tokens than they are entitled to. This could cause a loss of funds for the smart contract and its users, as well as potentially destabilizing the overall ecosystem. Additionally, if the attacker is able to continuously exploit this vulnerability, it could lead to a complete loss of collateral for the smart contract.

## Proof of Concept

1.) Bob creates a malicious contract that mimics the redeem function of the RToken contract.
2.) Bob then sends a large amount of RToken to his malicious contract.
3.) Bob then calls the redeem function on the malicious contract, passing in the address of the RToken contract and an unauthorized address as the redeemer.
4.) The RToken contract, not properly checking that the redeemer is an authorized address, sends the collateral ERC20 tokens to the unauthorized address controlled by Bob.
5.) Bob is able to steal the collateral ERC20 tokens, resulting in a loss for the RToken contract and its users.

## Tools Used

Manual Review 

## Recommended Mitigation Steps

on the [line 446](https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/p1/RToken.sol#L446) :

```
function redeem(uint256 amount) external notFrozen {
        
        address redeemer = _msgSender();

       // rest of the code
```

we need to check wether is that msgSender was authorized 

```
address redeemer = msg.sender;
require(isAuthorized[redeemer], "Redeemer address is not authorized");
```

```
mapping(address => bool) public isAuthorized;
```

That mapping stores a `boolean` value for each address, indicating whether or not that address is authorized. In the redeem function, we check if `isAuthorized[redeemer]` is true, and if not, the function will stop execution and throw an error message "Redeemer address is not authorized".
Overflow vulnerability in `worstCasePrice` variable.
Audit: 2023-01-reserve-findings
Severity: HIGH

# Lines of code

https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/plugins/trading/GnosisTrade.sol#L45-L57


# Vulnerability details

## Impact

```
    // == Economic parameters
    // This trade is on behalf of origin. Only origin may call settle(), and the `buy` tokens
    // from this trade's acution will all eventually go to origin.
    address public origin;
    IERC20Metadata public sell; // address of token this trade is selling
    IERC20Metadata public buy; // address of token this trade is buying
    uint256 public initBal; // {qTok}, this trade's balance of `sell` when init() was called
    uint48 public endTime; // timestamp after which this trade's auction can be settled
    uint192 public worstCasePrice; // {buyTok/sellTok}, the worst price we expect to get at Auction
    // We expect Gnosis Auction either to meet or beat worstCasePrice, or to return the `sell`
    // tokens. If we actually *get* a worse clearing that worstCasePrice, we consider it an error in
    // our trading scheme and call broker.reportViolation()
```
The `worstCasePrice` variable is declared as a uint192, which has the potential of overflow issues. This could lead to unexpected behavior and loss of funds.

The `worstCasePrice` variable is of type `uint192`, which is a fixed-point decimal with a maximum `value of 2^192-1`. If the value stored in this variable exceeds this maximum, it will cause an overflow, resulting in an incorrect value being stored. This can happen if the value is set to a large value, or if calculations are performed on the variable that causes it to exceed the maximum value.

If the `worstCasePrice` variable overflows and ends up storing a value that is less than the clearing price, the `settle()` function will consider the trade profitable and transfer the buy tokens to the origin address. However, if the trade was actually not profitable, it would result in a loss of funds.

## Proof of Concept

An attacker will craft a trade where the calculated `worstCasePrice` exceeds the maximum value of a uint192 (2^192-1) and submit it to the contract. This could cause the `worstCasePrice` variable to overflow, and the value stored in the contract would be incorrect.

```
contract Attacker {
    function exploit(GnosisTrade trade) public {
        // Craft a trade where the worstCasePrice exceeds the maximum value of a uint192
        uint192 largeValue = 2**192;
        trade.init(..., largeValue);
    }
}
```
The attacker contract calls the `init` function of the `GnosisTrade` contract with a large value for the `worstCasePrice` parameter, which exceeds the maximum value of a `uint192`. This causes the `worstCasePrice` variable to overflow, leading to unexpected behavior in the rest of the contract.

## Tools Used

Manaul audit.

## Recommended Mitigation Steps

Use a library like `OpenZeppelin's SafeMath` library, which includes methods for performing arithmetic operations that throw an error w
High Severity Reentrancy Vulnerability in `stateTransition` Modifier
Audit: 2023-01-reserve-findings
Severity: HIGH

# Lines of code

https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/plugins/trading/GnosisTrade.sol#L59-L65


# Vulnerability details

## Impact

Lack of reentrancy protection in the `stateTransition` modifier occurs in the following line of code.

```
modifier stateTransition(TradeStatus begin, TradeStatus end) {
        require(status == begin, "Invalid trade state");
        status = TradeStatus.PENDING;
        _;
        assert(status == TradeStatus.PENDING);
        status = end;
    }
```
In the `GnosisTrade` smart contract, the `stateTransition` modifier is used to enforce the state-machine pattern and to protect against reentrancy, however, it does not have any code that prevents reentrancy by external contracts calling the same function simultaneously.

As you can see there is no code that will prevent reentrancy while the function is executing.

For example, an attacker could call the `init()` function, and while the `init()` function is still executing, the attacker could call the `init()` function again. This could cause the smart contract to set the state variables multiple times or cause the smart contract to initiate multiple auctions with the same parameters, which could lead to unexpected behavior and potential loss of funds.

## Proof of Concept

```
pragma solidity ^0.8.9;

import "./GnosisTrade.sol";

contract Attacker {
    GnosisTrade gnosisTrade;

    function attack(address gnosisTradeAddress) public {
        gnosisTrade = GnosisTrade(gnosisTradeAddress);
        //call the init function
        gnosisTrade.init();
        //call the init function again before the first call is completed 
        gnosisTrade.init();
    }
}
```

In this example, the Attacker contract is calling the `init()` function of the `GnosisTrade` contract twice, before the first call is completed. Since the `stateTransition` modifier does not have any code that prevents reentrancy, the state of the `GnosisTrade` contract could be modified multiple times in quick succession, which could cause unexpected behavior such as initiating multiple auctions with the same parameters or losing funds.


## Tools Used

Manual audit.

## Recommended Mitigation Steps

One of the most common ways to prevent `reentrancy` is to use a `mutex`, which is a flag variable that indicates whether the smart contract is currently executing a call. The `init()` function should check the state of the mutex before executing, and if it's already set, the function should immediately return without doing anything.

```
bool mutex = false;
modifier stateTransition(TradeStatus begin, TradeStatus end) {
        require(status == begin, "Invalid trade state");
        require(!mutex, "Reentrancy detected");
        mutex = true;
        _;
        mutex = false;
        status = end;
    }
```
Or use a guard condition, which is a condition that prevents the smart contract from executing the same call twice. The guard condition can be i
## Significant roundoff error in melt() function
Audit: 2023-01-reserve-findings
Severity: HIGH

# Lines of code

https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/p1/Furnace.sol#L74
https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/p1/Furnace.sol#L81


# Vulnerability details

## Significant roundoff error in melt() function

Significant roundoff error is caused when calculating numPeriods. Also frequent calling of this function caused sever error. 

Proof of Concept

    70  function melt() external notPausedOrFrozen {
    71      if (uint48(block.timestamp) < uint64(lastPayout) + period) return;
    72
    73      // # of whole periods that have passed since lastPayout
    74      uint48 numPeriods = uint48((block.timestamp) - lastPayout) / period;
    75
    76    // Paying out the ratio r, N times, equals paying out the ratio (1 - (1-r)^N) 1 time.
    77    uint192 payoutRatio = FIX_ONE.minus(FIX_ONE.minus(ratio).powu(numPeriods));
    78
    79        uint256 amount = payoutRatio.mulu_toUint(lastPayoutBal);
    80
    81        lastPayout += numPeriods * period;
    82        lastPayoutBal = rToken.balanceOf(address(this)) - amount;
    83        if (amount > 0) rToken.melt(amount);
    84    }
    
https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/p1/Furnace.sol#L74
    
    Consider this senario.
    
    period = 1000
    lastPayout = Y 
    block.timestamp = Y + 1999 

    So numPeriods   = uint48((block.timestamp) - lastPayout) / period

                    = (Y + 1999 - Y)/1000
              
                    = 1999/1000 = 1
              
 But in this situation numPeriods should be approximatly 2 .
 
 this error propogate futher such that , 
 
        payoutRatio = (1 - (1-r)^N) 
 
        payoutRatio shoud be = (1 - (1-r)^2)
 
        But payoutRatio now = (1 - (1-r)^1)
 
 Also it affected to amount , lastPayout , lastPayoutBal . 
 
        81  lastPayout += numPeriods * period;
        
https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/p1/Furnace.sol#L81
        
Because of above line these wrong calculated values are accumulated in lastPayout . If someone call this function frequently such as (lastPayout + 1.9999period) in time intervals , eventually error is going to be huge. 

## Tools Used

Vs code

## Recommended Mitigation Steps

consider calculate like this, Basically do the multipication first and devide eventually. ( Basically this one. A^(b/c)  = A^b/A^c)


    numPeriods = uint48((block.timestamp) - lastPayout) / period
    consider x = uint48((block.timestamp) - lastPayout)
    and  y  = period
    so numPeriods(N) = x/y
 
    payoutRatio = (1 - (1-r)^N) 
                = 1 -((1-r)^x)/((1-r)^y)
function withdraw() in StRSR won't update contract state (totalDrafts) in all cases which can cause wrong fund distribution and fund stucking in the contract
Audit: 2023-01-reserve-findings
Severity: HIGH

# Lines of code

https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/p1/StRSR.sol#L300-L337


# Vulnerability details

## Impact
Function `withdraw()`  complete an account's unstaking. it transfers user draft withdrawals and updates `totalDrafts`. but when calculated `rsrAmount` is 0 code returns and won't updates `totalDrafts` which can cause wrong calculations as those draft items removed from user address and `totalDrafts` would not shoe the real sum of all drafts. this would cause some funds to be locked in contract forever and also wrong draft and rsr calculation for the next interaction as `totalDrafts` don't show correct.

## Proof of Concept
This is `withdraw()` code:
```
    function withdraw(address account, uint256 endId) external notPausedOrFrozen {
        // == Refresh ==
        assetRegistry.refresh();

        // == Checks + Effects ==
        require(basketHandler.fullyCollateralized(), "RToken uncollateralized");
        require(basketHandler.status() == CollateralStatus.SOUND, "basket defaulted");

        uint256 firstId = firstRemainingDraft[draftEra][account];
        CumulativeDraft[] storage queue = draftQueues[draftEra][account];
        if (endId == 0 || firstId >= endId) return;

        require(endId <= queue.length, "index out-of-bounds");
        require(queue[endId - 1].availableAt <= block.timestamp, "withdrawal unavailable");

        uint192 oldDrafts = firstId > 0 ? queue[firstId - 1].drafts : 0;
        uint192 draftAmount = queue[endId - 1].drafts - oldDrafts;

        // advance queue past withdrawal
        firstRemainingDraft[draftEra][account] = endId;

        // ==== Compute RSR amount
        uint256 newTotalDrafts = totalDrafts - draftAmount;
        // newDraftRSR: {qRSR} = {qDrafts} * D18 / D18{qDrafts/qRSR}
        uint256 newDraftRSR = (newTotalDrafts * FIX_ONE_256 + (draftRate - 1)) / draftRate;
        uint256 rsrAmount = draftRSR - newDraftRSR;

        if (rsrAmount == 0) return;

        // ==== Transfer RSR from the draft pool
        totalDrafts = newTotalDrafts;
        draftRSR = newDraftRSR;

        emit UnstakingCompleted(firstId, endId, draftEra, account, rsrAmount);

        // == Interaction ==
        IERC20Upgradeable(address(rsr)).safeTransfer(account, rsrAmount);
    }
```
As you can see code updated the value of the `totalDraft` after the return and if `rsrAmount` would be 0 then code won't update `totalDraft` and `totalDraft` won't show correct sum of all the active drafts. this would inflate `totalDraft` over time and can cause cause locking of some funds in the contract forever.

## Tools Used
VIM

## Recommended Mitigation Steps
set the values before the return.
User funds can be locked in RToken contract for a long time
Audit: 2023-01-reserve-findings
Severity: HIGH

# Lines of code

https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/p1/RToken.sol#L344
https://github.com/reserve-protocol/protocol/blob/df7ecadc2bae74244ace5e8b39e94bc992903158/contracts/p1/RToken.sol#L186


# Vulnerability details

## Impact
Unnecessary delay on the first issuance will lock the first issuer's deposit and other following deposits.

## Proof of Concept
Users can issue new RTokens by depositing the necessary collaterals.
The protocol is designed to limit issuance by some rate and the minimum rate is 10k whole RTok. (constant)

```solidity
RToken.sol
46:     // MIN_BLOCK_ISSUANCE_LIMIT: {qRTok/block} 10k whole RTok
47:     uint256 public constant MIN_BLOCK_ISSUANCE_LIMIT = 10_000 * FIX_ONE;
```

Based on the issuance rate, new issuances might go through some vesting period and users can call the function `vest()` to get the RTokens actually minted only after vesting.
The vesting time is decided by the function `whenFinished()`.

```solidity
RToken.sol
342:     /// Add amtRToken's worth of issuance delay to allVestAt, and return the resulting finish time.
343:     /// @return finished D18{block} The new value of allVestAt
344:     function whenFinished(uint256 amtRToken) private returns (uint192 finished) {
345:         // Calculate the issuance rate (if this is the first issuance in the block)
346:         if (lastIssRateBlock < block.number) {
347:             lastIssRateBlock = block.number;
348:
349:             // D18{rTok/block} = D18{1/block} * D18{rTok} / D18{1}
350:             // uint192 downcast is safe, max value representations are 1e18 * 1e48 / 1e18
351:             lastIssRate = uint192((issuanceRate * totalSupply()) / FIX_ONE);
352:             // uint192(<) is equivalent to Fix.lt
353:             if (lastIssRate < MIN_BLOCK_ISSUANCE_LIMIT) lastIssRate = MIN_BLOCK_ISSUANCE_LIMIT;
354:         }
355:
356:         // make `before` be the fractional-block when this issuance should start;
357:         // before = max(allVestAt, block.number - 1)
358:         uint192 before = allVestAt; // D18{block number}
359:         // uint192 downcast is safe: block numbers are smaller than 1e38
360:         uint192 nowStart = uint192(FIX_ONE * (block.number - 1)); // D18{block} = D18{1} * {block}
361:         if (nowStart > before) before = nowStart;
362:
363:         // finished: D18{block} = D18{block} + D18{1} * D18{RTok} / D18{rtok/block}
364:         // uint192() downcast here is safe because:
365:         //   lastIssRate is at least 1e24 (from MIN_ISS_RATE), and
366:         //   amtRToken is at most 1e48, so
367:         //   what's downcast is at most (1e18 * 1e48 / 1e24) = 1e38 < 2^192-1
368:         finished = before + uint192((FIX_ONE_256 * amtRToken + (lastIssRate - 1)) / lastIssRate);
369:         allVestAt = finished;
370:     }
```

According to the current implementation `lastIssRate` becomes `MIN_BLOCK_ISSUANCE_LIMIT=1e22` in the function `whenFinished()` for the f