0xpanicError Q

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

# Low Issues

| |Issue|Instances|
|-|:-|:-:|
| [L-1](#L-1) | Truncation errors due to division | 2 |
### [L-1] Truncation errors due to division
Variables that represent value of ERC20 tokens should always have 18 decimal places. There is no need to divide
`underlyingValue` and `derivativeReceivedEthValue` by `10**18` as they are remultiplied in later lines anyways. Doing this
causes rounding errors which can lead to unwanted concequences.

*Instances (2)*:
```solidity
File: contracts/SafEth/SafEth.sol

72:   underlyingValue +=

73:      (derivatives[i].ethPerDerivative(derivatives[i].balance()) *

74:          derivatives[i].balance()) /

75       10 ** 18;

81:   else preDepositPrice = (10 ** 18 * underlyingValue) / totalSupply;

```

```solidity
File: contracts/SafEth/SafEth.sol

92:   uint derivativeReceivedEthValue = (derivative.ethPerDerivative(

93:     depositAmount

94:   ) * depositAmount) / 10 ** 18;

95    totalStakeValueEth += derivativeReceivedEthValue;

98:   uint256 mintAmount = (totalStakeValueEth * 10 ** 18) / preDepositPrice;

```

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

72:   underlyingValue +=

73:      (derivatives[i].ethPerDerivative(derivatives[i].balance()) *

74:          derivatives[i].balance()) /

75       10 ** 18;

81:   else preDepositPrice = (10 ** 18 * underlyingValue) / totalSupply;

// Code block 2 (solidity):
File: contracts/SafEth/SafEth.sol

92:   uint derivativeReceivedEthValue = (derivative.ethPerDerivative(

93:     depositAmount

94:   ) * depositAmount) / 10 ** 18;

95    totalStakeValueEth += derivativeReceivedEthValue;

98:   uint256 mintAmount = (totalStakeValueEth * 10 ** 18) / preDepositPrice;

File: contracts/SafEth/SafEth.sol

72:   underlyingValue +=

73:      (derivatives[i].ethPerDerivative(derivatives[i].balance()) *

74:          derivatives[i].balance()) /

75       10 ** 18;

81:   else preDepositPrice = (10 ** 18 * underlyingValue) / totalSupply;

File: contracts/SafEth/SafEth.sol

92:   uint derivativeReceivedEthValue = (derivative.ethPerDerivative(

93:     depositAmount

94:   ) * depositAmount) / 10 ** 18;

95    totalStakeValueEth += derivativeReceivedEthValue;

98:   uint256 mintAmount = (totalStakeValueEth * 10 ** 18) / preDepositPrice;


tsvetanovv G

## [G-01] `x = x - y` costs less gas than `x -= y`, same for addition
`EntryPoint.sol:`
```
81: 	collected += _executeUserOp(i, ops[i], opInfos[i]);
101: 	totalOps += opsPerAggregator[i].userOps.length;
135: 	collected += _executeUserOp(opIndex, ops[i], opInfos[opIndex]);
468: 	actualGas += preGas - gasleft();
```
`VerifyingSingletonPaymaster.sol`:
```
51: 	paymasterIdBalances[paymasterId] += msg.value;
58: 	paymasterIdBalances[msg.sender] -= amount;
128: 	paymasterIdBalances[extractedPaymasterId] -= actualGasCost;
```
You can replace all `-=` and `+=` occurrences to save gas

***

## [G-02] UNCHECKING ARITHMETICS OPERATIONS THAT CAN’T UNDERFLOW/OVERFLOW

Solidity version 0.8+ comes with implicit overflow and underflow checks on unsigned integers. When an overflow or an underflow isn’t possible (as an example, when a comparison is made before the arithmetic operation), some gas can be saved by using an unchecked block.
[Reference](https://docs.soliditylang.org/en/v0.8.10/control-structures.html#checked-or-unchecked-arithmetic)

`EntryPoint.sol:`
```
100: 	for (uint256 i = 0; i < opasLen; i++) {
107: 	for (uint256 a = 0; a < opasLen; a++) {
112: 	for (uint256 i = 0; i < opslen; i++) {
128: 	for (uint256 a = 0; a < opasLen; a++) {
134: 	for (uint256 i = 0; i < opslen; i++) {
```

## [G-03] SPLITTING REQUIRE() STATEMENTS THAT USE `&&` SAVES GAS
`ModuleManager.sol`
```
34: 	require(module != address(0) && module != SENTINEL_MODULES, "BSA101");
49: 	require(module != address(0) && module != SENTINEL_MODULES, "BSA101");
68: 	require(msg.sender != SENTINEL_MODULES && modules[msg.sender] != address(0), "BSA104");
```

// Code block 1 (unknown):
81: 	collected += _executeUserOp(i, ops[i], opInfos[i]);
101: 	totalOps += opsPerAggregator[i].userOps.length;
135: 	collected += _executeUserOp(opIndex, ops[i], opInfos[opIndex]);
468: 	actualGas += preGas - gasleft();

// Code block 2 (unknown):
51: 	paymasterIdBalances[paymasterId] += msg.value;
58: 	paymasterIdBalances[msg.sender] -= amount;
128: 	paymasterIdBalances[extractedPaymasterId] -= actualGasCost;

// Code block 3 (unknown):
100: 	for (uint256 i = 0; i < opasLen; i++) {
107: 	for (uint256 a = 0; a < opasLen; a++) {
112: 	for (uint256 i = 0; i < opslen; i++) {
128: 	for (uint256 a = 0; a < opasLen; a++) {
134: 	for (uint256 i = 0; i < opslen; i++) {

// Code block 4 (unknown):
34: 	require(module != address(0) && module != SENTINEL_MODULES, "BSA101");
49: 	require(module != address(0) && module != SENTINEL_MODULES, "BSA101");
68: 	require(msg.sender != SENTINEL_MODULES && modules[msg.sender] != address(0), "BSA104");


kodyvim G

## Gas Optimization
 Add unchecked block to line 630 on `CashManager.sol` since its value cannot overflow/underflow because of the Mintlimit check.
https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/CashManager.sol#L630
```js
//before
if (collateralAmountIn > mintLimit - currentMintAmount) {
      revert MintExceedsRateLimit();
    }

    currentMintAmount += collateralAmountIn;

//after
if (collateralAmountIn > mintLimit - currentMintAmount) {
      revert MintExceedsRateLimit();
    }

   unchecked { currentMintAmount += collateralAmountIn; }
```
Add unchecked block to line 649 on `CashManager.sol` since its value cannot overflow/underflow because of the redeemLimit check.
https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/CashManager.sol#L649
```js
//before
if (amount > redeemLimit - currentRedeemAmount) {
      revert RedeemExceedsRateLimit();
    }

    currentRedeemAmount += amount;
//after
if (amount > redeemLimit - currentRedeemAmount) {
      revert RedeemExceedsRateLimit();
    }

    unchecked { currentRedeemAmount += amount; }
```

// Code block 1 (js):
//before
if (collateralAmountIn > mintLimit - currentMintAmount) {
      revert MintExceedsRateLimit();
    }

    currentMintAmount += collateralAmountIn;

//after
if (collateralAmountIn > mintLimit - currentMintAmount) {
      revert MintExceedsRateLimit();
    }

   unchecked { currentMintAmount += collateralAmountIn; }

// Code block 2 (js):
//before
if (amount > redeemLimit - currentRedeemAmount) {
      revert RedeemExceedsRateLimit();
    }

    currentRedeemAmount += amount;
//after
if (amount > redeemLimit - currentRedeemAmount) {
      revert RedeemExceedsRateLimit();
    }

    unchecked { currentRedeemAmount += amount; }


ZanyBonzy Q

1. Unnecessary cast in [`getRSETHPrice`](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTOracle.sol#L66) should be avoided
```
    function getRSETHPrice() external view returns (uint256 rsETHPrice) {
       ...

        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;
    }
```
The `asset_idx` counter is a uint16 value and is being compared to the uint256 `supportedAssetCount` variable. In making this comparison, the `asset_idx` is repeatedly casted into uint256, which is unnecessary.
Also, in the rare case that the `supportedAssetCount` is greater than `type(uint16).max`, the constant unchecked increment in the loop might cause the `asset_idx` value to wrap around and start over from 0 when it reaches its max value. This results in an infinite loop which can dos system.
If the uint16 type is desired, then consider implementing a safeCast library to protect against overflows.

2. [`updatePriceOracleFor`](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTOracle.sol#L66) function doesn't check if oracle already exists.
    ```
    function updatePriceOracleFor(
        address asset,
        address priceOracle
    )
        external
        onlyLRTManager
        onlySupportedAsset(asset)
    {
        UtilLib.checkNonZeroAddress(priceOracle);
        assetPriceOracle[asset] = priceOracle;
        emit AssetPriceOracleUpdate(asset, priceOracle);
    }
    ```

3. [`updatePriceFeedFor`](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src

    function updatePriceOracleFor(
        address asset,
        address priceOracle
    )
        external
        onlyLRTManager
        onlySupportedAsset(asset)
    {
        UtilLib.checkNonZeroAddress(priceOracle);
        assetPriceOracle[asset] = priceOracle;
        emit AssetPriceOracleUpdate(asset, priceOracle);
    }
    ```

3. [`updatePriceFeedFor`](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/oracles/ChainlinkPriceOracle.sol#L45) function doesn't check if priceFeed already exists.
    ```
       function updatePriceFeedFor(address asset, address priceFeed) external onlyLRTManager onlySupportedAsset(asset) {
        UtilLib.checkNonZeroAddress(priceFeed);
        assetPriceFeed[asset] = priceFeed;
        emit AssetPriceFeedUpdate(asset, priceFeed);
    }

4. The [`RSETH`](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/RSETH.sol#L54) contract implements a `burnFrom` function.

// Code block 1 (unknown):
function getRSETHPrice() external view returns (uint256 rsETHPrice) {
       ...

        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 2 (unknown):
function updatePriceOracleFor(
        address asset,
        address priceOracle
    )
        external
        onlyLRTManager
        onlySupportedAsset(asset)
    {
        UtilLib.checkNonZeroAddress(priceOracle);
        assetPriceOracle[asset] = priceOracle;
        emit AssetPriceOracleUpdate(asset, priceOracle);
    }


0xGordita G

# [G-01] Cache the balance retrieval to avoid retrieving it twice.
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L73-L74
Before 532939 After 524794
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L141-L142
Before 729728 722422
# [G-02]  Maintain running totals instead of looping for adjustWeights and addDerivative
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L165-L175
Example update
```
function addDerivative(address _contractAddress, uint256 _weight) external onlyOwner {
    derivatives[derivativeCount] = IDerivative(_contractAddress);
    weights[derivativeCount] = _weight;
    derivativeCount++;

    totalWeight += _weight; // Maintain a running total of weights
    emit DerivativeAdded(_contractAddress, _weight, derivativeCount);
}
```
Before 102462 After 99501
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L182-L195
Example update
```
function adjustWeight(uint256 _derivativeIndex, uint256 _newWeight) external onlyOwner {
    require(_derivativeIndex < derivativeCount, "Invalid derivative index");

    uint256 _oldWeight = weights[_derivativeIndex];
    weights[_derivativeIndex] = _newWeight;

    // Update totalWeight using the difference between the new and old weights
    totalWeight = totalWeight - _oldWeight + _newWeight;

    emit WeightChange(_derivativeIndex, _newWeight);
    }
```
Before 46507 after 41294

// Code block 1 (unknown):
function addDerivative(address _contractAddress, uint256 _weight) external onlyOwner {
    derivatives[derivativeCount] = IDerivative(_contractAddress);
    weights[derivativeCount] = _weight;
    derivativeCount++;

    totalWeight += _weight; // Maintain a running total of weights
    emit DerivativeAdded(_contractAddress, _weight, derivativeCount);
}

// Code block 2 (unknown):
function adjustWeight(uint256 _derivativeIndex, uint256 _newWeight) external onlyOwner {
    require(_derivativeIndex < derivativeCount, "Invalid derivative index");

    uint256 _oldWeight = weights[_derivativeIndex];
    weights[_derivativeIndex] = _newWeight;

    // Update totalWeight using the difference between the new and old weights
    totalWeight = totalWeight - _oldWeight + _newWeight;

    emit WeightChange(_derivativeIndex, _newWeight);
    }

SafEth.sol#L73-L74, SafEth.sol#L141-L142, SafEth.sol#L165-L175, SafEth.sol#L182-L195


0xRajkumar Q

# 1.Wrong index passed "DerivativeAdded()"
## In SafEth contract we have "addDerivative()" function which emits event "DerivativeAdded()" and this event expect index of newly derivative.
## In "addDerivative()" function we always add new derivative and increases derivativeCount by one and this same variable is always passed into event "DerivativeAdded()" that's why we always pass wrong index which is index of next derivative.
#### References
https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L194
#### Mitigation step
We should pass derivativeCount-- instead of derivativeCount
````
    function addDerivative(
        address _contractAddress,
        uint256 _weight
    ) external onlyOwner {
        derivatives[derivativeCount] = IDerivative(_contractAddress);
        weights[derivativeCount] = _weight;
        derivativeCount++;

        uint256 localTotalWeight = 0;
        for (uint256 i = 0; i < derivativeCount; i++)
            localTotalWeight += weights[i];
        totalWeight = localTotalWeight;
        emit DerivativeAdded(_contractAddress, _weight, derivativeCount--);
    }

````
# 2.Contract Owner Has Too Many Privileges
## The owner of the contracts has too many privileges relative to standard users. The consequence is disastrous if the contract owner’s private key has been compromised. And, in the event the key was lost or unrecoverable, no implementation upgrades and system parameter updates will ever be possible. For a project this grand, it increases the likelihood that the owner will be targeted by an attacker, especially given the insufficient protection on sensitive owner private keys. The concentration of privileges creates a single point of failure; and, here are some of the incidents that could possibly transpire:
### Transfer ownership and mess up with all the setter functions, hijacking the entire protocol.

#### Consider:

splitting privileges (e.g. via the multisig option) to ensure that no one address h

        for (uint i = 0; i < derivativeCount; i++)
            underlyingValue +=
                (derivatives[i].ethPerDerivative(derivatives[i].balance()) *
                    derivatives[i].balance()) /
                10 ** 18;

        uint256 totalSupply = totalSupply();
        uint256 preDepositPrice; // rice of safETH in regards to ETH
        if (totalSupply == 0)
            preDepositPrice = 10 ** 18; // initializes with a price of 1
        else preDepositPrice = (10 ** 18 * underlyingValue) / totalSupply;

// Code block 1 (unknown):
function addDerivative(
        address _contractAddress,
        uint256 _weight
    ) external onlyOwner {
        derivatives[derivativeCount] = IDerivative(_contractAddress);
        weights[derivativeCount] = _weight;
        derivativeCount++;

        uint256 localTotalWeight = 0;
        for (uint256 i = 0; i < derivativeCount; i++)
            localTotalWeight += weights[i];
        totalWeight = localTotalWeight;
        emit DerivativeAdded(_contractAddress, _weight, derivativeCount--);
    }


hunter_w3b G

# Gas-Optmization for Kelp DAO | rsETH Protocol

## [G-01] Avoid contract existence checks by using low level calls

**Issue Description**\
Prior to Solidity 0.8.10, the compiler would insert extra code to check for contract existence before external function calls, even if the call had a return value. This wasted gas by performing a check that wasn't necessary.

**Proposed Optimization**\
For functions that make external calls with return values in Solidity <0.8.10, optimize the code to use low-level calls instead of regular calls. Low-level calls skip the unnecessary contract existence check.

Example:

```solidity
//Before:

contract C {
  function f() external returns(uint) {
    address(otherContract).call(abi.encodeWithSignature("func()"));
  }
}

//After:

contract C {
  function f() external returns(uint) {
    (bool success,) = address(otherContract).call(abi.encodeWithSignature("func()"));
    require(success);
    return decodeReturnValue();
  }
}
```

**Estimated Gas Savings**\
Each avoided EXTCODESIZE check saves 100 gas. If 10 external calls are made in a common function, this would save 1000 gas total.

**Attachments**

- **Code Snippets**

```solidity
File: src/oracles/ChainlinkPriceOracle.sol

38        return AggregatorInterface(assetPriceFeed[asset]).latestAnswer();
```

https://github.com/code-423n4/2023-11-kelp/blob/main/src/oracles/ChainlinkPriceOracle.sol#L38

```solidity
File:  src/utils/LRTConfigRoleChecker.sol

21        if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.MANAGER, msg.sender)) {

29        if (!IAccessControl(address(lrtConfig)).hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {

36        if (!IAccessControl(address(lrtConfig)).hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {
```

https://github.com/code-423n4/2023-11-kelp/blob/main/src/utils/LRTConfigRoleChecker.sol#L21

```solidity
File: src/LRTDepositPool.sol

79        assetLyingInDepositPool = IERC20(asset).balanceOf(address(this));

83            assetLyingInNDCs += IERC

// Code block 1 (solidity):
//Before:

contract C {
  function f() external returns(uint) {
    address(otherContract).call(abi.encodeWithSignature("func()"));
  }
}

//After:

contract C {
  function f() external returns(uint) {
    (bool success,) = address(otherContract).call(abi.encodeWithSignature("func()"));
    require(success);
    return decodeReturnValue();
  }
}

// Code block 2 (solidity):
File: src/oracles/ChainlinkPriceOracle.sol

38        return AggregatorInterface(assetPriceFeed[asset]).latestAnswer();

// Code block 3 (solidity):
File:  src/utils/LRTConfigRoleChecker.sol

21        if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.MANAGER, msg.sender)) {

29        if (!IAccessControl(address(lrtConfig)).hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {

36        if (!IAccessControl(address(lrtConfig)).hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {

//Before:

contract C {
  function f() external returns(uint) {
    address(otherContract).call(abi.encodeWithSignature("func()"));
  }
}

//After:

contract C {
  function f() external returns(uint) {
    (bool success,) = address(otherContract).call(abi.encodeWithSignature("func()"));
    require(success);
    return decodeReturnValue();
  }
}

File: src/oracles/ChainlinkPriceOracle.sol

38        return AggregatorInterface(assetPriceFeed[asset]).latestAnswer();

File:  src/utils/LRTConfigRoleChecker.sol

21        if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.MANAGER, msg.sender)) {

29        if (!IAccessControl(address(lrtConfig)).hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {

36        if (!IAccessControl(address(lrtConfig)).hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {


0xn006e7 G

# Table of Contents

| S.N. | Issues | Instances | Gas Savings |
|:---- | :----  |   :----:  |   :----:    |
| [G-01](#g-01--varaibles-which-are-assigned-only-onceat-the-compile-time-in-the-contract-and-then-never-changed-thereafter-should-be-declared-constant) | Varaibles which are assigned only once(at the compile time) in the contract and then never changed thereafter should be declared constant | 2 | 4000 |
| [G-02](#g-02--dont-calculate-constants) | Don't calculate constants | 2 | - |
| [G-03](#g-03--use-assembly-to-write-contract-typeaddress-storage-varibales) | Use assembly to write contract type(address) storage varibales | 33 | - |
| [G-04](#g-04--avoid-caching-the-result-of-a-function-call-when-that-result-is-being-used-only-once) | Avoid caching the result of a function call when that result is being used only once | 18 | - |
| [G-05](#g-05--members-of-struct-can-be-packed-into-fewer-storage-slots) | Members of struct can be packed into fewer storage slots | 5 | 10000 |
| [G-06](#g-06--state-variables-can-be-packed-into-fewer-storage-slots) | state variables can be packed into fewer storage slots | 8 | 16000 |
| [G-07](#g-07--cache-calldatamemory-pointers-for-complex-types-to-avoid-complex-offset-calculations) | Cache calldata/memory pointers for complex types to avoid complex offset calculations | 1 | - |

## [G-01] : Varaibles which are assigned only once(at the compile time) in the contract and then never changed thereafter should be declared constant

Constant variables are stored directly in bytecode rather than storage unlike state variables and thus are much cheaper to read from(costing 3 gas via `PUSH32` opcode usage).

Note : These are the instances missed by automated finding(the exact issue found in automated finding is "variables only set in the constructor should be declared immutables" which is a bit different from this one)

2 instances in 2 files

### 1) contracts/lybra/token/esLBR.sol :: Line 20

#### Estimated gas savings : 1 storage s

File: contracts/lybra/token/esLBR.sol
20:     uint256 maxSupply = 100_000_000 * 1e18;

File: contracts/lybra/token/LBR.sol
15:     uint256 maxSupply = 100_000_000 * 1e18;


lukris02 Q

# QA Report for Biconomy - Smart Contract Wallet contest
## Overview
During the audit, 4 low and 14 non-critical issues were found.
№ | Title | Risk Rating  | Instance Count
--- | --- | --- | ---
L-1 | Review is needed | Low | 10
L-2 | The require for not being a smart contract can be passed | Low | 1
L-3 | Use the two-step-transfer of ownership | Low | 1
L-4 | Misleading comment | Low | 1
NC-1 | Order of Functions | Non-Critical | 5
NC-2 | Order of Layout | Non-Critical | 6
NC-3 | Open TODOs | Non-Critical | 1
NC-4 | Typos | Non-Critical | 6
NC-5 | Unused named return variables | Non-Critical | 4
NC-6 | Commented code | Non-Critical | 12
NC-7 | Empty function body | Non-Critical | 1
NC-8 | Duplicate comment | Non-Critical | 1
NC-9 | Variables with similar names | Non-Critical | 4
NC-10 | No space between the control structures | Non-Critical | 2
NC-11 | "nice to have" | Non-Critical | 1
NC-12 | Missing NatSpec | Non-Critical | 6
NC-13 | Missing leading underscores | Non-Critical | 18
NC-14 | Maximum line length exceeded | Non-Critical | 65

## Low Risk Findings(5)
### L-1. Review is needed
##### Description
There are many places in the code that have questions and require further review.
##### Instances
- [```// review virtual```](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/BaseSmartAccount.sol#L59)
- [```// Review if we need to make view function```](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/BaseSmartAccount.sol#L86)
- [```// review? if rename wallet to account is must```](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L44)
- [```// review IEntryPoint private _entryPoint;```](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L58)
- [```//@review getNonce specific to EntryPoint requirements```](https://g

    function setOwner(address _newOwner) external mixedAuth {
        require(_newOwner != address(0), "Smart Account:: new Signatory address cannot be zero");
        address oldOwner = owner;
        owner = _newOwner;
        emit EOAChanged(address(this), oldOwner, _newOwner);
    }

#
## Non-Critical Risk Findings(14)
### NC-1. Order of Functions
##### Description
According to [Style Guide](https://docs.soliditylang.org/en/v0.8.16/style-guide.html#order-of-functions), ordering helps readers identify which functions they can call and to find the constructor and fallback definitions easier.
Functions should be grouped according to their visibility and ordered:
1) constructor
2) receive function (if exists)
3) fallback function (if exists)
4) external
5) public
6) internal
7) private
##### Instances
External functions should be placed before public:
- https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/BaseSmartAccount.sol#L61
- https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L109
- https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/BasePaymaster.sol#L28
- https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/verifying/singleton/VerifyingSingletonPaymaster.sol#L65

receive() function should be placed before fallback():
- https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/Proxy.sol#L36

##### Recommendation
Reorder functions where possible.
#
### NC-2. Order of Layout
##### Description
According to [Order of Layout](https://docs.soliditylang.org/en/v0.8.16/style-guide.html#order-of-layout), inside each contract, library or interface, use the following order:
1) Type declarations
2) State variables
3) Events
4) Modifiers
5) Functions
##### Instances
State variables should be placed before events:
- https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/base/ModuleManager.sol#L16-L18
- https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/base/FallbackManager.

BaseSmartAccount.sol#L59, BaseSmartAccount.sol#L86, SmartAccount.sol#L44, SmartAccount.sol#L58, BaseSmartAccount.sol#L61, SmartAccount.sol#L109, BasePaymaster.sol#L28, VerifyingSingletonPaymaster.sol#L65, Proxy.sol#L36, ModuleManager.sol#L16-L18

VerifyingSingletonPaymaster.sol, BaseSmartAccount.sol, BasePaymaster.sol, Proxy.sol, ModuleManager.sol, SmartAccount.sol


cryptostellar5 Q

### 01  REPLACE INLINE ASSEMBLY WITH ACCOUNT.CODE.LENGTH

*Number of Instances Identified: 1*

`<address>.code.length` can be used in Solidity >= 0.8.0 to access an account’s code size and check if it is a contract without inline assembly.

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/libs/LibAddress.sol

```
14: assembly { csize := extcodesize(account)
```

### 02 AVOID USING TX.ORIGIN

*Number of Instances Identified: 3*

`tx.origin` is a global variable in Solidity that returns the address of the account that sent the transaction.

Using the variable could make a contract vulnerable if an authorized account calls a malicious contract. You can impersonate a user using a third party contract.

This can make it easier to create a vault on behalf of another user with an external administrator (by receiving it as an argument).

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol

```
257: address payable receiver = refundReceiver == address(0) ? payable(tx.origin) : refundReceiver;
281: address payable receiver = refundReceiver == address(0) ? payable(tx.origin) : refundReceiver;
511: require(owner == hash.recover(userOp.signature) || tx.origin == address(0), "account: wrong signature");
```

### 03 REQUIRE() SHOULD BE USED INSTEAD OF ASSERT()

*Number of Instances Identified: 2*

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/Proxy.sol

```
16: assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));
```

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/common/Singleton.sol

```
13: assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));
```

### 04 FOR MODERN AND MORE READABLE CODE; UPDATE IMPORT USAGES

All the contracts in scope should upd

// Code block 1 (unknown):
14: assembly { csize := extcodesize(account)

// Code block 2 (unknown):
257: address payable receiver = refundReceiver == address(0) ? payable(tx.origin) : refundReceiver;
281: address payable receiver = refundReceiver == address(0) ? payable(tx.origin) : refundReceiver;
511: require(owner == hash.recover(userOp.signature) || tx.origin == address(0), "account: wrong signature");

// Code block 3 (unknown):
16: assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));

// Code block 4 (unknown):
13: assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));

LibAddress.sol, SmartAccount.sol, Proxy.sol, Singleton.sol


MiniGlome G

## Gas Optimizations
| |Issue|Instances|
|-|:-|:-:|
| [GAS-01] | Zero address check is done twice on same value | 2 |
| [GAS-02] | Remove unused pause functionality | 1 |

### [GAS-01] Zero address check is done twice on same value
In `LRTConfig.sol`, the zero address checks are performed inside the private functions with `UtilLib.checkNonZeroAddress(val)`. However the initializer already performs these zero address checks on all the parameters, thus, these checks are performed twice.
Consider moving the following checks to their respective external functions so that the checks are not performed twice during the initialization.

*Instances (2)*:
```solidity
File: src/LRTConfig.sol
81:        UtilLib.checkNonZeroAddress(asset);

157:        UtilLib.checkNonZeroAddress(val);

```
https://github.com/code-423n4/2023-11-kelp/blob/c5fdc2e62c5e1d78769f44d6e34a6fb9e40c00f0/src/LRTConfig.sol#L81
https://github.com/code-423n4/2023-11-kelp/blob/c5fdc2e62c5e1d78769f44d6e34a6fb9e40c00f0/src/LRTConfig.sol#L157

### [GAS-02] Remove unused pause functionality
The `LRTOracle` contract inherits from `PausableUpgradeable` and implements a `pause()` and `unpause()` functions. However the "pausing" has no effect because the `whenNotPaused` modifier is never used.
Consider removing the `PausableUpgradeable` inherited contract to save gas.

*Instances (1)*:
```solidity
File: src/LRTOracle.sol
19: contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, PausableUpgradeable {

102:     function pause() external onlyLRTManager { //@audit [GAS] Pause has no effect
        _pause();
    }

107:    function unpause() external onlyLRTAdmin {
        _unpause();
    }

```
https://github.com/code-423n4/2023-11-kelp/blob/c5fdc2e62c5e1d78769f44d6e34a6fb9e40c00f0/src/LRTOracle.sol#L19
https://github.com/code-423n4/2023-11-kelp/blob/c5fdc2e62c5e1d78769f44d6e34a6fb9e40c00f0/src/LRTOracle.sol#L102-L109

// Code block 1 (solidity):
File: src/LRTConfig.sol
81:        UtilLib.checkNonZeroAddress(asset);

157:        UtilLib.checkNonZeroAddress(val);

// Code block 2 (solidity):
File: src/LRTOracle.sol
19: contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, PausableUpgradeable {

102:     function pause() external onlyLRTManager { //@audit [GAS] Pause has no effect
        _pause();
    }

107:    function unpause() external onlyLRTAdmin {
        _unpause();
    }

File: src/LRTConfig.sol
81:        UtilLib.checkNonZeroAddress(asset);

157:        UtilLib.checkNonZeroAddress(val);

File: src/LRTOracle.sol
19: contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, PausableUpgradeable {

102:     function pause() external onlyLRTManager { //@audit [GAS] Pause has no effect
        _pause();
    }

107:    function unpause() external onlyLRTAdmin {
        _unpause();
    }

LRTConfig.sol#L81, LRTConfig.sol#L157, LRTOracle.sol#L19, LRTOracle.sol#L102-L109


alymurtazamemon Q

# Ondo Finance - Quality Assurance Report

# Low Risk Findings

## Table Of Content

| Number                                                                                | Issue                                                                                | Instances |
| :--------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------- | --------: |
| [L-01](#l-01---contracts-should-use-the-latest-version-of-solidity-to-be-safe-from-bug-fixes)                    | Contracts should use the `latest version` of solidity to be safe from `bug fixes`                    |         6 |
| [L-02](#l-02---missing-validation-for-address0-in-the-constructors-or-in-the-functions-changing-state-variables) | Missing validation for `address(0)` in the constructors or in the functions changing state variables |        12 |
| [L-03](#l-03---shadow-variables)                                                                                | Shadow Variables                                                                                |         7 |
| [L-04](#l-04---unsafe-low-level-call)                                                                            | Unsafe `low-level` call                                                                              |         2 |
| [L-05](#l-05---division-by-zero-value-will-revert-the-transaction)                                               | `Division` by zero value will revert the transaction                                                 |         3 |
| [L-06](#l-06---multiplication-with-zero-value-will-make-the-whole-calculation-zero)                              | `Multiplication` with zero value will make the whole calculation zero                                |         6 |
| [L-07](#l-07---emitting-incorrect-event-information)

`Findings Links`

[DestinationBridge.sol - Line 16](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L16)

[SourceBridge.sol - Line 01](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/SourceBridge.sol#L1)

[IRWADynamicOracle.sol - Line 16](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/rwaOracles/IRWADynamicOracle.sol#L16)

[RWADynamicOracle.sol - Line 16](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/rwaOracles/RWADynamicOracle.sol#L16)

[rUSDYFactory.sol - Line 16](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDYFactory.sol#L16)

[rUSDY.sol - Line 16](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L16)

**Recommended Mitigation Steps**

Update the contracts version to be safe from minor bug fixes between the used version and current solidity version.

### [L-02] - Missing validation for `address(0)` in the constructors or in the functions changing state variables.

**Details**

It is recommended to check for `address(0)` when updating state variables through constructor or functions. This can save the protocol from accidental updates.

  Spotted Findings

`Example`

`Findings Links`

[DestinationBridge.sol - Line 56 - 60](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L56-L60)

[DestinationBridge.sol - Line 210](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L210)

[DestinationBridge.sol - Line 220](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L220)

[SourceBridge.sol - Line 41 - 44](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/SourceBridge.sol#L41-L44)

[RWADynamicOracle.sol - Line 31 - 33](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/rwaOracles/RWADynamicOracle.sol#L31-L33)

[rUSDYFactory.sol - Line 52](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDYFactory.sol#L52)

[rUSDYFactory.sol - Line 76 - 80](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDYFactory.sol#L76-L80)

[rUSDY.sol - Line 110 - 115](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L110-L115)

[rUSDY.sol - Line 663](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L663)

[rUSDY.sol - Line 701](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L701)

[rUSDY.sol - Line 712](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L712)

[rUSDY.sol - Line 723](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L723)

### [L-03] - Shadow Variables.

**Details**

Consider the compiler warnings into consideration and avoid the variable shadowing.

  Spotted Findings

`Example`

DestinationBridge.sol#L16, SourceBridge.sol#L1, IRWADynamicOracle.sol#L16, RWADynamicOracle.sol#L16, rUSDYFactory.sol#L16, rUSDY.sol#L16, DestinationBridge.sol#L56-L60, DestinationBridge.sol#L210, DestinationBridge.sol#L220, SourceBridge.sol#L41-L44, RWADynamicOracle.sol#L31-L33, rUSDYFactory.sol#L52, rUSDYFactory.sol#L76-L80, rUSDY.sol#L110-L115, rUSDY.sol#L663, rUSDY.sol#L701, rUSDY.sol#L712, rUSDY.sol#L723

rUSDYFactory.sol, RWADynamicOracle.sol, rUSDY.sol, IRWADynamicOracle.sol, SourceBridge.sol, DestinationBridge.sol


crack the kelp Q

## Impact
Asset price is fetched from `assetPriceOracle[asset]`. If it is not set, `depositAsset` function will not work as following call [will revert](https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTOracle.sol#L46) due to call to `address(0)`.
```
IPriceFetcher(assetPriceOracle[asset]).getAssetPrice(asset);
```

## Proof of Concept

```
contract LRTDepositPoolTest is BaseTest, RSETHTest {
    LRTDepositPool public lrtDepositPool;
    LRTOracle public lrtOracle;
    NodeDelegator public nodeDelegator;
    ILRTConfig public ilrtConfig;
    MockEigenStrategyManager public mockEigenStraregyManager;
    MockStrategy public mockStrategy1;
    MockStrategy public mockStrategy2;

    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));

        //deploy rsETH
        proxyAdmin = new ProxyAdmin();
        RSETH tokenImpl = new RSETH();
        TransparentUpgradeableProxy tokenProxy = new TransparentUpgradeableProxy(
                address(tokenImpl),
                address(proxyAdmin),
                ""
            );
        rseth = RSETH(address(tokenProxy));

        //deploy lrtConfig
        proxyAdmin = new ProxyAdmin();
        LRTConfig lrtConfigImpl = new LRTConfig();
        TransparentUpgradeableProxy lrtConfigProxy = new TransparentUpgradeableProxy(
                address(lrtConfigImpl),
                address(proxyAdmin),
                ""
            );

        lrtConfig = LRTConfig(address(lrtConfigProxy));

        // initialize RSETH. LRTCOnfig is already initialized in RSETHTest
        // rseth.initialize

contract LRTDepositPoolTest is BaseTest, RSETHTest {
    LRTDepositPool public lrtDepositPool;
    LRTOracle public lrtOracle;
    NodeDelegator public nodeDelegator;
    ILRTConfig public ilrtConfig;
    MockEigenStrategyManager public mockEigenStraregyManager;
    MockStrategy public mockStrategy1;
    MockStrategy public mockStrategy2;

    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));

        //deploy rsETH
        proxyAdmin = new ProxyAdmin();
        RSETH tokenImpl = new RSETH();
        TransparentUpgradeableProxy tokenProxy = new TransparentUpgradeableProxy(
                address(tokenImpl),
                address(proxyAdmin),
                ""
            );
        rseth = RSETH(address(tokenProxy));

        //deploy lrtConfig
        proxyAdmin = new ProxyAdmin();
        LRTConfig lrtConfigImpl = new LRTConfig();
        TransparentUpgradeableProxy lrtConfigProxy = new TransparentUpgradeableProxy(
                address(lrtConfigImpl),
                address(proxyAdmin),
                ""
            );

        lrtConfig = LRTConfig(address(lrtConfigProxy));

        // initialize RSETH. LRTCOnfig is already initialized in RSETHTest
        // rseth.initialize(address(admin), address(lrtConfig));
        // add rsETH to LRT config
        // lrtConfig.setRSETH(address(rseth));
        // add oracle to LRT config

        // deploy LRTOracle
        ProxyAdmin proxyAdmin1 = new ProxyAdmin();
        lrtOracle = new LRTOracle();
        TransparentUpgradeableProxy contractProxy1 = new TransparentUpgradeablePr

// Code block 1 (unknown):
IPriceFetcher(assetPriceOracle[asset]).getAssetPrice(asset);


0xackermann G

# Gas Report

[Exclusive findings](#exclusive-findings) is below the [automated findings](#automated-findings).

---

## Automated Findings
Automated findings output for the [Ethos-Core package](https://docs.reaper.farm/ethos-reserve-bounty-hunter-documentation/useful-information/slither-output-ethos-core) and [Ethos-Vault package](https://docs.reaper.farm/ethos-reserve-bounty-hunter-documentation/useful-information/slither-output-ethos-vault).

## Gas Optimizations

| |Issue|Instances|
|-|:-|:-:|
| [GAS-1](#GAS-1) | Use assembly to check for `address(0)` | 8 |
| [GAS-2](#GAS-2) | Using bools for storage incurs overhead | 9 |
| [GAS-3](#GAS-3) | Cache array length outside of loop | 8 |
| [GAS-4](#GAS-4) | State variables should be cached in stack variables rather than re-reading them from storage | 10 |
| [GAS-5](#GAS-5) | Use calldata instead of memory for function arguments that do not get mutated | 1 |
| [GAS-6](#GAS-6) | Use Custom Errors | 73 |
| [GAS-7](#GAS-7) | Don't initialize variables with default value | 23 |
| [GAS-8](#GAS-8) | Long revert strings | 35 |
| [GAS-9](#GAS-9) | Functions guaranteed to revert when called by normal users can be marked `payable` | 7 |
| [GAS-10](#GAS-10) | `++i` costs less gas than `i++`, especially when it's used in `for`-loops (`--i`/`i--` too) | 17 |
| [GAS-11](#GAS-11) | Using `private` rather than `public` for constants, saves gas | 30 |
| [GAS-12](#GAS-12) | Use != 0 instead of > 0 for unsigned integer comparison | 27 |
| [GAS-13](#GAS-13) | `internal` functions not called by the contract should be removed | 1 |
### [GAS-1] Use assembly to check for `address(0)`
*Saves 6 gas per instance*

*Instances (8)*:
```solidity
File: Ethos-Core/contracts/ActivePool.sol

93:         require(_treasuryAddress != address(0), "Treasury cannot be 0 address");

```
[Link to code](https://github.com/code-423n4/2023-02-ethos/tree/main/Ethos-Core/contracts/ActivePool.sol)

```solidity
File: Ethos-Core/contracts/LUSDT

File: Ethos-Core/contracts/LUSDToken.sol

312:         assert(sender != address(0));

313:         assert(recipient != address(0));

321:         assert(account != address(0));

329:         assert(account != address(0));

337:         assert(owner != address(0));

338:         assert(spender != address(0));

348:             _recipient != address(0) &&

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

93:         require(_treasuryAddress != address(0), "Treasury cannot be 0 address");


martin Q

## Introduction

Ethos QA report was done by martin, with a main focus on the low severity and non-critical security aspects of the implementaion and logic of the project.

## Findings Summary

The following issues were found, categorized by their severity:

### L-01 Consider implementing Two-Factor `updateCollateralRatios` with pending and approve functions

Because of admin human error it’s possible to set a new `_MCR` and `_CCR` invalid values. When you want to change these values, it’s better to propose a change, and then approve this changes.

_There are **1** instances of this issue:_

```solidity
85: function updateCollateralRatios(
```

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/CollateralConfig.sol

### L-02 `revert()` should be used instead of `assert()`

The comment above clarifies that it is impossible to open a trove with zero withdrawn LUSD, in such case it's better to add the check and revert providing a description of necessary.

_There are **2** instances of this issue:_

```solidity
128: assert(MIN_NET_DEBT > 0);

197: assert(vars.compositeDebt > 0);
```

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/BorrowerOperations.sol

### L-03 `_safeMint()` should be used rather than `_mint()` wherever possible

When minting NFTs, the code uses `_safeMint` function of the OZ reference implementation. This function is safe because it checks whether the receiver can receive ERC721 tokens. The can prevent the case that a NFT will be minted to a contract that cannot handle ERC721 tokens. However, this external function call creates a security loophole. Specifically, the attacker can perform a reentrant call inside the onERC721Received callback. More detailed information why a reeentrancy can occur - https://blocksecteam.medium.com/when-safemint-becomes-unsafe-lessons-from-the-hypebears-security-incident-2965209bda2a.

_There are **2** instances of this issue:_

```solidity
427: _lusdToken.mint(lqtyStaki

// Code block 1 (solidity):
85: function updateCollateralRatios(

// Code block 2 (solidity):
128: assert(MIN_NET_DEBT > 0);

197: assert(vars.compositeDebt > 0);

85: function updateCollateralRatios(

128: assert(MIN_NET_DEBT > 0);

197: assert(vars.compositeDebt > 0);


chrisdior4 G

# Gas Optimization report

| G-O    |Issue|
|:------:|:----|
| [G‑01] | Using private rather than public for constants, saves gas | 9 |
| [G‑02] | There's no need to set default values for variables | 9 |
| [G‑03] | Consider using custom errors instead of require statements with string error | 9 |
| [G‑04] | ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too) | 9 |
| [G‑05] | Cache array length outside of loop | 9 |
| [G‑06] | Bytes constants are more efficient than string constants | 9 |
| [G‑07] | Use require instead of assert | 9 |
| [G‑08] | Use x != 0 instead of x > 0 for uint types | 9 |
| [G‑09] | Long revert strings | 9 |
| [G‑10] | x = x - y costs less gas than x -= y, same for addition | 9 |
| [G‑11] | Using storage instead of memory for structs/arrays saves gas | 9 |
| [G‑12] | `internal` functions only called once can be inlined to save gas | 9 |
| [G‑13] | Splitting require() statements that use && saves gas | 9 |

Total: 13 issues

## [G-01] Using private rather than public for constants, saves gas

File: `CollateralConfig.sol`

If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table.

```solidity
uint256 constant public MIN_ALLOWED_MCR = 1.1 ether; // 110%
...
uint256 constant public MIN_ALLOWED_CCR = 1.5 ether; // 150%
```

Lines of code:

- https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/CollateralConfig.sol#L21

- https://github.com/code-423n4/2023-02-ethos/blob

Lines of code:

- https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/CollateralConfig.sol#L18

File:  `ActivePool.sol`

If a variable is not set/initialized, the default value is assumed (0, false, 0x0 … depending on the data type). You are simply wasting gas if you directly initialize it with its default value.

// Code block 1 (solidity):
uint256 constant public MIN_ALLOWED_MCR = 1.1 ether; // 110%
...
uint256 constant public MIN_ALLOWED_CCR = 1.5 ether; // 150%


0xhacksmithh Q

### [Low-01]```approve``` could be front-runned
*instances()*
```
File: Ethos-Core/contracts/LUSDToken.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L230
```

### [NC-01] OMISSIONS In Events
*instances(Multiple Instances as shown in folling links)*
```
File: Ethos-Core/contracts/BorrowerOperations.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/BorrowerOperations.sol#L92-L106
```
```
File: Ethos-Core/contracts/TroveManager.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L186-L223
```
```
File: Ethos-Core/contracts/ActivePool.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/ActivePool.sol#L58-L67
```
```
File: Ethos-Core/contracts/StabilityPool.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/StabilityPool.sol#L233-L257
```
```
File: Ethos-Core/contracts/LUSDToken.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L78-L82
```
```
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LQTY/LQTYStaking.sol#L49-L62
```

### [NC-02] No ```Natspec``` for external or public fnctions
*instances(6)*
```
File: Ethos-Core/contracts/TroveManager.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L310
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L513
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L939
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L962
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L982
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L1016
```

### [NC-03] ```constant``` values such as a call to ```keccak

// Code block 1 (unknown):
File: Ethos-Core/contracts/LUSDToken.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L230

// Code block 2 (unknown):
File: Ethos-Core/contracts/BorrowerOperations.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/BorrowerOperations.sol#L92-L106

// Code block 3 (unknown):
File: Ethos-Core/contracts/TroveManager.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L186-L223

// Code block 4 (unknown):
File: Ethos-Core/contracts/ActivePool.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/ActivePool.sol#L58-L67

// Code block 5 (unknown):
File: Ethos-Core/contracts/StabilityPool.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/StabilityPool.sol#L233-L257

// Code block 6 (unknown):
File: Ethos-Core/contracts/LUSDToken.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LUSDToken.sol#L78-L82

// Code block 7 (unknown):
File: Ethos-Core/contracts/LQTY/LQTYStaking.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LQTY/LQTYStaking.sol#L49-L62

// Code block 8 (unknown):
File: Ethos-Core/contracts/TroveManager.sol
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L310
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L513
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L939
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L962
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L982
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L1016

LUSDToken.sol#L230, BorrowerOperations.sol#L92-L106, TroveManager.sol#L186-L223, ActivePool.sol#L58-L67, StabilityPool.sol#L233-L257, LUSDToken.sol#L78-L82, LQTYStaking.sol#L49-L62, TroveManager.sol#L310, TroveManager.sol#L513, TroveManager.sol#L939, TroveManager.sol#L962, TroveManager.sol#L982, TroveManager.sol#L1016

StabilityPool.sol, TroveManager.sol, BorrowerOperations.sol, LQTYStaking.sol, LUSDToken.sol, ActivePool.sol


yjrwkk Q

### [QA-001] Unsafe ERC721 operations

It is recommended to use OpenZeppelin's safeTransferFrom.

[ajna-core/src/RewardsManager.sol#L250](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol#L250)
```
IERC721(address(positionManager)).transferFrom(msg.sender, address(this), tokenId_);
```
[ajna-core/src/RewardsManager.sol#L302](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol#L302)

### [QA-002] Use scientific notation rather than exponentiation

E.g. `1e18` instead of `10 ** 18`. While the compiler knows to optimize away the exponentiation, it is a better coding practice to use idioms that do not require compiler optimization, if they exist.

[ajna-grants/src/grants/libraries/Maths.sol#L6](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/libraries/Maths.sol#L6)
```
uint256 public constant WAD = 10**18;
```
[ajna-grants/src/grants/libraries/Maths.sol#L30](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/libraries/Maths.sol#L30)
[ajna-grants/src/grants/libraries/Maths.sol#L34](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/libraries/Maths.sol#L34)
[ajna-grants/src/grants/libraries/Maths.sol#L38](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/libraries/Maths.sol#L38)
[ajna-grants/src/grants/libraries/Maths.sol#L47](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/libraries/Maths.sol#L47)

### [QA-003] Numeric values having to do with time should use time units for readability

Suffixes like `seconds`, `minutes`, `hours`, `days` and `weeks` after literal numbers can be used to specify units of time.

[ajna-grants/src/grants/base/StandardFunding.sol#L34](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol#L34)
```
uint256 internal constant CHALLENGE_PERIOD_LENGTH = 50400;
```
[ajna-grants/src/gr

// Code block 1 (unknown):
IERC721(address(positionManager)).transferFrom(msg.sender, address(this), tokenId_);

// Code block 2 (unknown):
uint256 public constant WAD = 10**18;

// Code block 3 (unknown):
uint256 internal constant CHALLENGE_PERIOD_LENGTH = 50400;

RewardsManager.sol#L250, RewardsManager.sol#L302, Maths.sol#L6, Maths.sol#L30, Maths.sol#L34, Maths.sol#L38, Maths.sol#L47, StandardFunding.sol#L34


Shogoki G

# GAS Savings Report

## GAS-001 - unfitting data type

In [Positionmanager:62](https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#L62) the internal member `_nextId` is defined as `uint176` as, together with the rest of the variables, this does not make up a full storage slot, it would be more efficient to occupy a full slot by using ?uint256` instead.

## GAS-002 - declare loop var outside of the loop

It is more gas efficient to put the declaration of the counter variable outside of the for loop:

```solidity
uint i;
for( ; i< numProposals;) {
    ...
```

### Occurences

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/Funding.sol#L62

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/Funding.sol#L112

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

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

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

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

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

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

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

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edcea

uint i;
for( ; i< numProposals;) {
    ...

  function _findProposalIndex(
        uint256 proposalId_,
        uint256[] memory array_
    ) internal pure returns (int256 index_) {

        index_ = -1; // default value indicating proposalId not in the array
        uint256 arrayLength = array_.length;
        require(arrayLength <= type(int256).max, "array too long");
        uint256 i;
        for (; i < arrayLength;) {
            //slither-disable-next-line incorrect-equality
            if (array_[i] == proposalId_) {
                index_ = int256(i); // cast only in one case
                break;
            }

            unchecked { ++i; }
        }
    }

uint i;
for( ; i< numProposals;) {
    ...

// Code block 1 (solidity):
uint i;
for( ; i< numProposals;) {
    ...

uint i;
for( ; i< numProposals;) {
    ...

PositionManager.sol#L62, Funding.sol#L62, Funding.sol#L112, StandardFunding.sol#L208, StandardFunding.sol#L324, StandardFunding.sol#L434, StandardFunding.sol#L468, StandardFunding.sol#L469, StandardFunding.sol#L491, StandardFunding.sol#L549

uint i;
for( ; i< numProposals;) {
    ...


0xnev Q

### Issues Template
| Letter | Name | Description |
|:--:|:-------:|:-------:|
| L  | Low risk | Potential risk |
| NC |  Non-critical | Non risky findings |
| R  | Refactor | Code changes |
| O | Ordinary | Commonly found issues |

| Total Found Issues | 5 |
|:--:|:--:|

### Low Risk Template
| Count | Title | Instances |
|:--:|:-------|:--:|
| [L-01] | Remove unecessary `receive() payable` function in EthRouter | 1 |
| [L-02] | Solmate’s `SafeTransferLib `doesn’t check whether the ERC20 contract exists| 21 |
| [L-03] | Confusing deadline comments| 4 |

| Total Low Risk Issues | 3 |
|:--:|:--:|

### Non-Critical Template
| Count | Title | Instances |
|:--:|:-------|:--:|
| [N-01] | Missing event for critical parameters init and change | 3 |
| [N-02] | Add timelock to critical functions | 3 |

| Total Non-Critical Issues | 2 |
|:--:|:--:|

### [L-01] Remove unecessary `receive() payable` function in EthRouter.sol
[EthRouter.sol#L88](https://github.com/code-423n4/2023-04-caviar/blob/main/src/EthRouter.sol#L88)
```solidity
/EthRouter.sol
88:    receive() external payable {}
```
There is no means of withdrawing ether sent to the `EthRouter.sol` contract in the event where ether is accidentally sent to it. This can lead to accidental locking of funds. Suggest removing unecessary `receive() external payable{}` function or implement withdrawal mechanism.

### [L-02] Solmate’s `SafeTransferLib `doesn’t check whether the ERC20 contract exists
[Factory.sol#L120](https://github.com/code-423n4/2023-04-caviar/blob/main/src/Factory.sol#L120)
```solidity
21 results - 3 files

/Factory.sol
120:            ERC721(_nft).safeTransferFrom(msg.sender, address(privatePool), tokenIds[i]);
```
[EthRouter.sol#L136](https://github.com/code-423n4/2023-04-caviar/blob/main/src/EthRouter.sol#L136)
[EthRouter.sol#L162](https://github.com/code-423n4/2023-04-caviar/blob/main/src/EthRouter.sol#L162)
[EthRouter.sol#L266](https://github.com/code-423n4/2023-04-caviar/blob/main/src/EthRouter.sol#L266

// Code block 1 (solidity):
/EthRouter.sol
88:    receive() external payable {}

// Code block 2 (solidity):
21 results - 3 files

/Factory.sol
120:            ERC721(_nft).safeTransferFrom(msg.sender, address(privatePool), tokenIds[i]);

/EthRouter.sol
88:    receive() external payable {}

21 results - 3 files

/Factory.sol
120:            ERC721(_nft).safeTransferFrom(msg.sender, address(privatePool), tokenIds[i]);

EthRouter.sol#L88, Factory.sol#L120, EthRouter.sol#L136, EthRouter.sol#L162, EthRouter.sol#L266


alexzoid Q

## [01] Floating Pragma

The compiler version is not locked, which may lead to deploying contracts with different or bugged versions:

- https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L2
- https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/Reth.sol#L2
- https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/SfrxEth.sol#L2
- https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/WstEth.sol#L2
```solidity
pragma solidity ^0.8.13;
```
To avoid potential issues, lock the pragma version and ensure that the chosen compiler version is free of known bugs:
```solidity
pragma solidity 0.8.19;
```

## [02] Unused Import

An import statement is present in the source file, but the imported file is not used:

- https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L4-L8
```solidity
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IWETH.sol";
import "../interfaces/uniswap/ISwapRouter.sol";
import "../interfaces/lido/IWStETH.sol";
import "../interfaces/lido/IstETH.sol";
```
- https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/Reth.sol#L5-L6
```solidity
import "../../interfaces/frax/IsFrxEth.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
```
- https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/WstEth.sol#L6
```solidity
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
```

To optimize the code and avoid redundancy, remove the unnecessary import.

## [03] Redundant Contract Inheritance

The `Initializable` contract is already inherited through the parent contract `OwnableUpgradeable`:
- https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L16
```solidity
contract SafEth is
    Initializable,
    ERC20Upgradeable,
    OwnableUpgradeable,
    SafEthStorage
```
-

// Code block 1 (solidity):
pragma solidity ^0.8.13;

// Code block 2 (solidity):
pragma solidity 0.8.19;

// Code block 3 (solidity):
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IWETH.sol";
import "../interfaces/uniswap/ISwapRouter.sol";
import "../interfaces/lido/IWStETH.sol";
import "../interfaces/lido/IstETH.sol";

// Code block 4 (solidity):
import "../../interfaces/frax/IsFrxEth.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

// Code block 5 (solidity):
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

// Code block 6 (solidity):
contract SafEth is
    Initializable,
    ERC20Upgradeable,
    OwnableUpgradeable,
    SafEthStorage

pragma solidity ^0.8.13;

pragma solidity 0.8.19;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IWETH.sol";
import "../interfaces/uniswap/ISwapRouter.sol";
import "../interfaces/lido/IWStETH.sol";
import "../interfaces/lido/IstETH.sol";

import "../../interfaces/frax/IsFrxEth.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract SafEth is
    Initializable,
    ERC20Upgradeable,
    OwnableUpgradeable,
    SafEthStorage

SafEth.sol#L2, Reth.sol#L2, SfrxEth.sol#L2, WstEth.sol#L2, SafEth.sol#L4-L8, Reth.sol#L5-L6, WstEth.sol#L6, SafEth.sol#L16

SfrxEth.sol, Reth.sol, WstEth.sol, SafEth.sol


Myd Analysis

## Table of Contents
1. Introduction
2. Approach
3. Architecture Overview
4. Codebase Quality Analysis
   4.1. Code Structure and Readability
   4.2. Use of Libraries and Standards
   4.3. Error Handling and Validation
   4.4. Test Coverage and Documentation
5. Contract Analysis
   5.1. V3Vault
   5.2. InterestRateModel
   5.3. V3Oracle
   5.4. Swapper
   5.5. AutoCompound
   5.6. AutoRange
   5.7. LeverageTransformer
   5.8. V3Utils
6. Centralization Risks
7. Mechanism Review
   7.1. Interest Rate Model
   7.2. Collateralization and Liquidation
   7.3. Oracle System
8. Systemic Risks
9. Recommendations
10. Conclusion

## 1. Introduction
Revert Lend is a decentralized lending protocol designed for Uniswap V3 liquidity providers (LPs). It allows LPs to collateralize their Uniswap V3 positions (NFTs) to borrow assets while retaining control over their LP positions. This report provides an in-depth analysis of the Revert Lend smart contracts, focusing on the architecture, code quality, potential issues, and risks.

## 2. Approach
The analysis of the Revert Lend codebase involved a thorough review of the smart contracts, including:
- Reading the whitepaper and technical documentation to understand the protocol's intended behavior and architecture.
- Reviewing the smart contract code line by line to identify potential vulnerabilities, code quality issues, and adherence to best practices.
- Analyzing the protocol's architecture and design choices to assess their soundness and potential risks.
- Examining the protocol's integration with external systems, such as Chainlink oracles and Uniswap V3 contracts.
- Considering the protocol's resilience to various attack vectors and potential exploits.

## 3. Architecture Overview
The Revert Lend protocol consists of several key components:
- V3Vault: The main contract that manages the lending and borrowing functionality, as well as the collateralization of Uniswap V3 positions.
- InterestRateModel: Responsible for calculating the


0x11singh99 G

# Gas Optimizations

**Note : _G-01_ and _G-12_ contains only those instances which were missed by bot. Since they are major gas savings so I included those missed instances. Gas Mentioned in these findings title is total gas saved by all instances of that finding covered in this report.**

## Table of Contents

- [G-01] [State variables can be packed into fewer storage slot by reducing their size (**Gas Saved: ~8000 Gas**)(Instances missed by bot)](#g-01-state-variables-can-be-packed-into-fewer-storage-slots-by-reducing-their-sizes-gas-saved-8000-gasinstances-missed-by-bot)

- [G-02] [State variable can be packed into fewer storage slots by truncating timestamp(**Gas Saved: ~2000 Gas**)](#g-02-state-variable-can-be-packed-into-fewer-storage-slots-by-truncating-timestampgas-saved-2000-gas)

- [G-03] [Pack the struct variable into fewer storage slots by re-ordering the variables(**Gas Saved: ~2000 Gas**)](#g-03-pack-the-struct-variables-into-fewer-storage-slots-by-re-ordering-the-variablesgas-saved-2000-gas)

- [G-04] [Refactor `borrow` function to avoid 1 sload](#g-04-refactor-borrow-function-to-avoid-1-sload)

- [G-05] [Refactor `configToken` function to fail early and `saves 1 external call` on failing](#g-05-refactor-configtoken-function-to-fail-early-and-saves-1-external-call-on-failing)
- [G-06] [Cache state variable outside of the else block to save 1 sload(**Gas Saved: ~100 Gas**)](#g-06-cache-state-variable-outside-of-the-else-block-to-save-1-sloadgas-saved-100-gas)
- [G-07] [Use direct global msg.sender instead of taking it as function parameter](#g-07-use-direct-global-msgsender-instead-of-taking-it-as-function-parameter)
- [G-08] [Cache calculations instead of re-calculating saves 3 checked subtraction(**Gas Saved: ~540 Gas**)](#g-08-cache-calculations-instead-of-re-calculating-saves-3-checked-subtraction)
- [G-09] [Struct can be packed into fewer storage slot by truncating time(**Gas Saved: ~4000 Gas**)](#g-09-struct-can-be-packed-into-fewer-storage-slot

File : InterestRateModel.sol

23:    uint256 public multiplierPerSecondX96;
24:    uint256 public baseRatePerSecondX96;
25:    uint256 public jumpMultiplierPerSecondX96;

File : InterestRateModel.sol

13:  uint256 public constant YEAR_SECS = 31557600; // taking into account leap years
14:
15:  uint256 public constant MAX_BASE_RATE_X96 = Q96 / 10; // 10%
16:  uint256 public constant MAX_MULTIPLIER_X96 = Q96 * 2; // 200%
...
...

82:  function setValues(
         uint256 baseRatePerYearX96,
         uint256 multiplierPerYearX96,
         uint256 jumpMultiplierPerYearX96,
         uint256 _kinkX96
87:     ) public onlyOwner {
88:    if (
89:        baseRatePerYearX96 > MAX_BASE_RATE_X96 || multiplierPerYearX96 > MAX_MULTIPLIER_X96
90:             || jumpMultiplierPerYearX96 > MAX_MULTIPLIER_X96
91:        ) {
92:            revert InvalidConfig();
93:        }
94:
95:  baseRatePerSecondX96 = baseRatePerYearX96 / YEAR_SECS;
96:  multiplierPerSecondX96 = multiplierPerYearX96 / YEAR_SECS;
97:  jumpMultiplierPerSecondX96 = jumpMultiplierPerYearX96 / YEAR_SECS;


pontifex Q

## Non Critical
### N-1 PositionManager.sol#L54_Incorrect comment about `positions` mapping
It is obviously that the comment in the #L54 is incorrect. It should be replaced with correct information.
```solidity
54:    /// @dev Mapping of `token id => ajna pool address` for which token was minted.
55:    mapping(uint256 => mapping(uint256 => Position)) internal positions;
```
https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#L54

### N-2 PositionManager.sol_Incorrect comments with `LiquidityNotRemoved()` error
Lines [L#166](https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#LL166C1-L166C78) and [L#258](https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#LL258C1-L258C80) contain wrong information about handled errors. The code below the comments doesn't revert with the `LiquidityNotRemoved()` error. These comments should be replaced with correct information.
```solidity
166:     *  @dev    positions token to burn has liquidity `LiquidityNotRemoved()`

258:     *  @dev    - positions token to burn has liquidity `LiquidityNotRemoved()`
```

### N-3 PositionManager.sol_Typo in comments
The line [L#348](https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/PositionManager.sol#L348) contains wrong information about the `RemoveLiquidityFailed()` error. There aren't this type errors in the code. It is possible that it is just a typo.
```solidity
348:     *  @dev    - position not tracked `RemoveLiquidityFailed()`

369:            if (position.depositTime == 0 || position.lps == 0) revert RemovePositionFailed();

375:            if (!positionIndex.remove(index)) revert RemovePositionFailed();
```
### N-4 StandardFunding.sol#L619_Variable `support` need not be initialized to `1`
The `support` variable can be in

// Code block 1 (solidity):
54:    /// @dev Mapping of `token id => ajna pool address` for which token was minted.
55:    mapping(uint256 => mapping(uint256 => Position)) internal positions;

// Code block 2 (solidity):
166:     *  @dev    positions token to burn has liquidity `LiquidityNotRemoved()`

258:     *  @dev    - positions token to burn has liquidity `LiquidityNotRemoved()`

// Code block 3 (solidity):
348:     *  @dev    - position not tracked `RemoveLiquidityFailed()`

369:            if (position.depositTime == 0 || position.lps == 0) revert RemovePositionFailed();

375:            if (!positionIndex.remove(index)) revert RemovePositionFailed();

54:    /// @dev Mapping of `token id => ajna pool address` for which token was minted.
55:    mapping(uint256 => mapping(uint256 => Position)) internal positions;

166:     *  @dev    positions token to burn has liquidity `LiquidityNotRemoved()`

258:     *  @dev    - positions token to burn has liquidity `LiquidityNotRemoved()`

348:     *  @dev    - position not tracked `RemoveLiquidityFailed()`

369:            if (position.depositTime == 0 || position.lps == 0) revert RemovePositionFailed();

375:            if (!positionIndex.remove(index)) revert RemovePositionFailed();


elolpuer G

## contracts\smart-contract-wallet\SmartAccount.sol

[Link to function in github.com](https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L460)

### Description

There is no point in the ```onlyOwner``` modifier, because we check the owner in ```_requireFromEntryPointOrOwner()```.

### Code w/o onlyOwner

```

function execute(address dest, uint value, bytes calldata func) external {
    _requireFromEntryPointOrOwner();
    _call(dest, value, func);
}

function executeBatch(address[] calldata dest, bytes[] calldata func) external {
    _requireFromEntryPointOrOwner();
    require(dest.length == func.length, "wrong array lengths");
    for (uint i = 0; i < dest.length;) {
        _call(dest[i], 0, func[i]);
        unchecked {
            ++i;
        }
    }
}

```

// Code block 1 (unknown):
function execute(address dest, uint value, bytes calldata func) external {
    _requireFromEntryPointOrOwner();
    _call(dest, value, func);
}

function executeBatch(address[] calldata dest, bytes[] calldata func) external {
    _requireFromEntryPointOrOwner();
    require(dest.length == func.length, "wrong array lengths");
    for (uint i = 0; i < dest.length;) {
        _call(dest[i], 0, func[i]);
        unchecked {
            ++i;
        }
    }
}


chaduke G

G1. adjustWeight() can save gas by eliminating the for loop:
```diff
 function adjustWeight(
        uint256 _derivativeIndex,
        uint256 _weight
    ) external onlyOwner {
+       if(_derivativeIndex >= derivativeCount) CannotAdjustWeightForNonExistingDerivative();
+       uint256  localTotalWeight = totalWeight-weights[_derivativeIndex];
        weights[_derivativeIndex] = _weight;
+       uint256  localTotalWeight += _weight;
-        uint256 localTotalWeight = 0;
-        for (uint256 i = 0; i < derivativeCount; i++)
-            localTotalWeight += weights[i];
         totalWeight = localTotalWeight;

        emit WeightChange(_derivativeIndex, _weight);
    }
```

G2. We can save gas for addDerivative() by eliminating the for loop.
```diff
function addDerivative(
        address _contractAddress,
        uint256 _weight
    ) external onlyOwner {
        derivatives[derivativeCount] = IDerivative(_contractAddress);
        weights[derivativeCount] = _weight;
        derivativeCount++;

-        uint256 localTotalWeight = 0;
-        for (uint256 i = 0; i < derivativeCount; i++)
-            localTotalWeight += weights[i];
-        totalWeight = localTotalWeight;
+        totalWeight = totalWeight+_weight;
        emit DerivativeAdded(_contractAddress, _weight, derivativeCount);
    }
```
G3. One can simply return poolPrice() here:
```diff
 function ethPerDerivative(uint256 _amount) public view returns (uint256) {
        if (poolCanDeposit(_amount))
            return
                RocketTokenRETHInterface(rethAddress()).getEthValue(10 ** 18);
-        else return (poolPrice() * 10 ** 18) / (10 ** 18);
+        else return poolPrice();
    }
```

// Code block 1 (diff):
function adjustWeight(
        uint256 _derivativeIndex,
        uint256 _weight
    ) external onlyOwner {
+       if(_derivativeIndex >= derivativeCount) CannotAdjustWeightForNonExistingDerivative();
+       uint256  localTotalWeight = totalWeight-weights[_derivativeIndex];
        weights[_derivativeIndex] = _weight;
+       uint256  localTotalWeight += _weight;
-        uint256 localTotalWeight = 0;
-        for (uint256 i = 0; i < derivativeCount; i++)
-            localTotalWeight += weights[i];
         totalWeight = localTotalWeight;

        emit WeightChange(_derivativeIndex, _weight);
    }

// Code block 2 (diff):
function addDerivative(
        address _contractAddress,
        uint256 _weight
    ) external onlyOwner {
        derivatives[derivativeCount] = IDerivative(_contractAddress);
        weights[derivativeCount] = _weight;
        derivativeCount++;

-        uint256 localTotalWeight = 0;
-        for (uint256 i = 0; i < derivativeCount; i++)
-            localTotalWeight += weights[i];
-        totalWeight = localTotalWeight;
+        totalWeight = totalWeight+_weight;
        emit DerivativeAdded(_contractAddress, _weight, derivativeCount);
    }

// Code block 3 (diff):
function ethPerDerivative(uint256 _amount) public view returns (uint256) {
        if (poolCanDeposit(_amount))
            return
                RocketTokenRETHInterface(rethAddress()).getEthValue(10 ** 18);
-        else return (poolPrice() * 10 ** 18) / (10 ** 18);
+        else return poolPrice();
    }

function adjustWeight(
        uint256 _derivativeIndex,
        uint256 _weight
    ) external onlyOwner {
+       if(_derivativeIndex >= derivativeCount) CannotAdjustWeightForNonExistingDerivative();
+       uint256  localTotalWeight = totalWeight-weights[_derivativeIndex];
        weights[_derivativeIndex] = _weight;
+       uint256  localTotalWeight += _weight;
-        uint256 localTotalWeight = 0;
-        for (uint256 i = 0; i < derivativeCount; i++)
-            localTotalWeight += weights[i];
         totalWeight = localTotalWeight;

        emit WeightChange(_derivativeIndex, _weight);
    }

function addDerivative(
        address _contractAddress,
        uint256 _weight
    ) external onlyOwner {
        derivatives[derivativeCount] = IDerivative(_contractAddress);
        weights[derivativeCount] = _weight;
        derivativeCount++;

-        uint256 localTotalWeight = 0;
-        for (uint256 i = 0; i < derivativeCount; i++)
-            localTotalWeight += weights[i];
-        totalWeight = localTotalWeight;
+        totalWeight = totalWeight+_weight;
        emit DerivativeAdded(_contractAddress, _weight, derivativeCount);
    }

function ethPerDerivative(uint256 _amount) public view returns (uint256) {
        if (poolCanDeposit(_amount))
            return
                RocketTokenRETHInterface(rethAddress()).getEthValue(10 ** 18);
-        else return (poolPrice() * 10 ** 18) / (10 ** 18);
+        else return poolPrice();
    }


sm stack Q

## Low Risk
### [L-1] approve can revert if the current approval is not zero

**Description:**

`Vault::_depositAndStakeOnConvex` must fail if previous allowance exists.

**Proof of Concept:**

Curve LP token is designed to revert if current allowance is not zero. Reference is in [this link](https://github.com/curvefi/curve-contract/blob/b0bbf77f8f93c9c5f4e415bce9cd71f0cdee960e/contracts/tokens/CurveTokenV1.vy#L117C69-L117C69).

**Recommended Mitigation:**

Approve zero amount before the current approval part.

```diff
diff --git a/core/solidity/contracts/core/Vault.sol b/core/solidity/contracts/core/Vault.sol
index 62bc9ad..af75436 100644
--- a/core/solidity/contracts/core/Vault.sol
+++ b/core/solidity/contracts/core/Vault.sol
@@ -318,6 +318,7 @@ contract Vault is IVault, Context {

   /// @dev Internal function for depositing and staking on convex
   function _depositAndStakeOnConvex(address _token, IBooster _booster, uint256 _amount, uint256 _poolId) internal {
+    IERC20(_token).approve(address(_booster), 0);
     IERC20(_token).approve(address(_booster), _amount);
     if (!_booster.deposit(_poolId, _amount, true)) revert Vault_DepositAndStakeOnConvexFailed();
   }
```

## Non-Critical Issue
### [NC-1] No Reason to use `ERC20VotesComp` to `AmphoraProtocolToken`.

**Description:**

`AmphoraProtocolToken.sol` inherits `ERC20VotesComp` from Openzeppelin, which is deprecated and [removed](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md) at the repository now.

**Proof of Concept:**

See the top part of [CHANGELOG.md](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md) at Openzeppelin.

**Recommended Mitigation:**

Change `ERC20VotesComp` to `ERC20Votes` at [`AmphoraProtocolToken.sol`](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/governance/AmphoraProtocolToken.sol#L6), the type of votes from `uint96 ` to `uint256`, and `amph.getP

// Code block 1 (diff):
diff --git a/core/solidity/contracts/core/Vault.sol b/core/solidity/contracts/core/Vault.sol
index 62bc9ad..af75436 100644
--- a/core/solidity/contracts/core/Vault.sol
+++ b/core/solidity/contracts/core/Vault.sol
@@ -318,6 +318,7 @@ contract Vault is IVault, Context {

   /// @dev Internal function for depositing and staking on convex
   function _depositAndStakeOnConvex(address _token, IBooster _booster, uint256 _amount, uint256 _poolId) internal {
+    IERC20(_token).approve(address(_booster), 0);
     IERC20(_token).approve(address(_booster), _amount);
     if (!_booster.deposit(_poolId, _amount, true)) revert Vault_DepositAndStakeOnConvexFailed();
   }


0xAnah G

# DOPEX GAS OPTIMISATIONS

## INTRODUCTION
The majority of optimizations underwent benchmarking using the protocol's tests, specifically employing the following configuration: `solc version 0.8.19`, optimizer enabled, and `200` runs. For optimizations that were not subjected to benchmarking, their rationale is elucidated through EVM gas expenses and opcodes.

Highlighted below are optimizations exclusively targeting state-mutating functions and view/pure functions invoked by state-mutating functions. In the discussion that follows, only runtime gas is emphasized, given its inevitable dominance over deployment gas costs throughout the protocol's lifetime. Additionally, certain code excerpts may be abbreviated for brevity, and comments within the code snippets may include @audit tags to facilitate the explanation of issues.

## TABLE OF FINDINGS
| Number |Issue|Instances|Total Gas Saved|
|-|:-|:-:|:-:|
| G-01| Using calldata instead of memory for read-only arguments in external functions saves gas | 7 | 2797 |
| G-02| Private functions only called once can be inlined to save gas | 1 | 46 |
| G-03| Redundant state variable getters | 1 |   |
| G-04| Use the existing Local variable/global variable when equal to a state variable to avoid reading from state | 4 | 1410 |
| G-05| Avoid using state variable in emit | 4 |  2341 |
| G-06| Structs can be modified to fit in fewer storage slots | 1 | 2000 |
| G-07| Unnecessary require statements | 1 |  317 |
| G-08| Declaring Unnecessary variables | 1 | 3 |
| G-09| Why emitting two events when you can emit one | 1 | 427  |
| G-10| Use constants for state variables whose value is known beforehand and is never changed | 1 | 2194  |
| G-11| State variables only set in the constructor should be declared immutable | 2 | 60964  |
| G-12| Unchecked block for addition that cannot overflow | 6 | 826  |
| G-13| Unbounded Gas Consumption Risk Due to External Call Recipients | 1 |   |
| G-14| Refactor external/internal function to avoid unn

file: contracts/core/RdpxV2Core.sol

240:  function addAssetTotokenReserves(
241:    address _asset,
242:    string memory _assetSymbol @audit change memory to calldata
243:  ) external onlyRole(DEFAULT_ADMIN_ROLE) {
 .
 .
 .
264:  }

#### Gas saving for `addAssetTotokenReserves()` function obtained via protocol test: Avg 318 gas
|  | Min | Max | Avg | # Calls |
|----------|----------|----------|----------|----------|
| Before | 96795 | 118125 | 104095 | 48 |
| After | 96477 | 117807 | 103777 | 48 |

2. #### Make the `_assetSymbol` parameter of `RdpxV2Core.removeAssetFromtokenReserves()` `calldata`
- https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L271


Shubham G

## Gas Optimizations

| |Issue|Instances|
|-|:-|:-:|
| [GAS-01](#GAS-01) | Sort Solidity operations using short-circuit mode | 2 |
| [GAS-02](#GAS-02) | bytes constants are more efficient than string constants| 1 |
| [GAS-03](#GAS-03) | Using bools for storage incurs overhead | 4 |
| [GAS-04](#GAS-04) | Inverting the condition of an if-else-statement saves gas | 2 |
| [GAS-05](#GAS-05) | Use ERC721A instead ERC721 variables | 1 |
| [GAS-06](#GAS-06) | Unused cached variable inside the same function | 2 |

## [GAS-01] Sort Solidity operations using short-circuit mode

Short-circuiting is a solidity contract development model that uses OR/AND logic to sequence different cost operations. It puts low gas cost operations in the front and high gas cost operations in the back, so that if the front is low If the cost operation is feasible, you can skip (short-circuit) the subsequent high-cost Ethereum virtual machine operation.

```solidity
File: main/ajna-grants/src/grants/base/ExtraordinaryFunding.sol

L:139       if (proposal.startBlock > block.number || proposal.endBlock < block.number || proposal.executed) {
```
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/ExtraordinaryFunding.sol#L139

```solidity
File: /main/ajna-grants/src/grants/base/StandardFunding.sol

L:358       if (!_standardFundingVoteSucceeded(proposalId_) || proposal.executed) revert ProposalNotSuccessful();
```
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol#L358

### Recommended

`proposal.executed` should be the 1st parameter inside the `if` condition.

```solidity
L:139       if (proposal.executed || proposal.startBlock > block.number || proposal.endBlock < block.number) {
```

## [GAS-02] bytes constants are more efficient than string constants

If the data can fit in 32 bytes, the bytes32 data type can be used instead of bytes or strings, as it is less robust in terms of robustness.

```solidity
File: main/ajna

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

L:139       if (proposal.startBlock > block.number || proposal.endBlock < block.number || proposal.executed) {

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

L:358       if (!_standardFundingVoteSucceeded(proposalId_) || proposal.executed) revert ProposalNotSuccessful();

// Code block 3 (solidity):
L:139       if (proposal.executed || proposal.startBlock > block.number || proposal.endBlock < block.number) {

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

L:139       if (proposal.startBlock > block.number || proposal.endBlock < block.number || proposal.executed) {

File: /main/ajna-grants/src/grants/base/StandardFunding.sol

L:358       if (!_standardFundingVoteSucceeded(proposalId_) || proposal.executed) revert ProposalNotSuccessful();

L:139       if (proposal.executed || proposal.startBlock > block.number || proposal.endBlock < block.number) {


cheatc0d3 Q

### `addNewSupportedAsset` function can be more optimized

https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTConfig.sol#L80

Add more comprehensive checks for the `asset` address.

```solidity
function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {
    require(asset != address(0), "LRTConfig: Asset is zero address");
    require(asset != address(this), "LRTConfig: Asset cannot be this contract");
    // Additional checks specific to asset properties
    // ...
}
```

### `addNewSupportedAsset` function can be more optimized

https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTConfig.sol#L80

Include validation for `depositLimit` to handle edge cases.

```solidity
function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {
    require(depositLimit > 0, "LRTConfig: Deposit limit must be positive");
    require(depositLimit <= MAX_DEPOSIT_LIMIT, "LRTConfig: Deposit limit exceeds maximum allowed");
    // ...
}
```

### Check Return Values of External Calls

https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTDepositPool.sol#L71

Failure to check the return values of external contract calls could lead to unexpected behavior.

```solidity
function getAssetDistributionData(address asset)
    // ... existing function signature
{
    // ... existing validations
    uint256 ndcsCount = nodeDelegatorQueue.length;
    for (uint256 i = 0; i < ndcsCount; ++i) {
        address ndc = nodeDelegatorQueue[i];
        // ... existing checks

        uint256 ndcBalance = IERC20(asset).balanceOf(ndc);
        require(ndcBalance >= 0, "LRTDepositPool: Balance query failed");

        uint256 stakedBalance = INodeDelegator(ndc).getAssetBalance(asset);
        require(stakedBalance >= 0, "LRTDepositPool: Staked balance query failed");

        assetLyingInNDCs += ndcBalance;
        assetStakedInEigenLayer += stakedBalance;
    }
}

}
```

### `transferAssetToNod

// Code block 1 (solidity):
function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {
    require(asset != address(0), "LRTConfig: Asset is zero address");
    require(asset != address(this), "LRTConfig: Asset cannot be this contract");
    // Additional checks specific to asset properties
    // ...
}

// Code block 2 (solidity):
function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {
    require(depositLimit > 0, "LRTConfig: Deposit limit must be positive");
    require(depositLimit <= MAX_DEPOSIT_LIMIT, "LRTConfig: Deposit limit exceeds maximum allowed");
    // ...
}

// Code block 3 (solidity):
function getAssetDistributionData(address asset)
    // ... existing function signature
{
    // ... existing validations
    uint256 ndcsCount = nodeDelegatorQueue.length;
    for (uint256 i = 0; i < ndcsCount; ++i) {
        address ndc = nodeDelegatorQueue[i];
        // ... existing checks

        uint256 ndcBalance = IERC20(asset).balanceOf(ndc);
        require(ndcBalance >= 0, "LRTDepositPool: Balance query failed");

        uint256 stakedBalance = INodeDelegator(ndc).getAssetBalance(asset);
        require(stakedBalance >= 0, "LRTDepositPool: Staked balance query failed");

        assetLyingInNDCs += ndcBalance;
        assetStakedInEigenLayer += stakedBalance;
    }
}

}

function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {
    require(asset != address(0), "LRTConfig: Asset is zero address");
    require(asset != address(this), "LRTConfig: Asset cannot be this contract");
    // Additional checks specific to asset properties
    // ...
}

function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {
    require(depositLimit > 0, "LRTConfig: Deposit limit must be positive");
    require(depositLimit <= MAX_DEPOSIT_LIMIT, "LRTConfig: Deposit limit exceeds maximum allowed");
    // ...
}

function getAssetDistributionData(address asset)
    // ... existing function signature
{
    // ... existing validations
    uint256 ndcsCount = nodeDelegatorQueue.length;
    for (uint256 i = 0; i < ndcsCount; ++i) {
        address ndc = nodeDelegatorQueue[i];
        // ... existing checks

        uint256 ndcBalance = IERC20(asset).balanceOf(ndc);
        require(ndcBalance >= 0, "LRTDepositPool: Balance query failed");

        uint256 stakedBalance = INodeDelegator(ndc).getAssetBalance(asset);
        require(stakedBalance >= 0, "LRTDepositPool: Staked balance query failed");

        assetLyingInNDCs += ndcBalance;
        assetStakedInEigenLayer += stakedBalance;
    }
}

}


Aymen0909 Q

# QA Report

## Summary

|               | Issue         | Risk     | Instances     |
| :-------------: |:-------------|:-------------:|:-------------:|
| 1 | Many functions not reverting when they are supposed to in `PositionManager` | Low | 2 |
| 2 | arrays length not checked in the `_execute` function | Low | 1 |
| 3 | Immutable state variables lack zero address checks | Low | 3 |
| 4 | `constant` should be used instead of `immutable` | NC |  1 |

## Findings

### 1- Many functions not reverting when they are supposed to in `PositionManager` :

#### Risk : Low

The comments of each function indicates the conditions for which the function should revert but there are many functions in the `PositionManager` contract that do not revert when they are supposed to, If this is an error in the comments then they should be rewitten to correspand to the code but if the functions are really supposed to revert as specified in the comments then the functions code should be reviewed and required checks must be added.

#### Proof of Concept
Instances include :

File: PositionManager.sol [Line 157-216](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/PositionManager.sol#L157-L216)

In the code linked above the function `memorializePositions` is supposed to revert when the positions token to burn has liquidity but it does not.

File: PositionManager.sol [Line 243-333](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/PositionManager.sol#L243-L333)

In the code linked above the function `moveLiquidity` is supposed to revert when the positions token to burn has liquidity but it does not.

#### Mitigation
Review the code of the aferomentioned functions and add the required checks if necessary

### 2- arrays length not checked in the `_execute` function :

#### Risk : Low

The `_execute` function is used to excute the calldata of the passed proposals, for the function to work correctely all the array passed as arguments must have the same length and

function _execute(
    uint256 proposalId_,
    address[] memory targets_,
    uint256[] memory values_,
    bytes[] memory calldatas_
) internal {
    // use common event name to maintain consistency with tally
    emit ProposalExecuted(proposalId_);

    string memory errorMessage = "Governor: call reverted without message";
    for (uint256 i = 0; i < targets_.length; ++i) {
        (bool success, bytes memory returndata) = targets_[i].call{value: values_[i]}(calldatas_[i]);
        Address.verifyCallResult(success, returndata, errorMessage);
    }
}

erc20PoolFactory  = erc20Factory_;
erc721PoolFactory = erc721Factory_;


fs0c Q

| Letter | Name | Description |
| --- | --- | --- |
| L | Low | Low severity/Potentially risky |
| N | Non-critical | Non-risky findings |

## [L-01] No restrictions on minting to invalid recipients.

### Impact and POC

Certain transfer restrictions imposed in the LUSDToken are not properly handled during the minting.
The LUSDToken forbids any transfer to a special set of addresses specified in the `_requireValidRecipient` function:

```solidity
function _requireValidRecipient(address _recipient) internal view {
        require(
            _recipient != address(0) &&
            _recipient != address(this),
            "LUSD: Cannot transfer tokens directly to the LUSD token contract or the zero address"
        );
        require(
            !stabilityPools[_recipient] &&
            !troveManagers[_recipient] &&
            !borrowerOperations[_recipient],
            "LUSD: Cannot transfer tokens directly to the StabilityPool, TroveManager or BorrowerOps"
        );
    }
```

But these restrictions are not followed in minting. This could lead to the minting of tokens to invalid recipient addresses.

### Recommendation

Add _requireValidRecipient(account) before any state changing operations in `_mint`

## [L-02] **Incorrect TCR calculation in batchLiquidateTroves() during Recovery Mode.**

### Impact and POC

TCR is temporarily miscalculated in **batchLiquidateTroves.**

When calculating system's entire collateral, we should also exclude the liquidated trove's surplus collateral, since liquidation closes the trove and makes the surplus collateral claimable by the trove owner. This means, this line of code should look like this:

```solidity
vars.entireSystemColl = vars.entireSystemColl.
                    sub(singleLiquidation.collToSendToSP).
                    sub(singleLiquidation.collSurplus);
```

The miscalculated entire collateral is used only to calculate the TCR and check if the system has been able to exit Recovery Mode. The miscalculation only

// Code block 1 (solidity):
function _requireValidRecipient(address _recipient) internal view {
        require(
            _recipient != address(0) &&
            _recipient != address(this),
            "LUSD: Cannot transfer tokens directly to the LUSD token contract or the zero address"
        );
        require(
            !stabilityPools[_recipient] &&
            !troveManagers[_recipient] &&
            !borrowerOperations[_recipient],
            "LUSD: Cannot transfer tokens directly to the StabilityPool, TroveManager or BorrowerOps"
        );
    }

// Code block 2 (solidity):
vars.entireSystemColl = vars.entireSystemColl.
                    sub(singleLiquidation.collToSendToSP).
                    sub(singleLiquidation.collSurplus);

function _requireValidRecipient(address _recipient) internal view {
        require(
            _recipient != address(0) &&
            _recipient != address(this),
            "LUSD: Cannot transfer tokens directly to the LUSD token contract or the zero address"
        );
        require(
            !stabilityPools[_recipient] &&
            !troveManagers[_recipient] &&
            !borrowerOperations[_recipient],
            "LUSD: Cannot transfer tokens directly to the StabilityPool, TroveManager or BorrowerOps"
        );
    }

vars.entireSystemColl = vars.entireSystemColl.
                    sub(singleLiquidation.collToSendToSP).
                    sub(singleLiquidation.collSurplus);