xanoutas/solidity-security-findings huggingface dataset:
Incorrect initialization of `rUSDY.sol`
Audit: 2023-09-ondo-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/usdy/rUSDY.sol#L109-L147


# Vulnerability details

## Impact
rUSDY.sol contract inherits PausableUpgradeable contract but does not invoke its initialzers during its own initialization. Due to which the state of PausableUpgradeable contract remain uninitialized.

```Solidity
File: contracts/usdy/rUSDY.sol

contract rUSDY is
  Initializable,
  ContextUpgradeable,
  PausableUpgradeable,

  // some code

```

```Solidity
File: contracts/usdy/rUSDY.sol

  function initialize(
    address blocklist,
    address allowlist,
    address sanctionsList,
    address _usdy,
    address guardian,
    address _oracle
  ) public virtual initializer {
    __rUSDY_init(blocklist, allowlist, sanctionsList, _usdy, guardian, _oracle);
  }

  function __rUSDY_init(
    address blocklist,
    address allowlist,
    address sanctionsList,
    address _usdy,
    address guardian,
    address _oracle
  ) internal onlyInitializing {
    __BlocklistClientInitializable_init(blocklist);
    __AllowlistClientInitializable_init(allowlist);
    __SanctionsListClientInitializable_init(sanctionsList);
    __rUSDY_init_unchained(_usdy, guardian, _oracle);
   }
```

`PausableUpgradeable` initialization is very much important and it looks as below,


```Solidity
File: contracts/security/PausableUpgradeable.sol

    function __Pausable_init() internal onlyInitializing {
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal onlyInitializing {
        _paused = false;
    }
```

