descharre G

# Summary
|ID     | Finding|  Gas saved | Instances|
|:----: | :---           |  :----:         |:----:         |
|G-01      |Make for loops unchecked| - |  12 |
|G-02      |Add unchecked block when operands can't under/overflow| 536 | 15 |
|G-03      |Don't write to memory when variable is only used once| 10 | 1 |
|G-04      |Unnecessary nonReentrant modifier| 2374 | 1 |
|G-05      |Save return value to memory instead of calling function multiple times| - | 1 |
|G-06      |function `_atLeastRole()` can be made more gas efficiënt| 300 | 1 |
|G-07      |Initialize a static array instead of a dynamic array| 300 | - |
|G-08      |Unnecessary if/require statements| - | 2 |
|G-09      |Internal functions only called once can be inlined to save gas| 30 | 1 |
|G-10      |Using double if/require statement instead of && consumes less gas| 15 | 7 |
|G-11      |Use the calldata variable when it has the same value as a state variable| 200 | 1 |
|G-12      |Bytes32 constant is cheaper than string constant| - | 4 |
|G-13      |Combine events to save gas| 5000 | 6 |
|G-14      |Amount is always equal to balance after - balance before| 980 | 1 |
# Details
## [G-01] Make for loops unchecked
The risk of for loops getting overflowed is extremely low. Because it always increments by 1 and is limited to the arrays length. Even if the arrays are extremely long, it will take a massive amount of time and gas to let the for loop overflow. The longer the array, the more gas you will save.

