Jorgect Q

#LOW ISSUES REPORT

## [L-01] Require xsalt for proposal can be so low

To submit a proposal in the Salty protocol, users must have staked a specific quantity of salt. The exact amount is determined by a percentage set by the DAO, multiplied by the total number of salt tokens staked in the protocol.

The issue arises when the total staked amount is very low, as it results in a low requirement of XSALT needed to make a proposal.

```
function _possiblyCreateProposal( string memory ballotName, BallotType ballotType, address address1, uint256 number1, string memory string1, string memory string2 ) internal returns (uint256 ballotID)
		{
		require( block.timestamp >= firstPossibleProposalTimestamp, "Cannot propose ballots within the first 45 days of deployment" );

		// The DAO can create confirmation proposals which won't have the below requirements
		if ( msg.sender != address(exchangeConfig.dao() ) )
			{
			// Make sure that the sender has the minimum amount of xSALT required to make the proposal
			uint256 totalStaked = staking.totalShares(PoolUtils.STAKED_SALT);
			uint256 requiredXSalt = ( totalStaked * daoConfig.requiredProposalPercentStakeTimes1000() ) / ( 100 * 1000 );

			require( requiredXSalt > 0, "requiredXSalt cannot be zero" );

			uint256 userXSalt = staking.userShareForPool( msg.sender, PoolUtils.STAKED_SALT );
			require( userXSalt >= requiredXSalt, "Sender does not
 have enough xSALT to make the proposal" );  <--------

			// Make sure that the user doesn't already have an active proposal
			require( ! _userHasActiveProposal[msg.sender], "Users can only have one active proposal at a time" );
			}
...
}
```
[[Link]](https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/dao/Proposals.sol#L81C2-L99C5)

## Impact
the dao can be spamed  making so many proposals for part of the users.

## Recomendation
Consider implementing a minimum threshold that users must stake to submit a proposal.

## [L-02] missing <= in

function proposeTokenWhitelisting( IERC20 token, string calldata tokenIconURL, string calldata description ) external nonReentrant returns (uint256 _ballotID)
		{
		require( address(token) != address(0), "token cannot be address(0)" );
		require( token.totalSupply() < type(uint112).max, "Token supply cannot exceed uint112.max" ); // 5 quadrillion max supply with 18 decimals of precision  <--------

		require( _openBallotsForTokenWhitelisting.length() < daoConfig.maxPendingTokensForWhitelisting(), "The maximum number of token whitelisting proposals are already pending" );
		require( poolsConfig.numberOfWhitelistedPools() < poolsConfig.maximumWhitelistedPools(), "Maximum number of whitelisted pools already reached" );
		require( ! poolsConfig.tokenHasBeenWhitelisted(token, exchangeConfig.wbtc(), exchangeConfig.weth()), "The token has already been whitelisted" );

		string memory ballotName = string.concat("whitelist:", Strings.toHexString(address(token)) );

		uint256 ballotID = _possiblyCreateProposal( ballotName, BallotType.WHITELIST_TOKEN, address(token), 0, tokenIconURL, description );
		_openBallotsForTokenWhitelisting.add( ballotID );

		return ballotID;
		}

// Code block 1 (unknown):
function _possiblyCreateProposal( string memory ballotName, BallotType ballotType, address address1, uint256 number1, string memory string1, string memory string2 ) internal returns (uint256 ballotID)
		{
		require( block.timestamp >= firstPossibleProposalTimestamp, "Cannot propose ballots within the first 45 days of deployment" );

		// The DAO can create confirmation proposals which won't have the below requirements
		if ( msg.sender != address(exchangeConfig.dao() ) )
			{
			// Make sure that the sender has the minimum amount of xSALT required to make the proposal
			uint256 totalStaked = staking.totalShares(PoolUtils.STAKED_SALT);
			uint256 requiredXSalt = ( totalStaked * daoConfig.requiredProposalPercentStakeTimes1000() ) / ( 100 * 1000 );

			require( requiredXSalt > 0, "requiredXSalt cannot be zero" );

			uint256 userXSalt = staking.userShareForPool( msg.sender, PoolUtils.STAKED_SALT );
			require( userXSalt >= requiredXSalt, "Sender does not
 have enough xSALT to make the proposal" );  <--------

			// Make sure that the user doesn't already have an active proposal
			require( ! _userHasActiveProposal[msg.sender], "Users can only have one active proposal at a time" );
			}
...
}


deepkin Q

## LRTConfig.sol

### initialize param doc typo
https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTConfig.sol#L40

### updateAssetStrategy() doesn't verify Strategy underlying token
https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTConfig.sol#L109-L122

Ignoring Strategy underlying token can lead to errors.

#### Recommendation
Check underlying token
https://github.com/Layr-Labs/eigenlayer-contracts/blob/master/src/contracts/strategies/StrategyBase.sol#L53C19-L53C34

## LRTDepositPool.sol
### There is no option to transfer back assets that have been transferred by mistake.
It's still useful to have such fallback in case of mistakes.
#### Recommendation
Implement admin access function to send assets back.

### transferAssetToNodeDelegator not protected with "whenNotPaused"
https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTDepositPool.sol#L183-L197
From overall context it seems that during any error it's better to freeze not only external, but also internal DAO intercommunications

## NodeDelegator.sol

### With current implementation maxApproveToEigenStrategyManager() can be merged with depositAssetIntoStrategy() because there are no another scenarios where approve is needed
https://github.com/code-423n4/2023-11-kelp/blob/main/src/NodeDelegator.sol#L38-L68

## LRTOracle.sol
### Pricing calculation depends on Eigenlayer shares state
https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTOracle.sol#L52-L79
```
@audit getTotalAssetDeposits will use Eigenlayer Strategy contracts underhood
uint256 totalAssetAmt = ILRTDepositPool(lrtDepositPoolAddr).getTotalAssetDeposits(asset);
```
If something bad may happen with Eigenlayer strategy it will have huge impact on the Oracle and Kelp contracts.
#### Recommendation
It make sense to add some additional logic to mitigate the such issues(TWAP, price snapshots, etc).

### No "whenNotPaused" usage but contract is still Pausable
https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTOracle.s

// Code block 1 (unknown):
@audit getTotalAssetDeposits will use Eigenlayer Strategy contracts underhood
uint256 totalAssetAmt = ILRTDepositPool(lrtDepositPoolAddr).getTotalAssetDeposits(asset);

LRTConfig.sol#L40, LRTConfig.sol#L109-L122, StrategyBase.sol#L53-L19, LRTDepositPool.sol#L183-L197, NodeDelegator.sol#L38-L68, LRTOracle.sol#L52-L79

LRTOracle.sol, NodeDelegator.sol, StrategyBase.sol, LRTConfig.sol, LRTDepositPool.sol


indijanc G

## Use unchecked{} when there's logically no way of under- or overflow
There's a lot of places in the contracts where an unchecked block can be used to reduce gas cost. Pretty much all the for loops can have the unchecked index increment as there's no way of under- or overflow. Testing in Remix the cost savings between `i++` and `unchecked{i++}` is 120 gas. With so many for loop iteration this can save up a considerable amount of gas. See the following diff where the unchecked block could be added and see the audit comments for the rationale. See bottom tables to review gas savings as recorded by the project test suite.

#### Diff
```diff
diff --git a/src/EthRouter.sol b/src/EthRouter.sol
index 125001d..6e99563 100644
--- a/src/EthRouter.sol
+++ b/src/EthRouter.sol
@@ -103,7 +103,8 @@ contract EthRouter is ERC721TokenReceiver {
         }

         // loop through and execute the the buys
-        for (uint256 i = 0; i < buys.length; i++) {
+        // @audit-info - no way of providing so many buys that this would overflow before getting out of gas error (same for inner loops)
+        for (uint256 i = 0; i < buys.length; i = uncheckedInc(i)) {
             if (buys[i].isPublicPool) {
                 // execute the buy against a public pool
                 uint256 inputAmount = Pair(buys[i].pool).nftBuy{value: buys[i].baseTokenAmount}(
@@ -113,7 +114,7 @@ contract EthRouter is ERC721TokenReceiver {
                 // pay the royalties if buyer has opted-in
                 if (payRoyalties) {
                     uint256 salePrice = inputAmount / buys[i].tokenIds.length;
-                    for (uint256 j = 0; j < buys[i].tokenIds.length; j++) {
+                    for (uint256 j = 0; j < buys[i].tokenIds.length; j = uncheckedInc(j)) {
                         // get the royalty fee and recipient
                         (uint256 royaltyFee, address royaltyRecipient) =
                             getRoyalty(buys[i].nft, buys[i].tokenIds[j], salePrice);
@@ -13


report

---
sponsor: "Salty.IO"
slug: "2024-01-salty"
date: "2024-04-19"
title: "Salty.IO"
findings: "https://github.com/code-423n4/2024-01-salty-findings/issues"
contest: 320
---

# Overview

## About C4

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

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

During the audit outlined in this document, C4 conducted an analysis of the Salty.IO smart contract system written in Solidity. The audit took place between January 16—January 30 2024.

Following the C4 audit, 3 wardens, [0xpiken](https://code4rena.com/@0xpiken), [t0x1c](https://code4rena.com/@t0x1c), and [zzebra83](https://code4rena.com/@zzebra83) reviewed the mitigations for all identified issues; the [mitigation review report](#mitigation-review) is appended below the audit report.

## Wardens

180 Wardens contributed reports to Salty.IO:

  1. [0xpiken](https://code4rena.com/@0xpiken)
  2. [t0x1c](https://code4rena.com/@t0x1c)
  3. [handsomegiraffe](https://code4rena.com/@handsomegiraffe)
  4. [zzebra83](https://code4rena.com/@zzebra83)
  5. [0xRobocop](https://code4rena.com/@0xRobocop)
  6. [Banditx0x](https://code4rena.com/@Banditx0x)
  7. [klau5](https://code4rena.com/@klau5)
  8. [niroh](https://code4rena.com/@niroh)
  9. [oakcobalt](https://code4rena.com/@oakcobalt)
  10. [Bauchibred](https://code4rena.com/@Bauchibred)
  11. [fnanni](https://code4rena.com/@fnanni)
  12. [peanuts](https://code4rena.com/@peanuts)
  13. [ether\_sky](https://code4rena.com/@ether_sky)
  14. [0xAsen](https://code4rena.com/@0xAsen)
  15. [grearlake](https://code4rena.com/@grearlake)
  16. [Draiakoo](https://code4rena.com/@Draiakoo)
  17. [Toshii](https://code4rena.com/@Toshii)
  18. [J4X](https://code4rena.com/@J4X)
  19. [haxatron](https://code4rena.

62: 	salt.safeTransfer( address(teamVestingWallet), 10 * MILLION_ETHER );

teamVestingWallet = new VestingWallet( address(upkeep), uint64(block.timestamp), 60 * 60 * 24 * 365 * 10 );


peanuts Q

### [L-01] Two-step ownership is good when changing owners

Auth.sol transferOwnership transfers the authority of an owner without having a two-step process. It is desirable to have a two-step process when changing the authority to prevent any mistakes.

```
  function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
        Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.

        // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be
        // aware that this makes protected functions uncallable even to the owner if the authority is out of order.
        return
            (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) ||
            user == owner;
    }
```

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/Dependencies/Auth.sol

### [L-02] Check for 0 address input in constructors and important state changes

Check for 0 address input when changing addresses in important state changes as well as constructors, to prevent wrong address changes that may be irreversible, or would waste a lot of gas if redeployed.

```
    constructor(address _owner, Authority _authority) {
        // Check owner is zero address
        owner = _owner;
        authority = _authority;

        emit OwnershipTransferred(msg.sender, _owner);
        emit AuthorityUpdated(msg.sender, _authority);
    }
```

### [L-03] closedStatus is checked twice when removing a cdp

`_removeCdp()` checks that cdpStatus is not nonExistent or Active. `_removeCdp()` is internal and only called in `_closeCdp()`. `_closeCdp()` also checks that the closedStatus is not nonExistent or Active. Since `_removeCdp()` is only called through `_closeCdp()` and not anywhere else, the check should only be in `_removeCdp()` and not in `_closeCdp()`.

```
    function _closeCdpWithoutRemovingSortedCdps(bytes32 _cdpId, Status cl

// Code block 1 (unknown):
function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
        Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.

        // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be
        // aware that this makes protected functions uncallable even to the owner if the authority is out of order.
        return
            (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) ||
            user == owner;
    }

// Code block 2 (unknown):
constructor(address _owner, Authority _authority) {
        // Check owner is zero address
        owner = _owner;
        authority = _authority;

        emit OwnershipTransferred(msg.sender, _owner);
        emit AuthorityUpdated(msg.sender, _authority);
    }


Bnke0x0 G

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

#### Impact
Avoids a Gusset (20000 gas)

#### Findings:
```
2023-04-caviar/src/EthRouter.sol::220 => address payable privatePool,
2023-04-caviar/src/Factory.sol::45 => address public privatePoolImplementation;
2023-04-caviar/src/Factory.sol::48 => address public privatePoolMetadata;
2023-04-caviar/src/Factory.sol::51 => uint16 public protocolFeeRate;
2023-04-caviar/src/PrivatePool.sol::82 => address public baseToken;
2023-04-caviar/src/PrivatePool.sol::85 => address public nft;
2023-04-caviar/src/PrivatePool.sol::88 => uint56 public changeFee;
2023-04-caviar/src/PrivatePool.sol::91 => uint16 public feeRate;
2023-04-caviar/src/PrivatePool.sol::94 => bool public initialized;
2023-04-caviar/src/PrivatePool.sol::97 => bool public payRoyalties;
2023-04-caviar/src/PrivatePool.sol::100 => bool public useStolenNftOracle;
2023-04-caviar/src/PrivatePool.sol::104 => uint128 public virtualBaseTokenReserves;
2023-04-caviar/src/PrivatePool.sol::112 => uint128 public virtualNftReserves;
2023-04-caviar/src/PrivatePool.sol::116 => bytes32 public merkleRoot;
```

### [G02] Not using the named return variables when a function returns, wastes deployment gas

#### Findings:
```
2023-04-caviar/src/PrivatePoolMetadata.sol::109 => return _svg;
```

### [G03] It costs more gas to initialize variables to zero than to let the default of zero be applied

#### Impact
Issue Information: [G011](https://github.com/Bnke0x0/c4-common-issues/blob/main/0-Gas-Optimizations.md#g011---It-costs-more-gas-to-initialize-variables-to-zero-than-to-let-the-default-of-zero-be-applied)

#### Findings:
```
2023-04-caviar/src/EthRouter.sol::106 => for (uint256 i = 0; i < buys.length; i++) {
2023-04-caviar/src/EthRouter.sol::116 => for (uint256 j = 0; j < buys[i].tokenIds.length; j++) {
2023-04-caviar/src/EthRouter.sol::134 => for (uint256 j = 0; j < buys[i].tokenIds.length; j++) {
2023-04-caviar/src/EthRouter.sol::159 => for

// Code block 1 (unknown):
2023-04-caviar/src/EthRouter.sol::220 => address payable privatePool,
2023-04-caviar/src/Factory.sol::45 => address public privatePoolImplementation;
2023-04-caviar/src/Factory.sol::48 => address public privatePoolMetadata;
2023-04-caviar/src/Factory.sol::51 => uint16 public protocolFeeRate;
2023-04-caviar/src/PrivatePool.sol::82 => address public baseToken;
2023-04-caviar/src/PrivatePool.sol::85 => address public nft;
2023-04-caviar/src/PrivatePool.sol::88 => uint56 public changeFee;
2023-04-caviar/src/PrivatePool.sol::91 => uint16 public feeRate;
2023-04-caviar/src/PrivatePool.sol::94 => bool public initialized;
2023-04-caviar/src/PrivatePool.sol::97 => bool public payRoyalties;
2023-04-caviar/src/PrivatePool.sol::100 => bool public useStolenNftOracle;
2023-04-caviar/src/PrivatePool.sol::104 => uint128 public virtualBaseTokenReserves;
2023-04-caviar/src/PrivatePool.sol::112 => uint128 public virtualNftReserves;
2023-04-caviar/src/PrivatePool.sol::116 => bytes32 public merkleRoot;

// Code block 2 (unknown):
2023-04-caviar/src/PrivatePoolMetadata.sol::109 => return _svg;


0xAgro Q

# QA Report
## Finding Summary
||Issue|Instances|
|-|-|-|
|[NC-01]|Long Lines (> 120 Characters)|26|
|[NC-02]|Spelling Mistakes|8|
|[NC-03]|`assert` Used Over `require`|2|
|[NC-04]|Underscore Notation Not Used / Not Used Consistently|2|
|[NC-05]|Named Imports Not Used|All Contracts|
|[NC-06]|Contract Layout Voids Solidity Docs|13 Contracts|
|[NC-07]|Explicit Data Types Not Used Consistently|10 Contracts|
|[NC-08]|Contracts Missing `@title` NatSpec Tag|8 Contracts|
|[NC-09]|Order of Functions Not Compliant With Solidity Docs|7 Contracts|
|[NC-10]|No License Indication|2 Contracts|

### [NC-01 Long Lines (> 120 Characters)

Lines with greater length than 120 characters are used. The [Solidity Style Guide](https://docs.soliditylang.org/en/v0.8.17/style-guide.html#maximum-line-lengthhttps://docs.soliditylang.org/en/v0.8.17/style-guide.html#maximum-line-length) suggests that all lines should be 120 characters or less in width.

The following lines are longer than 120 characters, it is suggested to shorten these lines:

*contracts/lending/JumpRateModelV2.sol*
*  [57](https://github.com/code-423n4/2023-01-ondo/tree/main/contracts/lending/JumpRateModelV2.sol#L57).

*contracts/lending/tokens/cCash/CCash.sol*
*  [147](https://github.com/code-423n4/2023-01-ondo/tree/main/contracts/lending/tokens/cCash/CCash.sol#L147), [191](https://github.com/code-423n4/2023-01-ondo/tree/main/contracts/lending/tokens/cCash/CCash.sol#L191), [230](https://github.com/code-423n4/2023-01-ondo/tree/main/contracts/lending/tokens/cCash/CCash.sol#L230), [234](https://github.com/code-423n4/2023-01-ondo/tree/main/contracts/lending/tokens/cCash/CCash.sol#L234).

*contracts/lending/tokens/cToken/CErc20.sol*
*  [147](https://github.com/code-423n4/2023-01-ondo/tree/main/contracts/lending/tokens/cToken/CErc20.sol#L147), [191](https://github.com/code-423n4/2023-01-ondo/tree/main/contracts/lending/tokens/cToken/CErc20.sol#L191), [230](https://github.com/code-423n4/2023-01-ondo/tree/main/contracts/lending/token

97:	assert(cashProxyAdmin.owner() == guardian);

106:	assert(cashKYCSenderProxyAdmin.owner() == guardian);

JumpRateModelV2.sol#L57, CCash.sol#L147, CCash.sol#L191, CCash.sol#L230, CCash.sol#L234, CErc20.sol#L147, CErc20.sol#L191


DJINN Q

# Solidity version out of date
```
pragma solidity 0.8.12;
```
## Affected files
- All files in scope

## Synopsis
Using an out-of-date Solidity compiler can introduce vulnerabilities and bugs into your smart contracts for a few reasons:

- Outdated compilers may not support the latest features or optimizations, which can result in contracts that are less efficient or less secure.
- Outdated compilers may not fix known bugs or vulnerabilities in the compiler itself, which could allow an attacker to exploit these issues to compromise your contract.
- Newer versions of Solidity may introduce breaking changes that can cause existing contracts compiled with an older version to behave in unexpected ways. This can lead to vulnerabilities if the contract relies on certain assumptions that are no longer valid in the newer version of Solidity.

## Details
Some bugs present in version 0.8.12:
- SOL-2022-6
- SOL-2022-5
- SOL-2022-2
- SOL-2022-1

*you can find a more complete list of all the known vulnerabilities [here](https://docs.soliditylang.org/en/v0.8.17/bugs.html)*
## Recommendation
It is generally a good idea to use the latest version of Solidity when writing or deploying contracts, as this will ensure that you have access to the latest features and optimizations and that you are not using a version of the compiler that is known to have vulnerabilities.


tnevler G

# Report
## Gas Optimizations ##
### [G-1]: The increment in for loop post condition can be made unchecked
**Context:**

1. ```for (uint256 i = 0; i < opasLen; i++) {``` [L100](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L100)
1. ```for (uint256 a = 0; a < opasLen; a++) {``` [L107](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L107)
1. ```for (uint256 i = 0; i < opslen; i++) {``` [L112](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L112)
1. ```for (uint256 a = 0; a < opasLen; a++) {``` [L128](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L128)
1. ```for (uint256 i = 0; i < opslen; i++) {``` [L134](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L134)

**Description:**

[This](https://gist.github.com/hrkrshnn/ee8fabd532058307229d65dcd5836ddc#the-increment-in-for-loop-post-condition-can-be-made-unchecked) can save 30-40 gas per loop iteration.

**Recommendation:**

Example how to fix. Change:
```
for (uint256 i = 0; i < orders.length; ++i) {
   // Do the thing
}
```

To:
```
for (uint256 i = 0; i < orders.length;) {
   // Do the thing
   unchecked { ++i; }
}
```

### [G-2]: Place subtractions where the operands can't underflow in unchecked {} block
**Context:**

```paymasterIdBalances[msg.sender] -= amount;``` [L58](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/verifying/singleton/VerifyingSingletonPaymaster.sol#L58)

**Description:**

Some gas can be saved by using an unchecked {} block if an underflow isn't possible because of a previous require() or if-statement.

### [G-3]:

// Code block 1 (unknown):
for (uint256 i = 0; i < orders.length; ++i) {
   // Do the thing
}

// Code block 2 (unknown):
for (uint256 i = 0; i < orders.length;) {
   // Do the thing
   unchecked { ++i; }
}

EntryPoint.sol#L100, EntryPoint.sol#L107, EntryPoint.sol#L112, EntryPoint.sol#L128, EntryPoint.sol#L134, VerifyingSingletonPaymaster.sol#L58


horsefacts Q

# Low

## `CashKYCSender`: KYC check may lead to unrecoverable assets

The `CashKYCSender` token applies a KYC check to the caller and `from` address in its [`_beforeTokenTransfer`](https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b6b4561e09460b2e6471eb694efdd6c70/contracts/cash/token/CashKYCSender.sol#L56-L75) function, but not to the `to` address:

```solidity
  function _beforeTokenTransfer(
    address from,
    address to,
    uint256 amount
  ) internal override {
    super._beforeTokenTransfer(from, to, amount);

    require(
      _getKYCStatus(_msgSender()),
      "CashKYCSender: must be KYC'd to initiate transfer"
    );

    if (from != address(0)) {
      // Only check KYC if not minting
      require(
        _getKYCStatus(from),
        "CashKYCSender: `from` address must be KYC'd to send tokens"
      );
    }
  }
```

This means it's possible for a KYC'd owner of a `CashKYCSender` token to lose access to their assets by transferring them to a contract address that does not represent a human and cannot KYC, like a smart wallet, vault contract, or noncustodial DeFi protocol. Once tokens are transferred in, the smart contract will be blocked from initiating token transfers out. The composability of ERC20 tokens and protocols that interact with them makes it especially easy for users to make this mistake.

Recommendation: Since KYC checks break composability with other protocols, prevent all transfers to non-KYC'd addresses (i.e., use `CashKYCSenderReceiver` for all tokens).

## `OndoPriceOracleV2`: Oracle cannot support tokens with more than 28 decimals

`OndoPriceOracleV2` calculates a `scaleFactor` by subtracting the collateral token's `decimals()` and the configured Chainlink price feed's `decimals()` from 36. Since Chainlink USD price feeds use 8 decimals, this calculation will revert with a checked arithmetic error if a collateral token has more than 28 decimals:

[`OndoPriceOracleV2`](https://github.com/code-423n4/2023-01-ondo/blob/f3426e5b

    fTokenToChainlinkOracle[fToken].scaleFactor = (10 **
      (36 -
        uint256(IERC20Like(underlying).decimals()) -
        uint256(AggregatorV3Interface(chainlinkOracle).decimals())));

// Code block 1 (solidity):
function _beforeTokenTransfer(
    address from,
    address to,
    uint256 amount
  ) internal override {
    super._beforeTokenTransfer(from, to, amount);

    require(
      _getKYCStatus(_msgSender()),
      "CashKYCSender: must be KYC'd to initiate transfer"
    );

    if (from != address(0)) {
      // Only check KYC if not minting
      require(
        _getKYCStatus(from),
        "CashKYCSender: `from` address must be KYC'd to send tokens"
      );
    }
  }


eeshenggoh G

## Summary

These are the findings for Gas Optimization. Will start from this hierarchy:
1) [contracts/core]
2) [contracts/governance]
3) [contracts/periphery]
4) [contracts/utils]

## Vulnerability Details
### [G002] Cache Array Length Outside of Loop
```
File: USDA.sol

47:   modifier paysInterest() {
48:     for (uint256 _i; _i < _vaultControllers.length();) {
49:       IVaultController(_vaultControllers.at(_i)).calculateInterest();
50:       unchecked {
51:         _i++;
52:       }
53:     }
54:     _;
55:   }

```
```
File: Vault.sol
169:     for (uint256 _i; _i < _tokenAddresses.length;) {
170:       IVaultController.CollateralInfo memory _collateralInfo = CONTROLLER.tokenCollateralInfo(_tokenAddresses[_i]);
171:       if (_collateralInfo.tokenId == 0) revert Vault_TokenNotRegistered();
172:       if (_collateralInfo.collateralType != IVaultController.CollateralType.CurveLPStakedOnConvex) {
173:         revert Vault_TokenNotCurveLP();
174:       }

```
```
File: Vault.sol
169:     for (uint256 _i; _i < _tokenAddresses.length;) {
170:       IVaultController.CollateralInfo memory _collateralInfo = CONTROLLER.tokenCollateralInfo(_tokenAddresses[_i]);
171:       if (_collateralInfo.tokenId == 0) revert Vault_TokenNotRegistered();
172:       if (_collateralInfo.collateralType != IVaultController.CollateralType.CurveLPStakedOnConvex) {
173:         revert Vault_TokenNotCurveLP();
174:       }
```
```
File: VaultController.sol
255:     for (uint256 _i; _i < _tokenAddresses.length;) {
256:       _tokenId = _oldVaultController.tokenId(_tokenAddresses[_i]);
257:       if (_tokenId == 0) revert VaultController_WrongCollateralAddress();
258:       _tokensRegistered++;
```
```
File: VaultController.sol
868:     for (uint192 _i; _i < enabledTokens.length; ++_i) {
869:       CollateralInfo memory _collateral = tokenAddressCollateralInfo[enabledTokens[_i]];
```
```
File: VaultController.sol
896:     for (uint192 _i; _i < enabledTokens.length; ++_i) {
897:       CollateralIn

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

47:   modifier paysInterest() {
48:     for (uint256 _i; _i < _vaultControllers.length();) {
49:       IVaultController(_vaultControllers.at(_i)).calculateInterest();
50:       unchecked {
51:         _i++;
52:       }
53:     }
54:     _;
55:   }

// Code block 2 (unknown):
File: Vault.sol
169:     for (uint256 _i; _i < _tokenAddresses.length;) {
170:       IVaultController.CollateralInfo memory _collateralInfo = CONTROLLER.tokenCollateralInfo(_tokenAddresses[_i]);
171:       if (_collateralInfo.tokenId == 0) revert Vault_TokenNotRegistered();
172:       if (_collateralInfo.collateralType != IVaultController.CollateralType.CurveLPStakedOnConvex) {
173:         revert Vault_TokenNotCurveLP();
174:       }

// Code block 3 (unknown):
File: Vault.sol
169:     for (uint256 _i; _i < _tokenAddresses.length;) {
170:       IVaultController.CollateralInfo memory _collateralInfo = CONTROLLER.tokenCollateralInfo(_tokenAddresses[_i]);
171:       if (_collateralInfo.tokenId == 0) revert Vault_TokenNotRegistered();
172:       if (_collateralInfo.collateralType != IVaultController.CollateralType.CurveLPStakedOnConvex) {
173:         revert Vault_TokenNotCurveLP();
174:       }

// Code block 4 (unknown):
File: VaultController.sol
255:     for (uint256 _i; _i < _tokenAddresses.length;) {
256:       _tokenId = _oldVaultController.tokenId(_tokenAddresses[_i]);
257:       if (_tokenId == 0) revert VaultController_WrongCollateralAddress();
258:       _tokensRegistered++;

// Code block 5 (unknown):
File: VaultController.sol
868:     for (uint192 _i; _i < enabledTokens.length; ++_i) {
869:       CollateralInfo memory _collateral = tokenAddressCollateralInfo[enabledTokens[_i]];


McToady Q

## [I-01] Precision loss in RankedBattle NRN distribution
Actual $NRN claimable after a round in `RankedBattle` will likely be less than `rankedNrnDistribution` due to rounding errors.

**PoC**
Log showing this:
```solidity
  Alice NRN 1206896551724137931034
  Bob NRN 1724137931034482758620
  Chad NRN 2068965517241379310344
  Dave NRN 0
  Error: a == b not satisfied [uint]
        Left: 4999999999999999999998
       Right: 5000000000000000000000
```
Add the following foundry test to `RankedBattle.t.sol` to recreate this:
```solidity
    function testClaimNRNNoPrecisionLoss() public {
        address alice = makeAddr("alice");
        address bob = makeAddr("bob");
        address chad = makeAddr("chad");
        address dave = makeAddr("dave");

        address[] memory users = new address[](4);
        users[0] = alice;
        users[1] = bob;
        users[2] = chad;
        users[3] = dave;

        // Set up all 4 users with a fighter, and have them stake 4k $NRN
        for (uint256 i; i < users.length; ++i) {
            address user = users[i];
            _mintFromMergingPool(user);
            _fundUserWith4kNeuronByTreasury(user);
            _fundUserWith4kNeuronByTreasury(user);
            uint256 stakeAmount = (i + 1) * 200 ether;
            vm.prank(user);
            _rankedBattleContract.stakeNRN(stakeAmount, i);
        }

        // Alice beats bob
        _rankedBattleContract.updateBattleRecord(0, 50, 0, 1500, false);
        _rankedBattleContract.updateBattleRecord(1, 50, 2, 1500, true);
        // Chad beats dave
        _rankedBattleContract.updateBattleRecord(2, 50, 0, 1500, false);
        _rankedBattleContract.updateBattleRecord(3, 50, 2, 1500, true);
        // Bob beats dave twice
        _rankedBattleContract.updateBattleRecord(1, 50, 0, 1500, false);
        _rankedBattleContract.updateBattleRecord(3, 50, 2, 1500, true);
        _rankedBattleContract.updateBattleRecord(1, 50, 0, 1500, false);
        _rankedBattleCont

    function testClaimNRNNoPrecisionLoss() public {
        address alice = makeAddr("alice");
        address bob = makeAddr("bob");
        address chad = makeAddr("chad");
        address dave = makeAddr("dave");

        address[] memory users = new address[](4);
        users[0] = alice;
        users[1] = bob;
        users[2] = chad;
        users[3] = dave;

        // Set up all 4 users with a fighter, and have them stake 4k $NRN
        for (uint256 i; i < users.length; ++i) {
            address user = users[i];
            _mintFromMergingPool(user);
            _fundUserWith4kNeuronByTreasury(user);
            _fundUserWith4kNeuronByTreasury(user);
            uint256 stakeAmount = (i + 1) * 200 ether;
            vm.prank(user);
            _rankedBattleContract.stakeNRN(stakeAmount, i);
        }

        // Alice beats bob
        _rankedBattleContract.updateBattleRecord(0, 50, 0, 1500, false);
        _rankedBattleContract.updateBattleRecord(1, 50, 2, 1500, true);
        // Chad beats dave
        _rankedBattleContract.updateBattleRecord(2, 50, 0, 1500, false);
        _rankedBattleContract.updateBattleRecord(3, 50, 2, 1500, true);
        // Bob beats dave twice
        _rankedBattleContract.updateBattleRecord(1, 50, 0, 1500, false);
        _rankedBattleContract.updateBattleRecord(3, 50, 2, 1500, true);
        _rankedBattleContract.updateBattleRecord(1, 50, 0, 1500, false);
        _rankedBattleContract.updateBattleRecord(3, 50, 2, 1500, true);

        for (uint256 i; i < users.length; ++i) {
            uint256 userPoints = _rankedBattleContract.accumulatedPointsPerAddress(users[i], 0);
            console.log("User Points", userPoints);
        }
        vm.stopPrank();

        _rankedBattleContract.setNewRound();

        uint256 aliceNRN = _rankedBattleContract.getUnclaimedNRN(alice);
        uint256 bobNRN = _rankedBattleContract.getUnclaimedNRN(bob);
        uint256 chadNRN = _rankedBattleContract.getUnclaimedNRN(chad);


Bnke0x0 G

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

#### Impact
Avoids a Gusset (20000 gas)
#### Findings:
```
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccount.sol::51 => address public owner;
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccount.sol::59 => IEntryPoint private _entryPoint;
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccountNoAuth.sol::51 => address public owner;
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccountNoAuth.sol::59 => IEntryPoint private _entryPoint;
```

### [G02] State variables can be packed into fewer storage slots

#### Impact
If variables occupying the same slot are both written the same
function or by the constructor avoids a separate Gsset (20000 gas).
#### Findings:
```
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccount.sol::51 => address public owner;
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccountNoAuth.sol::51 => address public owner;
```

### [G03] `<array>.length` should not be looked up in every loop of a `for` loop

#### Impact
Even memory arrays incur the overhead of bit tests and bit shifts to
calculate the array length. Storage array length checks incur an extra
Gwarmaccess (100 gas) PER-LOOP.
#### Findings:
```
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccount.sol::468 => for (uint i = 0; i < dest.length;) {
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccountNoAuth.sol::458 => for (uint i = 0; i < dest.length;) {
```

### [G04] `++i/i++` should be `unchecked{++i}`/`unchecked{++i}` when it is not possible for them to overflow, as is the case when used in `for` and `while` loops

#### Findings:
```
2023-01-biconomy-main/contracts/smart-contract-wallet/libs/Strings.sol::56 => for (uint256 i = 2 * length + 1; i > 1; --i) {
```

### [G05] `require()`/`revert()` strings longer than 32 bytes cost extra gas

#### Findings:
```
2023-01-biconomy-main/co

// Code block 1 (unknown):
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccount.sol::51 => address public owner;
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccount.sol::59 => IEntryPoint private _entryPoint;
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccountNoAuth.sol::51 => address public owner;
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccountNoAuth.sol::59 => IEntryPoint private _entryPoint;

// Code block 2 (unknown):
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccount.sol::51 => address public owner;
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccountNoAuth.sol::51 => address public owner;

// Code block 3 (unknown):
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccount.sol::468 => for (uint i = 0; i < dest.length;) {
2023-01-biconomy-main/contracts/smart-contract-wallet/SmartAccountNoAuth.sol::458 => for (uint i = 0; i < dest.length;) {

// Code block 4 (unknown):
2023-01-biconomy-main/contracts/smart-contract-wallet/libs/Strings.sol::56 => for (uint256 i = 2 * length + 1; i > 1; --i) {


BRONZEDISC Q

# Low

https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/perp-vault/PerpetualAtlanticVault.sol#L219-L230

```solidity
- does not check for 0 address in the `tokens` array
- does check for repeated addresses
```

https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/decaying-bonds/RdpxDecayingBonds.sol#L89-L107

```solidity
- does not check for 0 address in the `tokens` array
- does check for repeated addresses
```

https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L161-L173

```solidity
- does not check for 0 address in the `tokens` array
- does check for repeated addresses
```

https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L142-L153

```solidity
- does not check for 0 address in the `tokens` array
- does check for repeated addresses
```

# QA
---

### Layout Order [1]

- The best-practices for layout within a contract is the following order: state variables, events, modifiers, constructor and functions.

https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/reLP/ReLPContract.sol

```solidity
// place this event before the constructor
311:  event LogSetReLpFactor(uint256 _reLPFactor);
```

https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/perp-vault/PerpetualAtlanticVaultLP.sol

```solidity
// place this modifier before the constructor
295:  modifier onlyPerpVault() {
```

https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV3LiquidityAmo.sol

```solidity
// place these before the constructor
368:  event RecoveredERC20(address token, uint256 amount);
369:  event RecoveredERC721(address token, uint256 id);
370:  event LogAssetsTransfered(
379:  event log(uint);
```

https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol

```solidity
// place these before the constructor
387:  event LogAddLiquidity(
398:  event LogRemoveLiquidity(
407:  event LogSwap(
415:  event LogAssetsTransfered(
421:

// Code block 1 (solidity):
- does not check for 0 address in the `tokens` array
- does check for repeated addresses

// Code block 2 (solidity):
- does not check for 0 address in the `tokens` array
- does check for repeated addresses

// Code block 3 (solidity):
- does not check for 0 address in the `tokens` array
- does check for repeated addresses

// Code block 4 (solidity):
- does not check for 0 address in the `tokens` array
- does check for repeated addresses

// Code block 5 (solidity):
// place this event before the constructor
311:  event LogSetReLpFactor(uint256 _reLPFactor);

// Code block 6 (solidity):
// place this modifier before the constructor
295:  modifier onlyPerpVault() {

// Code block 7 (solidity):
// place these before the constructor
368:  event RecoveredERC20(address token, uint256 amount);
369:  event RecoveredERC721(address token, uint256 id);
370:  event LogAssetsTransfered(
379:  event log(uint);

- does not check for 0 address in the `tokens` array
- does check for repeated addresses

- does not check for 0 address in the `tokens` array
- does check for repeated addresses

- does not check for 0 address in the `tokens` array
- does check for repeated addresses

- does not check for 0 address in the `tokens` array
- does check for repeated addresses

// place this event before the constructor
311:  event LogSetReLpFactor(uint256 _reLPFactor);

// place this modifier before the constructor
295:  modifier onlyPerpVault() {

// place these before the constructor
368:  event RecoveredERC20(address token, uint256 amount);
369:  event RecoveredERC721(address token, uint256 id);
370:  event LogAssetsTransfered(
379:  event log(uint);

PerpetualAtlanticVault.sol#L219-L230, RdpxDecayingBonds.sol#L89-L107, RdpxV2Core.sol#L161-L173, UniV2LiquidityAmo.sol#L142-L153, ReLPContract.sol, PerpetualAtlanticVaultLP.sol, UniV3LiquidityAmo.sol, UniV2LiquidityAmo.sol

RdpxDecayingBonds.sol, PerpetualAtlanticVault.sol, RdpxV2Core.sol, UniV3LiquidityAmo.sol, ReLPContract.sol, UniV2LiquidityAmo.sol, PerpetualAtlanticVaultLP.sol


Josiah Q

## MODERN MODULARITY ON IMPORT USAGES
For cleaner Solidity code in conjunction with the rule of modularity and modular programming, it is recommended using named imports with curly braces (limiting to the needed instances if possible) instead of adopting the global import approach.

Suggested fix for a contract instance as an example:

[ReaperVaultERC4626.sol#L5-L6](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L5-L6)

```
import {ReaperVaultV2} from "./ReaperVaultV2.sol";
import {IERC4626Functions} from "./interfaces/IERC4626Functions.sol";
```

## CODE SIMPLIFICATION
Unused or unneeded code lines can be removed from the function code block for better readability and logic flow. For example, no fee will be minted to LQTYStaking.sol when the system is in recovery mode. [`_requireValidMaxFeePercentage(_maxFeePercentage, isRecoveryMode)`](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/BorrowerOperations.sol#L648-L656) in BorrowerOperations.sol should therefore have its `isRecoveryMode` parameter and associated code lines removed just like it has been adopted in RedemptionHelper.sol.

Suggested fix:

```
    function _requireValidMaxFeePercentage(uint _maxFeePercentage) internal pure {
            require(_maxFeePercentage >= BORROWING_FEE_FLOOR && _maxFeePercentage <= DECIMAL_PRECISION,
                "Max fee percentage must be between 0.5% and 100%");
    }
```

With the above fix implemented, the functions, [`openTrove()`](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/BorrowerOperations.sol#L648-L656) and [`_adjustTrove()`](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/BorrowerOperations.sol#L293) calling it internally should also be refactored to:

```
        _requireValidMaxFeePercentage(_maxFeePercentage);
```

## BASERATE REMAINS ZERO UNTIL IT GETS INITIALIZED
The default value of `baseRate` remains `0` in TroveManager.sol

// Code block 1 (unknown):
import {ReaperVaultV2} from "./ReaperVaultV2.sol";
import {IERC4626Functions} from "./interfaces/IERC4626Functions.sol";

// Code block 2 (unknown):
function _requireValidMaxFeePercentage(uint _maxFeePercentage) internal pure {
            require(_maxFeePercentage >= BORROWING_FEE_FLOOR && _maxFeePercentage <= DECIMAL_PRECISION,
                "Max fee percentage must be between 0.5% and 100%");
    }

// Code block 3 (unknown):
_requireValidMaxFeePercentage(_maxFeePercentage);


hansfriese Q

## Low severity findings

### [L-01] Core contracts are susceptible to initializer re-entrancy due to OpenZeppelin version advisory

The version of OpenZeppelin in the core package falls within [this advisory](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-9c22-pwxw-p6hx), so advised to upgrade to avoid accidentally adding a vulnerability if external calls are made.

### [L-02] Re-entrancy risk in openTrove

- https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L526
  Although unlikely bad collateral will be included, it is recommended to keep CEI pattern.
  Otherwise, malicious strategy can reenter `report()` function and cause problems.
  (It is understood strategy is added by admin and this is very unlikely)

### [L-03] No rewards swapped in \_harvestCore

- https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L114-L125

When `steps` are not initialized it seems admin has to `setHarvestSteps` first, but this may not happen so rewards aren't swapped.

### [L-04] Call `_disableInitializers()`

- https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L61
  It is recommended to call `_disableInitializers()` in the initializer function.

### [L-05] Wrong event string

- https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L155
  `require(_feeBPS <= PERCENT_DIVISOR / 5, "Fee cannot be higher than 20 BPS");`
  I believe the code is correct and the event string is misleading here, should be changed into 2000 BPS or 20%.

### [L-06] Wrong comments

- https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/BorrowerOperations.sol#L660
  "collateral ratio" → "nominal .."
- https://github.com/code-423n4/2023-02-ethos/blob/736

ReaperVaultV2.sol#L526, ReaperStrategyGranarySupplyOnly.sol#L114-L125, ReaperBaseStrategyv4.sol#L61, ReaperVaultV2.sol#L155, BorrowerOperations.sol#L660

ReaperBaseStrategyv4.sol, BorrowerOperations.sol, ReaperStrategyGranarySupplyOnly.sol, ReaperVaultV2.sol


umarkhatab_465 Q

# Unknown Dos to the Admin while calling `multiexCall`
## Summary
While calling the `multiexcall` function inside `SourceBridge.sol` , the admin passes multiple potential calls in the form of array. The function executes multiple calls( or transactions ) in a single call.
But here's the caveat , if one of them fails , the entire set of transactions fail.

```solidity

function multiexcall(
    ExCallData[] calldata exCallData
  ) external payable override onlyOwner returns (bytes[] memory results) {
    results = new bytes[](exCallData.length);
    for (uint256 i = 0; i < exCallData.length; ++i) {
      (bool success, bytes memory ret) = address(exCallData[i].target).call{
        value: exCallData[i].value
      }(exCallData[i].data);
->      require(success, "Call Failed");
      results[i] = ret;
    }
  }
```

The `require` statement at the end checks if the transaction has succeeded.
If not, it reverts.

Unfortunately, the admin has no way of knowing which transaction failed!
Let's say the admin has 10 transactions , he can't know which transaction was a black sheep to remove and execute the function again.

Situation gets worse when the admin has calls in the factor 100s.

# Recommendation
instead of require statement , try to have some offchain mechanism in conjuction with onchain (emitting events of reverting transaction data to try again with) or just an array of pending/unsuccessful transactions and rest should be proceeded if they all are independent.

// Code block 1 (solidity):
function multiexcall(
    ExCallData[] calldata exCallData
  ) external payable override onlyOwner returns (bytes[] memory results) {
    results = new bytes[](exCallData.length);
    for (uint256 i = 0; i < exCallData.length; ++i) {
      (bool success, bytes memory ret) = address(exCallData[i].target).call{
        value: exCallData[i].value
      }(exCallData[i].data);
->      require(success, "Call Failed");
      results[i] = ret;
    }
  }


BRONZEDISC Q

## QA
---

### Layout Order [1]

- The best-practices for layout within a contract is the following order: state variables, events, modifiers, constructor and functions.

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

```solidity
// struct coming after functions, should come before.
646:    struct LocalVariables_getSingularCollateralGain {
```

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

```solidity
// struct coming after a function, should come before them.
70:    struct LocalVariables_getRedemptionHints {
```

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

```solidity
// modifier coming after all the functions
128:    modifier checkCollateral(address _collateral) {
```

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

```solidity
// struct coming after functions, should come before.
220:    struct LocalVariables_rebalance {
```

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

```solidity
// struct coming after functions, should come before.
643:    struct LocalVariables_getSingularCollateralGain {
```

---

### Function Visibility [2]

- 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: constructor, receive function (if exists), fallback function (if exists), public, external, internal, private. Within a grouping, place the view and pure functions last.

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

```solidity
// internal function coming before external one
203:    function _getPendingCollateralGain(address _user) internal view returns (address[] memory assets, uint[] memory amounts) {
```

https://github.com/code-423n4/202

// Code block 1 (solidity):
// struct coming after functions, should come before.
646:    struct LocalVariables_getSingularCollateralGain {

// Code block 2 (solidity):
// struct coming after a function, should come before them.
70:    struct LocalVariables_getRedemptionHints {

// Code block 3 (solidity):
// modifier coming after all the functions
128:    modifier checkCollateral(address _collateral) {

// Code block 4 (solidity):
// struct coming after functions, should come before.
220:    struct LocalVariables_rebalance {

// Code block 5 (solidity):
// struct coming after functions, should come before.
643:    struct LocalVariables_getSingularCollateralGain {

// Code block 6 (solidity):
// internal function coming before external one
203:    function _getPendingCollateralGain(address _user) internal view returns (address[] memory assets, uint[] memory amounts) {

// struct coming after functions, should come before.
646:    struct LocalVariables_getSingularCollateralGain {

// struct coming after a function, should come before them.
70:    struct LocalVariables_getRedemptionHints {

// modifier coming after all the functions
128:    modifier checkCollateral(address _collateral) {

// struct coming after functions, should come before.
220:    struct LocalVariables_rebalance {

// struct coming after functions, should come before.
643:    struct LocalVariables_getSingularCollateralGain {

// internal function coming before external one
203:    function _getPendingCollateralGain(address _user) internal view returns (address[] memory assets, uint[] memory amounts) {

StabilityPool.sol, HintHelpers.sol, CollateralConfig.sol, ActivePool.sol, LQTYStaking.sol

StabilityPool.sol, LQTYStaking.sol, ActivePool.sol, CollateralConfig.sol, HintHelpers.sol


BARW Q

# Redundant Check

## Redundant Check at `cdpManager::_openCdp`
`vars.netStEthBalance` is always greater than or equal 2e.

```C++
        // @info vars.netStEthBalance >= 2e
        _requireAtLeastMinNetStEthBalance(vars.netStEthBalance);
        // @audit Redundant Check for netStEthBalance
        require(vars.netStEthBalance > 0, "BorrowerOperations: zero collateral for openCdp()!");
```
### [Related code](https://github.com/code-423n4/2023-10-badger/blob/f2f2e2cf9965a1020661d179af46cb49e993cb7e/packages/contracts/contracts/BorrowerOperations.sol#L439-L472)

## Redundant Check at `EBTCToken::_requireValidRecipient`

```C++
    function _requireValidRecipient(address _recipient) internal view {
        require(
            _recipient != address(0) && _recipient != address(this),
            "EBTC: Cannot transfer tokens directly to the EBTC token contract or the zero address"
        );
        require(
            _recipient != cdpManagerAddress && _recipient != borrowerOperationsAddress,
            "EBTC: Cannot transfer tokens directly to the CdpManager or BorrowerOps"
        );
    }
```
### [Related code](https://github.com/code-423n4/2023-10-badger/blob/f2f2e2cf9965a1020661d179af46cb49e993cb7e/packages/contracts/contracts/EBTCToken.sol#L295C42-L311)

## Redundant value setting

```C++
        uint256 liquidatorRewardShares = cdpManager.getCdpLiquidatorRewardShares(_cdpId);
```

`Cdps[_cdpId].liquidatorRewardShares` is always equals `collateral.getSharesByPooledEth(LIQUIDATOR_REWARD)`, there is no need to get it from the struct.

## Should Prevent Zero Amount Transfer Attack

There is a restriction on transferring an amount of zero. It should be evaluated that the current allowance is greater than or equal to the maximum of the amount and 1, thereby necessitating the approval to be non-zero.

```C++
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external override returns (bool) {
        _require

// Code block 1 (unknown):
### [Related code](https://github.com/code-423n4/2023-10-badger/blob/f2f2e2cf9965a1020661d179af46cb49e993cb7e/packages/contracts/contracts/BorrowerOperations.sol#L439-L472)

## Redundant Check at `EBTCToken::_requireValidRecipient`

// Code block 2 (unknown):
### [Related code](https://github.com/code-423n4/2023-10-badger/blob/f2f2e2cf9965a1020661d179af46cb49e993cb7e/packages/contracts/contracts/EBTCToken.sol#L295C42-L311)

## Redundant value setting

// Code block 3 (unknown):
`Cdps[_cdpId].liquidatorRewardShares` is always equals `collateral.getSharesByPooledEth(LIQUIDATOR_REWARD)`, there is no need to get it from the struct.

## Should Prevent Zero Amount Transfer Attack

There is a restriction on transferring an amount of zero. It should be evaluated that the current allowance is greater than or equal to the maximum of the amount and 1, thereby necessitating the approval to be non-zero.


Sathish9098 Q

# LOW FINDINGS

| LOW COUNT | Issues  | Instances  |
|---------- |---------|----------- |
| [L-1] | The ``DEFAULT_ADMIN_ROLE`` to withdraw tokens, regardless of whether the situation is genuinely an ``emergency`` or ``not ``  | 2 |
| [L-2] | Using a very short deadline ``(block.timestamp + 1)`` can lead to ``Reverts``  | 3  |
| [L-3] | Ensuring ``sufficient gas`` to prevent reverts in transactions involving ``UniswapV2Router`` and ``UniswapV2Pair ``  | 1 |
| [L-4] | ``DEFAULT_ADMIN_ROLE`` can be single point of failure   | 10  |
| [L-5] | Failure to check ``_whenNotPaused()`` in the ``redeem()``,``mint()`` function results in ``unintended behaviors`` and poses a ``potential risk``  | 2 |
| [L-6] | Revert on ``approval`` to ``Zero Address`` | 1  |
| [L-7] | Divide by zero should be avoided   | 3 |
| [L-8] | Signature use at deadlines should be allowed  | 2  |
| [L-9] | Vulnerable version of openzeppelin-Contracts used   | 1  |
| [L-10] | The absence of robust ``uint256`` value ``sanity checks`` for critical parameter assignments poses a technical risk   | 1  |
| [L-11] | Add ``blocklist`` function for ``NFT ``  | -  |
| [L-12] | Don't use deprecated ``Counters.sol`` library  | 1 |
| [L-13] | Unchecked Return Value in ``swapExactTokensForTokens()`` Function May Lead to ``Loss of Funds``  | 2 |
| [L-14] | Contracts Fail to check ``Token Blacklist`` before executing token transfers    | -  |
| [L-15] | Add setter function to ``rdpxV2Core`` variable   | 1 |
| [L-16] | Lack of symbol existence check for ``_assetSymbol`` Allows for ``Duplicate Symbols ``  | 1  |
| [L-17] | Critical address changes should use ``two-step procedure``   | 2 |
| [L-18] | Unused ``EnumerableSet`` library   | 1 |

##

## [L-1] The ``DEFAULT_ADMIN_ROLE`` to withdraw tokens, regardless of whether the situation is ``genuinely`` an ``emergency`` or ``not ``

### Impact
Allowing ``administrators`` to withdraw tokens without restriction can create a ``conflict of interest``, where they may prioritiz

FILE: 2023-08-dopex/contracts/amo/UniV2LiquidityAmo.sol

function emergencyWithdraw(
    address[] calldata tokens
  ) external onlyRole(DEFAULT_ADMIN_ROLE) {
    IERC20WithBurn token;

    for (uint256 i = 0; i < tokens.length; i++) {
      token = IERC20WithBurn(tokens[i]);
      token.safeTransfer(msg.sender, token.balanceOf(address(this)));
    }

    emit LogEmergencyWithdraw(msg.sender, tokens);
  }

Require(emergencyActive, "Protocol is not in emergency situation");


ybansal2403 G

# Summary

Some optimizations were benchmarked via the protocol's tests. Optimizations that were not benchmarked are explained properly. The following command was used to run the tests for the benchmarks below: `forge test` and the gas report was generated using `forge test --gas-report`

## Gas Optimizations

| Number        | Issue                                                                                | Instances |
| ------------- | :--------------------------------------------------------------------------------------------- | :-------: |
| [G-01](#g-01) | State variables that are used multiple times in a function should be cached in stack variables |     4     |
| [G-02](#g-02) | Structs can be packed into fewer storage slots                                                 |     1     |
| [G-03](#g-03) | State variables can be packed into fewer storage slots                                         |     1     |
| [G-04](#g-04) | Use do while loops instead of for loops                                                        |     8     |
| [G-05](#g-05) | Use nested if statements instead of &&                                                         |     9     |
| [G-06](#g-06) | Use hardcode address instead of address(this)                                                  |     9     |
| [G-07](#g-07) | Do not calculate constants                                                                     |     2     |
| [G-08](#g-08) | Use assembly to compute hashes to save gas                                                     |     4     |
| [G-09](#g-09) | Use constants instead of type(uintx).max                                                       |     3     |

## [G-01] State variables that are used multiple times in a function should be cached in stack variables

_The following instances are missed in the 4naly3er report_

When performing multiple operations on a state variable in a function, it is recommended to cache it f

File: packages/contracts/contracts/ActivePool.sol

//@audit  systemCollShares at line 295
299:  collateral.sharesOf(address(this)) >= systemCollShares,


arialblack14 Q

# QA REPORT

### Summary of low risk issues

| Number      | Issue details                                         | Instances |
| ------------- | ------------------------------------------------------- | :---------: |
| [L-1](#L1)  | Use of`block.timestamp`                               |    20    |
| [L-2](#L3)  | `ecrecover()` not checked for signer address of zero. |     2     |
| [L-3](#L6)  | Avoid hardcoded values.                               |     2     |
| [L-4](#L8)  | Lock pragmas to specific compiler version.            |     4     |

*Total: 4 issues.*

### Summary of non-critical issues

| Number         | Issue details                                                                                | Instances |
| ---------------- | -------------------------------------------------------------------------------------------------------- | :---------: |
| [NC-1](#NC1)   | Consider adding checks for signature malleability.                                                     |     1     |
| [NC-2](#NC3)   | Missing timelock for critical changes.                                                                 |     7     |
| [NC-3](#NC5)   | Use scientific notation (e.g.`1e18`) rather than exponentiation (e.g.`10**18`).                        |     2     |
| [NC-4](#NC6)   | Lines are too long.                                                                                |    11    |
| [NC-5](#NC7)   | For modern and more readable code, update import usages.                                               |    102    |
| [NC-6](#NC11) | Avoid whitespaces while declaring mapping variables.                                                   |    35    |
| [NC-7](#NC12) | Use of`bytes.concat()` instead of `abi.encodePacked()`.                                                |     1     |

*Total: 7 issues.*

---

### Low Risk Issues

### [L-1] Use of `block.timestamp`

##### Description

Block timestamps have historically been used f

87: uint256 endTimestamp = block.timestamp > lastDistributionTime ? lastDistributionTime : block.timestamp;
93: lastIssuanceTimestamp = block.timestamp;
113: lastDistributionTime = block.timestamp.add(distributionPeriod);
114: lastIssuanceTimestamp = block.timestamp;

128: deploymentStartTime = block.timestamp;


zabihullahazadzoi G

## Gas Optimizations

| |Issue|Instances|Estimated Gas Saved|
|-|:-|:-:|-:|
| [GAS-1](#GAS-1) | 'Don't compare boolean expressions to boolean literals' | 1 | 9 |
| [GAS-2](#GAS-2) | Increments can be unchecked to save gas | 11 | 660 |
| [GAS-3](#GAS-3) | `array[index] += amount` is cheaper than `array[index] = array[index] + amount` (or related variants) | 2 | 76 |
| [GAS-4](#GAS-4) | Avoid emitting storage values | 2 | - |
| [GAS-5](#GAS-5) |  Avoid updating storage when the value hasn’t changed | 63 | 50400 |
| [GAS-6](#GAS-6) | Using this to access functions results in an external call, wasting gas | 6 | 600 |
| [GAS-7](#GAS-7) | Using bools for storage incurs overhead | 4 | 400 |
| [GAS-8](#GAS-8) | bytes constants are more efficient than string constants | 11 | - |
| [GAS-9](#GAS-9) | Cache array length outside of loop | 5 | 15 |
| [GAS-10](#GAS-10) | Multiple accesses of the same mapping/array key/index should be cached | 12 | 504 |
| [GAS-11](#GAS-11) | The result of a function call should be cached rather than re-calling the function | 35 | 3500 |
| [GAS-12](#GAS-12) | State variables that are used multiple times in a function should be cached in stack variables | 69 | 6900 |
| [GAS-13](#GAS-13) | Use calldata instead of memory for function arguments that do not get mutated | 6 | 1800 |
| [GAS-14](#GAS-14) | Gas savings can be achieved by changing the model for assigning value to the structure | 8 | 2080 |
| [GAS-15](#GAS-15) | Multiple address/ID mappings can be combined into a single mapping of an address/ID to a struct, where appropriate | 6 | - |
| [GAS-16](#GAS-16) | Consider activating via-ir for deploying | 1 | - |
| [GAS-17](#GAS-17) | Expressions for constant values such as a call to keccak256(), should use immutable rather than constant | 7 | - |
| [GAS-18](#GAS-18) | Constructors can be marked as payable to save deployment gas | 19 | 399 |
| [GAS-19](#GAS-19) | Use custom errors rather than revert()/require() strings to save gas | 150 | 7500 |
|

File: packages/contracts/contracts/CdpManager.sol

 332:         require(redemptionsPaused == false, "CdpManager: Redemptions Paused");

File: packages/contracts/contracts/Governor.sol

 46:         for (uint256 i = 0; i < users.length(); i++) {

 57:             for (uint256 i = 0; i < _usrs.length; i++) {

 76:         for (uint8 i = 0; i < type(uint8).max; i++) {

 84:             for (uint8 i = 0; i < type(uint8).max; i++) {

 98:         for (uint8 i = 0; i < type(uint8).max; i++) {

 107:             for (uint8 i = 0; i < type(uint8).max; i++) {

 122:         for (uint8 i = 0; i < roleIds.length; i++) {

 137:             for (uint256 i = 0; i < _sigs.length; ++i) {


emmac002 Q

# Report

## Low Risk and Non-Critical Issues

| |Issue|Instances|
|-|:-|:-:|
| [LOW-1] | OWNER CAN RENOUNCE OWNERSHIP | 12 |
| [LOW-2] | LOSS OF PRECISION DUE TO ROUNDING | 3 |
| [LOW-3] | INITIALIZE() FUNCTION CAN BE CALLED BY ANYBODY | 1 |
| [LOW-4] | VARIABLE NAME IS CONFUSING | 1 |
| [LOW-5] | HARDCODE THE ADDRESS CAUSES NO FUTURE UPDATES | 6 |
| [LOW-6] | REQUIRE()/REVERT() STATEMENTS SHOULD HAVE DESCRIPTIVE REASON STRINGS | 11 |
| [LOW-7] | RECIPIENT MAY BE ADDRESS(0) | 3 |
| [LOW-8] | MISSING EVENT FOR CRITICAL PARAMETERS INIT AND CHANGE | 6 |
| [N-1] | CONSTANT VALUES SUCH AS A CALL TO KECCAK256(), SHOULD USED TO IMMUTABLE RATHER THAN CONSTANT | 8 |
| [N-2] | FOR FUNCTIONS, FOLLOW SOLIDITY STANDARD NAMING CONVENTIONS | 1 |
| [N-3] | LACK OF EVENT EMISSION AFTER CRITICAL INITIALIZE() FUNCTION | 1 |
| [N-4] | UNUSED CONSTRUCTOR | 1 |
| [N-5] | EMPTY BLOCKS SHOULD BE REMOVED OR EMIT SOMETHING | 2 |
| [N-6] | FLOATING PRAGMA | 4 |
| [N-7] | NOT USING THE NAMED RETURN VARIABLES ANYWHERE IN THE FUNCTION IS CONFUSING | 1 |
| [N-8] | USE REQUIRE INSTEAD OF ASSERT | 20 |
| [N-9] | OPEN TODOS | 2 |
| [N-10] | DUPLICATE IMPORT STATEMENTS | 2 |
| [N-11] | NUMERIC VALUES HAVING TO DO WITH TIME SHOULD USE TIME UNITS FOR READABILITY | 2 |
| [N-12] | LARGE MULTIPLES OF TEN SHOULD USE SCIENTIFIC NOTATION | 1 |
| [N-13] | USE SCIENTIFIC NOTATION (E.G. 1E18) RATHER THAN EXPONENTIATION (E.G. 10**18) | 1 |
| [N-14] | DUPLICATED REQUIRE()/REVERT() CHECKS SHOULD BE REFACTORED TO A MODIFIER OR FUNCTION | 6 |
| [N-15] | COMMENT DOUBLE SPACING | 1 |
| [N-16] | INCONSISTENT NATSPEC FORMAT | 1 |

### [LOW-1] OWNER CAN RENOUNCE OWNERSHIP
Typically, the contract’s owner is the account that deploys the contract. As a result, the owner is able to perform certain privileged activities.

The Openzeppelin’s Ownable used in this project contract implements renounceOwnership. This can represent a certain risk if the ownership is renounced for any other reason than by design. Renouncing owner

File: Ethos-Core/contracts/CollateralConfig.sol

46:    function initialize(
47:        address[] calldata _collaterals,
48:        uint256[] calldata _MCRs,
49:        uint256[] calldata _CCRs
50:    ) external override onlyOwner

85:    function updateCollateralRatios(
86:            address _collateral,
87:            uint256 _MCR,
88:            uint256 _CCR
89:    ) external onlyOwner checkCollateral(_collateral) {

File: Ethos-Core/contracts/ActivePool.sol

71:  function setAddresses(
72:        address _collateralConfigAddress,
73:        address _borrowerOperationsAddress,
74:        address _troveManagerAddress,
75:        address _stabilityPoolAddress,
76:        address _defaultPoolAddress,
77:        address _collSurplusPoolAddress,
78:        address _treasuryAddress,
79:        address _lqtyStakingAddress,
80:        address[] calldata _erc4626vaults
81:    )
82:        external
83:        onlyOwner

132: function setYieldingPercentageDrift(uint256 _driftBps) external onlyOwner {

138: function setYieldClaimThreshold(address _collateral, uint256 _threshold) external onlyOwner {

144: function setYieldDistributionParams(uint256 _treasurySplit, uint256 _SPSplit, uint256 _stakingSplit) external onlyOwner {

214: function manualRebalance(address _collateral, uint256 _simulatedAmountLeavingPool) external onlyOwner {


cryptonue Q

# [L] Lack of duplicate check on `nodeDelegatorQueue`

There is no unique check on nodeDelegatorQueue thus open for potential duplicates of data. Moreover there is no function to remove the nodeDelegatorQueue.

```js
File: LRTDepositPool.sol
162:     function addNodeDelegatorContractToQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin {
163:         uint256 length = nodeDelegatorContracts.length;
164:         if (nodeDelegatorQueue.length + length > maxNodeDelegatorCount) {
165:             revert MaximumNodeDelegatorCountReached();
166:         }
167:
168:         for (uint256 i; i < length;) {
169:             UtilLib.checkNonZeroAddress(nodeDelegatorContracts[i]);
170:             nodeDelegatorQueue.push(nodeDelegatorContracts[i]);
171:             emit NodeDelegatorAddedinQueue(nodeDelegatorContracts[i]);
172:             unchecked {
173:                 ++i;
174:             }
175:         }
176:     }
```

# [NC] redundant variable

as seen there is this code `IERC20 token = IERC20(asset);` which doesn't do anything much, redundant variable assignment, we can just use the `asset` directly rather than create a `token` variable.

```js
File: NodeDelegator.sol
51:     function depositAssetIntoStrategy(address asset)
52:         external
53:         override
54:         whenNotPaused
55:         nonReentrant
56:         onlySupportedAsset(asset)
57:         onlyLRTManager
58:     {
59:         address strategy = lrtConfig.assetStrategy(asset);
60:         IERC20 token = IERC20(asset); // @audit why is this?
61:         address eigenlayerStrategyManagerAddress = lrtConfig.getContract(LRTConstants.EIGEN_STRATEGY_MANAGER);
62:
63:         uint256 balance = token.balanceOf(address(this));
64:
65:         emit AssetDepositIntoStrategy(asset, strategy, balance);
66:
67:         IEigenStrategyManager(eigenlayerStrategyManagerAddress).depositIntoStrategy(IStrategy(strategy), token, balance);
68:     }
```

// Code block 1 (js):
File: LRTDepositPool.sol
162:     function addNodeDelegatorContractToQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin {
163:         uint256 length = nodeDelegatorContracts.length;
164:         if (nodeDelegatorQueue.length + length > maxNodeDelegatorCount) {
165:             revert MaximumNodeDelegatorCountReached();
166:         }
167:
168:         for (uint256 i; i < length;) {
169:             UtilLib.checkNonZeroAddress(nodeDelegatorContracts[i]);
170:             nodeDelegatorQueue.push(nodeDelegatorContracts[i]);
171:             emit NodeDelegatorAddedinQueue(nodeDelegatorContracts[i]);
172:             unchecked {
173:                 ++i;
174:             }
175:         }
176:     }

// Code block 2 (js):
File: NodeDelegator.sol
51:     function depositAssetIntoStrategy(address asset)
52:         external
53:         override
54:         whenNotPaused
55:         nonReentrant
56:         onlySupportedAsset(asset)
57:         onlyLRTManager
58:     {
59:         address strategy = lrtConfig.assetStrategy(asset);
60:         IERC20 token = IERC20(asset); // @audit why is this?
61:         address eigenlayerStrategyManagerAddress = lrtConfig.getContract(LRTConstants.EIGEN_STRATEGY_MANAGER);
62:
63:         uint256 balance = token.balanceOf(address(this));
64:
65:         emit AssetDepositIntoStrategy(asset, strategy, balance);
66:
67:         IEigenStrategyManager(eigenlayerStrategyManagerAddress).depositIntoStrategy(IStrategy(strategy), token, balance);
68:     }


georgits Q

## Use latest Solidity version with a stable pragma statement
Files - [CTokenCash.sol](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/lending/tokens/cCash/CTokenCash.sol), [CTokenModified.sol](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/lending/tokens/cToken/CTokenModified.sol), [CCashDelegate.sol](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/lending/tokens/cCash/CCashDelegate.sol), [CTokenDelegate.sol](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/lending/tokens/cToken/CTokenDelegate.sol), [JumpRateModelV2.sol](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/lending/JumpRateModelV2.sol), [CCash.sol](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/lending/tokens/cCash/CCash.sol), [CErc20.sol](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/lending/tokens/cToken/CErc20.sol), [CTokenInterfacesModifiedCash.sol](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/lending/tokens/cCash/CTokenInterfacesModifiedCash.sol), [cErc20ModifiedDelegator.sol](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/lending/tokens/cErc20ModifiedDelegator.sol)

## Wrong input validation
CTokenCash.sol - [585](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/lending/tokens/cCash/CTokenCash.sol#L585)

CTokenModified.sol - [585](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/lending/tokens/cToken/CTokenModified.sol#L585)

```
 *@param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)
 *@param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)
```
Should be something like `redeemTokensIn != 0 && redeemAmountIn == 0 || redeemTokensIn == 0 && redeemAmountIn != 0` since only of them one can have non-zero value

## `initialize` can be called by anyone
CashKYCSender.s

// Code block 1 (unknown):
*@param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)
 *@param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)

CTokenCash.sol, CTokenModified.sol, CCashDelegate.sol, CTokenDelegate.sol, JumpRateModelV2.sol, CCash.sol, CErc20.sol, CTokenInterfacesModifiedCash.sol, cErc20ModifiedDelegator.sol, CTokenCash.sol#L585, CTokenModified.sol#L585

CTokenCash.sol, CTokenModified.sol, CErc20.sol, CTokenDelegate.sol, JumpRateModelV2.sol, cErc20ModifiedDelegator.sol, CTokenInterfacesModifiedCash.sol, CCash.sol, CCashDelegate.sol


0xhex G

# Gas Optimization

# Summary

| Number | Gas                                                                                | context |
| :----: | :------------------------------------------------------------------------------------------------------- | :-----: |
| [G-01] | Functions guaranteed to revert when called by normal users can be marked payable                         |   25    |
| [G-02] | Use assembly to perform efficient back-to-back calls                                                     |    2    |
| [G-03] | Expressions for constant values such as a call to keccak256(), should use immutable rather than constant |    5    |
| [G-04] | Can make the variable outside the loop to save Gas                                                       |    2    |
| [G-05] | Avoid emitting storage values                                                                            |    2    |
| [G-06] | Avoid contract existence checks by using low level calls                                                 |    3    |
| [G-07] | Use do while loops instead of for loops                                                                  |    5    |
| [G-08] | abi.encode() is less efficient than abi.encodePacked()                                                   |    3    |
| [G-09] | Stack variable used as a cheaper cache for a state variable is only used once                            |    1    |
| [G-10] | Use Assembly To Check For address(0)                                                                     |    8    |

## [G-01] Functions guaranteed to revert when called by normal users can be marked payable

If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.

```solidity
File:  contracts/bridge/SourceBridge.sol
121

File:  contracts/bridge/SourceBridge.sol
121     function setDestinationChainContractAddress(
    string memory destinationChain,
    address contractAddress
  ) external onlyOwner {

136  function pause() external onlyOwner {

145  function unpause() external onlyOwner {

File:  contracts/rwaOracles/RWADynamicOracle.sol
151    function setRange(
    uint256 endTimestamp,
    uint256 dailyInterestRate
  ) external onlyRole(SETTER_ROLE) {

186    function overrideRange(
    uint256 indexToModify,
    uint256 newStart,
    uint256 newEnd,
    uint256 newDailyIR,
    uint256 newPrevRangeClosePrice
  ) external onlyRole(DEFAULT_ADMIN_ROLE) {

241 function pauseOracle() external onlyRole(PAUSER_ROLE) {

248  function unpauseOracle() external onlyRole(DEFAULT_ADMIN_ROLE) {


0xepley Analysis

# 🛠 AI Arena
***In AI Arena you train an AI character to battle in a platform fighting game. Imagine a cross between Pokémon and Super Smash Bros, but the characters are AIs, and you can train them to learn almost any skill in preparation for battle.***

### Summary
| List |Head |Details|
|:--|:----------------|:------|
|a) |Overview of the AI Arena Project| Summary of the whole Protocol |
|b) |Technical Architecture| Architecture of the smart contracts |
|c) |The approach I would follow when reviewing the code | Stages in my code review and analysis |
|d) |Analysis of the code base | What is unique? How are the existing patterns used? "Solidity-metrics" was used  |
|e) |Test analysis | Test scope of the project and quality of tests |
|f) |Security Approach of the Project | Audit approach of the Project |
|g) |In-depth architecture assessment of business logic | Architecture of the Protocol|
|h) |Codebase Quality | Overall Code Quality of the Project |
|i) |Other Audit Reports and Automated Findings | What are the previous Audit reports and their analysis |
|j) |Contract Functionalities| Functionality of different Contracts involved |
|k) |Full representation of the project’s risk model| What are the risks associated with the project |
|l) |Packages and Dependencies Analysis | Details about the project Packages |
|m) |New insights and learning of project from this audit | Things learned from the project |
|n) |Point of improvements | Things that could be improved |

## a) Overview of the AI Arena Project
The AI Arena is a comprehensive blockchain-based ecosystem that integrates NFT (Non-Fungible Token) technology with competitive gaming and an innovative economic model. This ecosystem allows users to own, train, and compete with unique digital fighters represented as NFTs, engaging in ranked battles within a global competitive landscape. Central to its economy is the Neuron ($NRN) token, which facilitates transactions, staking, and rewards within the AI Arena.

Install libraries using forge and compile contracts.

After installing and building contracts I ran this command to execute all the test scripts:


erictee Q

### [N-01] ```require()``` should be used instead of ```assert()```

#### Impact
Prior to solidity version 0.8.0, hitting an assert consumes the remainder of the transaction’s available gas rather than returning it, as ```require()```/```revert()``` do. ```assert()``` should be avoided even past solidity version 0.8.0 as its [documentation](https://docs.soliditylang.org/en/v0.8.14/control-structures.html#panic-via-assert-and-error-via-require) states that “The assert function creates an error of type Panic(uint256). … Properly functioning code should never create a Panic, not even on invalid external input. If this happens, then there is a bug in your contract which you should fix”.

#### Findings:
```
Ethos-Core/contracts/LUSDToken.sol:L312        assert(sender != address(0));

Ethos-Core/contracts/LUSDToken.sol:L313        assert(recipient != address(0));

Ethos-Core/contracts/LUSDToken.sol:L321        assert(account != address(0));

Ethos-Core/contracts/LUSDToken.sol:L329        assert(account != address(0));

Ethos-Core/contracts/LUSDToken.sol:L337        assert(owner != address(0));

Ethos-Core/contracts/LUSDToken.sol:L338        assert(spender != address(0));

Ethos-Core/contracts/TroveManager.sol:L417            assert(_LUSDInStabPool != 0);

Ethos-Core/contracts/TroveManager.sol:L1224            assert(totalStakesSnapshot[_collateral] > 0);

Ethos-Core/contracts/TroveManager.sol:L1279        assert(closedStatus != Status.nonExistent && closedStatus != Status.active);

Ethos-Core/contracts/TroveManager.sol:L1342        assert(troveStatus != Status.nonExistent && troveStatus != Status.active);

Ethos-Core/contracts/TroveManager.sol:L1348        assert(index <= idxLast);

Ethos-Core/contracts/TroveManager.sol:L1414        assert(newBaseRate > 0); // Base rate is always non-zero after redemption

Ethos-Core/contracts/TroveManager.sol:L1489        assert(decayedBaseRate <= DECIMAL_PRECISION);  // The baseRate can decay to 0;

Ethos-Core/contracts/BorrowerOperat

### [N-02] Unused named returns

#### Impact
using both named returns and return statement is not neccessary, removing one of those can improve code clarity. ( see `@audit`)

#### Findings:
1.

// Code block 1 (unknown):
#### Impact
Prior to solidity version 0.8.0, hitting an assert consumes the remainder of the transaction’s available gas rather than returning it, as


0xfave Q

# L-01 Missing zero-address checks
## Impact
Checking addresses against zero-address during initialization or during setting is a security best-practice. However, such checks are missing in all address variable initializations.

Impact: Allowing zero-addresses will lead to contract reverts and force redeployments if there are no setters for such address variables.
## Proof of concept
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L124-L126
https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/amo/UniV3LiquidityAmo.sol#L76-L78
https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/amo/UniV3LiquidityAmo.sol#L274-L287
## Tools Used
manual review

## Recommended Mitigation Steps
add zero address validation
like
```
require(_weth != address(0), "RdpxV2Core: _weth cannot be 0 address");
```

// Code block 1 (unknown):
require(_weth != address(0), "RdpxV2Core: _weth cannot be 0 address");


0x4ka5h G

### G[1] Use arithmetic operating instead using loop for calculating totalWeight adjustment
[Link to github permalink](https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L165-L175)
```
function adjustWeight(
    uint256 _derivativeIndex,
    uint256 _weight
) external onlyOwner {
+    uint256 oldWeight = weights[_derivativeIndex];
+    weights[_derivativeIndex] = _weight;
+    totalWeight = totalWeight - oldWeight + _weight;

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

}
```

The code above shows a function called `adjustWeight` that allows the owner to adjust the weight of a derivative. The function has been optimized to reduce gas consumption by eliminating the loop and instead, tracking the old weight, updating the new weight, and recalculating the total weight with a simple arithmetic operation.

This new code adds a variable `oldWeight` to store the original weight of the derivative before updating it. Then, the function updates the derivative's weight with the new weight provided by the owner and recalculates the total weight by subtracting the old weight and adding the new weight. This eliminates the need for a loop that calculates the total weight of all derivatives.

## G[2] Use arithmetic operating instead using loop for new totalWeight calculating
[Link to github permalink](https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L182-L195)
```
function addDerivative(
        address _contractAddress,
        uint256 _weight
    ) external onlyOwner {
        derivatives[derivativeCount] = IDerivative(_contractAddress);
        weights[derivativeCount] = _weight;
        derivativeCount++;

       // @remind gas/extra calcualtion
+      totalWeight

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

       // @remind gas/extra calcualtion
+      totalWeight = totalWeight + _weight;

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

// Code block 1 (unknown):
function adjustWeight(
    uint256 _derivativeIndex,
    uint256 _weight
) external onlyOwner {
+    uint256 oldWeight = weights[_derivativeIndex];
+    weights[_derivativeIndex] = _weight;
+    totalWeight = totalWeight - oldWeight + _weight;

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

}


hunter_w3b G

# Gas-Optimization For Badger eBTC

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

**Issue Description**\
Prior versions of Solidity inserted unnecessary contract existence checks for external function calls, wasting gas.

**Proposed Optimization**\
Avoid contract existence checks by using low level calls.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**\
Up to 100 gas per external call by avoiding the EXTCODESIZE check for contract existence.

**Attachments**

- **Code Snippets**

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

183        collateral.transferShares(_account, _shares);

186            ICollSurplusPool(_account).increaseTotalSurplusCollShares(_shares);

272        uint256 oldRate = collateral.getPooledEthByShares(DECIMAL_PRECISION);

274        collateral.transfer(address(receiver), amount);

283        collateral.transferFrom(address(receiver), address(this), amountWithFee);

286        collateral.transfer(feeRecipientAddress, fee);

362        collateral.transferShares(feeRecipientAddress, _shares);

376        uint256 balance = IERC20(token).balanceOf(address(this));

381        IERC20(token).safeTransfer(cachedFeeRecipientAddress, amount);

```

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/ActivePool.sol#L183

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

363        vars.debt = cdpManager.getCdpDebt(_cdpId);

364

// 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: contracts/contracts/ActivePool.sol

183        collateral.transferShares(_account, _shares);

186            ICollSurplusPool(_account).increaseTotalSurplusCollShares(_shares);

272        uint256 oldRate = collateral.getPooledEthByShares(DECIMAL_PRECISION);

274        collateral.transfer(address(receiver), amount);

283        collateral.transferFrom(address(receiver), address(this), amountWithFee);

286        collateral.transfer(feeRecipientAddress, fee);

362        collateral.transferShares(feeRecipientAddress, _shares);

376        uint256 balance = IERC20(token).balanceOf(address(this));

381        IERC20(token).safeTransfer(cachedFeeRecipientAddress, amount);

//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: contracts/contracts/ActivePool.sol

183        collateral.transferShares(_account, _shares);

186            ICollSurplusPool(_account).increaseTotalSurplusCollShares(_shares);

272        uint256 oldRate = collateral.getPooledEthByShares(DECIMAL_PRECISION);

274        collateral.transfer(address(receiver), amount);

283        collateral.transferFrom(address(receiver), address(this), amountWithFee);

286        collateral.transfer(feeRecipientAddress, fee);

362        collateral.transferShares(feeRecipientAddress, _shares);

376        uint256 balance = IERC20(token).balanceOf(address(this));

381        IERC20(token).safeTransfer(cachedFeeRecipientAddress, amount);


SAQ G

## Summary

### Gas Optimization

no | Issue |Instances||
|-|:-|:-:|:-:|
| [G-01] | `Internal` functions only called once can be inlined to save gas | 1 | - |
| [G-02] | Using fixed bytes is cheaper than using string | 5 | - |
| [G-03] | Should use arguments instead of state variable | 2 | - |
| [G-04] | Before transfer of  some functions, we should check some variables for possible gas save | 1 | - |
| [G-05] | Do not calculate constant | 3 | - |
| [G-06] | Use hardcode address instead `address(this)` | 2 | - |
| [G-07] | Pre-increment and pre-decrement are cheaper than +1 ,-1 | 2 | - |

## Gas Optimizations

## [G-01] `Internal` functions only called once can be inlined to save gas

Not inlining costs 20 to 40 gas because of two extra JUMP instructions and additional stack operations needed for function calls.

```solidity
file: /src/FighterFarm.sol

447    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
        internal
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId);
    }

```
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L447C1-L452C6

## [G-02]  Using fixed bytes is cheaper than using string

As a rule of thumb, use bytes for arbitrary-length raw byte data and string for arbitrary-length string (UTF-8) data.
If you can limit the length to a certain number of bytes, always use one of bytes1 to bytes32 because they are much cheaper.

```solidity
file: /src/GameItems.sol

49    string public name = "AI Arena Game Items";

52    string public symbol = "AGI";

```
https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/GameItems.sol#L49C1-L49C48

```solidity
file: /src/AiArenaHelper.sol

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

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

```solidity
file: /src/FighterOps.sol

41        string modelHash;
42        string

// Code block 1 (solidity):
file: /src/FighterFarm.sol

447    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
        internal
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId);
    }

// Code block 2 (solidity):
file: /src/GameItems.sol

49    string public name = "AI Arena Game Items";

52    string public symbol = "AGI";

// Code block 3 (solidity):
file: /src/AiArenaHelper.sol

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

file: /src/FighterFarm.sol

447    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
        internal
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId);
    }

file: /src/GameItems.sol

49    string public name = "AI Arena Game Items";

52    string public symbol = "AGI";

file: /src/AiArenaHelper.sol

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


report

---
sponsor: "Amphora Protocol"
slug: "2023-07-amphora"
date: "2024-04-22"
title: "Amphora Protocol"
findings: "https://github.com/code-423n4/2023-07-amphora-findings/issues"
contest: 266
---

# Overview

## About C4

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

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

During the audit outlined in this document, C4 conducted an analysis of the Amphora Protocol smart contract system written in Solidity. The audit took place between July 21—July 26 2023.

## Wardens

73 Wardens contributed reports to the Amphora Protocol audit:

  1. [minhtrng](https://code4rena.com/@minhtrng)
  2. [said](https://code4rena.com/@said)
  3. [0xComfyCat](https://code4rena.com/@0xComfyCat)
  4. [ljmanini](https://code4rena.com/@ljmanini)
  5. [SanketKogekar](https://code4rena.com/@SanketKogekar)
  6. [emerald7017](https://code4rena.com/@emerald7017)
  7. [ak1](https://code4rena.com/@ak1)
  8. [K42](https://code4rena.com/@K42)
  9. [0xSmartContract](https://code4rena.com/@0xSmartContract)
  10. Musaka ([0x3b](https://code4rena.com/@0x3b) and [ZdravkoHr](https://code4rena.com/@ZdravkoHr))
  11. [Limbooo](https://code4rena.com/@Limbooo)
  12. [DavidGiladi](https://code4rena.com/@DavidGiladi)
  13. [qpzm](https://code4rena.com/@qpzm)
  14. [kutugu](https://code4rena.com/@kutugu)
  15. [giovannidisiena](https://code4rena.com/@giovannidisiena)
  16. [dharma09](https://code4rena.com/@dharma09)
  17. [0xWaitress](https://code4rena.com/@0xWaitress)
  18. [Giorgio](https://code4rena.com/@Giorgio)
  19. [SpicyMeatball](https://code4rena.com/@SpicyMeatball)
  20. [0xbranded](https://code4rena.com/@0xbranded)
  21. [Bauchibred](https://code4rena.com/@Bauchibred)
  22. [hunter\_w3b](https://code4rena.com/@hunter_w3b)

function withdraw(uint256 _susdAmount) external override {
    _withdraw(_susdAmount, _msgSender());
}

  function _withdraw(uint256 _susdAmount, address _target) internal paysInterest whenNotPaused {
    if (reserveAmount == 0) revert USDA_EmptyReserve();
    if (_susdAmount == 0) revert USDA_ZeroAmount();
    if (_susdAmount > this.balanceOf(_msgSender())) revert USDA_InsufficientFunds();
    // Account for the susd withdrawn
    reserveAmount -= _susdAmount;
    sUSD.transfer(_target, _susdAmount);
    _burn(_msgSender(), _susdAmount);

    emit Withdraw(_target, _susdAmount);
  }


0xhacksmithh Q

### [Low-01] While setting ```virtualNftReserves``` Contract doesn't checking Its scaled up or not
According to Code comments
```/// @dev The virtual NFT reserves that a user sets. If it's desired to set the reserves to match 16 NFTs then the
    /// virtual reserves should be set to 16e18. If weights are enabled by setting the merkle root to be non-zero then
    /// the virtual reserves should be set to the sum of the weights of the NFTs; where floor NFTs all have a weight of
    /// 1e18. A rarer NFT may have a weight of 2.3e18 if it's 2.3x more valuable than a floor.
```
Should scaled up by 10e18,
may be creation of pool user may input wrong value
*Instances()*
```
File:
https://github.com/code-423n4/2023-04-caviar/blob/main/src/PrivatePool.sol#L178
```
### [Low-02] Absence Of upper bound for ```changeFee``` During contract initialization and in further fee change functions.
Some upperbound should remain on chageFee parameter. Otherwise Pool owner could front-run and set fee to arbitary amount and draw more fund from user than intended.
*Instances()*
```
File:
https://github.com/code-423n4/2023-04-caviar/blob/main/src/PrivatePool.sol#L179
```

### [Low-03] Functions are expose to re-entrancy attacks
```buy()```, ```sell()```, ```change()```
Now there is no significant affect by reentrancy in pool, but it may affect future protocols that use this protocol as base.
Should use Openzeppelin Reentrancy gaurd when functions making external calls.

```
File:
https://github.com/code-423n4/2023-04-caviar/blob/main/src/PrivatePool.sol#L211-L280
```
### [Low-04] Nft transfer will be failed as is absence of approval
Function directly trying to send Nft Without approval,
First pool have to approve user to transfer Nft on behalf of it.
```solidity
          for (uint256 i = 0; i < tokenIds.length; i++) {
            // transfer the NFT to the caller
            ERC721(nft).safeTransferFrom(address(this), msg.sender, tokenIds[i]); // @audit i think missing approval
```

// Code block 1 (unknown):
Should scaled up by 10e18,
may be creation of pool user may input wrong value
*Instances()*

// Code block 2 (unknown):
### [Low-02] Absence Of upper bound for

// Code block 3 (unknown):
File:
https://github.com/code-423n4/2023-04-caviar/blob/main/src/PrivatePool.sol#L179

// Code block 4 (unknown):
Now there is no significant affect by reentrancy in pool, but it may affect future protocols that use this protocol as base.
Should use Openzeppelin Reentrancy gaurd when functions making external calls.

// Code block 5 (unknown):
### [Low-04] Nft transfer will be failed as is absence of approval
Function directly trying to send Nft Without approval,
First pool have to approve user to transfer Nft on behalf of it.


d3tonator G

###Summary
We measured the gas consumption of the loop using the Solidity compiler version 0.8.0 and compared it to the gas consumption of the same loop with pre-increments and pre-decrements.

Our analysis indicates that using post-increments and post-decrements in for loops can increase gas consumption significantly. Specifically, we observed that the use of post-increments and post-decrements increased the gas consumption of the for loop by approximately 8% compared to the use of pre-increments and pre-decrements.

We note that the observed increase in gas consumption is primarily due to the fact that post-increments and post-decrements require an additional operation to be performed after the loop body has been executed. This operation is necessary to update the loop counter.

###Proof of Concept
During the review, it analyzes that the smart contract contains a for loop, where a variable is incremented or decremented using post-increment and post-decrement operators. Specifically, the code under investigation is as follows:

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

Line 108:           for(uint256 i = 0; i < numCollaterals; i++) {

````

###Recommendations:
Based on our findings, we recommend that Solidity developers avoid the use of post-increments and post-decrements in for loops. Instead, developers should use pre-increments and pre-decrements wherever possible, as these operators do not require an additional operation to update the loop counter and are therefore more gas-efficient.

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

Line 108:           for(uint256 i = 0; i < numCollaterals; i++) {