This initializes the contract in `unpaused` state. Due to this _paused state is not initialized. This breaks the overall functionality with respect to `PausableUpgradeable.sol`. Openzeppelin reference can be checked [here](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/58fa0f81c4036f1a3b616fdffad2fd27e5d5ce21/contracts/security/PausableUpgradeable.sol#L34-L40)

It is to be noted that automated report has made this issue low severity and has some false positives too. The automated report does not mention the impact of non-initialization of `PausableUpgradeable` but it must be noted `PausableUpgradeable` intialization is very much required otherwise the contract will not be initialized in `unpaused` state.

## Proof of Concept
https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/usdy/rUSDY.sol#L109-L147

## Tools Used
Manual review

## Recommended Mitigation Steps
Consider initializing the `PausableUpgradeable` in `rUSDY.sol` `initialize()` function.

For example for understanding:

```Solidity

    function initialize(
       
      // some code

    ) public initializer {
+        __Pausable_init();

      // some code

    }
```


## Assessed type

Other
Owner cannot rescueToken if blocklisted.
Audit: 2023-09-ondo-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L322


# Vulnerability details

## Impact
Token could be stuck if owner is blocklisted by the token.

## Proof of Concept
`rescueToken` can be used to rescue token sent to the contracts.
https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L322
```solidity
function rescueTokens(address _token) external onlyOwner {
    uint256 balance = IRWALike(_token).balanceOf(address(this));
    IRWALike(_token).transfer(owner(), balance);
  }
```
but since the token is been sent to the owner's address without provision for an alternative address, if the owner is blocklisted by such token, the token would be stuck within the contract.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Allow owner to transfer token to an alternative address.


## Assessed type

Context
Potential Out of Bound Error When Accessing Range Array
Audit: 2023-09-ondo-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/rwaOracles/RWADynamicOracle.sol#L78


# Vulnerability details

**The code seems to be attempting to access an element of the 'ranges' array using an index calculated from the array's length minus one. However, during the deployment or initialization of the contract, if the length of 'ranges' is 1, this calculation results in an index of -1. In Solidity, this would cause an underflow, translating to a large index value and potentially leading to an out-of-bound error.**

## Impact
Attempting to access an out-of-bound index in the 'ranges' array can cause the contract to revert, leading to failed transactions. This could disrupt the normal operations of the contract and could also lead to unexpected behavior or loss of funds for users if not properly handled.

## Proof of Concept
Alice deploys the contract, and during initialization, only one range is set, causing the length of the 'ranges' array to be 1.
Bob interacts with the contract, calling a function that attempts to access the 'ranges' array using the index ranges.length - 1.
Given the current length is 1, the calculation results in an index of -1, causing an underflow.
The function call reverts due to this out-of-bound error, disrupting the expected behavior of the contract.

## Tools Used

## Recommended Mitigation Steps
Ensure that there are always at least two ranges as intended or include checks to prevent access when the length of the 'ranges' array is less than or equal to one. Additionally, comprehensive unit tests should be added to validate these scenarios.


## Assessed type

Other
Token recipient is an inaccessible address for contracts
Audit: 2023-09-ondo-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/SourceBridge.sol#L61-L82
https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L85-L114
https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L337-L353


# Vulnerability details

## Impact
The `msg.sender` address from the `SourceBridge.burnAndCallAxelar` function is used by the `DestinationBridge._mintIfThresholdMet` function as the `TOKEN` recipient. However, the `msg.sender` address will not be controllable by contracts on L2, so any tokens will be lost.

## Proof of Concept
The [`SourceBridge.burnAndCallAxelar`](https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/SourceBridge.sol#L61-L82) function constructs the `payload`:
```solidity
79    bytes memory payload = abi.encode(VERSION, msg.sender, amount, nonce++);
```
The `payload` then is decoded at the [`DestinationBridge._execute`](https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L85-L114) function and used to save transaction parameters in the `txnHashToTransaction` mapping as the `Transaction(srcSender, amt)` structure.
```solidity
90    (bytes32 version, address srcSender, uint256 amt, uint256 nonce) = abi
91      .decode(payload, (bytes32, address, uint256, uint256));

109    txnHashToTransaction[txnHash] = Transaction(srcSender, amt);
```
The [`DestinationBridge._mintIfThresholdMet`](https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L337-L353) uses the parameters for the tokens minting:
```solidity
339    Transaction memory txn = txnHashToTransaction[txnHash];

349      TOKEN.mint(txn.sender, txn.amount);
```
So if the `burnAndCallAxelar` function is called by a contract the tokens will be minted to a wrong address (not the contract address at the destination chain ).

## Tools Used
Manual review

## Recommended Mitigation Steps
Consider specifying recipients for any token transfers or reverting in the case of the sender is not an EOA.



## Assessed type

Other
Insufficient Gas Fee Estimation Leading to Incomplete Transactions
Audit: 2023-09-ondo-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/SourceBridge.sol#L72


# Vulnerability details

The contract allows a user to send Ether, presumably for transaction fees or gas. However, there is no mechanism in place to verify that the msg.value is sufficient to cover the actual gas cost for contract execution. Consequently, a scenario could arise where the transaction runs out of gas prematurely.

## Impact
If a user passes an insufficient gas fee when invoking the contract, two critical issues can arise:

Token Burning without Redemption: The tokens could get burned on the source chain but due to insufficient gas, the corresponding tokens on the destination chain might not be minted or transferred. This would result in a loss for the user and an inconsistency between the two chains.
Gas Wastage: The user could end up wasting the gas fee for a failed transaction, causing both financial loss and unnecessary network congestion.

## Proof of Concept
Imagine Alice wants to swap her tokens from the source chain to the destination chain using the contract. She initiates the burn on the source chain and sends a small gas fee along with her transaction, assuming it's sufficient.

Alice's transaction starts processing, but due to the insufficient gas she provided, the transaction fails midway. Now, her tokens on the source chain are already burned, and due to the incomplete transaction, Bob, who is supposed to receive the tokens on the destination chain, gets nothing.

Here, Alice loses her tokens, Bob doesn't receive anything, and the transaction fee is wasted. This scenario showcases the critical importance of ensuring adequate gas estimation and verification.

## Tools Used

## Recommended Mitigation Steps
Gas Estimation: Implement a function to estimate the required gas for the specific contract action and compare it against the msg.value. Refuse the transaction if the provided value is less than the estimated requirement.
Clear Documentation: Clearly document the estimated gas requirement for users intending to interact with the contract to prevent unintentional errors.
Refund Mechanism: Consider implementing a mechanism that refunds any excess Ether sent beyond the gas requirement.


## Assessed type

ETH-Transfer
guardian multisig should be timelock
Audit: 2023-09-ondo-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/usdy/rUSDYFactory.sol#L41
https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/usdy/rUSDY.sol#L680


# Vulnerability details

## Impact
Per the `rUSDYFactory.sol`, The Natspec states the guardian address is a multsig address which will be passed in constructor during deployement of factory contract.

```Solidity
  @notice `guardian` address in constructor is a msig.
```
and 

```Solidity
  constructor(address _guardian) {
    guardian = _guardian;
  }
```

There is very important issue which is very much required to be discussed in this report and it should not be merged with typical centralization issue.

Issue 1:
In `rUSDY.sol`, `burn()` is an `BURNER_ROLE` function which is basically handled by guardian address which can be checked [here](https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/usdy/rUSDY.sol#L145)

```Solidity
File: contracts/usdy/rUSDY.sol

  function burn(
    address _account,
    uint256 _amount
  ) external onlyRole(BURNER_ROLE) {
    uint256 sharesAmount = getSharesByRUSDY(_amount);

    _burnShares(_account, sharesAmount);

    usdy.transfer(msg.sender, sharesAmount / BPS_DENOMINATOR);

    emit TokensBurnt(_account, _amount);
  }
```

This function is used by `guardian` in case someone gets rUSDY who is technically not allowed to have it as teh given the underlying asset must comply with US regulations as  they are US bank deposits.

It can be understand the function wont be used regularly and can be considered as USDC `blacklist` functionality for basic understanding. But there is a direct risk involved here, the guardian can anytime burn the users tokens and after burning the `usdy` is transferred to `msg.sender` which is `guardian` address in this case.

```Solidity
    usdy.transfer(msg.sender, sharesAmount / BPS_DENOMINATOR);
```

so because of the terms and conditions the user signs to get on the [allowlist](https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/usdy/rUSDY.sol#L709) to have a USDY, the user is forfeitted the **100% asset** and getting transferred to `guardian` address.

The terms and conditions are strict but the users loss is permanent and too 100%. It is therefore, I argue to provide the timelock functionality with multisig to guardian address so that any users assets should be safe and transparency is created before making such change among users.

It is to be noted here, only instance is mentioned in automated report but this issue is not explained in automated report, also there is not recommendation provide in automated report for such issue. This issue is important from the interest point of users safety.

Another important thing to be noted here, there is no way to change guardian address. If timelock is implemented, guardian address changing f
In `DestinationBridge:rescueTokens` function the owner can steal user tokens
Audit: 2023-09-ondo-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L322-L325


# Vulnerability details

## Summary
In the `rescueToken` function, it opens the door to potential insecurity for user funds because it lacks additional conditions specifying which types of tokens or under what conditions the onlyOwner can use this function.

The function looks like:
- https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L322-L325

```solidity
  /**
   * @notice Admin function used to rescue ERC20 Tokens sent to the contract
   *
   * @param _token The address of the token to rescue
   */
  function rescueTokens(address _token) external onlyOwner {
    uint256 balance = IRWALike(_token).balanceOf(address(this));
    IRWALike(_token).transfer(owner(), balance);
  }
```

## Impact
Owner can steal the user funds.


## Tools Used
Manual review 

## Recommended Mitigation Steps
Improve the logic of this function and specify under what circumstances the owner can use it without jeopardizing user funds.


## Assessed type

Rug-Pull
Loss of token if a smart contract perform a cross-chain transfer using source bridge
Audit: 2023-09-ondo-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/SourceBridge.sol#L61
https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L90


# Vulnerability details

## Impact

Loss of a token ownership if a smart contract perform a cross-chain transfer using source bridge

## Proof of Concept

When a caller call [burnAndCallAxelar](https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/SourceBridge.sol#L61), the token is burnt on source chain

and the payload is encoded in this way:

```solidity
bytes memory payload = abi.encode(VERSION, msg.sender, amount, nonce++);
```

when on the dest chain triggers [_execute](https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L90), 

```solidity
(bytes32 version, address srcSender, uint256 amt, uint256 nonce) = abi
  .decode(payload, (bytes32, address, uint256, uint256));
```

and the token is [minted](https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L349) to srcSender, which is the same address from the source chain

but the issue is, if a smart contract call burnAndCallAxelar on source chain, the owner of the smart contract may not belong to the original caller in dest chain

in that case, the token ownership is lost

for example https://rekt.news/wintermute-rekt/

the false assumption of a mutlisig smart contract address is controlled by same owner in different network has cost 20M OP lost

## Tools Used

Manual Review

## Recommended Mitigation Steps

let user specify a recipient address in the source bridge when calling burnAndCallAxelar

then the recipient on dest bridge receives the minted token


## Assessed type

Token-Transfer
The `rUSDY.transferFrom` function can cause reentrancy if is a contract been approved
Audit: 2023-09-ondo-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L301-L312


# Vulnerability details

### Impact
The `rUSDY.transferFrom` function can cause reentrancy if is a contract been approved, the function looks like:

- https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L301-L312
```solidity
  function transferFrom(
    address _sender,
    address _recipient,
    uint256 _amount
  ) public returns (bool) {
    uint256 currentAllowance = allowances[_sender][msg.sender];
    require(currentAllowance >= _amount, "TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE");

    _transfer(_sender, _recipient, _amount);
    _approve(_sender, msg.sender, currentAllowance - _amount); // @audit doesnt follow the check- effect - interaction pattern
    return true;
  }
```

This could be an issue if it's a contract that has been approved to spend tokens, as it can reenter this function.


### Tools Used
Manual review.

### Recommended Mitigation Steps
Use the [CEI](https://dev.to/zaryab2000/the-significance-of-check-effects-interaction-pattern-5hn6) or add the OZ library `ReentrancyGuard`.


## Assessed type

Reentrancy
Funds will be lost in case the block reorg occurs on the chain of sending bridge
Audit: 2023-09-ondo-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/SourceBridge.sol#L61-L82
https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L85-L114


# Vulnerability details

## Impact
Funds will be lost in case the block reorg occurs on the chain of sending bridge
## Proof of Concept
consider the following scenerio on sending chain:

In block 1:  Alice sends the 1000 tokens to the destination bridge and the nonce for it is set to 10
In block 2: Bob sends the 1000 tokens to the destination bridge and the nonce for it is set to 11
In block 3: Alice again sends the 1000 tokens to the destination bridge and the nonce for it is set to 12

Not the events have been transmitted and axelar network have started its work.

Than the block reorg happens and block2 along with block 3 is orphaned. Which means the nonce gone. 

Now we have block 1 on which alice called the transaction with nonce 10. And we have the nonce 11 and 12 on our hand again.

So in the upcoming blocks the axelar network will be again called with the nonce of 11 and 12 which have been processed on the receiving chain and have minted tokens to alice and bob.

lets say reorg happened on bnb chain than the following in `_execute()` will be set to true for nonce 11 and 12 and will revert next time : 

```solidity
    if (isSpentNonce[chainToApprovedSender[srcChain]][nonce]) {
      revert NonceSpent();
    }
```

Now lets say two new user adam and eve sends the tokens in next two function, with nonce of 11 and 12.

This time _execute will revert due to the nonce being used before for the source chain, as destination is not aware of the block reorg.

As discussed in other issues that, if the _execute reverts once, the transaction is unplayable again and the tokens burnt on source chain are lost forver. Hence loss of funds for adam and eve

```solidity
 function _execute(
    string calldata srcChain,
    string calldata srcAddr,
    bytes calldata payload
  ) internal override whenNotPaused {
  
    (bytes32 version, address srcSender, uint256 amt, uint256 nonce) = abi
      .decode(payload, (bytes32, address, uint256, uint256));

    if (version != VERSION) {
      revert InvalidVersion();
    }
    if (chainToApprovedSender[srcChain] == bytes32(0)) {
      revert ChainNotSupported();
    }
    // each chain have only on approved sender that is the source bridge contract.
    if (chainToApprovedSender[srcChain] != keccak256(abi.encode(srcAddr))) {
      revert SourceNotSupported();
    }
    if (isSpentNonce[chainToApprovedSender[srcChain]][nonce]) {
      revert NonceSpent();
    }

    isSpentNonce[chainToApprovedSender[srcChain]][nonce] = true;

    // same payload would have the same txhash
    bytes32 txnHash = keccak256(payload);
    txnHashToTransaction[txnHash] = Transaction(srcSender, amt);
    _attachThreshold(amt, txnHash, srcChain);
    _approve