nadin Q

# QA Report

## Summary
Total 04 Low and 06 Non-Critical
### Low Risk Issues
- [L-01] EXPIRED PROPOSALS ARE NOT CHECKED
- [L-02] Consider using OpenZeppelin’s SafeCast library to prevent unexpected overflows when casting from uint256
- [L-03] Hard coding MAX_EFM_PROPOSAL_LENGTH can lead to a revert in ExtraordinaryFunding.proposExtraordinary()
- [L-04] The nonReentrant modifier should occur before all other modifiers
### Non-Critical Issues
- [N-01] immutable should be UPPERCASE
- [N-02] According to the syntax rules, use => mapping ( instead of => mapping( using spaces as keyword
- [N-03] Use SMTChecker
- [N-04] Assembly Codes Specific – Should Have Comments
- [N-05] Take advantage of Custom Error’s return value property
- [N-06] Use named parameters for mapping type declarations

## [L-01] EXPIRED PROPOSALS ARE NOT CHECKED
### Description:
In the implementation `GrantFund.state`, expired proposals are not check on the state function. Thus expired proposals still can be executed
### POC
[GrantFund.state](https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/GrantFund.sol#L45-L51)
```
    function state(
        uint256 proposalId_
    ) external view override returns (ProposalState) {
        FundingMechanism mechanism = findMechanismOfProposal(proposalId_);

        return mechanism == FundingMechanism.Standard ? _standardProposalState(proposalId_) : _getExtraordinaryProposalState(proposalId_);
    }
```
[_standardProposalState(proposalId_) ](https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/StandardFunding.sol#L505-L512)
```    function _standardProposalState(uint256 proposalId_) internal view returns (ProposalState) {
        Proposal memory proposal = _standardFundingProposals[proposalId_];

        if (proposal.executed)                                                     return ProposalState.Executed;
        else if (_distributions[p

// Code block 1 (unknown):
function state(
        uint256 proposalId_
    ) external view override returns (ProposalState) {
        FundingMechanism mechanism = findMechanismOfProposal(proposalId_);

        return mechanism == FundingMechanism.Standard ? _standardProposalState(proposalId_) : _getExtraordinaryProposalState(proposalId_);
    }


wahedtalash77 Q

# Low Risk Findings

## [L‑01] Use Ownable2Step rather than Ownable
`Ownable2Step` and `Ownable2StepUpgradeable` prevent the contract ownership from mistakenly being transferred to an address that cannot handle it (e.g. due to a typo in the address), by requiring that the recipient of the owner permissions actively accept via a contract call of its own.
```
23: contract VaultController is Pausable, IVaultController, ExponentialNoError, Ownable {
```

```
20: contract UFragments is Ownable, IERC20Metadata {
`
```
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/utils/UFragments.sol#L20

```
contract ChainlinkOracleRelay is OracleRelay, Ownable {
```
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/periphery/oracles/ChainlinkOracleRelay.sol#L11

```
contract CTokenOracle is OracleRelay, Ownable {
```
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/periphery/oracles/CTokenOracle.sol#L10

## [L-02] Dangerous Solidity compiler pragma range that spans breaking versions
In most contracts, the pragma statements are declared as pragma solidity >=0.6.0 <0.8.0;, which are unlocked and could cause the contracts to accidentally be compiled or deployed using an outdated or buggy compiler version.
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/periphery/oracles/UniswapV3OracleRelay.sol#L2C1-L2C1

# Non-Ctitical findings
## [N‑01] Use scientific notation rather than exponentiation
While the compiler knows to optimize away the exponentiation, it’s still better coding practice to use idioms that do not require compiler optimization, if they exist.
`uint256 public constant MAX_wUSDA_SUPPLY = 10_000_000 * (10 ** 18); // 10 M`
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/WUSDA.sol#L35C3-L35C78

` ) = _peekLiquidat

// Code block 1 (unknown):
23: contract VaultController is Pausable, IVaultController, ExponentialNoError, Ownable {

// Code block 2 (unknown):
20: contract UFragments is Ownable, IERC20Metadata {
`

// Code block 3 (unknown):
contract ChainlinkOracleRelay is OracleRelay, Ownable {

// Code block 4 (unknown):
contract CTokenOracle is OracleRelay, Ownable {

UFragments.sol#L20, ChainlinkOracleRelay.sol#L11, CTokenOracle.sol#L10, UniswapV3OracleRelay.sol#L2-L1, WUSDA.sol#L35-L3

WUSDA.sol, UniswapV3OracleRelay.sol, UFragments.sol, ChainlinkOracleRelay.sol, CTokenOracle.sol


nonseodion G

G-1 `_formatClAggregateAnswer` can be completely replaced to save gas

The function `_formatClAggregateAnswer` can be completely replaced with:

```
    function _formatClAggregateAnswer(
        int256 _ethBtcAnswer,
        int256 _stEthEthAnswer,
        uint8 _ethBtcDecimals,
        uint8 _stEthEthDecimals
    ) internal view returns (uint256) {

        return
            (
                uint256(_ethBtcAnswer) *
                uint256(_stEthEthAnswer) *
                EbtcMath.DECIMAL_PRECISION) / 10 ** (_ethBtcDecimals + _stEthEthDecimals);
    }
```

The function above simply scales the price first with `EbtcMath.DECIMAL_PRECISION` and eliminates the decimals of the stEthEth and ethBtc prices with `10 ** (_ethBtcDecimals + _stEthEthDecimals)` leaving the price to have only `EbtcMath.DECIMAL_PRECISION` decimal points.

Gas usage of old implementation: 4519
Gas usage of suggested implementation: 3910

G-2 Price Feed decimal calls can be reduced to 2 from 4
The Price Feed checks the decimals of the two Chainlink price feeds when it tries to get the current and previous round values from the price feeds. This amount to four calls altogether.

`decimals()` called twice when previous round data is fetched

```
    function _getPrevChainlinkResponse(
        uint80 _currentRoundEthBtcId,
        uint80 _currentRoundStEthEthId
    ) internal view returns (ChainlinkResponse memory prevChainlinkResponse) {
        // If first round, early return
        // Handles revert from underflow in _currentRoundEthBtcId - 1
        // and _currentRoundStEthEthId - 1
        // Behavior should be indentical to following block if this revert was caught
        if (_currentRoundEthBtcId == 0 || _currentRoundStEthEthId == 0) {
            return prevChainlinkResponse;
        }

        // Fetch decimals for both feeds:
        uint8 ethBtcDecimals;
        uint8 stEthEthDecimals;

        try ETH_BTC_CL_FEED.decimals() returns (uint8 decimals) {
            // If call to Chai

    function _getPrevChainlinkResponse(
        uint80 _currentRoundEthBtcId,
        uint80 _currentRoundStEthEthId
    ) internal view returns (ChainlinkResponse memory prevChainlinkResponse) {
        // If first round, early return
        // Handles revert from underflow in _currentRoundEthBtcId - 1
        // and _currentRoundStEthEthId - 1
        // Behavior should be indentical to following block if this revert was caught
        if (_currentRoundEthBtcId == 0 || _currentRoundStEthEthId == 0) {
            return prevChainlinkResponse;
        }

        // Fetch decimals for both feeds:
        uint8 ethBtcDecimals;
        uint8 stEthEthDecimals;

        try ETH_BTC_CL_FEED.decimals() returns (uint8 decimals) {
            // If call to Chainlink succeeds, record the current decimal precision
            ethBtcDecimals = decimals;
        } catch {
            // If call to Chainlink aggregator reverts, return a zero response with success = false
            return prevChainlinkResponse;
        }

        try STETH_ETH_CL_FEED.decimals() returns (uint8 decimals) {
            // If call to Chainlink succeeds, record the current decimal precision
            stEthEthDecimals = decimals;
        } catch {
            // If call to Chainlink aggregator reverts, return a zero response with success = false
            return prevChainlinkResponse;
        }

// Code block 1 (unknown):
function _formatClAggregateAnswer(
        int256 _ethBtcAnswer,
        int256 _stEthEthAnswer,
        uint8 _ethBtcDecimals,
        uint8 _stEthEthDecimals
    ) internal view returns (uint256) {

        return
            (
                uint256(_ethBtcAnswer) *
                uint256(_stEthEthAnswer) *
                EbtcMath.DECIMAL_PRECISION) / 10 ** (_ethBtcDecimals + _stEthEthDecimals);
    }


hassanshakeel13 Analysis

### Project Overview:

The decentralized financial ecosystem under analysis demonstrates a robust and intricate structure designed to facilitate transparent governance, decentralized decision-making, and comprehensive token reward mechanisms. At its core lies the DAO, DAO.sol, governing the entire ecosystem through a series of well-thought-out proposals and voting mechanisms. The project encompasses a suite of smart contracts managing stablecoins, native tokens, collateral, liquidity, and staking processes. Notable features include the integration of external systems through Chainlink and Uniswap, emphasizing adaptability and interoperability. The codebase reflects a commitment to security, modularity, and adherence to industry best practices.

### Governance and DAO Architecture:
The core of the ecosystem is anchored in DAO.sol, comprising 251 lines of code and reflecting a robust framework for decentralized governance. Proposals.sol, with 267 lines, complements DAO.sol, handling the intricacies of proposals and voting within the decentralized autonomous organization. This structure emphasizes transparency, accountability, and participatory decision-making.

### Reward Systems and Emissions:
The reward mechanisms are well-structured and decentralized. Emissions.sol, with 35 lines, seems dedicated to managing emissions, indicating a conscious effort to control token supply dynamics. RewardsEmitter.sol, encompassing 89 lines, orchestrates the distribution of rewards across the ecosystem. SaltRewards.sol, spanning 88 lines, emerges as a pivotal contract, intricately managing the allocation of rewards to staking and liquidity providers.

### Stablecoins and Token Management:
USDS.sol, with its 33 lines, serves as the bedrock for the stablecoin within the ecosystem. StableConfig.sol, standing at 104 lines, is indicative of a thorough approach to managing stability within the protocol. On the native token front, Salt.sol (16 lines) showcases an elegant and concise imple

// Example Multi-Signature Implementation
function executeMultiSig(address[] memory signers, bytes memory transaction) external {
    require(validateSignatures(signers, transaction), "Invalid signatures");
    // Execute the transaction
}

// Example Parameterized Timelock Implementation
function proposeTimelock(uint256 newTimelock) external onlyAdmin {
    // Additional checks and validations
    activeTimelock = block.timestamp + newTimelock;
}


Rickard Q

# USE A MORE RECENT VERSION OF SOLIDITY
Use a solidity version of at least 0.8.2 to get simple compiler automatic inclining.
Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads.
Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper than revert() / require().
Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the call has a return value.
Use a solidity version of at least 0.8.12 to get string.concat() to be used instead of abi.encodePacked(<str>,<str>)
Use at least 0.8.13 to adopt using for with a list of free functions.

- BaseSmartAccount.sol
- Proxy.sol
- SmartAccount.sol
- SmartAccountFactory.sol
- IAggregator.sol
- Executor.sol
- FallbackManager.sol
- ModuleManager.sol
- Enum.sol
- SecuredTokenTransfer.sol
- SignatureDecoder.sol
- Singleton.sol
- DefaultCallbackHandler.sol
- ERC721TokenReceiver.sol
- ERC777TokensRecipient.sol
- ERC1155TokenReceiver.sol
- IERC165.sol
- IERC1271Wallet.sol
- ISignatureValidator.sol
- LibAddress.sol
- Math.sol
- MultiSend.sol
- MultiSendCallOnly.sol

There are 23 instances of this issue:
```
pragma solidity 0.8.12;
```
# USE CUSTOM IMPORTS INSTEAD OF THE PLAIN “IMPORT” “FILE.SOL”
There are 38 instances of this issue:
BaseSmartAccount.sol
```
10	-	import "./common/Enum.sol";
10	+	import {Enum} from "./common/Enum.sol";
```
SmartAccount.sol
```
4	-	import "./libs/LibAddress.sol";
8	-	import "./BaseSmartAccount.sol";
9	-	import "./common/Singleton.sol";
10	-	import "./base/ModuleManager.sol";
11	-	import "./base/FallbackManager.sol";
12	-	import "./common/SignatureDecoder.sol";
13	-	import "./common/SecuredTokenTransfer.sol";
14	-	import "./interfaces/ISignatureValidator.sol";
15	-	import "./interfaces/IERC165.sol";

4	+	import {LibAddress} from "./libs/LibAddress.sol";
8	+	import {BaseSmartAccount} from "./BaseSmartAccount.sol";
9	+	import {Singleton} from "./common/Singleton.sol";
10	+	import {ModuleMa

// Code block 1 (unknown):
pragma solidity 0.8.12;

// Code block 2 (unknown):
10	-	import "./common/Enum.sol";
10	+	import {Enum} from "./common/Enum.sol";


gkrastenov Q

# Low issues

## [L-01] Elapsed time should be % day == 0
### Impact
When setting a new range, the elapsed time between the start and end of the period should be % DAY == 0 to minimize precision errors in the calculation of elapsed days.

### Recommended Mitigation Steps
Add an additional check for `(lastRange.end - endTimestamp) % day == 0` in the `setRange` function.

## [L-02] Incorrect events
### Impact
When `Transfer` and `TransferShares` events are emitted, the wrong value is set. The USDY amount should be multiplied by `BPS_DENOMINATOR`.

### Recommended Mitigation Steps
Make the following changes:

```solidity
emit Transfer(address(0), msg.sender, getRUSDYByShares(_USDYAmount * BPS_DENOMINATOR));

emit TransferShares(address(0), msg.sender, _USDYAmount * BPS_DENOMINATOR);
```

## [L-03] Missing check for sharesAmount >= BPS_DENOMINATOR in transferShares
In the `transferShares` function, a check for `sharesAmount >= BPS_DENOMINATOR` is missing,it should be similar to `unwrap` function. Small share amounts may result in precision errors.

## [L-04] setThresholds should not accept empty arrays
### Impact
If the `setThresholds` function receives empty arrays for `amounts` and `numOfApprovers`, it will delete `chainToThresholds[srcChain]` and the `_attachThreshold` function will fail.

### Recommended Mitigation Steps
Add an additional check for that:

```
f (amounts.length == 0) {
      revert ArrayLengthIsZero();
    }
```

## [L-05] if numOfApprovers[i] <= 2 than tx will be approved everytime
### Impact
If `numOfApprovers[i] <= 2`, every transaction for this amount will be approved only for one approver.

### Recommended Mitigation Steps
Add an additional check for that:
```
if(numOfApprovers[i] <= 2){
    revert SmallNumOfApprovers
}
```

## [L-06] if numOfApprovers[i] <= 2 than tx will be approved everytime
### Impact
If `numOfApprovers[i] <= 2`, every transaction for this amount will be approved only for one approver.

### Recommended Mitigation Steps

// Code block 1 (solidity):
emit Transfer(address(0), msg.sender, getRUSDYByShares(_USDYAmount * BPS_DENOMINATOR));

emit TransferShares(address(0), msg.sender, _USDYAmount * BPS_DENOMINATOR);

// Code block 2 (unknown):
f (amounts.length == 0) {
      revert ArrayLengthIsZero();
    }

// Code block 3 (unknown):
if(numOfApprovers[i] <= 2){
    revert SmallNumOfApprovers
}


CodeFoxInc G

# Gas Optimization

## Gas-01 The `onlyOwner` functions can be set as `payable` to save gas

### Context

[https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L165-L244](https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L165-L244)

The `onlyOwner` functions can be set as `payable` to save gas. Also it is the same for `adjustWeight` and `addDerivative` functions.

```diff
- function rebalanceToWeights() external onlyOwner {
+ function rebalanceToWeights() external onlyOwner payable {

...

function adjustWeight(
        uint256 _derivativeIndex,
        uint256 _weight
+    ) external onlyOwner payable {
-    ) external onlyOwner {

...

function addDerivative(
        address _contractAddress,
        uint256 _weight
-    ) external onlyOwner {
+    ) external onlyOwner payable {

...

function setMaxSlippage(
        uint _derivativeIndex,
        uint _slippage
-   ) external onlyOwner {
+    ) external onlyOwner payable { // @audit the previleged owner should be documented for users to understand the risks
        derivatives[_derivativeIndex].setMaxSlippage(_slippage);
        emit SetMaxSlippage(_derivativeIndex, _slippage);
    }

    /**
        @notice - Sets the minimum amount a user is allowed to stake
        @param _minAmount - amount to set as minimum stake value
    */
-    function setMinAmount(uint256 _minAmount) external onlyOwner {
+    function setMinAmount(uint256 _minAmount) external onlyOwner payable {
        minAmount = _minAmount;
        emit ChangeMinAmount(minAmount);
    }

    /**
        @notice - Owner only function that sets the maximum amount a user is allowed to stake
        @param _maxAmount - amount to set as maximum stake value
    */
-    function setMaxAmount(uint256 _maxAmount) external onlyOwner {
+    function setMaxAmount(uint256 _maxAmount) external onlyOwner payable {
        ma


bin2chen Q

L-01:`maxSlippage` Slippage does not provide real protection
Currently individual `derivatives` are protected against slippage when exchanging, but the estimated prices are all from the `pool price` of the same transaction
When the price drops sharply, the estimated price also drops sharply, and `minOut` also drops sharply, resulting in very limited protection from slippage
It is recommended to calculate `minOut` without adding `pool price` to the calculation, and to calculate `minOut` directly based on the expected eth

```solidity
contract SfrxEth is IDerivative, Initializable, OwnableUpgradeable {
    function withdraw(uint256 _amount) external onlyOwner {
...
-        uint256 minOut = (((ethPerDerivative(_amount) * _amount) / 10 ** 18) *
-            (10 ** 18 - maxSlippage)) / 10 ** 18;
+        uint256 minOut = (_amount / 10 ** 18 *
+            (10 ** 18 - maxSlippage)) / 10 ** 18;

```
```solidity
contract Reth is IDerivative, Initializable, OwnableUpgradeable {
...
    function deposit() external payable onlyOwner returns (uint256) {
-           uint256 minOut = ((((rethPerEth * msg.value) / 10 ** 18) *
+           uint256 minOut = (((msg.value / 10 ** 18) *
                ((10 ** 18 - maxSlippage))) / 10 ** 18);
```

L-02:stake()/unstake() minAmount/maxAmount Problem
1. take() only determines maxAmount for this time, and does not add how many shares the current user already has
2. unstake() does not limit `_safEthAmount`, so after unstake, the value of the user's remaining shares may be less than minAmount.

It is recommended to add a judgment to the existing shares, but not this minAmount/maxAmount does not work

L-03:adjustWeight() lacks the judgment _derivativeIndex < derivativeCount
If _derivativeIndex > derivativeCount, the adjustment is invalid
Suggestion.
```solidity
    function adjustWeight(
        uint256 _derivativeIndex,
        uint256 _weight
    ) external onlyOwner {

+       require(_derivativeIndex<derivativeCount,"bad i

// Code block 1 (solidity):
contract SfrxEth is IDerivative, Initializable, OwnableUpgradeable {
    function withdraw(uint256 _amount) external onlyOwner {
...
-        uint256 minOut = (((ethPerDerivative(_amount) * _amount) / 10 ** 18) *
-            (10 ** 18 - maxSlippage)) / 10 ** 18;
+        uint256 minOut = (_amount / 10 ** 18 *
+            (10 ** 18 - maxSlippage)) / 10 ** 18;

// Code block 2 (solidity):
contract Reth is IDerivative, Initializable, OwnableUpgradeable {
...
    function deposit() external payable onlyOwner returns (uint256) {
-           uint256 minOut = ((((rethPerEth * msg.value) / 10 ** 18) *
+           uint256 minOut = (((msg.value / 10 ** 18) *
                ((10 ** 18 - maxSlippage))) / 10 ** 18);

contract SfrxEth is IDerivative, Initializable, OwnableUpgradeable {
    function withdraw(uint256 _amount) external onlyOwner {
...
-        uint256 minOut = (((ethPerDerivative(_amount) * _amount) / 10 ** 18) *
-            (10 ** 18 - maxSlippage)) / 10 ** 18;
+        uint256 minOut = (_amount / 10 ** 18 *
+            (10 ** 18 - maxSlippage)) / 10 ** 18;

contract Reth is IDerivative, Initializable, OwnableUpgradeable {
...
    function deposit() external payable onlyOwner returns (uint256) {
-           uint256 minOut = ((((rethPerEth * msg.value) / 10 ** 18) *
+           uint256 minOut = (((msg.value / 10 ** 18) *
                ((10 ** 18 - maxSlippage))) / 10 ** 18);


lilizhu G

Duplicated require()/revert() checks should be refactored to a modifier or function。

**Saves deployment costs**

***There are 4 instances of this issue:***

```jsx
require( userShareForPool( msg.sender, collateralPoolID ) > 0, "User does not have any collateral" );
```

[https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/stable/CollateralAndLiquidity.sol#L83](https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/stable/CollateralAndLiquidity.sol#L83C12-L83C28)

https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/stable/CollateralAndLiquidity.sol#L98

https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/stable/CollateralAndLiquidity.sol#L98

```jsx
require( poolIDs.length == profitsForPools.length, "Incompatible array lengths" );
```

https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/rewards/SaltRewards.sol#L60

https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/rewards/SaltRewards.sol#L120

```jsx
require( bytes(country).length == 2, "Country must be an ISO 3166 Alpha-2 Code" );
```

https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/dao/Proposals.sol#L224

https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/dao/Proposals.sol#L233

```jsx
require( block.timestamp >= user.cooldownExpiration, "Must wait for the cooldown to expire" );
```

https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/staking/StakingRewards.sol#L67

https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/staking/StakingRewards.sol#L107

// Code block 1 (jsx):
require( userShareForPool( msg.sender, collateralPoolID ) > 0, "User does not have any collateral" );

// Code block 2 (jsx):
require( poolIDs.length == profitsForPools.length, "Incompatible array lengths" );

// Code block 3 (jsx):
require( bytes(country).length == 2, "Country must be an ISO 3166 Alpha-2 Code" );

// Code block 4 (jsx):
require( block.timestamp >= user.cooldownExpiration, "Must wait for the cooldown to expire" );

CollateralAndLiquidity.sol#L83, CollateralAndLiquidity.sol#L98, SaltRewards.sol#L60, SaltRewards.sol#L120, Proposals.sol#L224, Proposals.sol#L233, StakingRewards.sol#L67, StakingRewards.sol#L107

CollateralAndLiquidity.sol, StakingRewards.sol, Proposals.sol, SaltRewards.sol


SBSecurity Q

### [Low Risk](#low-risk)

| Count | Title |
| --- | --- |
| [L-01] | When contract is not paused `emergencywithdraw` is not possible |

| Total Low Risk Issues | 1 |
| --- | --- |

### [Non-Critical](#non-critical)

| Count | Title |
| --- | --- |
| [NC-01] | Typos |
| [NC-02] | Place commonly used strings in constants |

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

## Low Risk

## [L-01] When contract is not paused `emergencywithdraw` is not possible

## Impact

EmergencyWithdraw is intended to be used when there is a vulnerability in the protocol and funds are at risk. There are scenarios when immediate actions are needed and protocol admins should react without the need to trigger `Pause()` first.
However the current implementation of `emergencyWithdraw` function in most of the protocol’s contracts, this is not possible.
Despite the fact it doesn’t open any additional vulnerabilities, such a check is unnecessary in that types of functions
There can be scenarios where withdrawing all the user funds without the need to pause the protocol first can be critical for the good image of the protocol.

For example, `UniswapV2LiquidityAmo` and `UniswapV3LiquidityAmo` contracts `emergencyWithdraw` functions don’t have such a check.

https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/reserve/RdpxReserve.sol#L67

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

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

https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/core/RdpxV2Core.sol#L164

## Non-Critical

## **[N‑01] Typos**

```solidity
File: contracts/amo/UniV3LiquidityAmo.sol

/// @audit Uniswap
11:     // Uniswamp V3
```

https://github.com/code-423n4/2023-08-dopex/blob/b174dcd7b68a5372d7b9

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

/// @audit Uniswap
11:     // Uniswamp V3

RdpxReserve.sol#L67, RdpxDecayingBonds.sol#L96, PerpetualAtlanticVault.sol#L222, RdpxV2Core.sol#L164

PerpetualAtlanticVault.sol, RdpxV2Core.sol, RdpxDecayingBonds.sol, RdpxReserve.sol


shaflow2 Q

## [01]Avoid using deprecated methods

ChainlinkPriceOracle used the latestAnswer() function when requesting a price. But this method has already been enabled, consider using latestRoundData instead.

File:ChainlinkPriceOracle.sol
GitHub:[[37](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/oracles/ChainlinkPriceOracle.sol#L37)]
```solidity
    function getAssetPrice(address asset) external view onlySupportedAsset(asset) returns (uint256) {
        return AggregatorInterface(assetPriceFeed[asset]).latestAnswer();
    }
```

## [02]Return value type mismatch

In the chainlink contract AggregatorProxy, calling latestAnswer() returns the int256 type, while the project requests lastAnswer() and returns the uint256 type.
Although this will not cause security issues, consider maintaining consistent return value types.
File:ChainlinkPriceOracle.sol
GitHub:[[37](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/oracles/ChainlinkPriceOracle.sol#L37)]
```solidity
    function getAssetPrice(address asset) external view onlySupportedAsset(asset) returns (uint256) {
        return AggregatorInterface(assetPriceFeed[asset]).latestAnswer();
    }
```

File:chainlink/contracts/src/v0.7/dev/AggregatorProxy.sol
GitHub:[[41](https://github.com/smartcontractkit/chainlink/blob/66d9e23219831c8ecd937431ead528dc0e9afcbb/contracts/src/v0.7/dev/AggregatorProxy.sol#L41C15-L41C15)]
```solidity
    function latestAnswer() public view virtual override returns (int256 answer) {
        return s_currentPhase.aggregator.latestAnswer();
    }
```

// Code block 1 (solidity):
function getAssetPrice(address asset) external view onlySupportedAsset(asset) returns (uint256) {
        return AggregatorInterface(assetPriceFeed[asset]).latestAnswer();
    }

// Code block 2 (solidity):
function getAssetPrice(address asset) external view onlySupportedAsset(asset) returns (uint256) {
        return AggregatorInterface(assetPriceFeed[asset]).latestAnswer();
    }

// Code block 3 (solidity):
function latestAnswer() public view virtual override returns (int256 answer) {
        return s_currentPhase.aggregator.latestAnswer();
    }

function getAssetPrice(address asset) external view onlySupportedAsset(asset) returns (uint256) {
        return AggregatorInterface(assetPriceFeed[asset]).latestAnswer();
    }

function getAssetPrice(address asset) external view onlySupportedAsset(asset) returns (uint256) {
        return AggregatorInterface(assetPriceFeed[asset]).latestAnswer();
    }

function latestAnswer() public view virtual override returns (int256 answer) {
        return s_currentPhase.aggregator.latestAnswer();
    }


ArbitraryExecution G

### Redundant external `balanceOf` call

Gas savings in the [`deposit`](https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/SfrxEth.sol#L94) function in `SfrxEth.sol` can be had by returning the return value from the [`submitAndDeposit`](https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/SfrxEth.sol#L101) external call. This would eliminate two external `balanceOf` external calls, as well as the [subtraction operation](https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/SfrxEth.sol#L105).

### Redundant external `balanceOf` call

Gas savings in the [`withdraw`](https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/WstEth.sol#L56) function in `WstEth.sol` can be had by saving off the return value of the [`unwrap`](https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/WstEth.sol#L57) call and using that return value instead of making an additional [`balanceOf`](https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/WstEth.sol#L58) external call to the `STETH_TOKEN` address.

### Use an Array instead of a mapping

The following loop could be made more gas efficient by changing the `derivatives` variable type:

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

A storage pointer can't be used here because its a mapping so the elements won't be contiguous.
If the `derivatives` variable is changed from a mapping to an array a storage pointer could be used and would result in significant gas savings.

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

SfrxEth.sol#L94, SfrxEth.sol#L101, SfrxEth.sol#L105, WstEth.sol#L56, WstEth.sol#L57, WstEth.sol#L58


IceBear Q

## Non Critical Issues

| |Issue|Instances|
|-|:-|:-:|
| [N-1](#N-1) | Missing checks for `address(0)` when assigning values to address state variables  | 2 |
| [N-2](#N-2) | Use of block.timestamp | 4 |
| [N-3](#N-3) | Maximum Line Length | 103 |
| [N-4](#N-4) |  `require()` / `revert()` statements should have descriptive reason strings  | 1 |
| [N-5](#N-5) | Event is missing `indexed` fields | 12 |
| [N-6](#N-6) | Functions not used internally could be marked external  | 22 |
### [N-1] Missing checks for `address(0)` when assigning values to address state variables

*Find (2) instance(s) in contracts*:
```solidity
File: Factory.sol

130:         privatePoolMetadata = _privatePoolMetadata;

136:         privatePoolImplementation = _privatePoolImplementation;

```
[Factory.sol](https://github.com/code-423n4/2023-04-caviar/blob/main/src/Factory.sol)

### [N-2] Use of block.timestamp
Block timestamps have historically been used for a variety of applications, such as entropy for random numbers (see the 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.
#### Recommended Mitigation Steps
Block timestamps should not be used for entropy or generating random numbers — i.e., they should not be the deciding factor (either directly or through some derivation) for winning a game or changing an important state.

Time-sensitive logic is sometimes required; e.g., for unlocking contracts (time-locking), completing an ICO after a few weeks, or enforcing expiry dates. It is sometimes recommended to use block.number and an average block time to estimate times; with a 10 second block time, 1 week equates to approximately, 60480 blocks. Thus, specifying a block number at which to change a contract state can be more secure, as miners are unable

File: EthRouter.sol

101:         if (block.timestamp > deadline && deadline != 0) {

154:         if (block.timestamp > deadline && deadline != 0) {

228:         if (block.timestamp > deadline && deadline != 0) {

256:         if (block.timestamp > deadline && deadline != 0) {

// Code block 1 (solidity):
File: Factory.sol

130:         privatePoolMetadata = _privatePoolMetadata;

136:         privatePoolImplementation = _privatePoolImplementation;


ayden Q

1.When there is no limit to the range when setting the maxSlippage, if the slippage set exceeds a reasonable range, it may cause losses to the investor's funds
Recommended setting range：maxSlippage  %0.5 ~ %2

2.When the weights are set improperly, it may cause losses to investors. Improper weightings can cause the value of the derivative to deviate from the underlying asset, which may result in a lack of liquidity or inaccurate pricing for investors seeking to enter or exit positions. This may lead to losses for investors who have not properly assessed the risks and have invested in the derivative. It is important to properly set the weights and perform rigorous risk management to avoid such negative consequences.

3.When unstaking, it is necessary to check whether the user has a sufficient safEth balance.
https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L108#L129

```solidity
+ require(balanceOf(msg.sender)>=_safEthAmount, "insufficient balance");
```

// Code block 1 (solidity):
+ require(balanceOf(msg.sender)>=_safEthAmount, "insufficient balance");


SAQ G

## Summary

### Gas Optimization

no | Issue |Instances||
|-|:-|:-:|:-:|
| [G-01] | Add unchecked{} for subtractions where the operands cannot underflow because of a previous require() or if statement | 2 | - |
| [G-02] | keccak256() should only need to be called on a specific string literal once | 2 | - |
| [G-03] | Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead | 1 | - |
| [G-04] | Using fixed bytes is cheaper than using string | 8 | - |
| [G-05] | Expressions for constant values such as a call to keccak256(), should use immutable rather than constant | 5 | - |
| [G-06] | Can make the variable outside the loop to save gas | 5 | - |
| [G-07] | Using calldata instead of memory for read-only arguments in external functions, saves gas | 5 | - |
| [G-08] | Should use arguments instead of state variable | 4 | - |
| [G-09] | Use assembly to check for address(0) | 26 | - |
| [G-10] | Before transfer of  some functions, we should check some variables for possible gas save | 6 | - |
| [G-11] | Use bitmap to save gas | 5 | - |
| [G-12] | Require() or revert() statements that check input arguments should be at the top of the function   | 1 | - |
| [G-13] | Empty blocks should be removed or emit something | 1 | - |
| [G-14] | Don't initialize variables with default value | 1 | - |
| [G-15] | With assembly, .call (bool success)  transfer can be done gas-optimized | 2 | - |
| [G-16] | Duplicated require()/if() checks should be refactored to a modifier or function | 1 | - |
| [G-17] | Use constants instead of type(uintx).max | 7 | - |
| [G-18] | Use assembly to write address storage values | 3 | - |
| [G-19] | Multiple accesses of a mapping/array should use a local variable cache | 2 | - |
| [G-20] | Caching global variables is more expensive than using the actual variable (use msg.sender or block.timestamp instead of caching it) | 1 | - |
| [G-21] | A modifier used only once and not being inherited should be inlined to save gas | 1 | - |
| [G-22] | Do not c

file: /contracts/core/RdpxV2Core.sol

670      uint256 discountReceivedInWeth = _bondAmount -
671        _wethAmount -
672        rdpxAmountInWeth;

1002        balance = balance - totalWethDelegated;

file: /contracts/perp-vault/PerpetualAtlanticVault.sol

467        uint256 startTime = lastUpdateTime == 0
             ? (nextFundingPaymentTimestamp() - fundingDuration)
469          : lastUpdateTime;


Dewaxindo Q

## Potential Impact
This exploit allowed an attacker to “double exercise” ETH value and steal the collateral posted by certain users.

## Proof of Concept
1. In `SafEth.sol` Contract allows anyone to stake their ETH.
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/SafEth.sol#L63-L101

2. However inside the `stake()` function there is `msg.value` used inside a loop.
```Solidity
for (uint i = 0; i < derivativeCount; i++) {
            uint256 weight = weights[i];
            IDerivative derivative = derivatives[i];
            if (weight == 0) continue;
            uint256 ethAmount = (msg.value * weight) / totalWeight;

            // This is slightly less than ethAmount because slippage
            uint256 depositAmount = derivative.deposit{value: ethAmount}();
            uint derivativeReceivedEthValue = (derivative.ethPerDerivative(
                depositAmount
            ) * depositAmount) / 10 ** 18;
            totalStakeValueEth += derivativeReceivedEthValue;
        }
```
```Solidity
uint256 ethAmount = (msg.value * weight) / totalWeight;
```
3. As shown in the above code snippet, the loop function getting total amount of derivatives worth of ETH in system

4. This leads to the same `msg.value` amount of ETH would be re-used in the second or further `stake()` calls in the same transaction. But, only the first batch of ETH is received.

References(Past Incident):
- https://peckshield.medium.com/opyn-hacks-root-cause-analysis-c65f3fe249db
- https://blog.trailofbits.com/2021/12/16/detecting-miso-and-opyns-msg-value-reuse-vulnerability-with-slither/
- https://medium.com/opyn/opyn-eth-put-exploit-c5565c528ad2

## Tools Used

Slither

## Recommended Mitigation Steps

1. Use a local variable `msgValue` to keep the amount of `msg.value` in Solidity. This allows to calculate and book-keep how much ETH had been staked.
2. In addition, `address(this).balance` could be used to check if the smart contract

// Code block 1 (Solidity):
for (uint i = 0; i < derivativeCount; i++) {
            uint256 weight = weights[i];
            IDerivative derivative = derivatives[i];
            if (weight == 0) continue;
            uint256 ethAmount = (msg.value * weight) / totalWeight;

            // This is slightly less than ethAmount because slippage
            uint256 depositAmount = derivative.deposit{value: ethAmount}();
            uint derivativeReceivedEthValue = (derivative.ethPerDerivative(
                depositAmount
            ) * depositAmount) / 10 ** 18;
            totalStakeValueEth += derivativeReceivedEthValue;
        }

// Code block 2 (Solidity):
uint256 ethAmount = (msg.value * weight) / totalWeight;

for (uint i = 0; i < derivativeCount; i++) {
            uint256 weight = weights[i];
            IDerivative derivative = derivatives[i];
            if (weight == 0) continue;
            uint256 ethAmount = (msg.value * weight) / totalWeight;

            // This is slightly less than ethAmount because slippage
            uint256 depositAmount = derivative.deposit{value: ethAmount}();
            uint derivativeReceivedEthValue = (derivative.ethPerDerivative(
                depositAmount
            ) * depositAmount) / 10 ** 18;
            totalStakeValueEth += derivativeReceivedEthValue;
        }

uint256 ethAmount = (msg.value * weight) / totalWeight;


Josiah Q

## UNUTILIZED LIBRARY
Throughout the code bases, there are instances where functions in Math.sol are re-implemented instead of getting them utilized via library import.

[Math.sol](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/libs/Math.sol)

```
19:    function max(uint256 a, uint256 b) internal pure returns (uint256) {

26:    function min(uint256 a, uint256 b) internal pure returns (uint256) {
```
[SmartAccount.sol](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol)

```
181:    function max(uint256 a, uint256 b) internal pure returns (uint256) {

224:        require(gasleft() >= max((_tx.targetTxGas * 64) / 63,_tx.targetTxGas + 2500) + 500, "BSA010");
```
[UserOperation.sol](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/interfaces/UserOperation.sol)

```
53:        return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);

77    function min(uint256 a, uint256 b) internal pure returns (uint256) {
```
[EntryPoint.sol](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol)

```
492:        return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);

496:    function min(uint256 a, uint256 b) internal pure returns (uint256) {
```
## MISSING EVENTS ON CRITICAL OPERATIONS
Critical operations not triggering events will make it difficult to review the correct behavior of the contracts. Users and blockchain monitoring systems will not be able to easily detect suspicious behaviors without events.

Here is 1 instance found.

[VerifyingSingletonPaymaster.sol#L65](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/paymasters/verifying/singleton/VerifyingSingletonPaymaster.sol#L65)

```
    function setSigner( address _newVerifyingSigner) external on

// Code block 1 (unknown):
19:    function max(uint256 a, uint256 b) internal pure returns (uint256) {

26:    function min(uint256 a, uint256 b) internal pure returns (uint256) {

// Code block 2 (unknown):
181:    function max(uint256 a, uint256 b) internal pure returns (uint256) {

224:        require(gasleft() >= max((_tx.targetTxGas * 64) / 63,_tx.targetTxGas + 2500) + 500, "BSA010");

// Code block 3 (unknown):
53:        return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);

77    function min(uint256 a, uint256 b) internal pure returns (uint256) {

// Code block 4 (unknown):
492:        return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);

496:    function min(uint256 a, uint256 b) internal pure returns (uint256) {

Math.sol, SmartAccount.sol, UserOperation.sol, EntryPoint.sol, VerifyingSingletonPaymaster.sol#L65

VerifyingSingletonPaymaster.sol, EntryPoint.sol, Math.sol, SmartAccount.sol, UserOperation.sol


2997ms Q

# 1. Check the ```_amount == 0``` before executing

There are multiple places just checking address but not checking the _amount == 0 in rUSDY.sol file. If we check the amount == 0 first, it can save some gas and no need to execute then next steps.

https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L245
https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L277
https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L304
https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/usdy/rUSDY.sol#L488

# 2. Refactor the codes
https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L179-L183
```
 if (t.numberOfApprovalsNeeded <= t.approvers.length) {
      return true;
    } else {
      return false;
    }
```
This can be refactored to ```return t.numberOfApprovalsNeeded <= t.approvers.length```
# 3. Refactor the codes
https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L159
```
    if (t.approvers.length > 0) {
      for (uint256 i = 0; i < t.approvers.length; ++i) {
        if (t.approvers[i] == msg.sender) {
          revert AlreadyApproved();
        }
      }
    }
```
Remove the line of ``` if (t.approvers.length > 0)```, there is no need for this condition.

// Code block 1 (unknown):
if (t.numberOfApprovalsNeeded <= t.approvers.length) {
      return true;
    } else {
      return false;
    }

// Code block 2 (unknown):
# 3. Refactor the codes
https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/DestinationBridge.sol#L159

// Code block 3 (unknown):
Remove the line of

rUSDY.sol#L245, rUSDY.sol#L277, rUSDY.sol#L304, rUSDY.sol#L488, DestinationBridge.sol#L179-L183, DestinationBridge.sol#L159


MrPotatoMagic Q

## [N-01] Missing event emission for critical state changes

https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/miner/EUSDMiningIncentives.sol#L84
All functions from Line 84-130 do not have events and their emissions even though they change state variables.
```solidity
File: contracts/lybra/miner/EUSDMiningIncentives.sol
84:    function setToken(address _lbr, address _eslbr) external onlyOwner {
85:         LBR = _lbr;
86:         esLBR = _eslbr;
87:     }
88:
89:     function setLBROracle(address _lbrOracle) external onlyOwner {
90:         lbrPriceFeed = AggregatorV3Interface(_lbrOracle);
91:     }
92:
93:     function setPools(address[] memory _pools) external onlyOwner {
94:         for (uint i = 0; i < _pools.length; i++) {
95:             require(configurator.mintVault(_pools[i]), "NOT_VAULT");
96:         }
97:         pools = _pools;
98:     }
99:
100:     function setBiddingCost(uint256 _biddingRatio) external onlyOwner {
101:         require(_biddingRatio <= 8000, "BCE");
102:         biddingFeeRatio = _biddingRatio;
103:     }
104:
105:     function setExtraRatio(uint256 ratio) external onlyOwner {
106:         require(ratio <= 1e20, "BCE");
107:         extraRatio = ratio;
108:     }
109:
110:     function setPeUSDExtraRatio(uint256 ratio) external onlyOwner {
111:         require(ratio <= 1e20, "BCE");
112:         peUSDExtraRatio = ratio;
113:     }
114:
115:     function setBoost(address _boost) external onlyOwner {
116:         esLBRBoost = IesLBRBoost(_boost);
117:     }
118:
119:     function setRewardsDuration(uint256 _duration) external onlyOwner {
120:         require(finishAt < block.timestamp, "reward duration not finished");
121:         duration = _duration;
122:     }
123:
124:     function setEthlbrStakeInfo(address _pool, address _lp) external onlyOwner {
125:         ethlbrStakePool = _pool;
126:         ethlbrLpToken = _lp;
127:     }
128:     function setEUSDBuyoutAllowed

File: contracts/lybra/miner/EUSDMiningIncentives.sol
84:    function setToken(address _lbr, address _eslbr) external onlyOwner {
85:         LBR = _lbr;
86:         esLBR = _eslbr;
87:     }
88:
89:     function setLBROracle(address _lbrOracle) external onlyOwner {
90:         lbrPriceFeed = AggregatorV3Interface(_lbrOracle);
91:     }
92:
93:     function setPools(address[] memory _pools) external onlyOwner {
94:         for (uint i = 0; i < _pools.length; i++) {
95:             require(configurator.mintVault(_pools[i]), "NOT_VAULT");
96:         }
97:         pools = _pools;
98:     }
99:
100:     function setBiddingCost(uint256 _biddingRatio) external onlyOwner {
101:         require(_biddingRatio <= 8000, "BCE");
102:         biddingFeeRatio = _biddingRatio;
103:     }
104:
105:     function setExtraRatio(uint256 ratio) external onlyOwner {
106:         require(ratio <= 1e20, "BCE");
107:         extraRatio = ratio;
108:     }
109:
110:     function setPeUSDExtraRatio(uint256 ratio) external onlyOwner {
111:         require(ratio <= 1e20, "BCE");
112:         peUSDExtraRatio = ratio;
113:     }
114:
115:     function setBoost(address _boost) external onlyOwner {
116:         esLBRBoost = IesLBRBoost(_boost);
117:     }
118:
119:     function setRewardsDuration(uint256 _duration) external onlyOwner {
120:         require(finishAt < block.timestamp, "reward duration not finished");
121:         duration = _duration;
122:     }
123:
124:     function setEthlbrStakeInfo(address _pool, address _lp) external onlyOwner {
125:         ethlbrStakePool = _pool;
126:         ethlbrLpToken = _lp;
127:     }
128:     function setEUSDBuyoutAllowed(bool _bool) external onlyOwner {
129:         isEUSDBuyoutAllowed = _bool;
130:     }

File: contracts/lybra/configuration/LybraConfigurator.sol
98: function initToken(address _eusd, address _peusd) external onlyRole(DAO) {
99:         if (address(EUSD) == address(0)) EUSD = IEUSD(_eusd);
100:         if (address(peUSD) == address(0)) peUSD = IEUSD(_peusd);
101:     }

109: function setMintVault(address pool, bool isActive) external onlyRole(DAO) {
110:         mintVault[pool] = isActive;
111:     }

119: function setMintVaultMaxSupply(address pool, uint256 maxSupply) external onlyRole(DAO) {
120:         mintVaultMaxSupply[pool] = maxSupply;
121:     }


Dinesh11G Q

### 1st BUG
Unsafe ERC20 Operation(s)

#### Impact
Issue Information: [L001](https://github.com/byterocket/c4-common-issues/blob/main/2-Low-Risk.md#l001---unsafe-erc20-operations)

#### Findings:
```
2023-01-ondo/contracts/lending/compound/Comptroller.sol::1695 => comp.transfer(user, amount);
```
#### Tools used
Manual VS Code review

### 2nd BUG
Unspecific Compiler Version Pragma

#### Impact
Issue Information:
Avoid floating pragmas for non-library contracts.

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

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

It is recommended to pin to a concrete compiler version.

Example
🤦 Bad:

pragma solidity ^0.8.0;
🚀 Good:

pragma solidity 0.8.4;

#### Findings:
```
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/access/AccessControl.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/access/AccessControlEnumerable.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/access/IAccessControl.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/access/IAccessControlEnumerable.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/access/Ownable.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/proxy/ERC1967Proxy.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/proxy/ERC1967Upgrade.sol::4 => pragma solidity ^0.8.2;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/proxy/IBeacon.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzep

2023-01-ondo/contracts/cash/external/openzeppelin/contracts/access/AccessControl.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/access/AccessControlEnumerable.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/access/IAccessControl.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/access/IAccessControlEnumerable.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/access/Ownable.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/proxy/ERC1967Proxy.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/proxy/ERC1967Upgrade.sol::4 => pragma solidity ^0.8.2;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/proxy/IBeacon.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/proxy/Proxy.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/proxy/ProxyAdmin.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/proxy/TransparentUpgradeableProxy.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/proxy/draft-IERC1822.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/security/Pausable.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/security/ReentrancyGuard.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/token/ERC20.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/token/IERC20.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/contracts/token/IERC20Metadata.sol::4 => pragma solidity ^0.8.0;
2023-01-ondo/contracts/cash/external/openzeppelin/cont

// Code block 1 (unknown):
2023-01-ondo/contracts/lending/compound/Comptroller.sol::1695 => comp.transfer(user, amount);


Diana Q

| S No. | Issue | Instances |
|-----|-----|-----|
| [01] | Best practice is to prevent signature malleability | 1
| [02] | Large multiples of ten should use scientific notation | 6
| [03] | Require() should be used instead of assert() | 20
| [04] | Upgradeable contract is missing a \_\_gap[50] storage variable to allow for new storage variables in later versions | 3
| [05] | Adding a return statement when the function defines a named return variable, is redundant | 18
| [06] | Use a more recent version of solidity | 12
| [07] | Non-library or interface files should use fixed compiler versions, not floating ones | 4
| [08] | Use named imports instead of plain 'import file.sol' | 110

-------------

## 01 Best practice is to prevent signature malleability

Use OpenZeppelin’s `ECDSA` contract rather than calling `ecrecover()` directly

_There is 1 instance of this issue_

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

```
File: Ethos-Core/contracts/LUSDToken.sol

287: address recoveredAddress = ecrecover(digest, v, r, s);
```

-----

## 02 Large multiples of ten should use scientific notation

Use (e.g. 1e12) rather than decimal literals (e.g. 1000000000000), for better code readability

_There are 6 instances of this issue_

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

```
File: Ethos-Core/contracts/ActivePool.sol

127: require(_bps <= 10_000, "Invalid BPS value");
145: require(_treasurySplit + _SPSplit + _stakingSplit == 10_000, "Splits must add up to 10000 BPS");
258: vars.percentOfFinalBal = vars.finalBalance == 0 ? uint256(-1) : vars.currentAllocated.mul(10_000).div(vars.finalBalance);
262: vars.finalYieldingAmount = vars.finalBalance.mul(vars.yieldingPercentage).div(10_000);
291: vars.treasurySplit = vars.profit.mul(yieldSplitTreasury).div(10_000);
296: vars.stakingSplit = vars.profit.mul(yieldSplitStaking).div(10_000);
```

----------

## 03 Require() should be used instead

// Code block 1 (unknown):
File: Ethos-Core/contracts/LUSDToken.sol

287: address recoveredAddress = ecrecover(digest, v, r, s);

// Code block 2 (unknown):
File: Ethos-Core/contracts/ActivePool.sol

127: require(_bps <= 10_000, "Invalid BPS value");
145: require(_treasurySplit + _SPSplit + _stakingSplit == 10_000, "Splits must add up to 10000 BPS");
258: vars.percentOfFinalBal = vars.finalBalance == 0 ? uint256(-1) : vars.currentAllocated.mul(10_000).div(vars.finalBalance);
262: vars.finalYieldingAmount = vars.finalBalance.mul(vars.yieldingPercentage).div(10_000);
291: vars.treasurySplit = vars.profit.mul(yieldSplitTreasury).div(10_000);
296: vars.stakingSplit = vars.profit.mul(yieldSplitStaking).div(10_000);


IceBear Q

## Non Critical Issues

| |Issue|Instances|
|-|:-|:-:|
| [N-1](#N-1) | Large multiples of ten should use scientific notation rather than decimal literals, for readability | 21 |
| [N-2](#N-2) | Unused imports | 6 |
| [N-3](#N-3) | Unused parameters | 2 |
| [N-4](#N-4) | For modern and more readable code; update import usages | 31 |

## Low Issues

| |Issue|Instances|
|-|:-|:-:|
| [L-1](#L-1) |Use ownable2stepupgradeable instead of ownableupgradeable contract | 4 |
| [L-2](#L-2) | Non-library/interface files should use fixed compiler versions, not floating ones | 4 |
| [L-3](#L-3) | Unused/Empty RECEIVE()/FALLBACK() function | 4 |
| [L-4](#L-4) | Use of hard-coded addresses may cause errors | 11 |
| [L-5](#L-5) | initialize() function can be called by anybody | 7 |
|[L-6](#L-6) | No storage gap for upgradeable contract might lead to storage slot collision | 5 |
|[L-7](#L-7) | Lack of events emission after sensitive actions | 9 |

### [N-1] Large multiples of ten should use scientific notation rather than decimal literals, for readability
#### Recommendation
Scientific notation should be used for better code readability.
Use scientific notation (e.g. 1e18, 1e5) rather than exponentiation (e.g. 10**18, 100000).

*Find (21) instance(s) in contracts*:
```solidity
File: SafEth/SafEth.sol

54:         minAmount = 5 * 10 ** 17; // initializing with .5 ETH as minimum

55:         maxAmount = 200 * 10 ** 18; // initializing with 200 ETH as maximum

75:                 10 ** 18;

80:             preDepositPrice = 10 ** 18; // initializes with a price of 1

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

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

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

```
[SafEth/SafEth.sol](https://github.com/code-423n4/2023-03-asymmetry/tree/main/contracts/SafEth/SafEth.sol)

```solidity
File: SafEth/derivatives/Reth.sol

44:         maxSlippage = (1 * 10 ** 16); // 1%

171:

File: SafEth/derivatives/Reth.sol

44:         maxSlippage = (1 * 10 ** 16); // 1%

171:             uint rethPerEth = (10 ** 36) / poolPrice();

173:             uint256 minOut = ((((rethPerEth * msg.value) / 10 ** 18) *

174:                 ((10 ** 18 - maxSlippage))) / 10 ** 18);

214:                 RocketTokenRETHInterface(rethAddress()).getEthValue(10 ** 18);

215:         else return (poolPrice() * 10 ** 18) / (10 ** 18);

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

54:         minAmount = 5 * 10 ** 17; // initializing with .5 ETH as minimum

55:         maxAmount = 200 * 10 ** 18; // initializing with 200 ETH as maximum

75:                 10 ** 18;

80:             preDepositPrice = 10 ** 18; // initializes with a price of 1

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

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

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


LinKenji Q

## Titlte: Suboptimal Inheritance in `ChainlinkPriceOracle`.

## Impact

The `ChainlinkPriceOracle` contract inherits from `IPriceFetcher` instead of directly implementing the `ILRTOracle` interface. This is confusing and doesn't fully capture the intent that this is an oracle implementation.

## Proof of Concept

**[ChainlinkPriceOracle.sol](https://github.com/code-423n4/2023-11-kelp/blob/4b34abc952205e2a34bff893a0de0c75b8052149/src/oracles/ChainlinkPriceOracle.sol#L15-L19)**

```solidity
/// @title ChainlinkPriceOracle Contract
/// @notice contract that fetches the exchange rate of assets from chainlink price feeds
contract ChainlinkPriceOracle is IPriceFetcher, LRTConfigRoleChecker, Initializable {

  // ...

}
```

This shows `ChainlinkPriceOracle` inheriting from `IPriceFetcher` instead of `ILRTOracle`.

The `ChainlinkPriceOracle` contract currently inherits from:

- `IPriceFetcher`
- `LRTConfigRoleChecker`
- `Initializable`

But since this is a specific implementation of the `ILRTOracle` interface, it would be clearer to do:

```solidity
contract ChainlinkPriceOracle is ILRTOracle, LRTConfigRoleChecker, Initializable {

  // ...

}
```

The benefits:

- Makes the intent more clear - this implements the oracle interface

- Avoids confusing naming with `IPriceFetcher`

- Allows directly implementing `ILRTOracle` methods

So in summary, changing the inheritance to directly implement the oracle interface better captures the intent and simplifies the contract API.

## Recommended Mitigation

Change the inheritance to:

```solidity
contract ChainlinkPriceOracle is ILRTOracle, LRTConfigRoleChecker, Initializable {

  // ...

}
```

Directly inheriting from the oracle interface better conveys that this is an implementation contract.

## Title: Unnecessary Max Token Approval in NodeDelegator.

## Impact

The `maxApproveToEigenStrategyManager` function approves the EigenLayer manager contract to spend max uint256 tokens from the NodeDelegator. However, `depositAsset

// Code block 1 (solidity):
/// @title ChainlinkPriceOracle Contract
/// @notice contract that fetches the exchange rate of assets from chainlink price feeds
contract ChainlinkPriceOracle is IPriceFetcher, LRTConfigRoleChecker, Initializable {

  // ...

}

// Code block 2 (solidity):
contract ChainlinkPriceOracle is ILRTOracle, LRTConfigRoleChecker, Initializable {

  // ...

}

/// @title ChainlinkPriceOracle Contract
/// @notice contract that fetches the exchange rate of assets from chainlink price feeds
contract ChainlinkPriceOracle is IPriceFetcher, LRTConfigRoleChecker, Initializable {

  // ...

}

contract ChainlinkPriceOracle is ILRTOracle, LRTConfigRoleChecker, Initializable {

  // ...

}


Jorgect G

# GAS REPORT

## G-1 Use internal functions insted of public function.

internal functions are likely to be less gas expensive than public functions. This is because internal functions can only be called from within the same contract and do not need to go through the EVM's message-passing system, which can add additional gas costs.

it should change the functions below not only because internal function are more cheaper, also for security reason:

```
contract Factory.sol line 136
function setPrivatePoolImplementation(address _privatePoolImplementation) public onlyOwner {
        privatePoolImplementation = _privatePoolImplementation;
    }
```

```
contract PrivateFacotry.sol line 877
 function sumWeightsAndValidateProof(
        uint256[] memory tokenIds,
        uint256[] memory tokenWeights,
        MerkleMultiProof memory proof
    ) public view returns (uint256)
```

```
contract PrivateFacotry.sol line 921
  function buyQuote(
        uint256 outputAmount
    )
        public
        view
        returns (
            uint256 netInputAmount,
            uint256 feeAmount,
            uint256 protocolFeeAmount
        )
```

```
contract PrivateFacotry.sol line 978
  function changeFeeQuote(
        uint256 inputAmount
    ) public view returns (uint256 feeAmount, uint256 protocolFeeAmount)
```

### the next functions can be change to external
1. contract PrivateFacotry.sol line 254
2. contract PrivateFacotry.sol line 507
3. contract PrivateFacotry.sol line 385
4. contract PrivateFacotry.sol line 655
5. contract PrivateFacotry.sol line 699
6. contract PrivateFacotry.sol line 734
7. contract PrivateFacotry.sol line 752
8. contract PrivateFacotry.sol line 764
9. contract PrivateFacotry.sol line 778
10. contract PrivateFacotry.sol line 791
11. contract PrivateFacotry.sol line 807

// Code block 1 (unknown):
contract Factory.sol line 136
function setPrivatePoolImplementation(address _privatePoolImplementation) public onlyOwner {
        privatePoolImplementation = _privatePoolImplementation;
    }

// Code block 2 (unknown):
contract PrivateFacotry.sol line 877
 function sumWeightsAndValidateProof(
        uint256[] memory tokenIds,
        uint256[] memory tokenWeights,
        MerkleMultiProof memory proof
    ) public view returns (uint256)

// Code block 3 (unknown):
contract PrivateFacotry.sol line 921
  function buyQuote(
        uint256 outputAmount
    )
        public
        view
        returns (
            uint256 netInputAmount,
            uint256 feeAmount,
            uint256 protocolFeeAmount
        )

// Code block 4 (unknown):
contract PrivateFacotry.sol line 978
  function changeFeeQuote(
        uint256 inputAmount
    ) public view returns (uint256 feeAmount, uint256 protocolFeeAmount)


Audit_Avengers G

## Gas Optimizations

```markdown

|                 | Issue                                                         | Instances |   Gas   |
| :-------------: | :-----------------------------------------------------------: | :-------: | :-----: |
| [GAS-1](#GAS-1) | Variable can be left undeclared in memory                     |     1     |    3    |
| [GAS-2](#GAS-2) | Define `constant` variable instead of hardcoding in function  |     3     |   5-10  |
| [GAS-3](#GAS-3) | Multiple accesses directly to state variable                  |     6     |   20000 |
| [GAS-4](#GAS-4) | Variables need not be initialized to zero                     |     20    |    -    |
| [GAS-5](#GAS-5) | Pre-perform typecasting in `curBurnEpoch`                     |     1     |    3    |
```

### [GAS-1] Variable can be left undeclared in memory

_Instances (1)_:

```solidity
File: /ajna-grants/src/grants/GrantFund.sol
45:    function state(uint256 proposalId_)
		        external
		        view
		        override
		        returns (ProposalState)
		    {
		        FundingMechanism mechanism = findMechanismOfProposal(proposalId_);

		        return
		            mechanism == FundingMechanism.Standard

```

[Link to code](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/GrantFund.sol#L48)

_Recommended: As `findMechanismOfProposal()` returns a struct of FundingMechanism
It is better to directly compare `mechanism == findMechanismOfProposal(proposalId_)` instead.

### [GAS-2] Define `constant` variable instead of hardcoding in function

_Instances (3)_:

```solidity
File: /ajna-grants/src/grants/GrantFund.sol
208:    if (_fundedExtraordinaryProposals.length == 0) {
            return 0.5 * 1e18;
        }
        else {
            return 0.5 * 1e18 + (_fundedExtraordinaryProposals.length * (0.05 * 1e18));
        }

```

[Link to code](https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/

// Code block 1 (markdown):
|                 | Issue                                                         | Instances |   Gas   |
| :-------------: | :-----------------------------------------------------------: | :-------: | :-----: |
| [GAS-1](#GAS-1) | Variable can be left undeclared in memory                     |     1     |    3    |
| [GAS-2](#GAS-2) | Define `constant` variable instead of hardcoding in function  |     3     |   5-10  |
| [GAS-3](#GAS-3) | Multiple accesses directly to state variable                  |     6     |   20000 |
| [GAS-4](#GAS-4) | Variables need not be initialized to zero                     |     20    |    -    |
| [GAS-5](#GAS-5) | Pre-perform typecasting in `curBurnEpoch`                     |     1     |    3    |

// Code block 2 (solidity):
File: /ajna-grants/src/grants/GrantFund.sol
45:    function state(uint256 proposalId_)
		        external
		        view
		        override
		        returns (ProposalState)
		    {
		        FundingMechanism mechanism = findMechanismOfProposal(proposalId_);

		        return
		            mechanism == FundingMechanism.Standard

// Code block 3 (solidity):
File: /ajna-grants/src/grants/GrantFund.sol
208:    if (_fundedExtraordinaryProposals.length == 0) {
            return 0.5 * 1e18;
        }
        else {
            return 0.5 * 1e18 + (_fundedExtraordinaryProposals.length * (0.05 * 1e18));
        }

File: /ajna-grants/src/grants/GrantFund.sol
45:    function state(uint256 proposalId_)
		        external
		        view
		        override
		        returns (ProposalState)
		    {
		        FundingMechanism mechanism = findMechanismOfProposal(proposalId_);

		        return
		            mechanism == FundingMechanism.Standard

File: /ajna-grants/src/grants/GrantFund.sol
208:    if (_fundedExtraordinaryProposals.length == 0) {
            return 0.5 * 1e18;
        }
        else {
            return 0.5 * 1e18 + (_fundedExtraordinaryProposals.length * (0.05 * 1e18));
        }


leegh Q

# [N-01] Incorrect variable comment.
The comment should be "rsETH address" instead of "cbETH address".
```solidity
File: src/LRTConfig.sol

40:    /// @param rsETH_ cbETH address
```
[L40](https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTConfig.sol#L40)

# [N-02] Use same role limit for update asset information.
Consider use ```onlyRole(LRTConstants.MANAGER)``` for ```updateAssetStrategy```. Because ```updateAssetDepositLimit``` limit to MANAGER role, and the two functions are both used to change asset's information.
```solidity
File: src/LRTConfig.sol
109:    function updateAssetStrategy(
110:        address asset,
111:        address strategy
112:    )
113:        external
114:        onlyRole(DEFAULT_ADMIN_ROLE)
```
[L109-L114](https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTConfig.sol#L109-L114)

// Code block 1 (solidity):
File: src/LRTConfig.sol

40:    /// @param rsETH_ cbETH address

// Code block 2 (solidity):
File: src/LRTConfig.sol
109:    function updateAssetStrategy(
110:        address asset,
111:        address strategy
112:    )
113:        external
114:        onlyRole(DEFAULT_ADMIN_ROLE)

File: src/LRTConfig.sol

40:    /// @param rsETH_ cbETH address

File: src/LRTConfig.sol
109:    function updateAssetStrategy(
110:        address asset,
111:        address strategy
112:    )
113:        external
114:        onlyRole(DEFAULT_ADMIN_ROLE)


hihen G

# Gas Report

## Summary

Total **27 instances** over **5 issues**with **27395** gas saved:

|ID|Issue|Instances|Gas|
|:--:|:---|:--:|:--:|
| [[G-01]](#g-01-using-private-for-constants-saves-gas) | Using `private` for constants saves gas | 8 | 27248 |
| [[G-02]](#g-02-do-not-cache-state-variables-that-are-used-only-once) | Do not cache state variables that are used only once | 1 | 3 |
| [[G-03]](#g-03-initializers-can-be-marked-as-payable-to-save-deployment-gas) | Initializers can be marked as payable to save deployment gas | 6 | 126 |
| [[G-04]](#g-04-using-assembly-to-check-for-zero-can-save-gas) | Using assembly to check for zero can save gas | 3 | 18 |
| [[G-05]](#g-05-newer-versions-of-solidity-are-more-gas-efficient) | Newer versions of solidity are more gas efficient | 9 | - |

## Gas Optimizations

### [G-01] Using `private` for constants saves gas

If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that [returns a tuple](https://github.com/code-423n4/2022-08-frax/blob/90f55a9ce4e25bceed3a74290b854341d8de6afa/src/contracts/FraxlendPair.sol#L156-L178) of the values of all currently-public constants. Saves **3406-3606 gas** in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table

There are 8 instances:

- *RSETH.sol* ( [21](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/RSETH.sol#L21) ):

```solidity
21:     bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
```

- *LRTConstants.sol* ( [7](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/utils/LRTConstants.sol#L7), [9](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/utils/LRTConstants.sol#L9), [11

7:     bytes32 public constant R_ETH_TOKEN = keccak256("R_ETH_TOKEN");

9:     bytes32 public constant ST_ETH_TOKEN = keccak256("ST_ETH_TOKEN");

11:     bytes32 public constant CB_ETH_TOKEN = keccak256("CB_ETH_TOKEN");

14:     bytes32 public constant LRT_ORACLE = keccak256("LRT_ORACLE");

15:     bytes32 public constant LRT_DEPOSIT_POOL = keccak256("LRT_DEPOSIT_POOL");

16:     bytes32 public constant EIGEN_STRATEGY_MANAGER = keccak256("EIGEN_STRATEGY_MANAGER");

19:     bytes32 public constant MANAGER = keccak256("MANAGER");

// Code block 1 (solidity):
21:     bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

FraxlendPair.sol#L156-L178, RSETH.sol#L21, LRTConstants.sol#L7, LRTConstants.sol#L9


Praise Q

[L-01] ## _hashProposal() doesn't check to ensure the amounts of Eth to send and calldata to send equals the number of addresses to call
```
    function _hashProposal(
        address[] memory targets_,
        uint256[] memory values_,
        bytes[] memory calldatas_,
        bytes32 descriptionHash_
    ) internal pure returns (uint256 proposalId_) {
        proposalId_ = uint256(keccak256(abi.encode(targets_, values_, calldatas_, descriptionHash_)));
    }
```
https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/Funding.sol#L152-L159

// Code block 1 (unknown):
function _hashProposal(
        address[] memory targets_,
        uint256[] memory values_,
        bytes[] memory calldatas_,
        bytes32 descriptionHash_
    ) internal pure returns (uint256 proposalId_) {
        proposalId_ = uint256(keccak256(abi.encode(targets_, values_, calldatas_, descriptionHash_)));
    }


saneryee G

# Gas Optimizations Report

|         | Issue                                                                                | Instances |
| ------- | :--------------------------------------------------------------------------------------------------------------------------------- | :-------: |
| [G-001] | x += y or x -= y costs more gas than x = x + y or x = x - y for state variables                                                    |    22     |
| [G-002] | Splitting require() statements that use `&&` saves gas                                                                             |     3     |
| [G-003] | `storage` pointer to a structure is cheaper than copying each value of the structure into `memory`, same for `array` and `mapping` |    33     |
| [G-004] | Functions guaranteed to revert when called by normal users can be marked payable                                                   |    10     |
| [G-005] | internal functions only called once can be inlined to save gas                                                                     |     9     |
| [G-006] | Use named returns for local variables where it is possible.                                                                        |    17     |

## [G-001] x += y or x -= y costs more gas than x = x + y or x = x - y for state variables

### Impact

Using the addition operator instead of plus-equals saves 113 gas. Usually does not work with struct and mappings.

### Findings

Total:22

[scw-contracts/contracts/smart-contract-wallet/libs/Math.sol#L222](https://github.com/code-423n4/2023-01-biconomy/tree/main//scw-contracts/contracts/smart-contract-wallet/libs/Math.sol#L222)

```solidity
222:    result += 16;
```

[scw-contracts/contracts/smart-contract-wallet/libs/Math.sol#L271](https://github.com/code-423n4/2023-01-biconomy/tree/main//scw-contracts/contracts/smart-contract-wallet/libs/Math.sol#L271)

```solidity
271:    result += 16;
```

[scw-contr

// Code block 1 (solidity):
222:    result += 16;

// Code block 2 (solidity):
271:    result += 16;


twcctop Q

1:

wrap:error  emit message

```solidity
function wrap(uint256 _USDYAmount) external whenNotPaused {
    require(_USDYAmount > 0, "rUSDY: can't wrap zero USDY tokens");
      _mintShares(msg.sender, _USDYAmount * BPS_DENOMINATOR);
    usdy.transferFrom(msg.sender, address(this), _USDYAmount);
@>    emit Transfer(address(0), msg.sender, getRUSDYByShares(_USDYAmount));//:qa why transfer from  0
    emit TransferShares(address(0), msg.sender, _USDYAmount);
  }
```
shouldn't transfer from zero,should be
```solidity
 emit Transfer(msg.sender,address(this) , getRUSDYByShares(_USDYAmount));
```

2.
_burnShares:error  emit message
https://github.com/code-423n4/2023-09-ondo/blob/3362e1252f3a54943e2517460e5a7988388bc821/contracts/usdy/rUSDY.sol#L575-L610
```solidity

  function _burnShares(
    address _account,
    uint256 _sharesAmount
  ) internal whenNotPaused returns (uint256) {
    require(_account != address(0), "BURN_FROM_THE_ZERO_ADDRESS");

    _beforeTokenTransfer(_account, address(0), _sharesAmount);

    uint256 accountShares = shares[_account];
    require(_sharesAmount <= accountShares, "BURN_AMOUNT_EXCEEDS_BALANCE");

@>    uint256 preRebaseTokenAmount = getRUSDYByShares(_sharesAmount);

    totalShares -= _sharesAmount;

    shares[_account] = accountShares - _sharesAmount;

@>    uint256 postRebaseTokenAmount = getRUSDYByShares(_sharesAmount);

    emit SharesBurnt(
      _account,
      preRebaseTokenAmount,
      postRebaseTokenAmount,
      _sharesAmount
    );

    return totalShares;

    // Notice: we're not emitting a Transfer event to the zero address here since shares burn
    // works by redistributing the amount of tokens corresponding to the burned shares between
    // all other token holders. The total supply of the token doesn't change as the result.
    // This is equivalent to performing a send from `address` to each other token holder address,
    // but we cannot reflect this as it would require sending an unbounded number of eve

// Code block 1 (unknown):
shouldn't transfer from zero,should be

// Code block 2 (unknown):
2.
_burnShares:error  emit message
https://github.com/code-423n4/2023-09-ondo/blob/3362e1252f3a54943e2517460e5a7988388bc821/contracts/usdy/rUSDY.sol#L575-L610


Benterkiii Q

# Public functions that hasn't used internally can be external

Instances (4)

https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/AAMintPass.sol#L145
```solidity
    function totalSupply() public view returns (uint256) {
        return numTokensOutstanding;
    }
```
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/AAMintPass.sol#L150
```solidity
    function contractURI() public pure returns (string memory) {
        return "ipfs://bafybeifdvzwsjpxrkbyhqpz3y57j7nwm3eyyc3feqppqggslea3g5kk3jq";
    }
```
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterOps.sol#L53
```solidity
    function fighterCreatedEmitter(
```
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterOps.sol#L79
```solidity
    function viewFighterInfo(
```

// Code block 1 (solidity):
function totalSupply() public view returns (uint256) {
        return numTokensOutstanding;
    }

// Code block 2 (solidity):
function contractURI() public pure returns (string memory) {
        return "ipfs://bafybeifdvzwsjpxrkbyhqpz3y57j7nwm3eyyc3feqppqggslea3g5kk3jq";
    }

// Code block 3 (solidity):
function fighterCreatedEmitter(

// Code block 4 (solidity):
function viewFighterInfo(

function totalSupply() public view returns (uint256) {
        return numTokensOutstanding;
    }

function contractURI() public pure returns (string memory) {
        return "ipfs://bafybeifdvzwsjpxrkbyhqpz3y57j7nwm3eyyc3feqppqggslea3g5kk3jq";
    }

function fighterCreatedEmitter(

function viewFighterInfo(

AAMintPass.sol#L145, AAMintPass.sol#L150, FighterOps.sol#L53, FighterOps.sol#L79


Rolezn Q

### QA Issues
| # |Issue|
|-|-|
| [QA‑1](#QA‑1) | Max rerolls can be increased until max `uint8`
| [QA‑2](#QA‑2) | Fighter generation is limited to max `uint8`
| [QA‑3](#QA‑3) | It is not possible to remove staker after calling `FighterFarm.addStaker()`
| [QA‑4](#QA‑4) | Missing length check for `FighterFarm.iconsTypes`
| [QA‑5](#QA‑5) | `FighterFarm.mintFromMergingPool()` always creates fighterType 0
| [QA‑6](#QA‑6) | Project uses an old version of `openzeppelin-contracts`
| [QA‑7](#QA‑7) | In `FighterFarm.reRoll()` `approveSpender` should be called with 0 `amount` if `_neuronInstance.transferFrom()` fails
| [QA‑8](#QA‑8) | `generator` has different `uint` sizes on different functions
| [QA‑9](#QA‑9) | It is possible to `addAttributeProbabilities()` exceeding `uint8` `generation` values but unable to `deleteAttributeProbabilities()` delete anything exceeding `uint8` `generation`
| [QA‑10](#QA‑10) | It is not possible to remove addresses from `allowedBurningAddresses` once added
| [QA‑11](#QA‑11) | `GameItems.mint()` should be called `buyGameItem()` rather than `mint()`
| [QA‑12](#QA‑12) | `GameItems.mint()` should emit an event when `tranferFrom` has failed and purchase was unsuccessful.
| [QA‑13](#QA‑13) | An `event` should be emitted when winners have been picked in `MergingPool.pickWinners()`
| [QA‑14](#QA‑14) | `RankedBattle.setStakeAtRiskAddress()` should be renamed `RankedBattle.instantiateStakeAtRiskContract()`
| [QA‑15](#QA‑15) | `VoltageManager.useVoltageBattery()` can be set to require only the `VOLTAGE_COST` to allow players to be more efficient with their battery usage
| [QA‑16](#QA‑16) | `VoltageManager.spendVoltage()` can be called by the player.
| [QA‑17](#QA‑17) | Use a `constant` for `NRN` decimals
| [QA‑18]

/// @notice The maximum amount of rerolls for each fighter.
    uint8[2] public maxRerollsAllowed = [3, 3];

132: maxRerollsAllowed[fighterType] += 1;


0xta G

# Gas Optimization

# Summary

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

## [G-01] Use assembly to perform efficient back-to-back calls

If a similar external call is performed back-to-back, we can use assembly to reuse any function signatures and function parameters that stay the same. In addition, we can also reuse the same memory space for each function call (scratch space + free memory pointer + zero slot), which can potentially allow us to avoid memory expansion costs.
Note: In order to do this

File:  contracts/bridge/DestinationBridge.sol
323      uint256 balance = IRWALike(_token).balanceOf(address(this));
324      IRWALike(_token).transfer(owner(), balance);

File:   contracts/bridge/DestinationBridge.sol
210  function addApprover(address approver) external onlyOwner {

220  function removeApprover(address approver) external onlyOwner {

234    function addChainSupport(
    string calldata srcChain,
    string calldata srcContractAddress
  ) external onlyOwner {

255    function setThresholds(
    string calldata srcChain,
    uint256[] calldata amounts,
    uint256[] calldata numOfApprovers
  ) external onlyOwner {

286   function setMintLimit(uint256 mintLimit) external onlyOwner {

295  function setMintLimitDuration(uint256 mintDuration) external onlyOwner {

304  function pause() external onlyOwner {

313   function unpause() external onlyOwner {

322   function rescueTokens(address _token) external onlyOwner {


tala7985 G

## \[G‑1\] Newer versions of solidity are more gas efficient

The solidity language continues to pursue more efficient gas optimization schemes. Adopting a <ins>newer version of solidity</ins> can be more gas efficient.

```
pragma solidity 0.8.21;
```

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

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

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

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

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

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

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

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

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

## \[G‑2\] Initializers can be marked as payable to save deployment gas

Payable functions cost less gas to execute, because the compiler does not have to add extra checks to ensure that no payment is provided. Initializers can be safely marked as payable, because only the deployer or the factory contract would call the function without carrying any funds.

```
function initialize(
```

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

```
function initialize(address lrtConfigAddr) external initializer {
```

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

```
function initialize(address lrtConfigAddr) external initializer {
```

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

```
function initialize(address lrtConfigAddr) external initializer {
```

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

```
function initialize(address admin, address lrtConfigAddr) external initializer {
```

&nbs

// Code block 1 (unknown):
pragma solidity 0.8.21;

// Code block 2 (unknown):
function initialize(

// Code block 3 (unknown):
function initialize(address lrtConfigAddr) external initializer {

// Code block 4 (unknown):
function initialize(address lrtConfigAddr) external initializer {

// Code block 5 (unknown):
function initialize(address lrtConfigAddr) external initializer {

// Code block 6 (unknown):
function initialize(address admin, address lrtConfigAddr) external initializer {

LRTConfig.sol#L2, LRTDepositPool.sol#L2, NodeDelegator.sol#L2, LRTOracle.sol#L2, RSETH.sol#L2, ChainlinkPriceOracle.sol#L2, LRTConfigRoleChecker.sol#L2, UtilLib.sol#L2, LRTConfig.sol#L41, LRTDepositPool.sol#L31, LRTOracle.sol#L29

LRTConfigRoleChecker.sol, LRTOracle.sol, RSETH.sol, NodeDelegator.sol, ChainlinkPriceOracle.sol, UtilLib.sol, LRTConfig.sol, LRTDepositPool.sol


bin2chen Q

L-01: _mintIfThresholdMet() A malicious ALLOWLIST can duplicate mint

`_mintIfThresholdMet` does not follow the `Checks Effects Interactions` principle
If ALLOWLIST is a malicious contract, it is possible to repeat the mint token
It is recommended to clear before executing mint

```solidity
  function _mintIfThresholdMet(bytes32 txnHash) internal {
    bool thresholdMet = _checkThresholdMet(txnHash);
    Transaction memory txn = txnHashToTransaction[txnHash];
    if (thresholdMet) {
+     delete txnHashToTransaction[txnHash];
      _checkAndUpdateInstantMintLimit(txn.amount);
      if (!ALLOWLIST.isAllowed(txn.sender)) {
        ALLOWLIST.setAccountStatus(
          txn.sender,
          ALLOWLIST.getValidTermIndexes()[0],
          true
        );
      }
      TOKEN.mint(txn.sender, txn.amount);
-     delete txnHashToTransaction[txnHash];
      emit BridgeCompleted(txn.sender, txn.amount);
    }
```

L-02: transferFrom() proposes to ignore allowances if `_sender==msg.sender`.

The current `transferFrom()` still requires an allowance if `_sender==msg.sender`.
Some protocols that transfer out tokens use `transferFrom()` instead of `transfer()`.
Suggest adding `_sender==msg.sender` to ignore allowances to accommodate these protocols

L-03: transferFrom() Malicious Allowlist contract can reuse user's allowances

`transferFrom()` does not follow the `Checks Effects Interactions` principle

Currently it would be the following steps
1. `_transfer()` -> `_beforeTokenTransfer()` -> `_isAllowed()` -> `allowlist.isAllowed`
2. _approve(_sender, msg.sender, currentAllowance - _amount)

This way if the allowlist is maliciously contracted, you can reenter `transferFrom()` to reuse the allowance

Suggestion, modify allowances first, before executing `_transfer()`.

```diff
  function transferFrom(
    address _sender,
    address _recipient,
    uint256 _amount
  ) public returns (bool) {
    uint256 currentAllowance = allowances[_sender][msg.sender];
    require(currentAll

L-04: BURNER_ROLE can't burn off blacklisted user's token

Administrators with `BURNER_ROLE` privileges can execute `burn()` to burn a user's `shares` and transfer `usdy` to themselves.

Currently execute `burn()` -> `_burnShares()` -> `_beforeTokenTransfer()` -> `_isBlocked()` -> `blocklist.isBlocked()`

This way, if the user is blacklisted, the administrator `burn` is unable to execute the

Suggestion

`_beforeTokenTransfer()` no longer checks `_isBlocked/_isSanctioned/_isAllowed` if `msg.sender` has `BURNER_ROLE` privileges.

L-04: unwrap() leaves a small portion of each user in the contract

The current implementation of `unwrap()` is as follows.

// Code block 1 (solidity):
function _mintIfThresholdMet(bytes32 txnHash) internal {
    bool thresholdMet = _checkThresholdMet(txnHash);
    Transaction memory txn = txnHashToTransaction[txnHash];
    if (thresholdMet) {
+     delete txnHashToTransaction[txnHash];
      _checkAndUpdateInstantMintLimit(txn.amount);
      if (!ALLOWLIST.isAllowed(txn.sender)) {
        ALLOWLIST.setAccountStatus(
          txn.sender,
          ALLOWLIST.getValidTermIndexes()[0],
          true
        );
      }
      TOKEN.mint(txn.sender, txn.amount);
-     delete txnHashToTransaction[txnHash];
      emit BridgeCompleted(txn.sender, txn.amount);
    }


matrix_0wl G

## Gas Optimizations

|        | Issue                                                                                |
| ------ | :-------------------------------------------------------------------------------------------------------------------------------------------------- |
| GAS-1  | Use assembly to check for `address(0)`                                                                                |
| GAS-2  | BEFORE SOME FUNCTIONS, WE SHOULD CHECK SOME VARIABLES FOR POSSIBLE GAS SAVE                                                                         |
| GAS-3  | USING CALLDATA INSTEAD OF MEMORY FOR READ-ONLY ARGUMENTS IN EXTERNAL FUNCTIONS SAVES GAS                                                            |
| GAS-4  | Setting the constructor to payable                                                                                |
| GAS-5  | DON’T USE \_MSGSENDER() IF NOT SUPPORTING EIP-2771                                                                                |
| GAS-6  | USE FUNCTION INSTEAD OF MODIFIERS                                                                                |
| GAS-7  | IT COSTS MORE GAS TO INITIALIZE NON-CONSTANT/NON-IMMUTABLE VARIABLES TO ZERO THAN TO LET THE DEFAULT OF ZERO BE APPLIED                             |
| GAS-8  | INSTEAD OF CALCULATING A STATEVAR WITH KECCAK256() EVERY TIME THE CONTRACT IS MADE PRE CALCULATE THEM BEFORE AND ONLY GIVE THE RESULT TO A CONSTANT |
| GAS-9  | INTERNAL FUNCTIONS NOT CALLED BY THE CONTRACT SHOULD BE REMOVED TO SAVE DEPLOYMENT GAS                                                              |
| GAS-10 | KECCAK256() SHOULD ONLY NEED TO BE CALLED ON A SPECIFIC STRING LITERAL ONCE                                                                         |
| GAS-11 | The increment in for loop postcondi

File: contracts/lybra/configuration/LybraConfigurator.sol

99:         if (address(EUSD) == address(0)) EUSD = IEUSD(_eusd);

100:         if (address(peUSD) == address(0)) peUSD = IEUSD(_peusd);

File: contracts/lybra/miner/EUSDMiningIncentives.sol

76:         if (_account != address(0)) {


codeslide G

###  Gas Optimizations
There are 759 instances over 27 issues.
|      ID       | Description                                                                                | Count | Gas Per Instance | Gas Savings |
| :-----------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------- | ----: | ---------------: | ----------: |
| [G-01](#g-01) | `++i`/`i++` should be `unchecked{++i}`/`unchecked{i++}` when it is not possible for them to overflow, as is the case when used in `for`- and `while`-loops |    10 |               60 |         600 |
| [G-02](#g-02) | `>=` costs less gas than `>`                                                                                |    77 |                3 |         231 |
| [G-03](#g-03) | Constructors can be marked `payable`                                                                                |    19 |               21 |         399 |
| [G-04](#g-04) | Don't compare boolean expressions to boolean literals                                                                                |     1 |                9 |           9 |
| [G-05](#g-05) | Events should be emitted outside of loops                                                                                |     1 |              375 |         375 |
| [G-06](#g-06) | Functions guaranteed to revert when called by normal users can be marked `payable`                                                                         |    24 |               21 |         504 |
| [G-07](#g-07) | Gas use can be reduced by using Solidity 0.8.19 or later

File: packages/contracts/contracts/Governor.sol

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

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

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

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

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

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

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

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

File: packages/contracts/contracts/SortedCdps.sol

432:         for (uint256 i = 0; i < _len; ++i) {

449:         for (uint i = 0; i < _len; ++i) {


privateconstant G

# Gas Optimizations

## Summary

In total, `5` gas optimizations are found. Please also noted that the following do not inclue those included in the C4Audit output [here](https://gist.github.com/Picodes/0a53b4abfc71e0b9998e8b09aa283fb3).

## [G-01] USE REQUIRE INSTEAD OF ASSERT FOR ERROR HANDLING

The `assert()` and `require()` functions are a part of error handling in Solidity. They both check conditions and throw an error if they are not met.

The main difference between the two is the way they handle gas and changes made to the contract.

When `assert()` is used and the condition is false, all remaining gas is consumed and all changes made to the contract and any sub-calls are reversed. On the other hand, if `require()` is used and the condition is false, only changes made to the contract are reversed and any remaining gas fees are refunded.

_instance (2)_:

```diff
file: contracts/smart-contract-wallet/common/Singleton.sol, line 13

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

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

```diff
file: contracts/smart-contract-wallet/Proxy.sol, line 16

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

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

## [G-02] USE CALLDATA INSTEAD OF MEMORY IN `innerHandleOp()`

Using the `memory` keyword instead of `calldata` in the `innerHandleOp()` function in `EntryPoint.sol` is possible and can potenti

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

## [G-02] USE CALLDATA INSTEAD OF MEMORY IN `innerHandleOp()`

Using the `memory` keyword instead of `calldata` in the `innerHandleOp()` function in `EntryPoint.sol` is possible and can potentially reduce gas costs. The recommended changes are outlined below.

_instance (1)_:

// Code block 1 (diff):
file: contracts/smart-contract-wallet/common/Singleton.sol, line 13

+   require(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));
-   assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));

// Code block 2 (diff):
file: contracts/smart-contract-wallet/Proxy.sol, line 16

+   require(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));
-   assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));

file: contracts/smart-contract-wallet/common/Singleton.sol, line 13

+   require(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));
-   assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));

file: contracts/smart-contract-wallet/Proxy.sol, line 16

+   require(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));
-   assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("biconomy.scw.proxy.implementation")) - 1));


teawaterwire Q

In the `claimDelegateReward` function there is this line

```
// Check if Challenge Period is still active
if(block.number < _getChallengeStageEndBlock(currentDistribution.endBlock)) revert ChallengePeriodNotEnded();
```

After discussing with one of the sponsors it appears to be not quite right as it should be checked against the end of the distribution period not the end of the challenge period. Was asked to report it :)

// Code block 1 (unknown):
// Check if Challenge Period is still active
if(block.number < _getChallengeStageEndBlock(currentDistribution.endBlock)) revert ChallengePeriodNotEnded();