klau5 Q

# proposeCallContract: Incorrectly stores the description

## Links to affected code

[https://github.com/code-423n4/2024-01-salty/blob/aab6bbc6fe49d4dd37becc7bbd0c847ec4a7c1e6/src/dao/Proposals.sol#L218](https://github.com/code-423n4/2024-01-salty/blob/aab6bbc6fe49d4dd37becc7bbd0c847ec4a7c1e6/src/dao/Proposals.sol#L218)

## Impact

It incorrectly stores the description. This may prevent the description from being retrieved offchain.

## Proof of Concept

```solidity
function proposeCallContract( address contractAddress, uint256 number, string calldata description ) external nonReentrant returns (uint256 ballotID)
{
    require( contractAddress != address(0), "Contract address cannot be address(0)" );

    string memory ballotName = string.concat("callContract:", Strings.toHexString(address(contractAddress)) );
@>  return _possiblyCreateProposal( ballotName, BallotType.CALL_CONTRACT, contractAddress, number, description, "" );
}
```

When calling `_possiblyCreateProposal`, it passes the `description` as the `string1` parameter. An empty string is stored as description. Therefore, the description may not appear when retrieved offchain.

## Tools Used

Manual Review

## Recommended Mitigation Steps

Pass the `description` as the `string2` parameter.

```diff
function proposeCallContract( address contractAddress, uint256 number, string calldata description ) external nonReentrant returns (uint256 ballotID)
{
    require( contractAddress != address(0), "Contract address cannot be address(0)" );

    string memory ballotName = string.concat("callContract:", Strings.toHexString(address(contractAddress)) );
-   return _possiblyCreateProposal( ballotName, BallotType.CALL_CONTRACT, contractAddress, number, description, "" );
+   return _possiblyCreateProposal( ballotName, BallotType.CALL_CONTRACT, contractAddress, number, "", description );
}
```

# withdraw - Can leave less than DUST

## Links to affected code

[https://github.com/code-423n4/2024-01-salty/blob/aab6bbc6fe49d

# withdraw - Can leave less than DUST

## Links to affected code

[https://github.com/code-423n4/2024-01-salty/blob/aab6bbc6fe49d4dd37becc7bbd0c847ec4a7c1e6/src/pools/Pools.sol#L222-L224](https://github.com/code-423n4/2024-01-salty/blob/aab6bbc6fe49d4dd37becc7bbd0c847ec4a7c1e6/src/pools/Pools.sol#L222-L224)

## Impact

It can leave a deposit amount smaller than DUST.

## Proof of Concept

It does not check whether the remaining `_userDeposits` after withdrawal is more than DUST. You should avoid depositing less than DUST because you won't be able to get it out later unless you deposit it.

// Code block 1 (solidity):
function proposeCallContract( address contractAddress, uint256 number, string calldata description ) external nonReentrant returns (uint256 ballotID)
{
    require( contractAddress != address(0), "Contract address cannot be address(0)" );

    string memory ballotName = string.concat("callContract:", Strings.toHexString(address(contractAddress)) );
@>  return _possiblyCreateProposal( ballotName, BallotType.CALL_CONTRACT, contractAddress, number, description, "" );
}

// Code block 2 (diff):
function proposeCallContract( address contractAddress, uint256 number, string calldata description ) external nonReentrant returns (uint256 ballotID)
{
    require( contractAddress != address(0), "Contract address cannot be address(0)" );

    string memory ballotName = string.concat("callContract:", Strings.toHexString(address(contractAddress)) );
-   return _possiblyCreateProposal( ballotName, BallotType.CALL_CONTRACT, contractAddress, number, description, "" );
+   return _possiblyCreateProposal( ballotName, BallotType.CALL_CONTRACT, contractAddress, number, "", description );
}


0xMango Q

## Removing the last element of ```reserveAsset``` via the ```addAssetTotokenReserves()``` function does not properly update the ```reserveIndex``` mapping.

As mentioned in the #dopex-aug21 chat, further assets will be added to this array. ("BTC", "CRV")
The core contract makes much use of reserveIndes["TOKEN_NAME"] as a reliable way to interact with
the correct element. Normaly removing an element will set the value of reserveIndex["Said symbol"]
to 0. But removing the last element, does not update this, possibly making the contract think,
the element is still there if substituted with another token.

Example: Say we have ```[ZERO, WETH, RDPX, DPXETH, CRV]```.
The indexs:
```
reserveIndex["RDPX"] will be 2
reserveIndex["CRV"] will be 4.
```
Removing RDPX, will update the reserveIndex["RDPX"] to 0.
Removing CRV. The reserveIndex["CRV"] remains 4.
Furthermore having removed CRV & adding BTC to the array will mess with accounting.
New Array having removed CRV, added BTC:
```
[ZERO, WETH, RDPX, DPXETH, BTC]
```
If any contracts now read from reserveIndex["CRV"], they will be directed to the BTC block,
possibly transfering or burning the wrong token.

POC: Works as child of ```Setup.t.sol```
```
    function testAddReserve() public {
        // Using Setup.t.sol from sponsor as environment.
        // Adding Crv as the last asset:
        rdpxV2Core.addAssetTotokenReserves(
            address(0x82938347),
            "Crv"
        );

        (address crvAddress, uint256 crvBal, string memory crvSymb) = rdpxV2Core.reserveAsset(4);

        // Removes rdpx from reserveAssets array:
        rdpxV2Core.removeAssetFromtokenReserves(crvSymb);
        // Adds rdpx back as last element:
        rdpxV2Core.addAssetTotokenReserves(
            address(0xb1b1b1bb1),
            "BTC"
        );
        console.log("Ideally; rdpxV2Core.reserveIndex(crvSymbol) = 0 since it was removed.");

        console.log("State of array after removing Crv:");
        for(ui

// Code block 1 (unknown):
reserveIndex["RDPX"] will be 2
reserveIndex["CRV"] will be 4.

// Code block 2 (unknown):
[ZERO, WETH, RDPX, DPXETH, BTC]


T1MOH Q

# [L-01] Keep maximum length line at 120 according to solidity style guide

Description
Maximum line length is 120. Described in docs https://docs.soliditylang.org/en/v0.8.19/style-guide.html#maximum-line-length

You exceed this limit here:

https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/GrantFund.sol#L50

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    function _getMinimumThresholdPercentage() internal view returns (uint256) {
        // default minimum threshold is 50
        if (_fundedExtraordinaryProposals.length == 0) {
            return 0.5 * 1e18;
        }
        // minimum threshold increases according to the number of funded EFM proposals
        else {
            return 0.5 * 1e18 + (_fundedExtraordinaryProposals.length * (0.05 * 1e18));
        }
    }

    function _getMinimumThresholdPercentage() internal view returns (uint256) {
        // default minimum threshold is 50
        // minimum threshold increases according to the number of funded EFM proposals
        return 0.5 * 1e18 + (_fundedExtraordinaryProposals.length * (0.05 * 1e18));
    }

GrantFund.sol#L50, ExtraordinaryFunding.sol#L62, ExtraordinaryFunding.sol#L70, ExtraordinaryFunding.sol#L92, ExtraordinaryFunding.sol#L105, Funding.sol#L110, StandardFunding.sol#L310, StandardFunding.sol#L349, StandardFunding.sol#L355, StandardFunding.sol#L372, StandardFunding.sol#L421, StandardFunding.sol#L438, StandardFunding.sol#L541, StandardFunding.sol#L556, StandardFunding.sol#L578, StandardFunding.sol#L706

StandardFunding.sol, Funding.sol, ExtraordinaryFunding.sol, GrantFund.sol


catellatech Q

`Dear Caviar Team, as we have gone through each contract within the scope, we have noticed good practices that have been implemented. However, we have identified some inconsistencies that we recommend addressing. We understand that every team has a different level of good practices, but we believe that at least 90% of the recommendations in the following report should be applied for better gas efficiency, readability, and most importantly, safety.`

`Note: We have provided a description of the situation and recommendations to follow, including articles and resources we have created to help identify the problem and address it quickly, and to implement them in future projects.`

### Issues
| Letter | Name | Description |
|:--:|:-------:|:-------:|
| L  | Low risk | Potential risk |
| NC |  Non-critical | Non risky findings |
| R  | Refactor | Changing the code |

| Total Found Issues | 20 |
|:--:|:--:|

### Low Risk
| Count | Explanation | Instances |
|:--:|:-------|:--:|
| [L-01] | ADD A TIMELOCK TO CRITICAL FUNCTIONS | 1 |
| [L-02] | IN THE EVENTS, INCLUDE THE OLD AND NEW VALUES OF THE UPDATED PARAMETERS TO TRACK THE CHANGES MADE  | 3 |
| [L-03] | MISSING EVENTS FOR ONLY FUNCTIONS THAT CHANGE CRITICAL PARAMETERS | 3 |
| [L-04] | USE THE OPENZEPPELIN SAFECAST LIBRARY FOR CRITICAL FUNCTIONS | 2 |

| Total Low Issues | 4 | Total Instances | 9 |
|:--:|:--:|:--:|--:|

### Non-Critical
| Count | Explanation | Instances |
|:--:|:-------|:--:|
| [N-01] | USE OF FLOATING PRAGMA | all contracts |
| [N-02] | MANDATORY CHECKS FOR EXTRA SAFETY IN THE SETTERS  | 2 |
| [N-03] | FUNCTION WRITING THAT DOES NOT COMPLY WITH THE SOLIDITY STYLE GUIDE | 1 |
| [N-04] | MISSING EMERGENCY STOP (CIRCUIT BREAKER) PATTERN | 4 |
| [N-05] | TAKE ADVANTAGE OF CUSTOM ERROR'S RETURN VALUE PROPERTY | all the contracts |
| [N-06] | USE THE LATEST UPDATED VERSION OF OPENZEPPELIN DEPENDENCIES | |
| [N-07] | NEED FUZZING TEST | all contracts |
| [N-08] | USE OF BYTES.CONCAT() INSTEAD OF ABI.ENCODEPACKED

main/src/Factory.sol

141:  function setProtocolFeeRate(uint16 _protocolFeeRate) public onlyOwner

## [L-03] MISSING EVENTS FOR ONLY FUNCTIONS THAT CHANGE CRITICAL PARAMETERS
The afunctions that change critical parameters should emit events. Events allow capturing the changed parameters so that off-chain tools/interfaces can register such changes with timelocks that allow users to evaluate them and consider if they would like to engage/exit based on how they perceive the changes as affecting the trustworthiness of the protocol or profitability of the implemented financial services. The alternative of directly querying on-chain contract state for such changes is not considered practical for most users/usages.

missing events and timelocks do not promote transparency and if such changes immediately affect users' perception of fairness or trustworthiness, they could exit the protocol causing a reduction in liquidity which could negatively impact protocol TVL and reputation.

### PROOF OF CONCEPT


leegh Q

## [N-01] Function names should be camelCase.
```solidity
File: packages/contracts/contracts/BorrowerOperations.sol

824:    function _requireCdpisActive(ICdpManager _cdpManager, bytes32 _cdpId) internal view {
```
[[L824](https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L824)]

## [N-02] Use enum values instead of numerics.
CDP status are defined in an enum. Use the enum values instead of numerics when using CDP status.
```solidity
File: packages/contracts/contracts/BorrowerOperations.sol

826:        require(status == 1, "BorrowerOperations: Cdp does not exist or is closed");

831:        require(status == 0, "BorrowerOperations: Cdp is active or has been previously closed");
```
[[L826](https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L826), [L831](https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L831)]

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

824:    function _requireCdpisActive(ICdpManager _cdpManager, bytes32 _cdpId) internal view {

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

826:        require(status == 1, "BorrowerOperations: Cdp does not exist or is closed");

831:        require(status == 0, "BorrowerOperations: Cdp is active or has been previously closed");

File: packages/contracts/contracts/BorrowerOperations.sol

824:    function _requireCdpisActive(ICdpManager _cdpManager, bytes32 _cdpId) internal view {

File: packages/contracts/contracts/BorrowerOperations.sol

826:        require(status == 1, "BorrowerOperations: Cdp does not exist or is closed");

831:        require(status == 0, "BorrowerOperations: Cdp is active or has been previously closed");


JCK G

| Number | 	Issue | Instances |
|--------|--------|-----------|
|[G-01]| Cache external calls outside of loop to avoid re-calling function on each iteration   | 1 |
|[G-02]| Use assembly to validate msg.sender | 43 |
|[G-03]| State variables should be cached in stack variables rather than re-reading them from storage   | 30 |
|[G-04]| Use assembly to reuse memory space when making more than one external call   | 15 |
|[G-05]| Using delete statement can save gas | 2 |
|[G-06]| Use hardcoded address instead of address(this)   | 20 |
|[G-07]| Emit local variables instead of state variable (Save ~100 Gas)   | 14 |
|[G-08]| Avoid calling the same internal function multiple times   | 1 |
|[G-09]| Using assembly to revert with an error message   | 131 |
|[G-10]| Shorten arrays with inline assembly   | 19 |
|[G-11]| Don’t make variables public unless necessary   | 50 |
|[G-12]| When using storage instead of memory, we should cache any fields that need to be re-read in stack variables   | 7 |
|[G-13]| Use constants for variables that don’t change (Save a storage SLOT: 2200 Gas)   | 2 |
|[G-14]| Validate all parameters first before performing any other operations if there’s no side effects   | 6 |
|[G-15]| Use the already cached variable instead of reading from storage (Save 1 SLOAD: 100 Gas)   | 2 |
|[G-16]| Use uint256(1)/uint256(2) instead for true and false boolean states   | 12 |
|[G-17]| Add unchecked {} for subtractions where the operands can’t underflow because of previous checks   | 31 |
|[G-18]| Avoid contract existence checks by using low level calls   | 7 |

## [G-01] Cache external calls outside of loop to avoid re-calling function on each iteration

Performing STATICCALLs that do not depend on variables incremented in loops should always try to be avoided within the loop. In the following instances, we are able to cache the external calls outside of the loop to save a STATICCALL (100 gas) per loop iteration.

Cache minimumCollateralRatioPercent() external funct

file: blob/main/src/stable/CollateralAndLiquidity.sol

321   for ( uint256 i = startIndex; i <= endIndex; i++ )
				{
				address wallet = _walletsWithBorrowedUSDS.at(i);

				// Determine the minCollateralValue a user needs to have based on their borrowedUSDS
				uint256 minCollateralValue = (usdsBorrowedByUsers[wallet] * stableConfig.minimumCollateralRatioPercent()) / 100;

				// Determine minCollateral in terms of minCollateralValue
				uint256 minCollateral = (minCollateralValue * totalCollateralShares) / totalCollateralValue;

				// Make sure the user has at least minCollateral
				if ( userShareForPool( wallet, collateralPoolID ) < minCollateral )
					liquidatableUsers[count++] = wallet;
				}

file: blob/main/src/dao/Proposals.sol

86    if ( msg.sender != address(exchangeConfig.dao() ) )

98    require( ! _userHasActiveProposal[msg.sender], "Users can only have one active proposal at a time" );

124   require( msg.sender == address(exchangeConfig.dao()), "Only the DAO can create a confirmation proposal" );

132   require( msg.sender == address(exchangeConfig.dao()), "Only the DAO can mark a ballot as finalized" );


Aamir Q

## Summary

| severity       | Issues                                                                                | Instances |
| -------------- | ----------------------------------------------------------------------------------------------------------------- | --------- |
| [[L-0](#low0)] | Updating `maxNodeDelegatorCount` less than `nodeDelegatorQueue` should not be allowed.                            | 1         |
| [[L-1](#low1)] | `LRTConfig::updateAssetDepositLimit()` should not let asset deposit limit to set below the current deposit amount | 1         |

---

## Low

### [L-0] Updating `maxNodeDelegatorCount` less than `nodeDelegatorQueue` should not be allowed.

`LRTDepositPool::updateMaxNodeDelegatorCount(...)` does not check if the new max value is more than `nodeDelegatorQueue` length or not. If a value less than `nodeDelegatorQueue` length(or we can current number of active delegator) is used to call this function then it will not revert and will set that as `maxNodeDelegatorCount`. Now this will cause DoS in `addNodeDelegatorContractToQueue` due to below condition:

```Javascript
File: 2023-11-kelp/src/LRTDepositPool.sol

        if (nodeDelegatorQueue.length + length > maxNodeDelegatorCount) {
            revert MaximumNodeDelegatorCountReached();
        }
```

Github: [164-166](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTDepositPool.sol#L164C1-L166C10)

This condition will always met as the `maxNodeDelegatorCount` will always be less than `nodeDelegatorQueue.length + length`. In order for this to work again, the admin will have to call `LRTDepositPool::updateMaxNodeDelegatorCount(...)` again to update the max count.

#### PoC:

Test that proves that: [Test](https://github.com/Aamirusmani1552/kelp-audit/blob/a5566a18a540eaa34dd1c03e9c9a5c5df62a977e/test/LRTDepositPoolTest.t.sol#L530)

#### Recommendation:

It is recommended to add the following check

---

### [L-1] `LRTConfig::updateAssetDepositLimit(...)` should not let asset deposit limit to set below the current deposit amount

`LRTConfig::updateAssetDepositLimit(...)` does not check if the current asset Deposit limit is less than the current deposits for the asset. Because of this, the new limit will be set below current deposits and it will cause `LRTConfig::getAssetCurrentLimit(...)` to always revert due to underflow.

#### PoC:

Here is a test that proves that: [Test](https://github.com/Aamirusmani1552/kelp-audit/blob/a5566a18a540eaa34dd1c03e9c9a5c5df62a977e/test/LRTDepositPoolTest.t.sol#L228C5-L248C2)

#### Recommendation:

It is recommended to add the following check

// Code block 1 (Javascript):
File: 2023-11-kelp/src/LRTDepositPool.sol

        if (nodeDelegatorQueue.length + length > maxNodeDelegatorCount) {
            revert MaximumNodeDelegatorCountReached();
        }


foxb868 Analysis

## Overview

Kelp is a DAO-governed protocol that allows restaking of liquid staked assets like Lido's stETH to further compound yields. The key components are:

- **LRTConfig** - stores protocol configuration and contract addresses
- **LRTDepositPool** - allows users to deposit assets
- **NodeDelegator** - delegates assets to strategies
- **LRTOracle** - provides asset price feeds
- **RSETH** - receipt token representing deposited assets

**LRTConfig**

This contract stores critical protocol configuration like supported assets and contract addresses. It is the source of truth for integrations.

**Risks**:
- The admin can arbitrarily set any contract address, like LRTDepositPool. This could redirect user funds.

https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTConfig.sol#L165-L167

```solidity
    function setContract(bytes32 contractKey, address contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {
        _setContract(contractKey, contractAddress);
    }
```

- Assets could be added to the supported list without proper preparations. User funds could become stuck.

https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTConfig.sol#L73-L75

```solidity
    function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {
        _addNewSupportedAsset(asset, depositLimit);
    }
```

- No validation that set strategies match expected asset types. Could set a ETH strategy for DAI.

**Mitigations**:
- Use code hash checks before trusting contractMap addresses.
- Require assets have a non-zero strategy before accepting deposits.
- Make config immutable once stable.

**LRTDepositPool**

This is the user entry point to make deposits. It controls pool balances.

**Risks**:
- Arbitrary tokens can be transfered to NodeDelegators without input validation.

https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e4

// Code block 1 (solidity):
function setContract(bytes32 contractKey, address contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {
        _setContract(contractKey, contractAddress);
    }


Giorgio Q

## Ineffective deadline on decreaseLiquidity()

##Links

https://github.com/code-423n4/2024-03-revert-lend/blob/435b054f9ad2404173f36f0f74a5096c894b12b7/src/V3Vault.sol#L1072-L1076

## Vulnerability details

Using block.timestamp as the deadline argument when interacting with the Uniswap NFT Position Manager renders the deadline ineffective and defeats its intended purpose.

## Impact

Transaction may remain pending in the mempool, transactions can be maliciously executed at a later point, optmizing arbitrage on the MEV side.

## POC

[Here](https://github.com/code-423n4/2024-03-revert-lend/blob/435b054f9ad2404173f36f0f74a5096c894b12b7/src/V3Vault.sol#L1072-L1076)

```solidity
      if (liquidity > 0) {
            nonfungiblePositionManager.decreaseLiquidity(
                INonfungiblePositionManager.DecreaseLiquidityParams(tokenId, liquidity, 0, 0, block.timestamp)
            );
        }
```

We can see that block.timestamp is used as an argument, which will result in no deadline for the liquidity "swap".

## Mitigation route

Consider adding a parameter for the swap deadline.

## Use answer <= 0 instead answer < 0

## Link

https://github.com/code-423n4/2024-03-revert-lend/blob/435b054f9ad2404173f36f0f74a5096c894b12b7/src/V3Oracle.sol#L338

## Description

Under uncommon circumstances price feeds may return 0 which isn't desirable behavior, so it is best to add checks to avoid such conditions.

## Impact

The usage of 0 price is devastating to the protocol

## POC

```
        if (updatedAt + feedConfig.maxFeedAge < block.timestamp || answer < 0) {
```

As we can see above, if 0 is returned it will be accepted, this is not desirable behavior

## Mitigation route

Do use `answer <= 0` instead

// Code block 1 (solidity):
if (liquidity > 0) {
            nonfungiblePositionManager.decreaseLiquidity(
                INonfungiblePositionManager.DecreaseLiquidityParams(tokenId, liquidity, 0, 0, block.timestamp)
            );
        }

// Code block 2 (unknown):
if (updatedAt + feedConfig.maxFeedAge < block.timestamp || answer < 0) {


arialblack14 Q

# QA REPORT

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

### Description
Block timestamps have historically been used for a variety of applications, such as entropy for random numbers (see the *[Entropy Illusion](https://hacken.io/discover/most-common-smart-contract-vulnerabilities/#Entropy_Illusion)* for further details), locking funds for periods of time, and various state-changing conditional statements that are time-dependent. Miners have the ability to adjust timestamps slightly, which can prove to be dangerous if block timestamps are used incorrectly in smart contracts.

### ✅ Recommendation
Use oracle instead of `block.timestamp`

#### *Instances(7):*
File: [2023-01-ondo/contracts/cash/CashManager.sol](https://github.com/code-423n4/2023-01-ondo/tree/main/contracts/cash/CashManager.sol#L175 )
```solidity
175: block.timestamp -
176: (block.timestamp % epochDuration);
577: uint256 epochDifference = (block.timestamp - currentEpochStartTimestamp) /
584: block.timestamp -
585: (block.timestamp % epochDuration);
```
File: [2023-01-ondo/contracts/cash/kyc/KYCRegistry.sol](https://github.com/code-423n4/2023-01-ondo/tree/main/contracts/cash/kyc/KYCRegistry.sol#L92 )
```solidity
92: require(block.timestamp <= deadline, "KYCRegistry: signature expired");
```
File: [2023-01-ondo/contracts/lending/OndoPriceOracleV2.sol](https://github.com/code-423n4/2023-01-ondo/tree/main/contracts/lending/OndoPriceOracleV2.sol#L294 )
```solidity
294: (updatedAt >= block.timestamp - maxChainlinkOracleTimeDelay),
```

## [L-2] Use `call()` instead of `transfer()`

### Description
The `transfer()` function only allows the recipient to use 2300 gas. If the recipient uses more than that, transfers will fail. In the future gas costs might change increasing the likelihood of that happening.
Keep in mind that `call()` introduces the risk of reentrancy, but as the code follows the CEI pattern it should be fine.

### ✅ Recommendation
Replace `transfer()` calls with `call()`, keep in mind to check whether th

// Code block 1 (solidity):
175: block.timestamp -
176: (block.timestamp % epochDuration);
577: uint256 epochDifference = (block.timestamp - currentEpochStartTimestamp) /
584: block.timestamp -
585: (block.timestamp % epochDuration);

// Code block 2 (solidity):
92: require(block.timestamp <= deadline, "KYCRegistry: signature expired");

// Code block 3 (solidity):
294: (updatedAt >= block.timestamp - maxChainlinkOracleTimeDelay),

175: block.timestamp -
176: (block.timestamp % epochDuration);
577: uint256 epochDifference = (block.timestamp - currentEpochStartTimestamp) /
584: block.timestamp -
585: (block.timestamp % epochDuration);

92: require(block.timestamp <= deadline, "KYCRegistry: signature expired");

294: (updatedAt >= block.timestamp - maxChainlinkOracleTimeDelay),


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 < exCallData.length; ++i) {``` [L127](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/factory/CashFactory.sol#L127)
1. ```for (uint256 i = 0; i < exCallData.length; ++i) {``` [L137](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/factory/CashKYCSenderFactory.sol#L137)
1. ```for (uint256 i = 0; i < exCallData.length; ++i) {``` [L137](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/factory/CashKYCSenderReceiverFactory.sol#L137)
1. ```for (uint256 i = 0; i < length; i++) {``` [L163](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/kyc/KYCRegistry.sol#L163)
1. ```for (uint256 i = 0; i < length; i++) {``` [L180](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/kyc/KYCRegistry.sol#L180)
1. ```for (uint256 i = 0; i < size; ++i) {``` [L750](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/CashManager.sol#L750)
1. ```for (uint256 i = 0; i < size; ++i) {``` [L786](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/CashManager.sol#L786)
1. ```for (uint256 i = 0; i < size; ++i) {``` [L933](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/CashManager.sol#L933)
1. ```for (uint256 i = 0; i < exCallData.length; ++i) {``` [L961](https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/CashManager.sol#L961)

**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 c

// 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; }
}

CashFactory.sol#L127, CashKYCSenderFactory.sol#L137, CashKYCSenderReceiverFactory.sol#L137, KYCRegistry.sol#L163, KYCRegistry.sol#L180, CashManager.sol#L750, CashManager.sol#L786, CashManager.sol#L933, CashManager.sol#L961

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


0xmystery Q

## Unusable native transfer logic in RdpxDecayingBonds.emergencyWithdraw
The `RdpxDecayingBonds` contract is not inherently designed to accept native tokens, highlighted by the absence of a `receive` or `fallback` function. This makes the native transfer logic of `emergencyWithdraw` function unusable unless in the rare and unconventional event that another contract sends native tokens to `RdpxDecayingBonds.sol` using the `selfDestruct` method. This would allow native tokens to accrue in a manner that's unexpected and not immediately apparent. The presence of such funds can be perplexing, especially given the contract's design which suggests it shouldn't typically handle native tokens. Fortunately, the embedded `emergencyWithdraw` function can be invoked by administrators to reclaim these inadvertently received tokens, mitigating the risk of irretrievable funds.

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

```solidity
  /**
   * @notice Transfers all funds to msg.sender
   * @dev    Can only be called by the owner
   * @param  tokens The list of erc20 tokens to withdraw
   * @param  transferNative Whether should transfer the native currency
   * @param  to The address to transfer the funds to
   * @param  amount The amount to transfer
   * @param  gas The gas to use for the transfer
   **/
  function emergencyWithdraw(
    address[] calldata tokens,
    bool transferNative,
    address payable to,
    uint256 amount,
    uint256 gas
  ) external onlyRole(DEFAULT_ADMIN_ROLE) {
    _whenPaused();
    if (transferNative) {
      (bool success, ) = to.call{ value: amount, gas: gas }("");
      require(success, "RdpxReserve: transfer failed");
    }
    IERC20WithBurn token;

    for (uint256 i = 0; i < tokens.length; i++) {
      token = IERC20WithBurn(tokens[i]);
      token.safeTransfer(msg.sender, token.balanceOf(address(this)));
    }
  }
```
The protocol should decide with clarity if the contract sho

  /// @notice Precision used for prices, percentages and other calculations
  uint256 public constant DEFAULT_PRECISION = 1e8;

  /// @notice rDPX Ratio required when bonding
  uint256 public constant RDPX_RATIO_PERCENTAGE = 25 * DEFAULT_PRECISION;

// Code block 1 (solidity):
/**
   * @notice Transfers all funds to msg.sender
   * @dev    Can only be called by the owner
   * @param  tokens The list of erc20 tokens to withdraw
   * @param  transferNative Whether should transfer the native currency
   * @param  to The address to transfer the funds to
   * @param  amount The amount to transfer
   * @param  gas The gas to use for the transfer
   **/
  function emergencyWithdraw(
    address[] calldata tokens,
    bool transferNative,
    address payable to,
    uint256 amount,
    uint256 gas
  ) external onlyRole(DEFAULT_ADMIN_ROLE) {
    _whenPaused();
    if (transferNative) {
      (bool success, ) = to.call{ value: amount, gas: gas }("");
      require(success, "RdpxReserve: transfer failed");
    }
    IERC20WithBurn token;

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


tsvetanovv Q

## [QA-01] Use latest Solidity version

Solidity pragma versioning should be upgraded to latest available version. Currently the solidity version in contracts is 0.8.12 which was found to possess some bugs.

***

## [QA-02] Use stable pragma statement

Using a floating pragma `^0.8.12` statement is discouraged as code can compile to different bytecodes with different compiler versions. Use a stable pragma statement to get a deterministic bytecode.

***

## [QA-03] USE NAMED IMPORTS INSTEAD OF PLAIN `IMPORT ‘FILE.SOL’

`BaseSmartAccount.sol`:

```
import "@account-abstraction/contracts/interfaces/IAccount.sol";
import "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import "./common/Enum.sol";
```
`SmartAccount.sol`:

```
import "./libs/LibAddress.sol";
import "./BaseSmartAccount.sol";
import "./common/Singleton.sol";
import "./base/ModuleManager.sol";
import "./base/FallbackManager.sol";
import "./common/SignatureDecoder.sol";
import "./common/SecuredTokenTransfer.sol";
import "./interfaces/ISignatureValidator.sol";
import "./interfaces/IERC165.sol";

```
`EntryPoint.sol`:

```
import "../interfaces/IAccount.sol";
import "../interfaces/IPaymaster.sol";
import "../interfaces/IAggregatedAccount.sol";
import "../interfaces/IEntryPoint.sol";
import "../utils/Exec.sol";
import "./StakeManager.sol";
import "./SenderCreator.sol";
```

`StakeManager.sol`:
```
import "../interfaces/IStakeManager.sol";
```
`Executor.sol`:
```
import "../common/Enum.sol";
```
`FallbackManager.sol`:
```
import "../common/SelfAuthorized.sol";
```
`ModuleManager.sol `:
```
import "../common/Enum.sol";
import "../common/SelfAuthorized.sol";
import "./Executor.sol";
```
`DefaultCallbackHandler.sol`:
```
import "../interfaces/ERC1155TokenReceiver.sol";
import "../interfaces/ERC721TokenReceiver.sol";
import "../interfaces/ERC777TokensRecipient.sol";
import "../interfaces/IERC165.sol";
```
`VerifyingSingletonPaymaster.sol`:
```
import "../../BasePaymaster.sol";
import "../../PaymasterHelpe

// Code block 1 (unknown):
import "@account-abstraction/contracts/interfaces/IAccount.sol";
import "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import "./common/Enum.sol";

// Code block 2 (unknown):
import "./libs/LibAddress.sol";
import "./BaseSmartAccount.sol";
import "./common/Singleton.sol";
import "./base/ModuleManager.sol";
import "./base/FallbackManager.sol";
import "./common/SignatureDecoder.sol";
import "./common/SecuredTokenTransfer.sol";
import "./interfaces/ISignatureValidator.sol";
import "./interfaces/IERC165.sol";

// Code block 3 (unknown):
import "../interfaces/IAccount.sol";
import "../interfaces/IPaymaster.sol";
import "../interfaces/IAggregatedAccount.sol";
import "../interfaces/IEntryPoint.sol";
import "../utils/Exec.sol";
import "./StakeManager.sol";
import "./SenderCreator.sol";

// Code block 4 (unknown):
import "../interfaces/IStakeManager.sol";

// Code block 5 (unknown):
import "../common/Enum.sol";

// Code block 6 (unknown):
import "../common/SelfAuthorized.sol";

// Code block 7 (unknown):
import "../common/Enum.sol";
import "../common/SelfAuthorized.sol";
import "./Executor.sol";

// Code block 8 (unknown):
import "../interfaces/ERC1155TokenReceiver.sol";
import "../interfaces/ERC721TokenReceiver.sol";
import "../interfaces/ERC777TokensRecipient.sol";
import "../interfaces/IERC165.sol";


LethL G

## Findings Summary

|  | Issue | Instances |
|---|---|---|
| Gas-1 | `<x> += <y>` costs more gas than `<x> = <x> + <y>` for state variables | 9 |
| Gas-2 | Use of Named Returns for Local Variables Saves Gas | 35 |
| Gas-3 | Using a ternary operator instead of an "if-else" statement | 5 |
| Gas-4 | Expressions for constant values such as a call to `keccak256()`, should use immutable rather than constant | 8 |
| Gas-5 | Pre-calculate the hardcoded hash with `keccak256()` before and only use the result to save gas | 10 |
| Gas-6 | Using require instead of assert | 20 |

### [Gas-1] `<x> += <y>` costs more gas than `<x> = <x> + <y>` for state variables

Using `x = x+y` instead of `x += y` can help to save gas.
Similarly, using `<x> -= <y>` costs more gas than  `<x> = <x> - <y>`.

Instances(9):

```
File: Ethos-Vault/contracts/ReaperVaultV2.sol

168:        totalAllocBPS += _allocBPS;

194:        totalAllocBPS -= strategies[_strategy].allocBPS;

196:        totalAllocBPS += _allocBPS;

214:        totalAllocBPS -= strategies[_strategy].allocBPS;

396:                totalAllocated -= actualWithdrawn;

445:                totalAllocBPS -= bpsChange;

452:        totalAllocated -= loss;

515:                totalAllocated -= vars.debtPayment;

521:        totalAllocated += vars.credit;
```
[Link to Code](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol)

### [Gas-2] Use of Named Returns for Local Variables Saves Gas

Using named return values as temporary local variables can help you conserve gas.

For example, the following code block can be refactored as follows:
```
File: Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol

230:    function balanceOfPool() public view returns (uint256 supply) {
231:        (supply, , , , , , , , ) = IAaveProtocolDataProvider(DATA_PROVIDER).getUserReserveData(
232:        address(want),
233:        address(this)
234:        );
235:    }
```
[Link to Code](https://github.com/code-423n4/

// Code block 1 (unknown):
File: Ethos-Vault/contracts/ReaperVaultV2.sol

168:        totalAllocBPS += _allocBPS;

194:        totalAllocBPS -= strategies[_strategy].allocBPS;

196:        totalAllocBPS += _allocBPS;

214:        totalAllocBPS -= strategies[_strategy].allocBPS;

396:                totalAllocated -= actualWithdrawn;

445:                totalAllocBPS -= bpsChange;

452:        totalAllocated -= loss;

515:                totalAllocated -= vars.debtPayment;

521:        totalAllocated += vars.credit;

// Code block 2 (unknown):
File: Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol

230:    function balanceOfPool() public view returns (uint256 supply) {
231:        (supply, , , , , , , , ) = IAaveProtocolDataProvider(DATA_PROVIDER).getUserReserveData(
232:        address(want),
233:        address(this)
234:        );
235:    }


Jean_Pierre_Polnaref G

# c4udit Report

## Files analyzed
- 2024-01-salty/src/AccessManager.sol
- 2024-01-salty/src/ExchangeConfig.sol
- 2024-01-salty/src/ManagedWallet.sol
- 2024-01-salty/src/Salt.sol
- 2024-01-salty/src/SigningTools.sol
- 2024-01-salty/src/Upkeep.sol
- 2024-01-salty/src/arbitrage/ArbitrageSearch.sol
- 2024-01-salty/src/dao/DAO.sol
- 2024-01-salty/src/dao/DAOConfig.sol
- 2024-01-salty/src/dao/Parameters.sol
- 2024-01-salty/src/dao/Proposals.sol
- 2024-01-salty/src/dao/interfaces/ICalledContract.sol
- 2024-01-salty/src/dao/interfaces/IDAO.sol
- 2024-01-salty/src/dao/interfaces/IDAOConfig.sol
- 2024-01-salty/src/dao/interfaces/IProposals.sol
- 2024-01-salty/src/interfaces/IAccessManager.sol
- 2024-01-salty/src/interfaces/IExchangeConfig.sol
- 2024-01-salty/src/interfaces/IManagedWallet.sol
- 2024-01-salty/src/interfaces/ISalt.sol
- 2024-01-salty/src/interfaces/IUpkeep.sol
- 2024-01-salty/src/launch/Airdrop.sol
- 2024-01-salty/src/launch/BootstrapBallot.sol
- 2024-01-salty/src/launch/InitialDistribution.sol
- 2024-01-salty/src/launch/interfaces/IAirdrop.sol
- 2024-01-salty/src/launch/interfaces/IBootstrapBallot.sol
- 2024-01-salty/src/launch/interfaces/IInitialDistribution.sol
- 2024-01-salty/src/pools/PoolMath.sol
- 2024-01-salty/src/pools/PoolStats.sol
- 2024-01-salty/src/pools/PoolUtils.sol
- 2024-01-salty/src/pools/Pools.sol
- 2024-01-salty/src/pools/PoolsConfig.sol
- 2024-01-salty/src/pools/interfaces/IPoolStats.sol
- 2024-01-salty/src/pools/interfaces/IPools.sol
- 2024-01-salty/src/pools/interfaces/IPoolsConfig.sol
- 2024-01-salty/src/price_feed/CoreChainlinkFeed.sol
- 2024-01-salty/src/price_feed/CoreSaltyFeed.sol
- 2024-01-salty/src/price_feed/CoreUniswapFeed.sol
- 2024-01-salty/src/price_feed/PriceAggregator.sol
- 2024-01-salty/src/price_feed/interfaces/IPriceAggregator.sol
- 2024-01-salty/src/price_feed/interfaces/IPriceFeed.sol
- 2024-01-salty/src/rewards/Emissions.sol
- 2024-01-salty/src/rewards/RewardsConfig.sol
- 2024-01-salty/src/rewards/RewardsEmitter.sol
-

2024-01-salty/src/arbitrage/ArbitrageSearch.sol::115 => for( uint256 i = 0; i < 8; i++ )
2024-01-salty/src/dao/Proposals.sol::421 => uint256 bestID = 0;
2024-01-salty/src/dao/Proposals.sol::422 => uint256 mostYes = 0;
2024-01-salty/src/dao/Proposals.sol::423 => for( uint256 i = 0; i < _openBallotsForTokenWhitelisting.length(); i++ )
2024-01-salty/src/pools/PoolMath.sol::156 => uint256 shift = 0;
2024-01-salty/src/pools/PoolStats.sol::53 => for( uint256 i = 0; i < poolIDs.length; i++ )
2024-01-salty/src/pools/PoolStats.sol::65 => for( uint256 i = 0; i < poolIDs.length; i++ )
2024-01-salty/src/pools/PoolStats.sol::81 => for( uint256 i = 0; i < poolIDs.length; i++ )
2024-01-salty/src/pools/PoolStats.sol::106 => for( uint256 i = 0; i < poolIDs.length; i++ )
2024-01-salty/src/price_feed/CoreUniswapFeed.sol::82 => uint256 twap = 0;
2024-01-salty/src/rewards/RewardsEmitter.sol::59 => uint256 sum = 0;
2024-01-salty/src/rewards/RewardsEmitter.sol::60 => for( uint256 i = 0; i < addedRewards.length; i++ )
2024-01-salty/src/rewards/RewardsEmitter.sol::115 => uint256 sum = 0;
2024-01-salty/src/rewards/RewardsEmitter.sol::116 => for( uint256 i = 0; i < poolIDs.length; i++ )
2024-01-salty/src/rewards/RewardsEmitter.sol::146 => for( uint256 i = 0; i < rewards.length; i++ )
2024-01-salty/src/rewards/SaltRewards.sol::64 => for( uint256 i = 0; i < addedRewards.length; i++ )
2024-01-salty/src/rewards/SaltRewards.sol::87 => for( uint256 i = 0; i < addedRewards.length; i++ )
2024-01-salty/src/rewards/SaltRewards.sol::128 => uint256 totalProfits = 0;
2024-01-salty/src/rewards/SaltRewards.sol::129 => for( uint256 i = 0; i < poolIDs.length; i++ )
2024-01-salty/src/stable/CollateralAndLiquidity.sol::314 => uint256 count = 0;
2024-01-salty/src/stable/CollateralAndLiquidity.sol::338 => for ( uint256 i = 0; i < count; i++ )
2024-01-salty/src/staking/StakingRewards.sol::128 => uint256 claimableRewards = 0;
2024-01-salty/src/staking/StakingRewards.sol::152 => for( uint256 i = 0; i < poolIDs.lengt

2024-01-salty/src/SigningTools.sol::13 => require( signature.length == 65, "Invalid signature length" );
2024-01-salty/src/dao/Proposals.sol::167 => require( _openBallotsForTokenWhitelisting.length() < daoConfig.maxPendingTokensForWhitelisting(), "The maximum number of token whitelisting proposals are already pending" );
2024-01-salty/src/dao/Proposals.sol::224 => require( bytes(country).length == 2, "Country must be an ISO 3166 Alpha-2 Code" );
2024-01-salty/src/dao/Proposals.sol::233 => require( bytes(country).length == 2, "Country must be an ISO 3166 Alpha-2 Code" );
2024-01-salty/src/dao/Proposals.sol::423 => for( uint256 i = 0; i < _openBallotsForTokenWhitelisting.length(); i++ )
2024-01-salty/src/launch/Airdrop.sol::99 => return _authorizedUsers.length();
2024-01-salty/src/pools/PoolStats.sol::53 => for( uint256 i = 0; i < poolIDs.length; i++ )
2024-01-salty/src/pools/PoolStats.sol::65 => for( uint256 i = 0; i < poolIDs.length; i++ )
2024-01-salty/src/pools/PoolStats.sol::81 => for( uint256 i = 0; i < poolIDs.length; i++ )
2024-01-salty/src/pools/PoolStats.sol::106 => for( uint256 i = 0; i < poolIDs.length; i++ )
2024-01-salty/src/pools/PoolStats.sol::138 => _calculatedProfits = new uint256[](poolIDs.length);
2024-01-salty/src/pools/PoolsConfig.sol::47 => require( _whitelist.length() < maximumWhitelistedPools, "Maximum number of whitelisted pools already reached" );
2024-01-salty/src/pools/PoolsConfig.sol::115 => return _whitelist.length();
2024-01-salty/src/rewards/RewardsEmitter.sol::60 => for( uint256 i = 0; i < addedRewards.length; i++ )
2024-01-salty/src/rewards/RewardsEmitter.sol::109 => AddedReward[] memory addedRewards = new AddedReward[]( poolIDs.length );
2024-01-salty/src/rewards/RewardsEmitter.sol::116 => for( uint256 i = 0; i < poolIDs.length; i++ )
2024-01-salty/src/rewards/RewardsEmitter.sol::144 => uint256[] memory rewards = new uint256[]( pools.length );
2024-01-salty/src/rewards/RewardsEmitter.sol::146 => for( uint256 i = 0; i < rewards.lengt


desaperh Q

Audit report markdown format
============================

# Report
Audit report for REPO_GITHUB generated by *Dowsers*

## Summary

### Low issues
Total **32 instances** over **3 issues**

|ID|Issue|Instances|
| :---: | :---: | :---: |
|SWC-107|Reentrancy|13|
|SWC-120|Weak sources of randomness from chain attributes|18|
|SWC-127|Arbitrary jump with function type variable|1|

### Non-Critical/Quality issues
Total **214 instances** over **4 issues**

|ID|Issue|Instances|
| :---: | :---: | :---: |
|SWC-XX1|Insufficient coverage|80|
|SWC-111|Use of deprecated functions, aliases and keywords|48|
|SWC-XX2|Incorrect comparison implementation|80|
|SWC-110|*require()* should be used instead of *assert()*|6|

## Low issues

### [SWC-107] Reentrancy
**Description:**

Reduce the attack surface for malicious contracts trying to hijack control flow after an external call.

https://swcregistry.io/docs/SWC-107

https://fravoll.github.io/solidity-patterns/checks_effects_interactions.html

**Recommendation:**

The pattern of Checks Effects Interactions should be **checked and analysed** in order to prevent re-entrancy attacks.

*There are 13 instances of this issue:*
see instances

```solidity
File: /packages/contracts/contracts/BorrowerOperations.sol
range(211, 225): withdraws `_stEthBalanceDecrease` amount of collateral from the specified Cdp
    /// @dev If caller is different from Cdp owner, it will need approval from Cdp owner for this call
    /// @notice Successful execution is conditional on whether the withdrawal would bring down the ICR or TCR to the minimum requirement, e.g., MCR or CCR
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _stEthBalanceDecrease The total stETH collateral amount withdrawn (reduced) for the specified Cdp
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _l

File: /packages/contracts/contracts/BorrowerOperations.sol
range(211, 225): withdraws `_stEthBalanceDecrease` amount of collateral from the specified Cdp
    /// @dev If caller is different from Cdp owner, it will need approval from Cdp owner for this call
    /// @notice Successful execution is conditional on whether the withdrawal would bring down the ICR or TCR to the minimum requirement, e.g., MCR or CCR
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _stEthBalanceDecrease The total stETH collateral amount withdrawn (reduced) for the specified Cdp
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    function withdrawColl(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external override nonReentrantSelfAndCdpM {
        _adjustCdpInternal(_cdpId, _stEthBalanceDecrease, 0, false, _upperHint, _lowerHint, 0);
range(227, 241): withdraws `_debt` amount of eBTC token from the specified Cdp, thus increasing its debt accounting
    /// @dev If caller is different from Cdp owner, it will need approval from Cdp owner for this call
    /// @notice Successful execution is conditional on whether the withdrawal would bring down the ICR or TCR to the minimum requirement, e.g., MCR or CCR
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _debt The total debt collateral amount increased for the specified Cdp
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    function withdrawDebt(
        bytes32 _cdpId,
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _low

File: /packages/contracts/contracts/Interfaces/IBorrowerOperations.sol
range(41, 86): withdrawColl(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function withdrawDebt(
        bytes32 _cdpId,
        uint256 _amount,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function repayDebt(
        bytes32 _cdpId,
        uint256 _amount,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function closeCdp(bytes32 _cdpId) external;

    function adjustCdp(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function adjustCdpWithColl(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthBalanceIncrease
    ) external;

    function claimSurplusCollShares() external;

    function feeRecipientAddress() external view returns (address);


MSaptarshi G

## G-01 Loading from the memory cost less gas than loading from the storage

1.https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L130
2.https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L196

### Recommendation: Load from the memory
1.
```
+ uint256 recipientsLength = recipients.length;
 - require(recipients.length == amounts.length);
  + require(recipientsLength == amounts.length);
- uint256 recipientsLength = recipients.length;
   for (uint32 i = 0; i < recipientsLength; i++)
```

2.
```
+ uint256 getAllowance = allowance(account, msg.sender) ;
+       require(getAllowance >= amount, "ERC20: burn amount exceeds allowance");
-        require( allowance(account, msg.sender) >= amount,
                        "ERC20: burn amount exceeds allowance");
+       uint256 decreasedAllowance = getAllowance - amount;
-       uint256 decreasedAllowance = allowance(account, msg.sender) - amount;
```

// Code block 1 (unknown):
+ uint256 recipientsLength = recipients.length;
 - require(recipients.length == amounts.length);
  + require(recipientsLength == amounts.length);
- uint256 recipientsLength = recipients.length;
   for (uint32 i = 0; i < recipientsLength; i++)

// Code block 2 (unknown):
+ uint256 getAllowance = allowance(account, msg.sender) ;
+       require(getAllowance >= amount, "ERC20: burn amount exceeds allowance");
-        require( allowance(account, msg.sender) >= amount,
                        "ERC20: burn amount exceeds allowance");
+       uint256 decreasedAllowance = getAllowance - amount;
-       uint256 decreasedAllowance = allowance(account, msg.sender) - amount;


mgf15 Q

Low Risk and Non-Critical Issues .

[L-01] Using vulnerable dependency of OpenZeppelin
The package.json configuration file says that the project is using 3.3.0 of OZ which has a not last update version.

```
"devDependencies": {
    "@openzeppelin/contracts": "^3.3.0",
```
ref
https://security.snyk.io/package/npm/@openzeppelin%2Fcontracts

Recommendation:
Use patched versions
Latest non vulnerable version 4.8.0

Non-Critical Issues

[N-01] Stop using transferFrom() !

It is recommended to use safeTransferFrom() instead of transferFrom()
```
    function fund(uint amount) external onlyOwner {
        require(amount != 0, "cannot fund 0");
        OathToken.transferFrom(msg.sender, address(this), amount);
```

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

[N-02] Stop using transfer() !

it seems that the contract is using transfer to send tokens/ether .

```
        OathToken.transfer(_account, _OathAmount);
```
Code
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LQTY/CommunityIssuance.sol#L127

ref
https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/

[N-03] Use require instead of assert !

The Solidity assert() function is meant to assert invariants. Properly functioning code should never reach a failing assert statement.
```
assert(MIN_NET_DEBT > 0);

assert(vars.compositeDebt > 0);

assert(msg.sender == _borrower || (msg.sender == stabilityPoolAddress && _collTopUp > 0 && _LUSDChange == 0));

assert(_collWithdrawal <= vars.coll);
```

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

```
assert(totalStakesSnapshot[_collateral] > 0);

assert(closedStatus != Status.nonExistent && closedStatus != Status.active);

assert(newBaseRate > 0); // Base rate is always non-zero after redemption

assert(decayedBaseRate <= DECIMAL_PRECISION);  // The baseRate can decay to 0
```
https://github.com/code-423

// Code block 1 (unknown):
"devDependencies": {
    "@openzeppelin/contracts": "^3.3.0",

// Code block 2 (unknown):
function fund(uint amount) external onlyOwner {
        require(amount != 0, "cannot fund 0");
        OathToken.transferFrom(msg.sender, address(this), amount);

// Code block 3 (unknown):
OathToken.transfer(_account, _OathAmount);

// Code block 4 (unknown):
assert(MIN_NET_DEBT > 0);

assert(vars.compositeDebt > 0);

assert(msg.sender == _borrower || (msg.sender == stabilityPoolAddress && _collTopUp > 0 && _LUSDChange == 0));

assert(_collWithdrawal <= vars.coll);

// Code block 5 (unknown):
assert(totalStakesSnapshot[_collateral] > 0);

assert(closedStatus != Status.nonExistent && closedStatus != Status.active);

assert(newBaseRate > 0); // Base rate is always non-zero after redemption

assert(decayedBaseRate <= DECIMAL_PRECISION);  // The baseRate can decay to 0


ak1 Q

Low - 1

Incorrect check for `_setToken` and `_setContract` which overwrite the existing key's value

`LRTConfig` contract has the following logic to check and update the new token and contract.

https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTConfig.sol#L156-L163

```solidity
    function _setToken(bytes32 key, address val) private {
        UtilLib.checkNonZeroAddress(val);
        if (tokenMap[key] == val) { --------------->>>audit - not sufficient. lead to overwriting existing key
            revert ValueAlreadyInUse();
        }
        tokenMap[key] = val;
        emit SetToken(key, val);
    }
```

https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTConfig.sol#L172-L179

```solidity

    function _setContract(bytes32 key, address val) private {
        UtilLib.checkNonZeroAddress(val);
        if (contractMap[key] == val) { --------------------->> audit - not sufficient. lead to overwriting existing key
            revert ValueAlreadyInUse();
        }
        contractMap[key] = val;
        emit SetContract(key, val);
    }
```

Recommendation:

Update the code as shown below

```solidity
    function _setToken(bytes32 key, address val) private {
        UtilLib.checkNonZeroAddress(val);

        require(tokenMap[key] == address(0)); ----------->>> fix

        if (tokenMap[key] == val) { ------------->>>remove this check
            revert ValueAlreadyInUse();
        }
        tokenMap[key] = val;
        emit SetToken(key, val);
    }
```

// Code block 1 (solidity):
function _setToken(bytes32 key, address val) private {
        UtilLib.checkNonZeroAddress(val);
        if (tokenMap[key] == val) { --------------->>>audit - not sufficient. lead to overwriting existing key
            revert ValueAlreadyInUse();
        }
        tokenMap[key] = val;
        emit SetToken(key, val);
    }

// Code block 2 (solidity):
function _setContract(bytes32 key, address val) private {
        UtilLib.checkNonZeroAddress(val);
        if (contractMap[key] == val) { --------------------->> audit - not sufficient. lead to overwriting existing key
            revert ValueAlreadyInUse();
        }
        contractMap[key] = val;
        emit SetContract(key, val);
    }

// Code block 3 (solidity):
function _setToken(bytes32 key, address val) private {
        UtilLib.checkNonZeroAddress(val);

        require(tokenMap[key] == address(0)); ----------->>> fix

        if (tokenMap[key] == val) { ------------->>>remove this check
            revert ValueAlreadyInUse();
        }
        tokenMap[key] = val;
        emit SetToken(key, val);
    }

function _setToken(bytes32 key, address val) private {
        UtilLib.checkNonZeroAddress(val);
        if (tokenMap[key] == val) { --------------->>>audit - not sufficient. lead to overwriting existing key
            revert ValueAlreadyInUse();
        }
        tokenMap[key] = val;
        emit SetToken(key, val);
    }

function _setContract(bytes32 key, address val) private {
        UtilLib.checkNonZeroAddress(val);
        if (contractMap[key] == val) { --------------------->> audit - not sufficient. lead to overwriting existing key
            revert ValueAlreadyInUse();
        }
        contractMap[key] = val;
        emit SetContract(key, val);
    }

function _setToken(bytes32 key, address val) private {
        UtilLib.checkNonZeroAddress(val);

        require(tokenMap[key] == address(0)); ----------->>> fix

        if (tokenMap[key] == val) { ------------->>>remove this check
            revert ValueAlreadyInUse();
        }
        tokenMap[key] = val;
        emit SetToken(key, val);
    }


Cryptor Q

## L-01 No check on whether existing strategy has funds before changing them

https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTConfig.sol#L109-L122

Protocol does not check whether a strategy has funds in them before changing it. This could present some issues when withdrawing funds.

## L-02 No check on whether a strategy has been whitelisted in Eigen Layer
https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTConfig.sol#L109-L122
In Eigen Layer's deposit function, there is a check to make sure that a certain strategy is whitelisted. Kelp does not make that same check when it calls Eigen's deposit function. Therefore, there can be situations where a strategy is approved on Kelp but removed from Eigen Layer's whitelist, causing unexpected reverts

## L-03 Library is not needed

The Library in this function does not add much utility especially when it come to asset management as the constants are fixed and the admin can add new assets without using the library

## L-04 LRTOracle contracts are not pauseable

https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTOracle.sol#L31

None of the oracle functions in LRTOracle.sol are pauseable even though the contract inherits pauseable_init.

## L-05 Admin can renounce ownership

https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/3d4c0d5741b131c231e558d7a6213392ab3672a5/contracts/access/AccessControlUpgradeable.sol#L186-L190

Admin should not be able to renounce ownership as it would break several core contract functions

## L-06 Malicious Actor can make a donation attack to cause deposits to fail

```
   if (depositAmount > getAssetCurrentLimit(asset)) {
            revert MaximumDepositLimitReached();
        }
```

https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTDepositPool.sol#L132-L133

 The deposit function wi

// Code block 1 (unknown):
if (depositAmount > getAssetCurrentLimit(asset)) {
            revert MaximumDepositLimitReached();
        }

LRTConfig.sol#L109-L122, LRTOracle.sol#L31, AccessControlUpgradeable.sol#L186-L190, LRTDepositPool.sol#L132-L133

LRTConfig.sol, LRTOracle.sol, LRTDepositPool.sol, AccessControlUpgradeable.sol


GREY HAWK REACH Q

# [L-01] The max amount for a single deposit into EigenLayer strategy can't be reached.
# Lines of code

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

## Impact
Before users can deposit funds into the ```LRTDepositPool.sol``` contract via the ```depositAsset()``` function, a check is performed to see if the current amount doesn't exceed the maxPerDeposit set by the EigenLyaer strategy.
The EigenLayer strategy contract [StrategyBaseTVLLimits.sol](https://github.com/Layr-Labs/eigenlayer-contracts/blob/master/src/contracts/strategies/StrategyBaseTVLLimits.sol) where funds will be deposited has two important checks
```
/// The maximum deposit (in underlyingToken) that this strategy will accept per deposit
    uint256 public maxPerDeposit;
```
and

```
/// The maximum deposits (in underlyingToken) that this strategy will hold
    uint256 public maxTotalDeposits;
```
The ```depositLimitByAsset``` set in the ```LRTConfig.sol``` contract is there to check if the ```maxPerDeposit``` set in the Eigenlayer protocol is not exceeded. Problem arises in how this value is checked. As can be seen in the POC  ```getAssetBalance()``` returns deposited tokens + accrued rewards. Depending on how often deposits on EigenLayer strategies are not paused Kelp may not gather all of the allowed amount for a deposit. Which results in loosing possible rewards. As each deposit is performed there will be more accrued rewards resulting in a smaller pot gathered by depositors for a stake in EigenLayer strategies.

## Proof of Concept
  **1.** When kelp first start gathering deposit the hardcoded limit is 100_000e18, if this funds are collected and deposited now kelp have a deposit into EigenLayer which is generating yield
  **2.** Then kelp will increase the ```depositLimitByAsset``` to 200_000e18 in order to gather new deposits from users, and deposit in a for example a month when eigen unpauses their deposit function.
  **3.** During this time kelp has alr

// Code block 1 (unknown):
/// The maximum deposit (in underlyingToken) that this strategy will accept per deposit
    uint256 public maxPerDeposit;

// Code block 2 (unknown):
/// The maximum deposits (in underlyingToken) that this strategy will hold
    uint256 public maxTotalDeposits;


lukris02 G

# Gas Optimizations Report for Ondo Finance contest
## Overview
During the audit, 2 gas issues were found.
Total savings ~525.
№ | Title | Instance Count | Saved
--- | --- | --- | ---
G-1 | Use unchecked blocks for incrementing i | 9 | 315
G-2 | Use unchecked blocks for subtractions where underflow is impossible | 6 | 210

## Gas Optimizations Findings(2)
### G-1. Use unchecked blocks for incrementing i
##### Description
In Solidity 0.8+, there’s a default overflow and underflow check on unsigned integers. In the loops, "i" will not overflow because the loop will run out of gas before that.
##### Instances
- https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/factory/CashFactory.sol#L127
- https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/factory/CashKYCSenderFactory.sol#L137
- https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/factory/CashKYCSenderReceiverFactory.sol#L137
- https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/kyc/KYCRegistry.sol#L163
- https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/kyc/KYCRegistry.sol#L180
- https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/CashManager.sol#L750
- https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/CashManager.sol#L786
- https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/CashManager.sol#L933
- https://github.com/code-423n4/2023-01-ondo/blob/main/contracts/cash/CashManager.sol#L961

##### Recommendation
Change:
```
for (uint256 i; i < n; ++i) {
 // ...
}
```
to:
```
for (uint256 i; i < n;) {
 // ...
 unchecked { ++i; }
}
```

##### Saved
This saves ~30-40 gas per iteration.
So, ~35*9 = 315
#
### G-2. Use unchecked blocks for subtractions where underflow is impossible
##### Description
In Solidity 0.8+, there’s a default overflow and underflow check on unsigned integers. When an overflow or underflow isn’t possible (after require or if-statement), some gas can be saved by using

// Code block 1 (unknown):
for (uint256 i; i < n; ++i) {
 // ...
}

// Code block 2 (unknown):
for (uint256 i; i < n;) {
 // ...
 unchecked { ++i; }
}


niser93 G

## Gas Optimizations
|       |Issue  |Instances|Total Gas Saved|
|:-----:|:-----:|:-------:|:-------------:|
|GO-01|```>=``` is cheaper than ```>``` (and ```<=``` is cheaper than ```<```)|2|6|
|GO-02|Use alternative formulation in order to avoid NOT using AND instead of OR or vice versa|3|9|
|GO-03|Multiplication/division by 2 should use bit shifting|2|4|
|GO-04|Using ```private``` rather than ```public``` for constants, saves gas|16|-|
|GO-05|```require()``` or ```revert()``` statements that check input arguments should be at the top of the function|1|-|

### Comment
Due to the lack of test, we aren't be able to report gas saving tables.
Some report titles are same of [winning bot](https://gist.github.com/liveactionllama/27513952718ec3cbcf9de0fda7fef49c), but we report instances whose are't already found.

## GO-01
### ```>=``` is cheaper than ```>``` (and ```<=``` is cheaper than ```<```)
#### Description
Non-strict inequalities (>=) are cheaper than strict ones (>). This is due to some supplementary checks (ISZERO, 3 gas)).
 n>i is equivalent to n>=i-1 when n and i are integer

```diff
- for (uint256 i = 0; i < count + 10; i++) {
+ for (uint256 i = 0; i <= count + 9; i++) {
```

```diff
- for (uint256 i = 100; i > count + 10; i--) {
+ for (uint256 i = 100; i >= count + 11; i--) {
```

```
File: EUSDMiningIncentives.sol

  189         return (stakedLBRLpValue(user) * 10000) / stakedOf(user) < 500;

```
[https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/miner/EUSDMiningIncentives.sol#L189](https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/miner/EUSDMiningIncentives.sol#L189)

```
File: LybraConfigurator.sol

  254         if (fee > 10_000) revert('EL');

```
[https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/configuration/LybraConfigurator.sol#L254](https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/configuration/LybraConfigurator.sol#L254)

#### Mitigation

// Code block 1 (diff):
- for (uint256 i = 0; i < count + 10; i++) {
+ for (uint256 i = 0; i <= count + 9; i++) {

// Code block 2 (diff):
- for (uint256 i = 100; i > count + 10; i--) {
+ for (uint256 i = 100; i >= count + 11; i--) {

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

  189         return (stakedLBRLpValue(user) * 10000) / stakedOf(user) < 500;

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

  254         if (fee > 10_000) revert('EL');


MiksuJak G

# Report by MiksuJak

## Gas Optimizations

| |Issue|Instances|
|-|:-|:-:|
| [GAS-1](#GAS-1) | Store balance calls return values in `memory` instead of calling them multiple times in one function | 2 |
| [GAS-2](#GAS-2) | Store derivative address in `memory` whenever it is read from storage more than once | 3 |
| [GAS-3](#GAS-3) | Do not recalculate `localTotalWeights` when a `weight` is adjusted or added | 2 |

### [GAS-1] Store balance calls return values in `memory` instead of calling them multiple times in one function

Store `<address>.balance()` in a `memory` variable to save gas on addresses balance calls.

#### Instance 1:
__File: contracts/SafEth/SafEth.sol   | stake |   Lines: 71-75__

```solidity
for (uint i = 0; i < derivativeCount; i++)
	underlyingValue +=
		(derivatives[i].ethPerDerivative(derivatives[i].balance()) *
			derivatives[i].balance()) /
		10 ** 18;
```
Could be changed to:
```solidity
for (uint i = 0; i < derivativeCount; i++) {
	uint256 derivativeBalance = derivatives[i].balance();
	underlyingValue +=
		(derivatives[i].ethPerDerivative(derivativeBalance) *
			derivativeBalance) /
		10 ** 18;
}
```
Saves _8145 gas_ per call for __SafEth-Integration.test.ts:78__ test.

#### Instance 2:
__File: contracts/SafEth/SafEth.sol   | rebalanceToWeights |   Lines: 140-143__

```solidity
for (uint i = 0; i < derivativeCount; i++) {
	if (derivatives[i].balance() > 0)
		derivatives[i].withdraw(derivatives[i].balance());
}
```
Could be changed to:
```solidity
for (uint i = 0; i < derivativeCount; i++) {
	uint256 derivativeBalance = derivatives[i].balance();
	if (derivativeBalance > 0)
		derivatives[i].withdraw(derivativeBalance);
}
```
Saves _8154 gas_ for __SafEth-Integration.test.ts:94__ test.
Saves _4760 gas_ for __SafEth-Integration.test.ts:123__ test.

### [GAS-2] Store derivative address in `memory` whenever it is read from storage more than once

There are `for` loops iterating over `derivatives`  and performing multiple calls on each `derivative` i

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

// Code block 2 (solidity):
for (uint i = 0; i < derivativeCount; i++) {
	uint256 derivativeBalance = derivatives[i].balance();
	underlyingValue +=
		(derivatives[i].ethPerDerivative(derivativeBalance) *
			derivativeBalance) /
		10 ** 18;
}

// Code block 3 (solidity):
for (uint i = 0; i < derivativeCount; i++) {
	if (derivatives[i].balance() > 0)
		derivatives[i].withdraw(derivatives[i].balance());
}

// Code block 4 (solidity):
for (uint i = 0; i < derivativeCount; i++) {
	uint256 derivativeBalance = derivatives[i].balance();
	if (derivativeBalance > 0)
		derivatives[i].withdraw(derivativeBalance);
}

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

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

for (uint i = 0; i < derivativeCount; i++) {
	if (derivatives[i].balance() > 0)
		derivatives[i].withdraw(derivatives[i].balance());
}

for (uint i = 0; i < derivativeCount; i++) {
	uint256 derivativeBalance = derivatives[i].balance();
	if (derivativeBalance > 0)
		derivatives[i].withdraw(derivativeBalance);
}


Kaysoft Q

## [L-01] Remove unused input/unnamed parameter
File: VerifyingSingletonPaymaster, line: 97
- [VerifyingSingletonPaymaster.sol#L97](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/verifying/singleton/VerifyingSingletonPaymaster.sol#L97)

The `/*userOpHash*/` is commented and not used.  Remove unused parameter.

```
function validatePaymasterUserOp(UserOperation calldata userOp, bytes32 /*userOpHash*/, uint256 requiredPreFund)
    external view override returns (bytes memory context, uint256 deadline) {
        (requiredPreFund);
        bytes32 hash = getHash(userOp);

        PaymasterData memory paymasterData = userOp.decodePaymasterData();
        uint256 sigLength = paymasterData.signatureLength;

        //ECDSA library supports both 64 and 65-byte long signatures.
        // we only "require" it here so that the revert reason on invalid signature will be of "VerifyingPaymaster", and not "ECDSA"
        require(sigLength == 64 || sigLength == 65, "VerifyingPaymaster: invalid signature length in paymasterAndData");
        require(verifyingSigner == hash.toEthSignedMessageHash().recover(paymasterData.signature), "VerifyingPaymaster: wrong signature");
        require(requiredPreFund <= paymasterIdBalances[paymasterData.paymasterId], "Insufficient balance for paymaster id");
        return (userOp.paymasterContext(paymasterData), 0);
    }
```

### Recommended Mitigation Steps
- Remove the unused/commented `/*userOpHash*/`  parameter in `validatePaymasterUser` function.

## [L-02] Use latest stable pragma version 0.8.17
Files: All files.
Low level calls with solidity versions 0.8.14 and BELOW can result in optimizer bugs.
https://medium.com/certora/overly-optimistic-optimizer-certora-bug-disclosure-2101e3f7994d

see: https://swcregistry.io/docs/SWC-102
Simliar findings in Code4rena contests for reference:
https://code4rena.com/reports/2022-06-illuminate/#5-low-level-calls-with-solidity-version-0

const config: HardhatUserConfig = {
  // defaultNetwork: "ganache",
  solidity: {
    compilers: [
      {
        version: "0.8.12",
        settings: {
          optimizer: { enabled: true, runs: 200 },
        },
      },
      {
        version: "0.8.4",
        settings: {
          optimizer: { enabled: true, runs: 200 },
        },
      },
      {
        version: "0.8.9",
        settings: {
          optimizer: { enabled: true, runs: 200 },
        },
      },
    ],
  },

// Code block 1 (unknown):
function validatePaymasterUserOp(UserOperation calldata userOp, bytes32 /*userOpHash*/, uint256 requiredPreFund)
    external view override returns (bytes memory context, uint256 deadline) {
        (requiredPreFund);
        bytes32 hash = getHash(userOp);

        PaymasterData memory paymasterData = userOp.decodePaymasterData();
        uint256 sigLength = paymasterData.signatureLength;

        //ECDSA library supports both 64 and 65-byte long signatures.
        // we only "require" it here so that the revert reason on invalid signature will be of "VerifyingPaymaster", and not "ECDSA"
        require(sigLength == 64 || sigLength == 65, "VerifyingPaymaster: invalid signature length in paymasterAndData");
        require(verifyingSigner == hash.toEthSignedMessageHash().recover(paymasterData.signature), "VerifyingPaymaster: wrong signature");
        require(requiredPreFund <= paymasterIdBalances[paymasterData.paymasterId], "Insufficient balance for paymaster id");
        return (userOp.paymasterContext(paymasterData), 0);
    }


Audit_Avengers Q

A. LOW/MEDIUM RISK: Large(r) loan based griefing attack:
Although the protocol already protects against griefing attacks using dust loans, there is currently no protection in place for when larger loans are used to execute griefing attacks.

Impact:
An attacker could take out one or more large loans from depositors and keep the loan very close to the liquidation threshold, thereby artificially inflating the HTP. This potential griefing attack could disrupt the system by sustainably preventing other lenders from withdrawing their deposits.

The absence of a mitigation mechanism for this variant of the attack is concerning because it could lead to the locking of users' funds within the system, undermining the protocol's credibility and causing a possible loss of users. Additionally, this attack could prevent lenders from correctly adjusting the Liquidity Utilization Price (LUP), thereby manipulating market dynamics.

Proof of Concept:
The griefing attack could be executed as follows:

The attacker borrows a large amount from the system, choosing depositors who have a significant amount of funds.
The attacker ensures that the loan size remains very close to the liquidation threshold, thereby artificially inflating the HTP.

Recommended Mitigation Steps
Consider implementing additional checks or limits on borrowing activities. For instance, a limit on the loan-to-value (LTV) ratio could be introduced to prevent borrowers from taking out loans that are too close to the liquidation threshold, preventing an attacker from artificially inflating the HTP.

In addition, a mechanism could be implemented that adjusts the HTP calculation in response to large loans. This would reduce the impact that any single loan can have on the overall HTP.

Monitoring for suspicious borrowing patterns could also be beneficial. Patterns such as a user borrowing large amounts close to the liquidation threshold could trigger manual reviews or automated responses to protect the system and its user

File: /ajna-grants/src/grants/base/ExtraordinaryFunding.sol
78:    treasury -= tokensRequested;

        // execute proposal's calldata
        _execute(proposalId_, targets_, values_, calldatas_);

File: /ajna-core/src/PositionManager.sol
120:    erc20PoolFactory  = erc20Factory_;
        erc721PoolFactory = erc721Factory_;
    }


0xAgro Q

# QA Report
## Finding Summary

[**Low Severity**](#Low-Severity)
1. [**Unchecked Cast May Overflow**](#1-Unchecked-Cast-May-Overflow)
2. [**Consider a More Recent Solidity Version**](#2-Consider-a-More-Recent-Solidity-Version)
3. [**Code Function Does Not Match Comment**](#3-Code-Function-Does-Not-Match-Comment)
4. [**Low Coverage**](#4-Low-Coverage)
5. [**assert Used Over require**](#5-assert-Used-Over-require)
6. [**Drastic Compiler Version Variation**](#6-Drastic-Compiler-Version-Variation)
7. [**ERC20 Decimals Assumption**](#7-ERC20-Decimals-Assumption)
8. [**batchLiquidateTroves Ignores Checks In liquidate**](#8-batchLiquidateTroves-Ignores-Checks-In-liquidate)
9. [**LUSD Minting To Restricted Address**](#9-LUSD-Minting-To-Restricted-Address)
10. [**No Rebasing Token Support**](#10-No-Rebasing-Token-Support)

[**Non-Critical**](#Non-Critical)
1. [**Use of ecrecover**](#1-Use-of-ecrecover)
2. [**Consider Avoiding Sensitive Terms**](#2-Consider-Avoiding-Sensitive-Terms)
3. [**Explicit Variable Not Used**](#3-Explicit-Variable-Not-Used)
4. [**Variable Scopes Not Explicit**](#4-Variable-Scopes-Not-Explicit)
5. [**chainid Non-Assembly Function Available**](#5-chainid-Non-Assembly-Function-Available)
6. [**Use of deprecated now**](#6-Use-of-deprecated-now)
7. [**bytes.concat() Can Be Used Over abi.encodePacked()**](#7-bytesconcat-can-be-used-over-abiencodepacked)
8. [**Contracts Lacking NatSpec Headers**](#8-Contracts-Lacking-NatSpec-Headers)
9. [**Odd Name State**](#9-Odd-Name-State)
10. [**Be Explicitly Honest About Risk**](#10-Be-Explicitly-Honest-About-Risk)

[**General Style**](#General-Style)
1. [**Underscore Notation Not Used or Not Used Consistently**](#1-Underscore-Notation-Not-Used-or-Not-Used-Consistently)
2. [**Power of Ten Literal Not In Scientific Notation**](#2-Power-of-Ten-Literal-Not-In-Scientific-Notation)
3. [**Use of Exponentiation Over Scientific Notation**](#3-Use-of-Exponentiation-Over-Scientific-Notation)
4. [**Inconsistent Named Returns**](#

1329:	index = uint128(TroveOwners[_collateral].length.sub(1));

277:	vars.netAssetMovement = int256(vars.toDeposit) - int256(vars.toWithdraw) - int256(vars.profit);


dharma09 G

### [G-01] Cache multiple accesses of a mapping/array

Consider using a local `storage` or `calldata` variable when accessing a mapping/array value multiple times.

This can be useful to avoid recalculating the mapping hash and/or the array offsets.

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

```solidity
File: src/NodeDelegator.sol
109: for (uint256 i = 0; i < strategiesLength;) {
            assets[i] = address(IStrategy(strategies[i]).underlyingToken()); //@audit cache variable
            assetBalances[i] = IStrategy(strategies[i]).userUnderlyingView(address(this));
            unchecked {
                ++i;
            }
        }
```

### [G-02] Move the declaration of user outside the loop to reduce SLOAD (storage load) operations, as storage reads can be expensive in terms of gas.

Optimize gas usage by avoiding variable declarations inside loops

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

```solidity
File: src/LRTOracle.sol
66: for (uint16 asset_idx; asset_idx < supportedAssetCount;) {
            address asset = supportedAssets[asset_idx]; //@audit make variable outside loop
            uint256 assetER = getAssetPrice(asset);

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

            unchecked {
                ++asset_idx;
            }
        }
```

```diff
File: src/LRTOracle.sol
+             address asset;
+             uint256 assetER;
66: for (uint16 asset_idx; asset_idx < supportedAssetCount;) {
-            address asset = supportedAssets[asset_idx];
-            uint256 assetER = getAssetPrice(asset);
+             asset = supportedAssets[asset_idx];
+             assetER = getAssetPrice(asset);

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

// Code block 1 (solidity):
File: src/NodeDelegator.sol
109: for (uint256 i = 0; i < strategiesLength;) {
            assets[i] = address(IStrategy(strategies[i]).underlyingToken()); //@audit cache variable
            assetBalances[i] = IStrategy(strategies[i]).userUnderlyingView(address(this));
            unchecked {
                ++i;
            }
        }

// Code block 2 (solidity):
File: src/LRTOracle.sol
66: for (uint16 asset_idx; asset_idx < supportedAssetCount;) {
            address asset = supportedAssets[asset_idx]; //@audit make variable outside loop
            uint256 assetER = getAssetPrice(asset);

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

            unchecked {
                ++asset_idx;
            }
        }

File: src/NodeDelegator.sol
109: for (uint256 i = 0; i < strategiesLength;) {
            assets[i] = address(IStrategy(strategies[i]).underlyingToken()); //@audit cache variable
            assetBalances[i] = IStrategy(strategies[i]).userUnderlyingView(address(this));
            unchecked {
                ++i;
            }
        }

File: src/LRTOracle.sol
66: for (uint16 asset_idx; asset_idx < supportedAssetCount;) {
            address asset = supportedAssets[asset_idx]; //@audit make variable outside loop
            uint256 assetER = getAssetPrice(asset);

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

            unchecked {
                ++asset_idx;
            }
        }


koo Analysis

I think the EUSD and PEUSD are too centralization.
```solidity
    function transferFrom(address from, address to, uint256 amount) public returns (bool) {
        address spender = _msgSender();
        if (!configurator.mintVault(spender)) {
            _spendAllowance(from, spender, amount);
        }
        _transfer(from, to, amount);
        return true;
    }
```
Admin has the power to transfer the EUSD and PEUSD owned by anybody, which will violation of decentralization blockchain. And also, once a private key of the address which have mintVault permision and isRedemptionProvider permission leak and is controled bt a attacker. Attacker can stole everbody's EUSD and PEUSD. Further more, see the following code:
```solidity
    function rigidRedemption(address provider, uint256 peusdAmount) external virtual {
        require(configurator.isRedemptionProvider(provider), "provider is not a RedemptionProvider");
        require(borrowed[provider] >= peusdAmount, "peusdAmount cannot surpass providers debt");
        uint256 assetPrice = getAssetPrice();
        uint256 providerCollateralRatio = (depositedAsset[provider] * assetPrice * 100) / borrowed[provider];
        require(providerCollateralRatio >= 100 * 1e18, "provider's collateral ratio should more than 100%");
        _repay(msg.sender, provider, peusdAmount);
        uint256 collateralAmount = (((peusdAmount * 1e18) / assetPrice) * (10000 - configurator.redemptionFee())) / 10000;
        depositedAsset[provider] -= collateralAmount;
        collateralAsset.transfer(msg.sender, collateralAmount);
        emit RigidRedemption(msg.sender, provider, peusdAmount, collateralAmount, block.timestamp);
    }
```
Using stolen money, attacker then can use the rigidRedemption call to get all collateralAsset in the pool. It will cause serious damage to the user's money.

### Time spent:
20 hours

// Code block 1 (solidity):
function transferFrom(address from, address to, uint256 amount) public returns (bool) {
        address spender = _msgSender();
        if (!configurator.mintVault(spender)) {
            _spendAllowance(from, spender, amount);
        }
        _transfer(from, to, amount);
        return true;
    }

// Code block 2 (solidity):
function rigidRedemption(address provider, uint256 peusdAmount) external virtual {
        require(configurator.isRedemptionProvider(provider), "provider is not a RedemptionProvider");
        require(borrowed[provider] >= peusdAmount, "peusdAmount cannot surpass providers debt");
        uint256 assetPrice = getAssetPrice();
        uint256 providerCollateralRatio = (depositedAsset[provider] * assetPrice * 100) / borrowed[provider];
        require(providerCollateralRatio >= 100 * 1e18, "provider's collateral ratio should more than 100%");
        _repay(msg.sender, provider, peusdAmount);
        uint256 collateralAmount = (((peusdAmount * 1e18) / assetPrice) * (10000 - configurator.redemptionFee())) / 10000;
        depositedAsset[provider] -= collateralAmount;
        collateralAsset.transfer(msg.sender, collateralAmount);
        emit RigidRedemption(msg.sender, provider, peusdAmount, collateralAmount, block.timestamp);
    }

function transferFrom(address from, address to, uint256 amount) public returns (bool) {
        address spender = _msgSender();
        if (!configurator.mintVault(spender)) {
            _spendAllowance(from, spender, amount);
        }
        _transfer(from, to, amount);
        return true;
    }

function rigidRedemption(address provider, uint256 peusdAmount) external virtual {
        require(configurator.isRedemptionProvider(provider), "provider is not a RedemptionProvider");
        require(borrowed[provider] >= peusdAmount, "peusdAmount cannot surpass providers debt");
        uint256 assetPrice = getAssetPrice();
        uint256 providerCollateralRatio = (depositedAsset[provider] * assetPrice * 100) / borrowed[provider];
        require(providerCollateralRatio >= 100 * 1e18, "provider's collateral ratio should more than 100%");
        _repay(msg.sender, provider, peusdAmount);
        uint256 collateralAmount = (((peusdAmount * 1e18) / assetPrice) * (10000 - configurator.redemptionFee())) / 10000;
        depositedAsset[provider] -= collateralAmount;
        collateralAsset.transfer(msg.sender, collateralAmount);
        emit RigidRedemption(msg.sender, provider, peusdAmount, collateralAmount, block.timestamp);
    }


XDZIBECX Q

The `stakingToken.transferFrom` and `stakingToken.transfer` calls in the `stake` and `withdraw` functions, and the `rewardsToken.mint` call in the `getReward` function are not checked for their return value. Although it's not mandatory in ERC20 standard to return a boolean for these functions, some tokens do.

- here is the code of contract : https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/miner/stakerewardV2pool.sol#L1C1-L150C2

- to fix this,  added to the stake, withdraw, and getReward functions:

```solidity
if (stakingToken.transferFrom(msg.sender, address(this), _amount) == false) {
    revert("Transfer failed");
}

if (stakingToken.transfer(msg.sender, _amount) == false) {
    revert("Transfer failed");
}

if (rewardsToken.mint(msg.sender, _amount) == false) {
    revert("Mint failed");
}
```

// Code block 1 (solidity):
if (stakingToken.transferFrom(msg.sender, address(this), _amount) == false) {
    revert("Transfer failed");
}

if (stakingToken.transfer(msg.sender, _amount) == false) {
    revert("Transfer failed");
}

if (rewardsToken.mint(msg.sender, _amount) == false) {
    revert("Mint failed");
}


seeu Q

## Compiler version Pragma is non-specific

### Description

For non-library contracts, floating pragmas may be a security risk for application implementations, since a known vulnerable compiler version may accidentally be selected or security tools might fallback to an older compiler version ending up checking a different EVM compilation that is ultimately deployed on the blockchain.

### Findings

```
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/BasePaymaster.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L6 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/IAccount.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/IAggregatedAccount.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/IEntryPoint.sol#L6 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/IPaymaster.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/IStakeManager.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/SenderCreator.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/StakeManager.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-co

https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/BasePaymaster.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L6 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/IAccount.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/IAggregatedAccount.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/IEntryPoint.sol#L6 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/IPaymaster.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/IStakeManager.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/SenderCreator.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/StakeManager.sol#L2 => pragma solidity ^0.8.12;
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/UserOperation.sol#L2 => pragma solidity ^0.8.12;

BasePaymaster.sol#L2, EntryPoint.sol#L6, IAccount.sol#L2, IAggregatedAccount.sol#L2, IEntryPoint.sol#L6, IPaymaster.sol#L2, IStakeManager.sol#L2, SenderCreator.sol#L2, StakeManager.sol#L2, UserOperation.sol#L2

SenderCreator.sol, IEntryPoint.sol, IAggregatedAccount.sol, IStakeManager.sol, BasePaymaster.sol, IPaymaster.sol, IAccount.sol, EntryPoint.sol, UserOperation.sol, StakeManager.sol


wonjun Q

[L-1] events are missing an important parameter
The callers of these important functions are not published in emits.

Instances (3):
```
emit FundTreasury(fundingAmount\_, treasury);
```
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/GrantFund.sol#L64
```
emit QuarterlyDistributionStarted(
    newDistributionId\_,
    startBlock,
    endBlock
);
```
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol#L159
```
emit MoveStakedLiquidity(tokenId*, fromBuckets*, toBuckets\_);
```
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol#L187

Add caller to events. Add msg.sender parameter in event-emits.

[N-1] Invalid comments

Instances (2):

@notice User attempted to execute a proposal before the distribution period ended
->
@notice User attempted to start a new distribution period before the distribution period ended

https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/interfaces/IStandardFunding.sol#L16

@dev Mapping of `token id => ajna pool address` for which token was minted.
->
@dev A nested mapping of `token id => bucket index => Position` for each token's associated position in a bucket.

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

[N-2] Spellcheck

Instances (4):

The  to -> The distributionId to
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/interfaces/IStandardFunding.sol#L263

challengephase -> challenge phase
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol#L30

it's -> its
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/interfaces/IStandardFunding.sol#L325

it's -> its
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/interfaces/IStandardFunding.sol#L327

Consider using tools like the VSCode extension 'Code Spell Checker' or similar to help catc

// Code block 1 (unknown):
emit FundTreasury(fundingAmount\_, treasury);

// Code block 2 (unknown):
emit QuarterlyDistributionStarted(
    newDistributionId\_,
    startBlock,
    endBlock
);

// Code block 3 (unknown):
emit MoveStakedLiquidity(tokenId*, fromBuckets*, toBuckets\_);

GrantFund.sol#L64, StandardFunding.sol#L159, RewardsManager.sol#L187, IStandardFunding.sol#L16, PositionManager.sol#L54, IStandardFunding.sol#L263, StandardFunding.sol#L30, IStandardFunding.sol#L325, IStandardFunding.sol#L327

GrantFund.sol, IStandardFunding.sol, PositionManager.sol, StandardFunding.sol, RewardsManager.sol


Raihan G

# GAS OPTIMIZATION

# SUMMARY
|      |  issue  |  instance  |
|------|---------|------------|
|[G‑01]|Most important: avoid zero to one storage writes where possible|10|
|[G‑02]|Using mappings instead of arrays to avoid length checks|2|
|[G‑03]|Use storage pointers instead of memory where appropriate|1|
|[G‑04]|Use assembly to perform efficient back-to-back calls|5|
|[G‑05]|Avoid emitting storage values|3|
|[G‑06]|Structs can be modified to fit in fewer storage slots|1|
|[G‑07]|Pre-increment and pre-decrement are cheaper than +1 ,-1|11|
|[G‑08]|Gas Optimization: Favor Ternary Operation Over If-Else Statement|2|
|[G‑09]|Consider using OZ EnumerateSet in place of nested mappings|8|
|[G‑10]|Don’t make variables public unless it is necessary to do so|2|
|[G‑11]|It is sometimes cheaper to cache calldata|1|
|[G‑12]|Gas Optimization: Use Assembly for Writing Address Storage Values|9|
|[G‑13]|Sort Solidity operations using short-circuit mode|1|
|[G‑14]|Expressions for constant values such as a call to keccak256(), should use immutable rather than constant|3|
|[G‑15]|Do not calculate constants|3|
|[G‑16]|Avoid having ERC20 token balances go to zero, always keep a small amount|3|
|[G‑17]|ERC1155 is a cheaper non-fungible token than ERC721|2|
|[G‑18]|Use one ERC1155 or ERC6909 token instead of several ERC20 tokens|1|
|[G‑19]|Consider using alternatives to OpenZeppelin|7|
|[G‑20]|Using assembly to revert with an error message|17|
|[G‑21]|Common math operations, like min and max have gas efficient alternatives|1|

## [G-01] Most important: avoid zero to one storage writes where possible
Initializing a storage variable is one of the most expensive operations a contract can do.
When a storage variable goes from zero to non-zero, the user must pay 22,100 gas total (20,000 gas for a zero to non-zero write and 2,100 for a cold storage access).
This is why the Openzeppelin reentrancy guard registers functions as active or not with 1 and 2 rather than 0 and 1. It only costs 5,000 gas t

File:  src/GameItems.sol
64   uint256 _itemCount = 0;

File:  src/MergingPool.sol
29  uint256 public roundId = 0;

32  uint256 public totalPoints = 0;