- [ActivePool.sol#L108-L113](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/ActivePool.sol#L108-L113)
- [CollateralConfig.sol#L56-L73](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/CollateralConfig.sol#L56-L73)
- [StabilityPool.sol#L351-L356](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/StabilityPool.sol#L351-L356)
- [StabilityPool.sol#L397-L403](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/

## [G-02] Add unchecked block when operands can't under/overflow
When operands can't underflow/overflow because of a previous require() or if statement, you can use an unchecked block.
The default "checked" behavior costs more gas when calculating, because under-the-hood the EVM does extra checks for over/underflow.
|Code     |Explanation| Function |  Gas saved |
|:----: | :---           |  :----:         |:----:         |
|[ReaperVaultV2.sol#L194](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L194)|AllocBPS can never be higher than the totalAllocBPS| `updateStrategyAllocBPS()` |170 |
|[ReaperVaultV2.sol#L391](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L391)|Loss is decremented from value in the line above.
If loss would be really high it would already revert there.| `withdraw()` |90 |
|[ReaperVaultV2.sol#L396](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L396)| Total allocated is always more than the allocation of one strategy| `updateStrategyAllocBPS()` |218 |
|[ReaperVaultV2.sol#L330](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L330)| When tokens are sent to the vault, balance after is always
 greater than or equal to balance before| `deposit()` |58 |
|[ReaperStrategyGranarySupplyOnly.sol#L93](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L93)| Can be done because of previous if check| `_liquidatePosition()` |- |
|[ReaperStrategyGranarySupplyOnly.sol#L100](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L100)| Can be done because of previous if check| `_liquidatePosition()` |- |

This can also be done for divisions.

The expression type(int).min / (-1) is the only case where division causes an overflow. On average 35 gas saved:
- [Re

ActivePool.sol#L108-L113, CollateralConfig.sol#L56-L73, StabilityPool.sol#L351-L356, ReaperVaultV2.sol#L194, ReaperVaultV2.sol#L391, ReaperVaultV2.sol#L396, ReaperVaultV2.sol#L330, ReaperStrategyGranarySupplyOnly.sol#L93, ReaperStrategyGranarySupplyOnly.sol#L100

StabilityPool.sol, ReaperStrategyGranarySupplyOnly.sol, ReaperVaultV2.sol, ActivePool.sol, CollateralConfig.sol


ACai G

# verifing `public` to `external` for saving gas

Suggest to verify the function visibility quantifiers from `public` to `external` for saving gas.

- Factory.setPrivatePoolMetadata, Line 129
- Factory.setPrivatePoolImplementation, Line 135
- Factory.setProtocolFeeRate, Line 141
- Factory.withdraw, Line 148

# verifing the parameter visibility to `immutable` for saving gas
PrivatePool.constructor, Line 143-147
These `factory`, `royaltyRegistry` and `stolenNftOracle` parameter only set in the constructor function. So suggest to add `immutable` for saving gas.
```solidity
    constructor(address _factory, address _royaltyRegistry, address _stolenNftOracle) {
        factory = payable(_factory);
        royaltyRegistry = _royaltyRegistry;
        stolenNftOracle = _stolenNftOracle;
    }
```

// Code block 1 (solidity):
constructor(address _factory, address _royaltyRegistry, address _stolenNftOracle) {
        factory = payable(_factory);
        royaltyRegistry = _royaltyRegistry;
        stolenNftOracle = _stolenNftOracle;
    }


report

---
sponsor: "Kelp DAO"
slug: "2023-11-kelp"
date: "2023-12-11"
title: "Kelp DAO | rsETH"
findings: "https://github.com/code-423n4/2023-11-kelp-findings/issues"
contest: 305
---

# Overview

## About C4

Code4rena (C4) is an open organization consisting of security researchers, auditors, developers, and individuals with domain expertise in smart contracts.

A C4 audit is an event in which community participants, referred to as Wardens, review, audit, or analyze smart contract logic in exchange for a bounty provided by sponsoring projects.

During the audit outlined in this document, C4 conducted an analysis of the Kelp DAO | rsETH smart contract system written in Solidity. The audit took place between November 10—November 15 2023.

## Wardens

194 Wardens contributed reports to the Kelp DAO | rsETH audit:

  1. [m\_Rassska](https://code4rena.com/@m_Rassska)
  2. [CatsSecurity](https://code4rena.com/@CatsSecurity) ([nirlin](https://code4rena.com/@nirlin) and [cats](https://code4rena.com/@cats))
  3. [adriro](https://code4rena.com/@adriro)
  4. [Bauchibred](https://code4rena.com/@Bauchibred)
  5. [PENGUN](https://code4rena.com/@PENGUN)
  6. [SBSecurity](https://code4rena.com/@SBSecurity) ([Slavcheww](https://code4rena.com/@Slavcheww) and [Blckhv](https://code4rena.com/@Blckhv))
  7. [deth](https://code4rena.com/@deth)
  8. [0xDING99YA](https://code4rena.com/@0xDING99YA)
  9. [jayfromthe13th](https://code4rena.com/@jayfromthe13th)
  10. [Aamir](https://code4rena.com/@Aamir)
  11. [HChang26](https://code4rena.com/@HChang26)
  12. [almurhasan](https://code4rena.com/@almurhasan)
  13. [d3e4](https://code4rena.com/@d3e4)
  14. [anarcheuz](https://code4rena.com/@anarcheuz)
  15. [circlelooper](https://code4rena.com/@circlelooper)
  16. [hals](https://code4rena.com/@hals)
  17. [Bauer](https://code4rena.com/@Bauer)
  18. [ck](https://code4rena.com/@ck)
  19. [Pechenite](https://code4rena.com/@Pechenite) ([Bozho](https://code4rena.com/@Bozho) and [radev\_sw](https://code4rena

            contract LRTOracleMock {
              uint256 public price;

              constructor(uint256 _price) {
                  price = _price;
              }

              function getAssetPrice(address) external view returns (uint256) {
                  return price;
              }

              function submitNewAssetPrice(uint256 _newPrice) external {
                  price = _newPrice;
              }
            }
            ```
    *   `setUp()`:
        *   ```Solidity
            contract LRTDepositPoolTest is BaseTest, RSETHTest {
            LRTDepositPool public lrtDepositPool;

              function setUp() public virtual override(RSETHTest, BaseTest) {
                  super.setUp();

                  // deploy LRTDepositPool
                  ProxyAdmin proxyAdmin = new ProxyAdmin();
                  LRTDepositPool contractImpl = new LRTDepositPool();
                  TransparentUpgradeableProxy contractProxy = new TransparentUpgradeableProxy(
                      address(contractImpl),
                      address(proxyAdmin),
                      ""
                  );

                  lrtDepositPool = LRTDepositPool(address(contractProxy));

                  // initialize RSETH. LRTCOnfig is already initialized in RSETHTest
                  rseth.initialize(address(admin), address(lrtConfig));
                  vm.startPrank(admin);
                  // add rsETH to LRT config
                  lrtConfig.setRSETH(address(rseth));
                  // add oracle to LRT config
                  lrtConfig.setContract(LRTConstants.LRT_ORACLE, address(new LRTOracle()));
                  lrtConfig.setContract(LRTConstants.LRT_DEPOSIT_POOL, address(lrtDepositPool));
                  LRTOracle(lrtConfig.getContract(LRTConstants.LRT_ORACLE)).initialize(address(lrtConfig));

                  lrtDepositPool.initialize(address(lrtConfig));
                  // add minter role for rseth to lrtDepositPool


ladboy233 Q

| Issue Number | Description                                                         | Suggested Action                             |
|--------------|---------------------------------------------------------------------|----------------------------------------------|
| 1            | Function `flashFee` in `ActivePool` is not fully EIP 3156 compliant | Ensure compliance with EIP 3156              |
| 2            | Use of `increaseAllowance` / `decreaseAllowance` is deprecated in `EBTC.sol` token | Replace with secure alternatives             |
| 3            | Should validate if `ecrecover` returns address(0)                   | Implement validation for `ecrecover` return  |
| 4            | Address open `@todo` and `@audit` before deployment                 | Complete all TODOs and audits                |
| 5            | Rename `Governor` contract to `ACM` (Access Control Manager)        | Rename the contract as suggested             |

# function flashFee in ActivePool is not fully EIP 3156 complicant

According to https://code4rena.com/contests/2023-10-badger-ebtc-audit-certora-formal-verification-competition#top

> EIP Compliance
ActivePool: Should comply with EIP3156

according to https://eips.ethereum.org/EIPS/eip-3156

> The flashFee function MUST return the fee charged for a loan of amount token. If the token is not supported flashFee MUST revert.

so external implementation may replies on this function to validate whether flashloan is supported

if the active pool collateral is stETH,

if we take a look at the stETH smart contract

https://etherscan.io/token/0xae7ab96520de3a18e5e111b5eaab095312d7fe84#readProxyContract

the implementation contract is https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code

when the admin of stETH paused the token, no transfer can be allowed and no flashloan can be borrowed

https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code#F27#L445

```solidity
 function _transferShares(add

 function _transferShares(address _sender, address _recipient, uint256 _sharesAmount) internal {
        require(_sender != address(0), "TRANSFER_FROM_ZERO_ADDR");
        require(_recipient != address(0), "TRANSFER_TO_ZERO_ADDR");
        require(_recipient != address(this), "TRANSFER_TO_STETH_CONTRACT");
        _whenNotStopped();

        uint256 currentSenderShares = shares[_sender];
        require(_sharesAmount <= currentSenderShares, "BALANCE_EXCEEDED");

        shares[_sender] = currentSenderShares.sub(_sharesAmount);
        shares[_recipient] = shares[_recipient].add(_sharesAmount);
    }

   function flashFee(address token, uint256 amount) public view override returns (uint256) {
        require(token == address(collateral), "ActivePool: collateral Only");
        require(!flashLoansPaused, "ActivePool: Flash Loans Paused");
        require(ACTIVE_FLAG_POSITION.getStorageBool(), "collateral paused") // added code
        return (amount * feeBps) / MAX_BPS;
    }


jnrlouis G

# Report

## Gas Optimization

|               | Issue | Instances |
| ---------------------- | ------------ | -------------- |
| [GAS-1]   | Cache array length outside of loop     | 5           |
| [GAS-2] | Don't initialize variables with default value         | 8        |
| [GAS-3]    | Functions guaranteed to revert when called by normal users can be marked payable       | 12            |
| [GAS-4]    | Double && operator more expensive than nested if loop      | 2            |

### [GAS-1] Cache array length outside of loop

If not cached, the solidity compiler will always read the length of the array during each iteration. That is, if it is a storage array, this is an extra sload operation (100 additional extra gas for each iteration except for the first) and if it is a memory array, this is an extra mload operation (3 additional gas for each iteration except for the first).

*Instances (5)*:

```
File: SourceBridge.sol

    for (uint256 i = 0; i < exCallData.length; ++i)

```

```
File: DesinationBridge.sol

134    for (uint256 i = 0; i < thresholds.length; ++i)

160      for (uint256 i = 0; i < t.approvers.length; ++i)

264    for (uint256 i = 0; i < amounts.length; ++i)

```

```
File: rUSDYFactory.sol

130    for (uint256 i = 0; i < exCallData.length; ++i)

```

### [GAS-2] Don't initialize variables with default value

*Instances (8)*:

```
File: SourceBridge.sol

    for (uint256 i = 0; i < exCallData.length; ++i)

```

```
File: DesinationBridge.sol

134    for (uint256 i = 0; i < thresholds.length; ++i)

160      for (uint256 i = 0; i < t.approvers.length; ++i)

264    for (uint256 i = 0; i < amounts.length; ++i)

```

```
File: rUSDYFactory.sol

130    for (uint256 i = 0; i < exCallData.length; ++i)

```

```
File: RWADynamicOracle.sol

77    for (uint256 i = 0; i < length; ++i)

113    for (uint256 i = 0; i < length; ++i)

129    for (uint256 i = 0; i < length + 1; ++i)
```

### [GAS-3] Functions guaranteed to revert when called by normal users c

// Code block 1 (unknown):
File: SourceBridge.sol

    for (uint256 i = 0; i < exCallData.length; ++i)

// Code block 2 (unknown):
File: DesinationBridge.sol

134    for (uint256 i = 0; i < thresholds.length; ++i)

160      for (uint256 i = 0; i < t.approvers.length; ++i)

264    for (uint256 i = 0; i < amounts.length; ++i)

// Code block 3 (unknown):
File: rUSDYFactory.sol

130    for (uint256 i = 0; i < exCallData.length; ++i)

// Code block 4 (unknown):
File: SourceBridge.sol

    for (uint256 i = 0; i < exCallData.length; ++i)

// Code block 5 (unknown):
File: DesinationBridge.sol

134    for (uint256 i = 0; i < thresholds.length; ++i)

160      for (uint256 i = 0; i < t.approvers.length; ++i)

264    for (uint256 i = 0; i < amounts.length; ++i)

// Code block 6 (unknown):
File: rUSDYFactory.sol

130    for (uint256 i = 0; i < exCallData.length; ++i)

// Code block 7 (unknown):
File: RWADynamicOracle.sol

77    for (uint256 i = 0; i < length; ++i)

113    for (uint256 i = 0; i < length; ++i)

129    for (uint256 i = 0; i < length + 1; ++i)


ayden Q

1.The initial value of rewards is 0, so there is no need to use the += operator. We can simply use the = operator to assign the value
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol#L801

```solidity
    // skip reward calculation if update at the previous epoch was missed and if exchange rate decreased due to bad debt
    // prevents excess rewards from being provided from using a 0 value as an input to the interestFactor calculation below.
    if (prevBucketExchangeRate != 0 && prevBucketExchangeRate < curBucketExchangeRate) {

        // retrieve current deposit of the bucket
        (, , , uint256 bucketDeposit, ) = IPool(pool_).bucketInfo(bucketIndex_);

        uint256 burnFactor     = Maths.wmul(totalBurned_, bucketDeposit);
        uint256 interestFactor = interestEarned_ == 0 ? 0 : Maths.wdiv(
            Maths.WAD - Maths.wdiv(prevBucketExchangeRate, curBucketExchangeRate),
            interestEarned_
        );

        // calculate rewards earned for updating bucket exchange rate
-       rewards_ += Maths.wmul(UPDATE_CLAIM_REWARD, Maths.wmul(burnFactor, interestFactor));
+       rewards_  = Maths.wmul(UPDATE_CLAIM_REWARD, Maths.wmul(burnFactor, interestFactor));
    }
```

2.In the case where there is already a lastClaimedEpoch, setting up a separate mapping to track whether the epochToClaim* parameter has been claimed seems redundant. I believe it is sufficient to check whether epochToClaim* is greater than lastClaimedEpoch.
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol#L114#L125

```solidity
    function claimRewards(
        uint256 tokenId_,
        uint256 epochToClaim_
    ) external override {
        StakeInfo storage stakeInfo = stakes[tokenId_];

        if (msg.sender != stakeInfo.owner) revert NotOwnerOfDeposit();

_       if (isEpochClaimed[tokenId_][epochToClaim_]) revert AlreadyClaimed();

+       if (epochToClaim_ <= stakeInfo.lastClaimedEpoch) revert AlreadyCla

    function claimRewards(
        uint256 tokenId_,
        uint256 epochToClaim_
    ) external override {
        StakeInfo storage stakeInfo = stakes[tokenId_];

        if (msg.sender != stakeInfo.owner) revert NotOwnerOfDeposit();

_       if (isEpochClaimed[tokenId_][epochToClaim_]) revert AlreadyClaimed();

+       if (epochToClaim_ <= stakeInfo.lastClaimedEpoch) revert AlreadyClaimed();

        _claimRewards(stakeInfo, tokenId_, epochToClaim_, true, stakeInfo.ajnaPool);
    }

// Code block 1 (solidity):
// skip reward calculation if update at the previous epoch was missed and if exchange rate decreased due to bad debt
    // prevents excess rewards from being provided from using a 0 value as an input to the interestFactor calculation below.
    if (prevBucketExchangeRate != 0 && prevBucketExchangeRate < curBucketExchangeRate) {

        // retrieve current deposit of the bucket
        (, , , uint256 bucketDeposit, ) = IPool(pool_).bucketInfo(bucketIndex_);

        uint256 burnFactor     = Maths.wmul(totalBurned_, bucketDeposit);
        uint256 interestFactor = interestEarned_ == 0 ? 0 : Maths.wdiv(
            Maths.WAD - Maths.wdiv(prevBucketExchangeRate, curBucketExchangeRate),
            interestEarned_
        );

        // calculate rewards earned for updating bucket exchange rate
-       rewards_ += Maths.wmul(UPDATE_CLAIM_REWARD, Maths.wmul(burnFactor, interestFactor));
+       rewards_  = Maths.wmul(UPDATE_CLAIM_REWARD, Maths.wmul(burnFactor, interestFactor));
    }


kerdakov Q

The use of `unchecked` in the for loop in [NodeDelegator](https://github.com/code-423n4/2023-11-kelp/blob/c5fdc2e62c5e1d78769f44d6e34a6fb9e40c00f0/src/NodeDelegator.sol#L109C8-L115C10) seems unnecessary and could potentially lead to unintended consequences. The loop itself doesn't involve arithmetic operations that could overflow or underflow, so using `unchecked` here is unnecessary.

```
for (uint256 i = 0; i < strategiesLength;) {
    assets[i] = address(IStrategy(strategies[i]).underlyingToken());
    assetBalances[i] = IStrategy(strategies[i]).userUnderlyingView(address(this));
    unchecked {
        ++i;
    }
}
```

In fact, it's more common and safer to use a standard for loop without unchecked:

```
for (uint256 i = 0; i < strategiesLength; i++) {
    assets[i] = address(IStrategy(strategies[i]).underlyingToken());
    assetBalances[i] = IStrategy(strategies[i]).userUnderlyingView(address(this));
}
```

// Code block 1 (unknown):
for (uint256 i = 0; i < strategiesLength;) {
    assets[i] = address(IStrategy(strategies[i]).underlyingToken());
    assetBalances[i] = IStrategy(strategies[i]).userUnderlyingView(address(this));
    unchecked {
        ++i;
    }
}

// Code block 2 (unknown):
for (uint256 i = 0; i < strategiesLength; i++) {
    assets[i] = address(IStrategy(strategies[i]).underlyingToken());
    assetBalances[i] = IStrategy(strategies[i]).userUnderlyingView(address(this));
}


mahyar G

## Caching in local variable

Solidity by default checks underflow/overflow when doing any calculation, this uses some gas and calculating same values multiple times is not good approach. In [ProtocolRewardsPool](https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/miner/ProtocolRewardsPool.sol#L190) inside `getReward()` function `reward - eUSDShare` is used multiple times. It should be cached in local variable and use the variable insted of calculate it multiple times.

## Using `constant` variables

In [esLBR](https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/token/esLBR.sol#L20) and [LBR](https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/token/LBR.sol#L15) contracts `maxSupply` variable should be changed to `constant` variable since its value is not changing in the code, this can reduce gas costs.

## Using `immutable` variables

These variables can be changed to `immutable` since their value its not changing after initialization

1. [Line 50](https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/configuration/LybraConfigurator.sol#L50) in LybraConfigurator contract

2. [Line 55](https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/miner/EUSDMiningIncentives.sol#L55) in EUSDMiningIncentives contract

3. [Line 11](https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L11C19-L11C24) and [Line 12](https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L12) in LybraGovernance contract

## Using ternary operator insted of if statement

Using ternary operator can reduce deployment size and deployment costs

1. [Line 301](https://github.com/co

return totalMintedEUSD == 0 ? 0 : _EUSDAmount.mul(_totalShares).div(totalMintedEUSD);

return _totalShares == 0 ? 0 : _sharesAmount.mul(_totalSupply).div(_totalShares);

ProtocolRewardsPool.sol#L190, esLBR.sol#L20, LBR.sol#L15, LybraConfigurator.sol#L50, EUSDMiningIncentives.sol#L55, LybraGovernance.sol#L11-L19, LybraGovernance.sol#L12

EUSDMiningIncentives.sol, LybraConfigurator.sol, ProtocolRewardsPool.sol, esLBR.sol, LBR.sol, LybraGovernance.sol


Bnke0x0 G

### [G01] State variables only set in the constructor should be declared `immutable`

#### Impact
Avoids a Gusset (20000 gas)
#### Findings:
```

2023-01-ondo/contracts/cash/CashManager.sol::47 => address public assetRecipient;
2023-01-ondo/contracts/cash/CashManager.sol::50 => address public feeRecipient;
2023-01-ondo/contracts/cash/CashManager.sol::53 => address public assetSender;
2023-01-ondo/contracts/cash/CashManager.sol::97 => uint256 public currentEpoch;
2023-01-ondo/contracts/cash/CashManager.sol::100 => uint256 public epochDuration;
2023-01-ondo/contracts/cash/CashManager.sol::103 => uint256 public currentEpochStartTimestamp;
2023-01-ondo/contracts/cash/CashManager.sol::110 => uint256 public mintLimit;
2023-01-ondo/contracts/cash/CashManager.sol::113 => uint256 public currentMintAmount;
2023-01-ondo/contracts/cash/CashManager.sol::116 => uint256 public redeemLimit;
2023-01-ondo/contracts/cash/CashManager.sol::119 => uint256 public currentRedeemAmount;
2023-01-ondo/contracts/cash/factory/CashFactory.sol::49 => Cash public cashImplementation;
2023-01-ondo/contracts/cash/factory/CashFactory.sol::50 => ProxyAdmin public cashProxyAdmin;
2023-01-ondo/contracts/cash/factory/CashFactory.sol::51 => TokenProxy public cashProxy;
2023-01-ondo/contracts/cash/factory/CashKYCSenderFactory.sol::49 => CashKYCSender public cashKYCSenderImplementation;
2023-01-ondo/contracts/cash/factory/CashKYCSenderFactory.sol::50 => ProxyAdmin public cashKYCSenderProxyAdmin;
2023-01-ondo/contracts/cash/factory/CashKYCSenderFactory.sol::51 => TokenProxy public cashKYCSenderProxy;
2023-01-ondo/contracts/cash/factory/CashKYCSenderReceiverFactory.sol::49 => CashKYCSenderReceiver public cashKYCSenderReceiverImplementation;
2023-01-ondo/contracts/cash/factory/CashKYCSenderReceiverFactory.sol::50 => ProxyAdmin public cashKYCSenderReceiverProxyAdmin;
2023-01-ondo/contracts/cash/factory/CashKYCSenderReceiverFactory.sol::51 => TokenProxy public cashKYCSenderReceiverProxy;
2023-01-ondo/contracts/c

2023-01-ondo/contracts/cash/CashManager.sol::47 => address public assetRecipient;
2023-01-ondo/contracts/cash/CashManager.sol::50 => address public feeRecipient;
2023-01-ondo/contracts/cash/CashManager.sol::53 => address public assetSender;
2023-01-ondo/contracts/cash/CashManager.sol::97 => uint256 public currentEpoch;
2023-01-ondo/contracts/cash/CashManager.sol::100 => uint256 public epochDuration;
2023-01-ondo/contracts/cash/CashManager.sol::103 => uint256 public currentEpochStartTimestamp;
2023-01-ondo/contracts/cash/CashManager.sol::110 => uint256 public mintLimit;
2023-01-ondo/contracts/cash/CashManager.sol::113 => uint256 public currentMintAmount;
2023-01-ondo/contracts/cash/CashManager.sol::116 => uint256 public redeemLimit;
2023-01-ondo/contracts/cash/CashManager.sol::119 => uint256 public currentRedeemAmount;
2023-01-ondo/contracts/cash/factory/CashFactory.sol::49 => Cash public cashImplementation;
2023-01-ondo/contracts/cash/factory/CashFactory.sol::50 => ProxyAdmin public cashProxyAdmin;
2023-01-ondo/contracts/cash/factory/CashFactory.sol::51 => TokenProxy public cashProxy;
2023-01-ondo/contracts/cash/factory/CashKYCSenderFactory.sol::49 => CashKYCSender public cashKYCSenderImplementation;
2023-01-ondo/contracts/cash/factory/CashKYCSenderFactory.sol::50 => ProxyAdmin public cashKYCSenderProxyAdmin;
2023-01-ondo/contracts/cash/factory/CashKYCSenderFactory.sol::51 => TokenProxy public cashKYCSenderProxy;
2023-01-ondo/contracts/cash/factory/CashKYCSenderReceiverFactory.sol::49 => CashKYCSenderReceiver public cashKYCSenderReceiverImplementation;
2023-01-ondo/contracts/cash/factory/CashKYCSenderReceiverFactory.sol::50 => ProxyAdmin public cashKYCSenderReceiverProxyAdmin;
2023-01-ondo/contracts/cash/factory/CashKYCSenderReceiverFactory.sol::51 => TokenProxy public cashKYCSenderReceiverProxy;
2023-01-ondo/contracts/cash/kyc/KYCRegistryClient.sol::30 => IKYCRegistry public override kycRegistry;
2023-01-ondo/contracts/cash/kyc/KYCRegistryClient.sol::32 => uint256

2023-01-ondo/contracts/cash/CashManager.sol::47 => address public assetRecipient;
2023-01-ondo/contracts/cash/CashManager.sol::50 => address public feeRecipient;
2023-01-ondo/contracts/cash/CashManager.sol::53 => address public assetSender;
2023-01-ondo/contracts/lending/JumpRateModelV2.sol::24 => address public owner;
2023-01-ondo/contracts/lending/tokens/cCash/CTokenInterfacesModifiedCash.sol::387 => address public underlying;
2023-01-ondo/contracts/lending/tokens/cCash/CTokenInterfacesModifiedCash.sol::425 => address public implementation;
2023-01-ondo/contracts/lending/tokens/cErc20ModifiedDelegator.sol::573 => address public underlying;
2023-01-ondo/contracts/lending/tokens/cErc20ModifiedDelegator.sol::609 => address public implementation;
2023-01-ondo/contracts/lending/tokens/cToken/CTokenInterfacesModified.sol::385 => address public underlying;
2023-01-ondo/contracts/lending/tokens/cToken/CTokenInterfacesModified.sol::423 => address public implementation;


ayo_dev G

### 1. Use Uint256 to store Constants instead of Bytes32
Instead of using a bytes32 to store keccack256 hash as state variable, we can instead use a uint256 to store the state variables examples can be found in solady contract https://github.com/Vectorized/solady/blob/8c751db06e614e26e6acb9b385b463feef5e3a9f/src/tokens/ERC20.sol#L51
```
contract test {//deployment cost 113364 gas,
    uint256 public constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; //
}

contract test {//deployment cost 121071 gas,
    bytes32 public constant _TRANSFER_EVENT_SIGNATURE =
        keccak256(bytes("Transfer(address,address,uint256)"));
}
```
one reason this might be is because i think solidity use extra operations to check whether the bytes are valid bytes but does not do this for uint256
NOTE: uint256 is equal to bytes32 they both contain 32 bytes and can be typecasted and vice versa
an example of this problem can be found in the `LybraConfigurator` contract

Instances in the code:
https://github.com/code-423n4/2023-06-lybra/blob/5d70170f2c68dbd3f7b8c0c8fd6b0b2218784ea6/contracts/lybra/configuration/LybraConfigurator.sol#L76
https://github.com/code-423n4/2023-06-lybra/blob/5d70170f2c68dbd3f7b8c0c8fd6b0b2218784ea6/contracts/lybra/configuration/LybraConfigurator.sol#L77
https://github.com/code-423n4/2023-06-lybra/blob/5d70170f2c68dbd3f7b8c0c8fd6b0b2218784ea6/contracts/lybra/configuration/LybraConfigurator.sol#L78
https://github.com/code-423n4/2023-06-lybra/blob/5d70170f2c68dbd3f7b8c0c8fd6b0b2218784ea6/contracts/lybra/governance/GovernanceTimelock.sol#L10
https://github.com/code-423n4/2023-06-lybra/blob/5d70170f2c68dbd3f7b8c0c8fd6b0b2218784ea6/contracts/lybra/governance/GovernanceTimelock.sol#L11

### 2. Change The Visibility of the Bytes32 constant to private from public
There's no reason to use public on bytes32 constant variable, when you use public for a function solidity creates a getter for that variable similar to

contract test { //Deployment cost: 77126 gas
    bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
        keccak256(bytes("Transfer(address,address,uint256)"));
}

contract test { //Deployment cost: 121071 gas
    bytes32 public constant _TRANSFER_EVENT_SIGNATURE =
        keccak256(bytes("Transfer(address,address,uint256)"));
}

// Code block 1 (unknown):
contract test {//deployment cost 113364 gas,
    uint256 public constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; //
}

contract test {//deployment cost 121071 gas,
    bytes32 public constant _TRANSFER_EVENT_SIGNATURE =
        keccak256(bytes("Transfer(address,address,uint256)"));
}

ERC20.sol#L51, LybraConfigurator.sol#L76, LybraConfigurator.sol#L77, LybraConfigurator.sol#L78, GovernanceTimelock.sol#L10, GovernanceTimelock.sol#L11


Kenshin Q

# Low/QA
## Summary
|   **Risk**    |   **Number of findings**   |
|   :---:   |   :---:   |
|   Low |   2   |
|   Non Critical    |   1   |

## Low Risk Issues
|   **#**   |   **Findings**    |   **Instances**   |
|   :---:   |   :---   |   :---:   |
| [L-01](#l-01-executeextraordinary-could-be-prevented-by-startnewdistributionperiodL-01-executeExtraordinary-could-be-prevented-by-startNewDistributionPeriod) | `executeExtraordinary()` could be prevented by `startNewDistributionPeriod()` | 2 |
| [L-02](#l-02-multiple-functions-can-have-the-same-signature) | Multiple functions can have the same signature | 1 |

---

### L-01 `executeExtraordinary()` could be prevented by `startNewDistributionPeriod()`
#### Permalinks
**Number of instances:** `2`
https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/ExtraordinaryFunding.sol#L226
```solidity
File: ajna-grants/src/grants/base/ExtraordinaryFunding.sol

222:    function _getSliceOfNonTreasury(
223:        uint256 percentage_
224:    ) internal view returns (uint256) {
225:        uint256 totalAjnaSupply = IERC20(ajnaTokenAddress).totalSupply();
            // @audit treasury can be decreased from `startNewDistributionPeriod()`
226:        return Maths.wmul(totalAjnaSupply - treasury, percentage_);
227:    }
```

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/ExtraordinaryFunding.sol#L237
```solidity
File: ajna-grants/src/grants/base/ExtraordinaryFunding.sol

234:    function _getSliceOfTreasury(
235:        uint256 percentage_
236:    ) internal view returns (uint256) {
            // @audit treasury can be decreased from `startNewDistributionPeriod()`
237:        return Maths.wmul(treasury, percentage_);
238:    }
```

#### Description
Upon executing an extraordinary proposal, [2 conditions must be met](https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/

// Code block 1 (solidity):
File: ajna-grants/src/grants/base/ExtraordinaryFunding.sol

222:    function _getSliceOfNonTreasury(
223:        uint256 percentage_
224:    ) internal view returns (uint256) {
225:        uint256 totalAjnaSupply = IERC20(ajnaTokenAddress).totalSupply();
            // @audit treasury can be decreased from `startNewDistributionPeriod()`
226:        return Maths.wmul(totalAjnaSupply - treasury, percentage_);
227:    }

// Code block 2 (solidity):
File: ajna-grants/src/grants/base/ExtraordinaryFunding.sol

234:    function _getSliceOfTreasury(
235:        uint256 percentage_
236:    ) internal view returns (uint256) {
            // @audit treasury can be decreased from `startNewDistributionPeriod()`
237:        return Maths.wmul(treasury, percentage_);
238:    }

File: ajna-grants/src/grants/base/ExtraordinaryFunding.sol

222:    function _getSliceOfNonTreasury(
223:        uint256 percentage_
224:    ) internal view returns (uint256) {
225:        uint256 totalAjnaSupply = IERC20(ajnaTokenAddress).totalSupply();
            // @audit treasury can be decreased from `startNewDistributionPeriod()`
226:        return Maths.wmul(totalAjnaSupply - treasury, percentage_);
227:    }

File: ajna-grants/src/grants/base/ExtraordinaryFunding.sol

234:    function _getSliceOfTreasury(
235:        uint256 percentage_
236:    ) internal view returns (uint256) {
            // @audit treasury can be decreased from `startNewDistributionPeriod()`
237:        return Maths.wmul(treasury, percentage_);
238:    }


Sathish9098 Analysis

# Analysis- Kelp DAO

## Overiew
A collective DAO designed to unlock liquidity, DeFi and higher rewards for restaked assets through liquid restaking.

#### LRTConfig
This contract is used to manage the configuration of the LRT (Lido Rocket Pool) protocol. It stores the addresses of the core contracts, the list of supported assets, and the deposit limits for each asset. It also provides functions for adding new supported assets, updating deposit limits, and updating asset strategies.

#### LRTDepositPool
This contract is used to manage the deposit pool for Lido Rocket Pool (LRT) tokens. It allows users to deposit LST tokens and mint rETH tokens in exchange. It also allows the LRT admin to add new node delegator contracts and transfer assets to them. The contract can be paused or unpaused by the LRT admin.

#### NodeDelegator
The NodeDelegator contract is responsible for depositing assets into strategies. It can also transfer assets back to the LRT deposit pool.

#### LRTOracle
The LRTOracle contract is responsible for calculating the exchange rate of assets. It does this by reading from the priceFetcher interface, which may fetch the price from any supported oracle.

#### RSETH
The rsETH token contract is an ERC20 token contract that is used to represent the rsETH token. The rsETH token is a staked ETH token that is used to earn rewards on staked ETH.

## Architecture Recommentations

### Implementing Supported Asset Removal in the LRT Token Ecosystem

It is currently not possible to remove supported assets once they have been added to the ``supportedAssetList``

Implementing an asset removal mechanism in your smart contract can be a prudent decision, especially if there's a possibility that certain assets might need to be delisted or removed for various reasons.

```solidity

function _addNewSupportedAsset(address asset, uint256 depositLimit) private {
        UtilLib.checkNonZeroAddress(asset);
        if (isSupportedAsset[asset]) {
            revert AssetAlreadyS

function _addNewSupportedAsset(address asset, uint256 depositLimit) private {
        UtilLib.checkNonZeroAddress(asset);
        if (isSupportedAsset[asset]) {
            revert AssetAlreadySupported();
        }
        isSupportedAsset[asset] = true;
        supportedAssetList.push(asset);
        depositLimitByAsset[asset] = depositLimit;
        emit AddedNewSupportedAsset(asset, depositLimit);
    }

/// @dev private function to remove a supported asset
/// @param asset Asset address
function _removeSupportedAsset(address asset) private {
    require(isSupportedAsset[asset], "Asset not supported");

    isSupportedAsset[asset] = false;
    _removeAssetFromList(asset);
    delete depositLimitByAsset[asset];

    emit RemovedSupportedAsset(asset);
}


JCN G

# Summary
All optimizations (*with the exception of issue [G-10](#adding-a-derivative-will-increase-gas-costs-for-users-staking-and-unstaking-even-after-the-derivative-is-removed)*) were benchmarked via the protocol's tests, i.e. using the following config: `solc version 0.8.13`, `optimizer on`, and `100_000 runs`.

Below are the overall average gas savings for the tested functions (with all the optimizations applied):
| Function |    Before   |    After   | Avg Gas Savings |
| ------ | -------- | -------- | ------- |
| stake |  527253  |  511519  |  15734 |
| unstake |  516303  |  513131  |  3172 |
| addDerivative |  102462  |  99120  |  3342 |
| adjustWeight|  46519  |  39195  |  7324 |
| rebalanceToWeights|  727618  |  717607  |  10011 |
| setMaxAmount|  37155  |  37146  | 9 |
| setMaxSlippage|  58574  |  58532  | 42 |
| setMinAmount|  37099  |  37090  |  9 |
| setPauseStaking|  54296  |  54263  | 33 |
| setPauseUnstaking|  37243  |  37193  |  50 |
| deposit|  176462  |  176124  | 338 |
| withdraw|  181057  |  180930  | 127 |
| adminWithdrawDerivative|  195722  |  195594  | 128 |

**Total gas saved across all listed functions: 40319**

*Notes*:

- The [`gasReporter`](#gasreporter-output-with-all-optimizations-applied) output and [diffs](#diff-for-safethsol-with-all-optimizations-applied) with **all the optimizations applied** (*with the exception of issue [G-10](#adding-a-derivative-will-increase-gas-costs-for-users-staking-and-unstaking-even-after-the-derivative-is-removed)*) can be found at the end of the report.
- Some code snippets may be truncated to save space. Code snippets may also be accompanied by `@audit` tags in comments to aid in explaining the issue.

## Gas Optimizations
| Number |Issue|Instances|
|-|:-|:-:|
| [G-01](#state-variables-can-be-cached-instead-of-re-reading-them-from-storage) | State variables can be cached instead of re-reading them from storage | 22 |
| [G-02](#avoid-emitting-storage-values) | Avoid emitting storage valu

File: contracts/SafEth/SafEth.sol
63:    function stake() external payable {
64:        require(pauseStaking == false, "staking is paused");
65:        require(msg.value >= minAmount, "amount too low");
66:        require(msg.value <= maxAmount, "amount too high");
67:
68:        uint256 underlyingValue = 0;
69:
70:        // Getting underlying value in terms of ETH for each derivative
71:        for (uint i = 0; i < derivativeCount; i++) // @audit: sload on every iteration
72:            underlyingValue +=
73:                (derivatives[i].ethPerDerivative(derivatives[i].balance()) * // @audit: 1st and 2nd sload
74:                    derivatives[i].balance()) / // @audit: 3rd sload
75:                10 ** 18;
76:
77:        uint256 totalSupply = totalSupply();
78:        uint256 preDepositPrice; // Price of safETH in regards to ETH
79:        if (totalSupply == 0)
80:            preDepositPrice = 10 ** 18; // initializes with a price of 1
81:        else preDepositPrice = (10 ** 18 * underlyingValue) / totalSupply;
82:
83:        uint256 totalStakeValueEth = 0; // total amount of derivatives worth of ETH in system
84:        for (uint i = 0; i < derivativeCount; i++) { // @audit: sload on every iteration
85:            uint256 weight = weights[i];
86:            IDerivative derivative = derivatives[i]; // @audit: unecessary sload if weight == 0, move below if statement
87:            if (weight == 0) continue;
88:            uint256 ethAmount = (msg.value * weight) / totalWeight; // @audit: sload on every iteration
89:
90:            // This is slightly less than ethAmount because slippage
91:            uint256 depositAmount = derivative.deposit{value: ethAmount}();
92:            uint derivativeReceivedEthValue = (derivative.ethPerDerivative(
93:                depositAmount
94:            ) * depositAmount) / 10 ** 18;
95:            totalStakeValueEth += derivativeReceivedEthValue;
96:        }

https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L108-L119

### Cache `derivativeCount` and `derivatives[i]` to save ~ 3 SLOADs

*More SLOADs would actually be saved since storage slot access is occuring within a loop.*


KeyKiril Q

# Essential Early Checks

Key checks should be placed at the beginning part of a function logic where possible:

```solidity
    function getRSETHPrice() external view returns (uint256 rsETHPrice) {
    +    if (rsEthSupply == 0) {
    +       return 1 ether;
    +   }
        address rsETHTokenAddress = lrtConfig.rsETH();
        uint256 rsEthSupply = IRSETH(rsETHTokenAddress).totalSupply();

    -    if (rsEthSupply == 0) {
    -       return 1 ether;
    -   }

        uint256 totalETHInPool;
        address lrtDepositPoolAddr = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL);

        address[] memory supportedAssets = lrtConfig.getSupportedAssetList();
        uint256 supportedAssetCount = supportedAssets.length;

        for (uint16 asset_idx; asset_idx < supportedAssetCount;) {
            address asset = supportedAssets[asset_idx];
            uint256 assetER = getAssetPrice(asset);

            uint256 totalAssetAmt = ILRTDepositPool(lrtDepositPoolAddr).getTotalAssetDeposits(asset);
            totalETHInPool += totalAssetAmt * assetER;

            unchecked {
                ++asset_idx;
            }
        }

        return totalETHInPool / rsEthSupply;
    }
```

// Code block 1 (solidity):
function getRSETHPrice() external view returns (uint256 rsETHPrice) {
    +    if (rsEthSupply == 0) {
    +       return 1 ether;
    +   }
        address rsETHTokenAddress = lrtConfig.rsETH();
        uint256 rsEthSupply = IRSETH(rsETHTokenAddress).totalSupply();

    -    if (rsEthSupply == 0) {
    -       return 1 ether;
    -   }

        uint256 totalETHInPool;
        address lrtDepositPoolAddr = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL);

        address[] memory supportedAssets = lrtConfig.getSupportedAssetList();
        uint256 supportedAssetCount = supportedAssets.length;

        for (uint16 asset_idx; asset_idx < supportedAssetCount;) {
            address asset = supportedAssets[asset_idx];
            uint256 assetER = getAssetPrice(asset);

            uint256 totalAssetAmt = ILRTDepositPool(lrtDepositPoolAddr).getTotalAssetDeposits(asset);
            totalETHInPool += totalAssetAmt * assetER;

            unchecked {
                ++asset_idx;
            }
        }

        return totalETHInPool / rsEthSupply;
    }


Topmark Q

### Issue 1:
Using same name to represent different variables could cause conflict of interest and misrepresentations when dealing with Threshold and TxnThreshold struct in the DestinationBridge.sol contract. Variable Names should be adjusted accordingly.
https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L369-L377
```solidity
  struct Threshold {
    uint256 amount;
--->    uint256 numberOfApprovalsNeeded;
  }

  struct TxnThreshold {
--->    uint256 numberOfApprovalsNeeded;
    address[] approvers;
  }
```

// Code block 1 (solidity):
struct Threshold {
    uint256 amount;
--->    uint256 numberOfApprovalsNeeded;
  }

  struct TxnThreshold {
--->    uint256 numberOfApprovalsNeeded;
    address[] approvers;
  }


oyc_109 Q

## [L-01] Unspecific Compiler Version Pragma

Avoid floating pragmas for non-library contracts.

While floating pragmas make sense for libraries to allow them to be included with multiple different versions of applications, it may be a security risk for application implementations.

A known vulnerable compiler version may accidentally be selected or security tools might fall-back to an older compiler version ending up checking a different EVM compilation that is ultimately deployed on the blockchain.

It is recommended to pin to a concrete compiler version.

```
2023-01-ondo/contracts/lending/CompoundLens.sol::1 => pragma solidity ^0.5.16;
2023-01-ondo/contracts/lending/JumpRateModelV2.sol::1 => pragma solidity ^0.5.16;
2023-01-ondo/contracts/lending/ondo/ondo-token/IOndo.sol::2 => pragma solidity >=0.8.3;
2023-01-ondo/contracts/lending/ondo/ondo-token/LinearTimelock.sol::2 => pragma solidity >=0.8.3;
2023-01-ondo/contracts/lending/tokens/cCash/CCash.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cCash/CCashDelegate.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cCash/CTokenCash.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cCash/CTokenInterfacesModifiedCash.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/CTokenInterfaces.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/ComptrollerInterface.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/EIP20Interface.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/EIP20NonStandardInterface.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/ErrorReporter.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/ExponentialNoError.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/InterestRateMo

2023-01-ondo/contracts/lending/CompoundLens.sol::1 => pragma solidity ^0.5.16;
2023-01-ondo/contracts/lending/JumpRateModelV2.sol::1 => pragma solidity ^0.5.16;
2023-01-ondo/contracts/lending/ondo/ondo-token/IOndo.sol::2 => pragma solidity >=0.8.3;
2023-01-ondo/contracts/lending/ondo/ondo-token/LinearTimelock.sol::2 => pragma solidity >=0.8.3;
2023-01-ondo/contracts/lending/tokens/cCash/CCash.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cCash/CCashDelegate.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cCash/CTokenCash.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cCash/CTokenInterfacesModifiedCash.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/CTokenInterfaces.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/ComptrollerInterface.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/EIP20Interface.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/EIP20NonStandardInterface.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/ErrorReporter.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/ExponentialNoError.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20Delegate/InterestRateModel.sol::2 => pragma solidity ^0.8.10;
2023-01-ondo/contracts/lending/tokens/cErc20ModifiedDelegator.sol::7 => pragma solidity ^0.5.12;
2023-01-ondo/contracts/lending/tokens/cErc20ModifiedDelegator.sol::138 => pragma solidity ^0.5.12;
2023-01-ondo/contracts/lending/tokens/cErc20ModifiedDelegator.sol::181 => pragma solidity ^0.5.12;
2023-01-ondo/contracts/lending/tokens/cErc20ModifiedDelegator.sol::296 => pragma solidity ^0.5.16;
2023-01-ondo/contracts/lending/tokens/cErc20ModifiedDelegator.sol::302 => pragma solidity ^0.5.16;
2023-01-ondo/contracts/lending/tokens/c

2023-01-ondo/contracts/cash/CashManager.sol::175 => block.timestamp -
2023-01-ondo/contracts/cash/CashManager.sol::176 => (block.timestamp % epochDuration);
2023-01-ondo/contracts/cash/CashManager.sol::577 => uint256 epochDifference = (block.timestamp - currentEpochStartTimestamp) /
2023-01-ondo/contracts/cash/CashManager.sol::584 => block.timestamp -
2023-01-ondo/contracts/cash/CashManager.sol::585 => (block.timestamp % epochDuration);
2023-01-ondo/contracts/cash/kyc/KYCRegistry.sol::92 => require(block.timestamp <= deadline, "KYCRegistry: signature expired");
2023-01-ondo/contracts/lending/OndoPriceOracleV2.sol::294 => (updatedAt >= block.timestamp - maxChainlinkOracleTimeDelay),
2023-01-ondo/contracts/lending/ondo/ondo-token/LinearTimelock.sol::39 => return block.timestamp > cliffTimestamp;
2023-01-ondo/contracts/lending/ondo/ondo-token/LinearTimelock.sol::44 => return block.timestamp > cliffTimestamp + seedVestingPeriod;
2023-01-ondo/contracts/lending/ondo/ondo-token/LinearTimelock.sol::78 => elapsed = block.timestamp - cliffTimestamp;


0xNazgul Q

## [NAZ-L1] `removeTvlCap()` doesn't remove TVL cap
**Severity**: Low
**Context**: [`ReaperVaultV2.sol#L587`](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L587)

**Description**:
`removeTvlCap()` doesn't completely remove TVL cap. Although it does so effectively, it can be reset to lower than `type(uint256).max`.

**Recommendation**:
Consider adding in a check in `updateTvlCap()` like so:
```Solidity
function updateTvlCap(uint256 _newTvlCap) public {
    _atLeastRole(ADMIN);
    if (tvlCap != type(uint256).max) {
        tvlCap = _newTvlCap;
        emit TvlCapUpdated(tvlCap);
    }
}
```

// Code block 1 (Solidity):
function updateTvlCap(uint256 _newTvlCap) public {
    _atLeastRole(ADMIN);
    if (tvlCap != type(uint256).max) {
        tvlCap = _newTvlCap;
        emit TvlCapUpdated(tvlCap);
    }
}


Eeyore Q

## [L-01] Absence of duplicate address validation in `_tokenAddresses` array in `VaultController#_migrateCollateralsFrom` function

### Description

The `VaultController` contract offers the option to migrate token collateral data from an old contract during the `constructor` call.

However, if the `_migrateCollateralsFrom` function receives the same valid token address multiple times in the `_tokenAddresses` array, it can misconfigure the new `VaultController` contract.

This situation could lead to an overlong `enabledTokens` array that contains duplicate token addresses. As this array is utilized for collateral calculations, each entry should be unique to ensure accurate computations.

### Recommendation

An additional check should be added to the `_migrateCollateralsFrom` function to prevent duplicate addresses from entering the `enabledTokens` array.

```diff
    if (_tokenId == 0) revert VaultController_WrongCollateralAddress();
+   if (tokenAddressCollateralInfo[_tokenAddress].tokenId != 0) revert VaultController_TokenAlreadyRegistered();
    _tokensRegistered++;
```

## [L-02] `USDA` contract address should be registered only once in `VaultController` contract

### Description

In the `registerUSDA` function, no check is present that prevents changing an already registered `USDA` address.

There should never be a need to alter a set `USDA` address, as such a change could disrupt the composability of the `Amphora` protocol and potentially lead to user fund losses.

### Recommendation

Add a one-time registration check to the `registerUSDA` function to ensure that the `USDA` address cannot be modified once it has been set.

```diff
    function registerUSDA(address _usdaAddress) external override onlyOwner {
+   if (usda != address(0)) revert VaultController_UsdaAlreadyRegistered();
    usda = IUSDA(_usdaAddress);
```

## [L-03] Incorrect check in `VaultController#changeInitialBorrowingFee` function

### Description

In the `changeInitialBorrowingFee` funct

## [L-03] Incorrect check in `VaultController#changeInitialBorrowingFee` function

### Description

In the `changeInitialBorrowingFee` function, the conditional check used to verify the new borrowing fee against `MAX_INIT_BORROWING_FEE` is flawed. The condition `_newBorrowingFee >= MAX_INIT_BORROWING_FEE` should be `_newBorrowingFee > MAX_INIT_BORROWING_FEE` to allow `MAX_INIT_BORROWING_FEE` as a valid maximum value.

### Recommendation

Correct the conditional check in the `changeInitialBorrowingFee` function to include `MAX_INIT_BORROWING_FEE` as the maximum value for `_newBorrowingFee`.

// Code block 1 (diff):
if (_tokenId == 0) revert VaultController_WrongCollateralAddress();
+   if (tokenAddressCollateralInfo[_tokenAddress].tokenId != 0) revert VaultController_TokenAlreadyRegistered();
    _tokensRegistered++;

// Code block 2 (diff):
function registerUSDA(address _usdaAddress) external override onlyOwner {
+   if (usda != address(0)) revert VaultController_UsdaAlreadyRegistered();
    usda = IUSDA(_usdaAddress);

if (_tokenId == 0) revert VaultController_WrongCollateralAddress();
+   if (tokenAddressCollateralInfo[_tokenAddress].tokenId != 0) revert VaultController_TokenAlreadyRegistered();
    _tokensRegistered++;

function registerUSDA(address _usdaAddress) external override onlyOwner {
+   if (usda != address(0)) revert VaultController_UsdaAlreadyRegistered();
    usda = IUSDA(_usdaAddress);


REACH Q

## [L-01] NFTs may be minted without a liquidity pool position

https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/PositionManager.sol#L227-L241

Within `PositionManager.sol`, the mint function does not check for liquidity pool positions. This could lead to future vulnerabilities if improvements are made without this in mind.

We recommend checking for liquidity prior to minting an NFT.

## [L-02] Empty NFTs may be staked

https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol#L207-L245

Within `RewardsManager.sol`, an empty NFT can be staked. Rewards cannot be distributed, thus we are marking this as a low. However, similar to L-01, care must be taken here with future upgrades.

Mitigation from L-01 will suffice.

## [L-03] Period lengths in block numbers are constant

https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol#L29-L46

The blocks/minute is variable within Ethereum, and may even change drastically with forks.

As it stands, the average block is mined in 12.11 seconds today, down from 13.56 a year ago.

If you want the block count to remain constant, then you should update the documentation to reflect that. If you want the time(days/seconds/etc.) to remain constant, then you should be able to change the block numbers in period lengths. Adding setter functions and removing the `constant` modifier would suffice.

E.g., At 15 seconds per block (4 per minute), within `StandardFunding.sol`, the FUNDING_PERIOD_LENGTH should be 57600 for ~10 days. At 12.11 seconds, it should be 70965 blocks. It is set to 72000.

## [L-04] Global constant `GLOBAL_BUDGET_CONSTRAINT` does not match documentation

https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol#L27

From the docs pertaining to the Primary Funding Mechanism:

"Each quarter (90 days), up to a 2% of the treasury can be distributed to projects that win a competitive bidding p

/**
     * @notice Maximum percentage of tokens that can be distributed by the treasury in a quarter.
     * @dev Stored as a Wad percentage.
     */
    uint256 internal constant GLOBAL_BUDGET_CONSTRAINT = 0.03 * 1e18;

PositionManager.sol#L227-L241, RewardsManager.sol#L207-L245, StandardFunding.sol#L29-L46, StandardFunding.sol#L27


0xSmartContract Q

## Summary
### Low Risk Issues List
| Number |Issues Details|Context|
|:--:|:-------|:--:|
|[L-01]|Use ERC-5143: Slippage Protection for Tokenized Vault| 1 |
|[L-02]|Head Overflow Bug in Calldata Tuple ABI-Reencoding| 1 |
|[L-03]|`uint` type argument was use instead `uint256` for `permit`function , this will cause the function selector to be miscalculated | 1 |
|[L-04]|First ERC4626 deposit exploit can break share calculation |1 |
|[L-05]|initialize() function can be called by anybody| 1 |
|[L-06]|Insufficient coverage|All Contracts  |
|[L-07]|Missing Event for initialize| 1 |
|[L-08]|Project Upgrade and Stop Scenario should be| 1 |
|[L-09]|Loss of precision due to rounding in ` amount / uint256(rewardsPerSecond) `|1 |
|[L-10]|Use Fuzzing Test for complicated code bases | |
|[L-11]|Update codes to avoid Compile Errors|11 |
|[L-12]|Add to Event-Emit for critical functions|3 |
|[L-13]|Use `uint256` instead `uint`|477 |
|[L-14]|Signature Malleability of EVM's ecrecover()|1 |
|[L-15]|`sendCollateral` event is missing parameters|1 |
|[L-16]|Lack of Input Validation|1 |
|[L-17]|Prevent division by `0`|1 |
|[L-18]|Project has NPM Dependency which uses a vulnerable version : `@openzeppelin`|1 |
|[L-19]|Keccak Constant values should used to immutable rather than constant|8 |
|[L-20]|Due to the novelty of the ERC4626 standard, it is safer to use as upgradeable| |
|[L-21]|In the `setAddresses` function, there is no return of incorrect address identification|1 |

Total 21 issues

### Non-Critical Issues List
| Number |Issues Details|Context|
|:--:|:-------|:--:|
| [N-01] |Omissions in Events|2|
| [N-02] |NatSpec comments should be increased in contracts |All Contracts|
| [N-03] |`Function writing` that does not comply with the `Solidity Style Guide`| All Contracts |
| [N-04] |Include return parameters in NatSpec comments| All Constracs |
| [N-05] |Tokens accidentally sent to the contract cannot be recovered|1 |
| [N-06] |Repeated validation logic can be converted into a functi

Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol:
  159       */
  160:     function setHarvestSteps(address[2][] calldata _newSteps) external {
  161:         _atLeastRole(ADMIN);
  162:         delete steps;
  163:
  164:         uint256 numSteps = _newSteps.length;
  165:         for (uint256 i = 0; i < numSteps; i = i.uncheckedInc()) {
  166:             address[2] memory step = _newSteps[i];
  167:             require(step[0] != address(0));
  168:             require(step[1] != address(0));
  169:             steps.push(step);
  170:         }
  171:     }

Ethos-Core/contracts/LUSDToken.sol:
  261
  262:     function permit
  263:     (
  264:         address owner,
  265:         address spender,
  266:         uint amount,
  267:         uint deadline,
  268:         uint8 v,
  269:         bytes32 r,
  270:         bytes32 s
  271:     )
  272:         external
  273:         override
  274:     {


sil3th Q

## DOS due to blacklisted addresses
Tokens such as USDC which is supported by the protocol allow for address blacklisting. Add a check at the withdraw function to check whether the address to withdraw the shares to is blacklisted.
```@solidity
  function withdraw(uint256 assets, address receiver, address owner) external override returns (uint256) {
        (, uint256 shares) = _withdraw(receiver, owner, assets, false);
         return shares;
    }
```
[_withdraw](https://github.com/code-423n4/2024-03-revert-lend/blob/435b054f9ad2404173f36f0f74a5096c894b12b7/src/V3Vault.sol#L920-L952)

## No check whether `SetVault` is active
Autocompound transformer adjusts tokens which are in the vault via transform mode. The vault is set and or changed by the operator and can be in an active or inactive state. There is no check in the [AutoCompound](https://github.com/code-423n4/2024-03-revert-lend/blob/435b054f9ad2404173f36f0f74a5096c894b12b7/src/transformers/AutoCompound.sol#L87-L96) and [AutoRange](https://github.com/code-423n4/2024-03-revert-lend/blob/435b054f9ad2404173f36f0f74a5096c894b12b7/src/transformers/AutoRange.sol#L97-L104) transformers whether the vault is active or not.

## DOS in `_removeTokenFromOwner`
When the length of token Indexes becomes larger iterating through the tokenIndexes may become costly and result in gas cost that is more than block gas limit leaving the removal of tokens from owner in a DOS state since token Ids are not deleted even after removal.
```@solidity
function _removeTokenFromOwner(address from, uint256 tokenId) internal {
        uint256 lastTokenIndex = ownedTokens[from].length - 1;
        uint256 tokenIndex = ownedTokensIndex[tokenId];

        //if array becomes large since its not deleted itll lead to DOS due to oog
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = ownedTokens[from][lastTokenIndex];
            ownedTokens[from][tokenIndex] = lastTokenId;
            ownedTokensIndex[lastTokenId]

// Code block 1 (unknown):
[_withdraw](https://github.com/code-423n4/2024-03-revert-lend/blob/435b054f9ad2404173f36f0f74a5096c894b12b7/src/V3Vault.sol#L920-L952)

## No check whether `SetVault` is active
Autocompound transformer adjusts tokens which are in the vault via transform mode. The vault is set and or changed by the operator and can be in an active or inactive state. There is no check in the [AutoCompound](https://github.com/code-423n4/2024-03-revert-lend/blob/435b054f9ad2404173f36f0f74a5096c894b12b7/src/transformers/AutoCompound.sol#L87-L96) and [AutoRange](https://github.com/code-423n4/2024-03-revert-lend/blob/435b054f9ad2404173f36f0f74a5096c894b12b7/src/transformers/AutoRange.sol#L97-L104) transformers whether the vault is active or not.

## DOS in `_removeTokenFromOwner`
When the length of token Indexes becomes larger iterating through the tokenIndexes may become costly and result in gas cost that is more than block gas limit leaving the removal of tokens from owner in a DOS state since token Ids are not deleted even after removal.


0xAkira Q

## 1. Non-Critical-01. Using dynamic arrays

### Relevant GitHub Links

https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/AiArenaHelper.sol#L17

https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/AiArenaHelper.sol#L20

## Summary

Dynamic arrays are used instead of fixed size arrays

## Vulnerability Details

Use dynamic arrays to store elements, although there are no plans to add new arrays in the future.

## Impact

Using fixed-size arrays can help avoid potential problems associated with unexpected growth of dynamic structures. They are easy to manage in memory because their size remains constant throughout execution. Using fixed-size arrays saves gas

## Tools Used

[Forge](https://book.getfoundry.sh/reference/forge/forge)

## Recommendations

I recommend specifying a fixed size for arrays that will not grow over time.

```diff

- string[] public attributes = [
  "head",
  "eyes",
  "mouth",
  "body",
  "hands",
  "feet"
  ];

+ string[6] public attributes = [
"head",
"eyes",
"mouth",
"body",
"hands",
"feet"
];
```

---

## 2. Non-Critical-02. Two identical actions in the constructor

### Relevant GitHub Links

https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/AiArenaHelper.sol#L41-L52

## Summary

There are two identical actions in the constructor.

## Vulnerability Details

In the constructor there is a function `addAttributeProbabilities(0, probabilities);` which is used to Add attribute probabilities for a given generation. But also in this `constructor` below this function there is a loop that also Add attribute probabilities for generation 0

- loop in the constructor:

```solidity
for (uint8 i = 0; i < attributesLength; i++) {
            attributeProbabilities[0][attributes[i]] = probabilities[i];
            attributeToDnaDivisor[attributes[i]] = defaultAttributeDivisor[i];
        }
```

- function `addAttributeProbabilities`

```solidity
function addAttributeProbabilities(uint256 generation, uint8[][] memory probabilit

// Code block 1 (diff):
- string[] public attributes = [
  "head",
  "eyes",
  "mouth",
  "body",
  "hands",
  "feet"
  ];

+ string[6] public attributes = [
"head",
"eyes",
"mouth",
"body",
"hands",
"feet"
];

// Code block 2 (solidity):
for (uint8 i = 0; i < attributesLength; i++) {
            attributeProbabilities[0][attributes[i]] = probabilities[i];
            attributeToDnaDivisor[attributes[i]] = defaultAttributeDivisor[i];
        }


SleepingBugs G

## Use of `safeMath` in `pragma ^0.8.0`
### Summary
`SafeMath` is used but it's not needed anymore

### Github Permalinks
https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/lending/JumpRateModelV2.sol#L4
`import "./compound/SafeMath.sol";`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/lending/JumpRateModelV2.sol#L12
`using SafeMath for uint;`

### Mitigation
`SafeMath` can be not used as version `pragma ^0.8.0` avoiding a library deployment / calls to it

## Increments can be `unchecked` in loops
### Summary
Unchecked operations as the `++i` on for loops are cheaper than checked one.

### Details
In Solidity 0.8+, there’s a default overflow check on unsigned integers. It’s possible to uncheck this in for-loops and save some gas at each iteration, but at the cost of some code readability, as this uncheck cannot be made inline..

```diff
-    for (uint256 i; i < numIterations; i++) {
+    for (uint256 i; i < numIterations;) {
      // ...
+      unchecked { ++i; }
    // The risk of overflow is inexistent for a uint256 here.
    }
```

### Github Permalinks
https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/factory/CashFactory.sol#L127
`for (uint256 i = 0; i < exCallData.length; ++i) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/factory/CashKYCSenderFactory.sol#L137
`for (uint256 i = 0; i < exCallData.length; ++i) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/factory/CashKYCSenderReceiverFactory.sol#L137
`for (uint256 i = 0; i < exCallData.length; ++i) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/kyc/KYCRegistry.sol#L163
`for (uint256 i = 0; i < length; i++) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e0

### Github Permalinks
https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/factory/CashFactory.sol#L127
`for (uint256 i = 0; i < exCallData.length; ++i) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/factory/CashKYCSenderFactory.sol#L137
`for (uint256 i = 0; i < exCallData.length; ++i) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/factory/CashKYCSenderReceiverFactory.sol#L137
`for (uint256 i = 0; i < exCallData.length; ++i) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/kyc/KYCRegistry.sol#L163
`for (uint256 i = 0; i < length; i++) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/kyc/KYCRegistry.sol#L180
`for (uint256 i = 0; i < length; i++) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/CashManager.sol#L750
`for (uint256 i = 0; i < size; ++i) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/CashManager.sol#L786
`for (uint256 i = 0; i < size; ++i) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/CashManager.sol#L933
`for (uint256 i = 0; i < size; ++i) {`

https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70//contracts/cash/CashManager.sol#L961
`for (uint256 i = 0; i < exCallData.length; ++i) {`

### Mitigation
Add unchecked `++i` at the end of all the for loop where it's not expected to overflow and remove them from the for header

## Store using `Struct` over multiple `mappings`
### Summary
All these variables could be combine in a `Struct` in order to reduce the gas cost.

### Details
As noticed in this [gist](https://gist.github.com/alexon1234/b101e3ac51b

- - -

All indexes are `fToken`
https://github.com/code-423n4/2023-01-ondo/blob/12537cc94f4b0e9b213d53906aa2f95e425dd899/contracts/lending/OndoPriceOracleV2.sol#L54-L62

// Code block 1 (diff):
-    for (uint256 i; i < numIterations; i++) {
+    for (uint256 i; i < numIterations;) {
      // ...
+      unchecked { ++i; }
    // The risk of overflow is inexistent for a uint256 here.
    }

JumpRateModelV2.sol#L4, JumpRateModelV2.sol#L12, CashFactory.sol#L127, CashKYCSenderFactory.sol#L137, CashKYCSenderReceiverFactory.sol#L137, KYCRegistry.sol#L163, KYCRegistry.sol#L180, CashManager.sol#L750, CashManager.sol#L786, CashManager.sol#L933, CashManager.sol#L961, OndoPriceOracleV2.sol#L54-L62

CashManager.sol, CashKYCSenderFactory.sol, CashFactory.sol, JumpRateModelV2.sol, OndoPriceOracleV2.sol, KYCRegistry.sol, CashKYCSenderReceiverFactory.sol


twcctop G

https://github.com/code-423n4/2023-07-amphora/blob/5d1cea9410db5448760c834f001af04a72edf3e0/core/solidity/contracts/core/Vault.sol#L188-L200
```solidity

  for (uint256 _j; _j < _extraRewards;) {
        IVirtualBalanceRewardPool _virtualReward = _rewardsContract.extraRewards(_j);
        IERC20 _rewardToken = _virtualReward.rewardToken();
        uint256 _earnedReward = _virtualReward.earned(address(this));
        if (_earnedReward != 0) {
          _virtualReward.getReward();
          _rewardToken.transfer(_msgSender(), _earnedReward);
          emit ClaimedReward(address(_rewardToken), _earnedReward);
        }
        unchecked {
          ++_j;
        }
      }

```

transfer token in loop, take all amount in one time transfer is better

// Code block 1 (solidity):
for (uint256 _j; _j < _extraRewards;) {
        IVirtualBalanceRewardPool _virtualReward = _rewardsContract.extraRewards(_j);
        IERC20 _rewardToken = _virtualReward.rewardToken();
        uint256 _earnedReward = _virtualReward.earned(address(this));
        if (_earnedReward != 0) {
          _virtualReward.getReward();
          _rewardToken.transfer(_msgSender(), _earnedReward);
          emit ClaimedReward(address(_rewardToken), _earnedReward);
        }
        unchecked {
          ++_j;
        }
      }


0x6980 Q

# 1. for modern and more readable code; update import usages
Context:
```js
//File: Ethos-Core/contracts/CollateralConfig.sol
import "./Dependencies/CheckContract.sol";
import "./Dependencies/Ownable.sol";
import "./Dependencies/SafeERC20.sol";
import "./Interfaces/ICollateralConfig.sol";

//File: Ethos-Core/contracts/BorrowerOperations.sol
import "./Interfaces/IBorrowerOperations.sol";
import "./Interfaces/ICollateralConfig.sol";
import "./Interfaces/ITroveManager.sol";
import "./Interfaces/ILUSDToken.sol";
import "./Interfaces/ICollSurplusPool.sol";
import "./Interfaces/ISortedTroves.sol";
import "./Interfaces/ILQTYStaking.sol";
import "./Dependencies/LiquityBase.sol";
import "./Dependencies/Ownable.sol";
import "./Dependencies/CheckContract.sol";
import "./Dependencies/console.sol";
import "./Dependencies/SafeERC20.sol";

//File: Ethos-Core/contracts/TroveManager.sol
import "./Interfaces/ICollateralConfig.sol";
import "./Interfaces/ITroveManager.sol";
import "./Interfaces/IStabilityPool.sol";
import "./Interfaces/ICollSurplusPool.sol";
import "./Interfaces/ILUSDToken.sol";
import "./Interfaces/ISortedTroves.sol";
import "./Interfaces/ILQTYStaking.sol";
import "./Interfaces/IRedemptionHelper.sol";
import "./Dependencies/LiquityBase.sol";
// import "./Dependencies/Ownable.sol";
import "./Dependencies/CheckContract.sol";
import "./Dependencies/IERC20.sol";

//File: Ethos-Core/contracts/ActivePool.sol
import './Interfaces/IActivePool.sol';
import "./Interfaces/ICollateralConfig.sol";
import './Interfaces/IDefaultPool.sol';
import "./Interfaces/ICollSurplusPool.sol";
import "./Interfaces/ILQTYStaking.sol";
import "./Interfaces/IStabilityPool.sol";
import "./Interfaces/ITroveManager.sol";
import "./Dependencies/SafeMath.sol";
import "./Dependencies/Ownable.sol";
import "./Dependencies/CheckContract.sol";
import "./Dependencies/console.sol";
import "./Dependencies/SafeERC20.sol";
import "./Dependencies/IERC4626.sol";

//File: Ethos-Core/contracts/StabilityPool.sol
impor

//File: Ethos-Core/contracts/CollateralConfig.sol
import "./Dependencies/CheckContract.sol";
import "./Dependencies/Ownable.sol";
import "./Dependencies/SafeERC20.sol";
import "./Interfaces/ICollateralConfig.sol";

//File: Ethos-Core/contracts/BorrowerOperations.sol
import "./Interfaces/IBorrowerOperations.sol";
import "./Interfaces/ICollateralConfig.sol";
import "./Interfaces/ITroveManager.sol";
import "./Interfaces/ILUSDToken.sol";
import "./Interfaces/ICollSurplusPool.sol";
import "./Interfaces/ISortedTroves.sol";
import "./Interfaces/ILQTYStaking.sol";
import "./Dependencies/LiquityBase.sol";
import "./Dependencies/Ownable.sol";
import "./Dependencies/CheckContract.sol";
import "./Dependencies/console.sol";
import "./Dependencies/SafeERC20.sol";

//File: Ethos-Core/contracts/TroveManager.sol
import "./Interfaces/ICollateralConfig.sol";
import "./Interfaces/ITroveManager.sol";
import "./Interfaces/IStabilityPool.sol";
import "./Interfaces/ICollSurplusPool.sol";
import "./Interfaces/ILUSDToken.sol";
import "./Interfaces/ISortedTroves.sol";
import "./Interfaces/ILQTYStaking.sol";
import "./Interfaces/IRedemptionHelper.sol";
import "./Dependencies/LiquityBase.sol";
// import "./Dependencies/Ownable.sol";
import "./Dependencies/CheckContract.sol";
import "./Dependencies/IERC20.sol";

//File: Ethos-Core/contracts/ActivePool.sol
import './Interfaces/IActivePool.sol';
import "./Interfaces/ICollateralConfig.sol";
import './Interfaces/IDefaultPool.sol';
import "./Interfaces/ICollSurplusPool.sol";
import "./Interfaces/ILQTYStaking.sol";
import "./Interfaces/IStabilityPool.sol";
import "./Interfaces/ITroveManager.sol";
import "./Dependencies/SafeMath.sol";
import "./Dependencies/Ownable.sol";
import "./Dependencies/CheckContract.sol";
import "./Dependencies/console.sol";
import "./Dependencies/SafeERC20.sol";
import "./Dependencies/IERC4626.sol";

//File: Ethos-Core/contracts/StabilityPool.sol
import './Interfaces/IBorrowerOperations.sol';
import "./Interfaces/ICollateralCo

# 2. Use underscores for number literals.
- [TroveManager.sol#L54](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/TroveManager.sol#L54)
- [ReaperVaultV2.sol#L41](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L41)
Description:
There are occasions where certain numbers have been hardcoded, either in variable or in the code itself. Large numbers can become hard to read.

Recommendation:
Consider using underscores for number literals to improve its readability.
# 3. Showing the actual values of numbers in natspec comments makes checking and reading code easier.
- [ReaperBaseStrategyv4.sol#L24](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L24)
- [ReaperBaseStrategyv4.sol#L25](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L25)

TroveManager.sol#L54, ReaperVaultV2.sol#L41, ReaperBaseStrategyv4.sol#L24, ReaperBaseStrategyv4.sol#L25


ZanyBonzy G

### 1.  It is cheaper to emit only once after the loop has finished.

   SortedCdps.sol [L451](https://github.com/code-423n4/2023-10-badger/blob/f2f2e2cf9965a1020661d179af46cb49e993cb7e/packages/contracts/contracts/SortedCdps.sol#L451)
   ```
    for (uint i = 0; i < _len; ++i) {
               delete data.nodes[_ids[i]];
               emit NodeRemoved(_ids[i]); //@gas
           }
   ```

### 2. Multiple address/ID mappings can be combined into a single mapping of an address/ID to a struct, where appropriate

EBTCtoken.sol [L50](https://github.com/code-423n4/2023-10-badger/blob/f2f2e2cf9965a1020661d179af46cb49e993cb7e/packages/contracts/contracts/EBTCToken.sol#L50)
```
    // User data for EBTC token
    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;
```

RolesAuthority.sol [L32](https://github.com/code-423n4/2023-10-badger/blob/f2f2e2cf9965a1020661d179af46cb49e993cb7e/packages/contracts/contracts/Dependencies/RolesAuthority.sol#L32)
```
    mapping(address => bytes32) public getUserRoles;

    mapping(address => mapping(bytes4 => CapabilityFlag)) public capabilityFlag;

    mapping(address => mapping(bytes4 => bytes32)) public getRolesWithCapability;
```

### 3. Structs can be packed into fewer storage slots by truncating timestamp bytes for uint32 at the expense of breaking the protocol after the year 2106

IPricFeed.sol [L17](https://github.com/code-423n4/2023-10-badger/blob/f2f2e2cf9965a1020661d179af46cb49e993cb7e/packages/contracts/contracts/Interfaces/IPriceFeed.sol#L17)
```
struct ChainlinkResponse {
        uint80 roundEthBtcId;
        uint80 roundStEthEthId;
        uint256 answer;
        uint256 timestampEthBtc; //@note
        uint256 timestampStEthEth; //@note
        bool success;
    }
```

IPricFeed.sol [L26](https://github.com/code-423n4/2023-10-badger/blob/f2f2e2cf9965a1020661d179af46cb49e993cb7e/packages/contracts/contracts/Interfaces/IPriceFeed.sol#L26)
```
 struct Fallb

// Code block 1 (unknown):
for (uint i = 0; i < _len; ++i) {
               delete data.nodes[_ids[i]];
               emit NodeRemoved(_ids[i]); //@gas
           }

// Code block 2 (unknown):
// User data for EBTC token
    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;

// Code block 3 (unknown):
mapping(address => bytes32) public getUserRoles;

    mapping(address => mapping(bytes4 => CapabilityFlag)) public capabilityFlag;

    mapping(address => mapping(bytes4 => bytes32)) public getRolesWithCapability;

// Code block 4 (unknown):
struct ChainlinkResponse {
        uint80 roundEthBtcId;
        uint80 roundStEthEthId;
        uint256 answer;
        uint256 timestampEthBtc; //@note
        uint256 timestampStEthEth; //@note
        bool success;
    }

SortedCdps.sol#L451, EBTCToken.sol#L50, RolesAuthority.sol#L32, IPriceFeed.sol#L17, IPriceFeed.sol#L26

SortedCdps.sol, RolesAuthority.sol, IPriceFeed.sol, EBTCToken.sol


BenasVol Q

# AI Arena QA Audit Report

Lead Auditors:

-   [Benas Volkovas](https://github.com/BenasVolkovas)

# Table of Contents

-   [AI Arena QA Audit Report](#ai-arena-qa-audit-report)
-   [Table of Contents](#table-of-contents)
-   [Disclaimer](#disclaimer)
-   [Issues found](#issues-found)
-   [Findings](#findings)

# Disclaimer

I make all effort to find as many vulnerabilities in the code in the given time period, but holds no responsibilities for the findings provided in this document. A security audit is not an endorsement of the underlying business or product. The audit was time-boxed and the review of the code was solely on the security aspects of the Solidity implementation of the contracts.

# Issues found

| Severity | Number of issues found |
| -------- | ---------------------- |
| Low      | 3                      |
| Info     | 1                      |
| Total    | 4                      |

# Findings

## Low severity

### [L-01] `MergingPool::getFighterPoints` can only return points for token id 0, which makes the function redundant and misleading

**Description:** The `MergingPool::getFighterPoints` function is expected to return an array of points corresponding to the fighters' token IDs up to the specified maximum token ID. However, the return array `points` is only initialized with length of 1. If the `maxId` is greater than 1, the function will revert making it impossible to retrieve points for multiple fighters.

Also, the natspec documentation for the function is misleading as it states that `maxId` is the maximum token ID up to which the points will be retrieved. However, the loop inside only iterates up to `maxId - 1` and not including `maxId`.

```javascript
    function getFighterPoints(uint256 maxId) public view returns(uint256[] memory) {
@>      uint256[] memory points = new uint256[](1);
@>      for (uint256 i = 0; i < maxId; i++) {
            points[i] = fighterPoints[i];
        }
        return points;
    }
```

Reference: [MergingPool.s

function test_audit_RevertsIfTryingToGet2FighterPoints() public {
    // owner mints a fighter by claiming
    _mintFromMergingPool(_ownerAddress);
    _mintFromMergingPool(_ownerAddress);
    assertEq(_fighterFarmContract.ownerOf(0), _ownerAddress);
    assertEq(_fighterFarmContract.ownerOf(1), _ownerAddress);

    // rankedeBattle contract adds points
    vm.startPrank(address(_rankedBattleContract));
    _mergingPoolContract.addPoints(0, 100);
    _mergingPoolContract.addPoints(1, 200);
    vm.stopPrank();

    assertEq(_mergingPoolContract.totalPoints(), 300);

    // getFighterPoints for owners fighter
    uint256 maxId = 2;
    vm.expectRevert(stdError.indexOOBError);
    _mergingPoolContract.getFighterPoints(maxId);
}

// Code block 1 (javascript):
function getFighterPoints(uint256 maxId) public view returns(uint256[] memory) {
@>      uint256[] memory points = new uint256[](1);
@>      for (uint256 i = 0; i < maxId; i++) {
            points[i] = fighterPoints[i];
        }
        return points;
    }


mariodev G

For all `for` loops, use prefix increment `++i` notation instead of postfix `i++`.

Although minimal difference is observed, it is good practice to reduce as much as possible the amount of gas used if achieving the same functionality.

### POC

```solidity

contract One{
   uint256 public number;
   //Gas used : 43634
   function incrementByOne() public returns (uint256){
       return number++;
   }
}

contract Two{
   uint256 public number;
   //Gas used : 43628
   function incrementByOne() public returns (uint256){
       return ++number;
   }
}
```

Source: [Link](https://dev.to/jamiescript/gas-saving-techniques-in-solidity-324c#incrementing)

// Code block 1 (solidity):
contract One{
   uint256 public number;
   //Gas used : 43634
   function incrementByOne() public returns (uint256){
       return number++;
   }
}

contract Two{
   uint256 public number;
   //Gas used : 43628
   function incrementByOne() public returns (uint256){
       return ++number;
   }
}


Haipls Q

## Haven't require for add duplicate Derivative
The situation is aggravated by the fact that it is not possible to remove the derivative, only to exclude it from the calculations
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L182

## Using the wrong OwnableUpgradeable initialization flow
*Instances:*
```solidity
contracts\SafEth\SafEth.sol

53:        _transferOwnership(msg.sender);
```

Recommendation:
```solidity
    __Ownable_init()
```

## There are no methods to retrieve useful data for the user
The user can only check in manual mode whether it is profitable for him to `unstake` or not and how much he will receive eth in end

Recommendation:
Add various auxiliary methods that will allow the user to calculate his final rewards, etc.

## Owner can set incorrect settings
There is no validation for `setMinAmount` and `setMaxAmount`, `addDerivative` methods on valid input parameters.

The owner can mistakenly set 'minAmount > maxAmount', `maxAmount == 0` or set zero address to derivative, which will implicitly block the `stake` or `unstake` method

*Instances*
```solidity
contracts\SafEth\SafEth.sol

214:     function setMinAmount(uint256 _minAmount) external onlyOwner {
215:         minAmount = _minAmount;
216:         emit ChangeMinAmount(minAmount);
217:     }

223:     function setMaxAmount(uint256 _maxAmount) external onlyOwner {
224:         maxAmount = _maxAmount;
225:         emit ChangeMaxAmount(maxAmount);
226:     }
```
Recommendation:
Add at least that `_minAmount <= _maxAmount`, `_maxAmount > 0` requirement and check on zero address for `addDerivative`

## Remove unused import
*Instances*
```solidity
contracts\SafEth\SafEth.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5: import "../interfaces/IWETH.sol";
6: import "../interfaces/uniswap/ISwapRouter.sol";
7: import "../interfaces/lido/IWStETH.sol";
8: import "../interfaces/lido/IstETH.sol";

contracts\SafEth

// Code block 1 (solidity):
contracts\SafEth\SafEth.sol

53:        _transferOwnership(msg.sender);

// Code block 2 (solidity):
__Ownable_init()

// Code block 3 (solidity):
contracts\SafEth\SafEth.sol

214:     function setMinAmount(uint256 _minAmount) external onlyOwner {
215:         minAmount = _minAmount;
216:         emit ChangeMinAmount(minAmount);
217:     }

223:     function setMaxAmount(uint256 _maxAmount) external onlyOwner {
224:         maxAmount = _maxAmount;
225:         emit ChangeMaxAmount(maxAmount);
226:     }

contracts\SafEth\SafEth.sol

53:        _transferOwnership(msg.sender);

__Ownable_init()

contracts\SafEth\SafEth.sol

214:     function setMinAmount(uint256 _minAmount) external onlyOwner {
215:         minAmount = _minAmount;
216:         emit ChangeMinAmount(minAmount);
217:     }

223:     function setMaxAmount(uint256 _maxAmount) external onlyOwner {
224:         maxAmount = _maxAmount;
225:         emit ChangeMaxAmount(maxAmount);
226:     }


TomJ Q

## Table of Contents
### Low Risk Issues
- Consider adding checks of _sender and _recipient being different address for _transferShares()
- BURNER_ROLE cannot burn when contract paused or cannot burn blocked user's share

## Low Risk Issues
### Consider adding checks of _sender and _recipient being different address for _transferShares()

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

#### Issue
Since there is no input validation of _sender and _recipient being different address,
it is possible to send shares within same addresses for transfer(), transferFrom() and transferShares().
It is ideal to add below check in _transferShares() to avoid user from executing meaningless transaction.
```solidity
require(_sender != _recipient, "SAME_ADDRESS");
```

### BURNER_ROLE cannot burn when contract paused or cannot burn blocked user's share

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

#### Issue
One of the reason that BURNER_ROLE can burn rUSDY tokens from any account is to be able to burn tokens that are compromised or stolen.
If this actually happens, then it is an emergency and protocol has to react to the incident as soon as possible. However executing
burn function is not ideal for this situation since BURNER_ROLE has to specify exact amount of compromised/stolen amount as input parameter
(if the amount is greater the function will revert and if its less then not of all compromised/stolen are burned).
So better approach is to pause a contract or add user account that stole the token to blocklist. However this cause another problem
because BURNER_ROLE cannot burn rUSDY tokens when contract are paused or cannot burn blocked user's share.
Consider changing burn function so that BURNER_ROLE can burn tokens even if contract are paused or burn tokens from blocklist user.

// Code block 1 (solidity):
require(_sender != _recipient, "SAME_ADDRESS");


hunter_w3b Q

### L-1. In the `V3Oracle::getValue()` function, the `priceTokenX96` variable is calculated based on the `token` parameter passed to the function. However, when calculating the `value` and `feeValue` variables, the `priceTokenX96` variable is used regardless of whether the `token` parameter is `token0`, `token1`, or neither of them. This can lead to incorrect calculations of `value` and `feeValue` if the `token` parameter is not one of the tokens in the Uniswap V3 pool.

https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Oracle.sol#L95-L131

```solidity
    function getValue(uint256 tokenId, address token)
        external
        view
        override
        returns (uint256 value, uint256 feeValue, uint256 price0X96, uint256 price1X96)
    {
        (address token0, address token1, uint24 fee,, uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1) =
            getPositionBreakdown(tokenId);

        uint256 cachedChainlinkReferencePriceX96;

        (price0X96, cachedChainlinkReferencePriceX96) =
            _getReferenceTokenPriceX96(token0, cachedChainlinkReferencePriceX96);
        (price1X96, cachedChainlinkReferencePriceX96) =
            _getReferenceTokenPriceX96(token1, cachedChainlinkReferencePriceX96);

        uint256 priceTokenX96;
        if (token0 == token) {
            priceTokenX96 = price0X96;
        } else if (token1 == token) {
            priceTokenX96 = price1X96;
        } else {
            (priceTokenX96,) = _getReferenceTokenPriceX96(token, cachedChainlinkReferencePriceX96);
        }

        value = (price0X96 * (amount0 + fees0) / Q96 + price1X96 * (amount1 + fees1) / Q96) * Q96 / priceTokenX96;
        feeValue = (price0X96 * fees0 / Q96 + price1X96 * fees1 / Q96) * Q96 / priceTokenX96;
        price0X96 = price0X96 * Q96 / priceTokenX96;
        price1X96 = price1X96 * Q96 / priceTokenX96;

        // checks derived pool price for price manipulation attacks
        // this prevents manipulations of pool t

    function getValue(uint256 tokenId, address token)
        external
        view
        override
        returns (uint256 value, uint256 feeValue, uint256 price0X96, uint256 price1X96)
    {
        (address token0, address token1, uint24 fee,, uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1) =
            getPositionBreakdown(tokenId);

        uint256 cachedChainlinkReferencePriceX96;

        (price0X96, cachedChainlinkReferencePriceX96) =
            _getReferenceTokenPriceX96(token0, cachedChainlinkReferencePriceX96);
        (price1X96, cachedChainlinkReferencePriceX96) =
            _getReferenceTokenPriceX96(token1, cachedChainlinkReferencePriceX96);

        uint256 priceTokenX96;
        if (token0 == token) {
            priceTokenX96 = price0X96;
        } else if (token1 == token) {
            priceTokenX96 = price1X96;
        } else {
            (priceTokenX96,) = _getReferenceTokenPriceX96(token, cachedChainlinkReferencePriceX96);
        }

        value = (price0X96 * (amount0 + fees0) / Q96 + price1X96 * (amount1 + fees1) / Q96) * Q96 / priceTokenX96;
        feeValue = (price0X96 * fees0 / Q96 + price1X96 * fees1 / Q96) * Q96 / priceTokenX96;
        price0X96 = price0X96 * Q96 / priceTokenX96;
        price1X96 = price1X96 * Q96 / priceTokenX96;

        // checks derived pool price for price manipulation attacks
        // this prevents manipulations of pool to get distorted proportions of collateral tokens - for borrowing
        // when a pool is in this state, liquidations will be disabled - but arbitrageurs (or liquidator himself)
        // will move price back to reasonable range and enable liquidation
        uint256 derivedPoolPriceX96 = price0X96 * Q96 / price1X96;
        _checkPoolPrice(token0, token1, fee, derivedPoolPriceX96);
    }

    function _checkPoolPrice(address token0, address token1, uint24 fee, uint256 derivedPoolPriceX96) internal view {
        IUniswapV3Pool pool = _getPool(token0, token1, fee);
        uint256 priceX96 = _getReferencePoolPriceX96(pool, 0);
        _requireMaxDifference(priceX96, derivedPoolPriceX96, maxPoolPriceDifference);
    }


MohammedRizwan Q

## Summary

### Low Risk Issues
|Number|Issue|Instances| |
|-|:-|:-:|:-:|
| [L‑01] | should change decimal type to uint8 | 1 |
| [L‑02] | Zero address and Zero msg.value(zero amount) checks are missing | 1 |
| [L‑03] | Internal functions only called once can be inlined, code restructuring.  | 1 |
| [L‑04] | Missing check to ensure distribution period is not set as zero | 1 |
| [L‑05] | Critical Addresses Changes should adopt two-step address change procedure | 3 |
| [L‑06] | Used Hardcoded address causes no future updates and changes | 4 |

### Non-Critical Issues
|Number|Issue|Instances| |
|-|:-|:-:|:-:|
| [N‑01] | checkContract( ) dependencies can be used instead of require( ) | 1 |
| [N‑02] | pauseMinting/unPauseMinting functions should emit event to notify users | 1 |
| [N‑03] | Function writing that does not comply with the Solidity Style Guide | - |
| [N‑04] | Do not use floting solidity compiler version. Lock the solidity compiler version  | 4 |
| [N‑05] | Events for critical change is missing | 1 |
| [N‑06] | Use scientific notation rather than exponentiation | 2 |

### Low Risk Issues
### [L‑01]  should change decimal type to uint8
The decimals of Config struct is uint256 and the function getCollateralDecimals ( ) also returns the uint256. But the decimals are usually type of uint8, referring IERC20 dependency used in contract.

```solidity
File: Ethos-Core/contracts/CollateralConfig.sol

27    struct Config {
28        bool allowed;
29        uint256 decimals;
30        uint256 MCR;
31        uint256 CCR;
32    }

---
110    function getCollateralDecimals(
111        address _collateral
112    ) external override view checkCollateral(_collateral) returns (uint256) {
113        return collateralConfig[_collateral].decimals;
114    }
```
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/CollateralConfig.sol

File: Ethos-Core/contracts/CollateralConfig.sol

63            uint256 decimals = IERC20(collateral).decimals();

// Code block 1 (solidity):
File: Ethos-Core/contracts/CollateralConfig.sol

27    struct Config {
28        bool allowed;
29        uint256 decimals;
30        uint256 MCR;
31        uint256 CCR;
32    }

---
110    function getCollateralDecimals(
111        address _collateral
112    ) external override view checkCollateral(_collateral) returns (uint256) {
113        return collateralConfig[_collateral].decimals;
114    }


parsely Q

# [N-01] Consider in certain instances only importing only what is needed rather than using global imports.
### Context
All contracts
### Description
Importing only what is necessary is preferred above global imports

### Recommendation
```import {contractName} from "theContractFile.sol";```

# [N-02]  NatSpec comments should be added to public contracts
### Context
All public contracts eg. BorrowerOperations
### Description
According to the Solidity documentation it is recommended for all public contracts to have NatSpec comments added.
### Recommendation
Add NatSpec comments to the contracts that may be interacted with.

# [N-03] Remove unused import of Ownable in TroveManager.sol
### Context
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L14
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L18
### Description
The reference and import for Ownable is commented out.
### Recommendation
Remove unused import and reference to Ownable.

# [N-04] Remove unused import of console
### Context
```
LUSDToken.sol:9:import "./Dependencies/console.sol";
StabilityPool.sol:18:import "./Dependencies/console.sol";
LQTY/LQTYStaking.sol:9:import "../Dependencies/console.sol";
BorrowerOperations.sol:15:import "./Dependencies/console.sol";
ActivePool.sol:15:import "./Dependencies/console.sol";
```
### Description
It does not seem that the logging function is used within the code.
### Recommendation
Remove unused imports.

# [N-05] Once the setAddresses function is called there is no way to correct any incorrect addresses
### Context
```
LQTY/LQTYStaking.sol:66:    function setAddresses
LQTY/CommunityIssuance.sol:61:    function setAddresses
TroveManager.sol:232:    function setAddresses(
BorrowerOperations.sol:110:    function setAddresses(
ActivePool.sol:71:    function setAddresses(
```
### Description
Once the setAddresses function has been called the ownership is changed to address(0) and there

// Code block 1 (unknown):
# [N-02]  NatSpec comments should be added to public contracts
### Context
All public contracts eg. BorrowerOperations
### Description
According to the Solidity documentation it is recommended for all public contracts to have NatSpec comments added.
### Recommendation
Add NatSpec comments to the contracts that may be interacted with.

# [N-03] Remove unused import of Ownable in TroveManager.sol
### Context
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L14
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L18
### Description
The reference and import for Ownable is commented out.
### Recommendation
Remove unused import and reference to Ownable.

# [N-04] Remove unused import of console
### Context

// Code block 2 (unknown):
### Description
It does not seem that the logging function is used within the code.
### Recommendation
Remove unused imports.

# [N-05] Once the setAddresses function is called there is no way to correct any incorrect addresses
### Context