gabriel G

Using && operators inside require statements contribute to a higher execution cost as it tests both sides of the AND operation before reverting.

This means that every time we find && statements we should think about which one of the predicaments is the most probable fail cause for the specific function. As seen on `TroveManager.sol`:

```
function _requireMoreThanOneTroveInSystem(uint TroveOwnersArrayLength, address _collateral) internal view {
        require (TroveOwnersArrayLength > 1 && sortedTroves.getSize(_collateral) > 1);
    }
```
Could be replaced by:

```
function _requireMoreThanOneTroveInSystem(uint TroveOwnersArrayLength, address _collateral) external view {
       require (TroveOwnersArrayLength > 1);
       require (getSize(_collateral) > 1);
   }
```

This way, in case TroveOwnersArrayLength is <= 1, we revert the execution before accessing the `data` map. I've developed a oversimplified example contract to illustrate this issue:

```
// SPDX-License-Identifier: MIT
// Creator: gabriel

pragma solidity ^0.8.4;

contract Example {

    // Information for the list
    struct Data {
        uint256 size;                        // Current size of the list
    }

    // Each collateral has its own list of sorted troves
    mapping (address => Data) public data;

    function addToList(address _collateral) external {
        data[_collateral].size += 1;
    }

    function getSize(address _collateral) public view returns (uint256) {
        return data[_collateral].size;
    }

    function _requireMoreThanOneTroveInSystem1(uint TroveOwnersArrayLength, address _collateral) external view {
        require (TroveOwnersArrayLength > 1);
        require(getSize(_collateral) > 1);
    }
   function _requireMoreThanOneTroveInSystem2(uint TroveOwnersArrayLength, address _collateral) external view {
       require (TroveOwnersArrayLength > 1);
       require (getSize(_collateral) > 1);
   }
}
```

In the contract above, calling the _requireMoreThanOneTroveInS

// Code block 1 (unknown):
function _requireMoreThanOneTroveInSystem(uint TroveOwnersArrayLength, address _collateral) internal view {
        require (TroveOwnersArrayLength > 1 && sortedTroves.getSize(_collateral) > 1);
    }

// Code block 2 (unknown):
function _requireMoreThanOneTroveInSystem(uint TroveOwnersArrayLength, address _collateral) external view {
       require (TroveOwnersArrayLength > 1);
       require (getSize(_collateral) > 1);
   }

// Code block 3 (unknown):
// SPDX-License-Identifier: MIT
// Creator: gabriel

pragma solidity ^0.8.4;

contract Example {

    // Information for the list
    struct Data {
        uint256 size;                        // Current size of the list
    }

    // Each collateral has its own list of sorted troves
    mapping (address => Data) public data;

    function addToList(address _collateral) external {
        data[_collateral].size += 1;
    }

    function getSize(address _collateral) public view returns (uint256) {
        return data[_collateral].size;
    }

    function _requireMoreThanOneTroveInSystem1(uint TroveOwnersArrayLength, address _collateral) external view {
        require (TroveOwnersArrayLength > 1);
        require(getSize(_collateral) > 1);
    }
   function _requireMoreThanOneTroveInSystem2(uint TroveOwnersArrayLength, address _collateral) external view {
       require (TroveOwnersArrayLength > 1);
       require (getSize(_collateral) > 1);
   }
}


albahaca Q

## [L-01] _safeMint() should be used rather than _mint() wherever possible
_mint() is [discouraged](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4d8d2ed9798cc3383912a23b5e8d5cb602f7d4b/contracts/token/ERC721/ERC721.sol#L271) in favor of _safeMint() which ensures that the recipient is either an EOA or implements IERC721Receiver. Both open [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4d8d2ed9798cc3383912a23b5e8d5cb602f7d4b/contracts/token/ERC721/ERC721.sol#L238-L250) and [solmate](https://github.com/Rari-Capital/solmate/blob/4eaf6b68202e36f67cab379768ac6be304c8ebde/src/tokens/ERC721.sol#L180) have versions of this function so that NFTs aren’t lost if they’re minted to contracts that cannot transfer them back out.

```solidity
File:  packages/contracts/contracts/EBTCToken.sol
87   _mint(_account, _amount);
```
https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/EBTCToken.sol#L87

## [L‑02] Use Ownable2Step instead of 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.

```solidity
File:  packages/contracts/contracts/BorrowerOperations.sol
13  import "./Dependencies/Ownable.sol";
```
https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L13

## [L-03] no check if the burn amount is zero or not
if the amount is zero so the unhecked block will divided zero on 3 and we use gas for nothing ! if we set zero we may pass the _burn checks, i know it is passed by only permit but it's better to avoid this happen because it's seting by human and it means it can be set with 0 balance to burn !

```solidity
File:  packages/contracts/contracts/BorrowerOperations.sol
798  ebtcToken.burn(_account, _debt);

1103  ebtcTok

// Code block 1 (solidity):
File:  packages/contracts/contracts/EBTCToken.sol
87   _mint(_account, _amount);

// Code block 2 (solidity):
File:  packages/contracts/contracts/BorrowerOperations.sol
13  import "./Dependencies/Ownable.sol";

File:  packages/contracts/contracts/EBTCToken.sol
87   _mint(_account, _amount);

File:  packages/contracts/contracts/BorrowerOperations.sol
13  import "./Dependencies/Ownable.sol";

ERC721.sol#L271, ERC721.sol#L238-L250, ERC721.sol#L180, EBTCToken.sol#L87, BorrowerOperations.sol#L13


coryli G

## Calculations should be cached.
SLOADs are expensive (~100 gas) compared to MLOAD/MSTORE(~3gas).
### Instances
`PrivatePool.sol#L230`, `PrivatePool.sol#L236`, `PrivatePool.sol#L323`, `PrivatePool.sol#L335`

## Using Bools for storage incurs overhead
Use `uint256` for true/false to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing from ‘false’ to ‘true’, after having been ‘true’ in the past.
### Instances
`PrivatePool.sol#L94` `PrivatePool.sol#L97` `PrivatePool.sol#L100`

## `abi.encode()` is less efficient than `abi.encodePacked()`
Changing abi.encode function to abi.encodePacked can save gas since the abi.encode function pads extra null bytes at the end of the call data, which is unnecessary. Also, in general, abi.encodePacked is more gas-efficient (see Solidity-Encode-Gas-Comparison).
### Instances
`EthRouter.sol#L177` `EthRouter.sol#L675`

## No need to explicitly initialize variables with default values
If a variable is not set/initialized, it is assumed to have the default value (0 for uint, false for bool, address(0) for address…). Explicitly initializing it with its default value is an anti-pattern and wastes gas.
### Instances
`PrivatePool.sol#L237`, `PrivatePool.sol#L328` also every `for` loop counter.

## Increments can be unchecked

### Instances
`PrivatePool.sol#L238` `PrivatePool.sol#L272` `PrivatePool.sol#L329` `PrivatePool.sol#L441` `PrivatePool.sol#L446` `EthRouter.sol#L106` `EthRouter.sol#L116` `EthRouter.sol#L134` `EthRouter.sol#L159`
### Recommendation
```
for (uint256 i; i < tokenIds.length;) {
 // ...
 unchecked { ++i; }
}
```

## Public functions to external saves gas
### Instances
`PrivatePool.sol#L167` `PrivatePool.sol#L212` `PrivatePool.sol#L306` `PrivatePool.sol#L393` `PrivatePool.sol#L459` `EthRouter.sol#L99` `EthRouter.sol#L152` `EthRouter.sol#L226` `EthRouter.sol#L254` `EthRouter.sol/L302`
`Factory.sol#L84` `Factory.sol#L129` `Factory.sol#L135` `Factory.sol#L141` `Factory.sol#L148` `Fac

bytes32 public constant ON_FLASH_LOAN_SELECTOR = keccak256("ERC3156FlashBorrower.onFlashLoan");

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


SunSec Q

# asymmetry

### [L1] one step owner transferRole transfer actions done in a single-step manner are dangerous

## Impact
Inheriting from OpenZeppelin's Ownable contract means you are using a single-step ownership transfer pattern. If an admin provides an incorrect address for the new owner this will result in none of the onlyOwner marked methods being callable again. The better way to do this is to use a two-step ownership transfer approach, where the new owner should first claim its new rights before they are transferred.

## Proof of Concept
https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/WstEth.sol#L5

`import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";`

https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/SfrxEth.sol#L6
`import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";`

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

```
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
```
https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/Reth.sol#L13
```
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
```

## Tools Used
Manual Review
## Recommended Mitigation Steps
Use OpenZeppelin's Ownable2Step instead of Ownable

### [L2] Missing admin input sanitization admin

## Impact
Missing maximum value check that is set by the contract owner. This issue can allow the contract owner to set big sllippage or big weight even  over 100. It will cause unexpected operactions in protocol.

## Proof of Concept
1.https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L165-L174

For example, total weight should be 100 = 50/25/25 (3 derivatives). But there is no maximum threshold validation.
```
    function adjustWeight(
        uint256 _derivativeIndex,
        uint256 _weight
    ) external onlyOwner {

// Code block 1 (unknown):
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

// Code block 2 (unknown):
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

WstEth.sol#L5, SfrxEth.sol#L6, SafEth.sol#L9, Reth.sol#L13, SafEth.sol#L165-L174

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


Bube Q

# QA report

## Content

| Number  | Severity    | Issue Title                                                                               |
| --------| ------------|-------------------------------------------------------------------------------------------|
| [1]     | Low         | Missing two-step procedure for ownership transfer                                         |
| [2]     | Low         | Missing check for token existence in `RankedBattle::getBattleRecord` function             |
| [3]     | Low         | Missing check for token existence in `RankedBattle::getNrnDistribution` function          |
| [4]     | Low         | Incorrect `require` statement in ``Neuron::mint` function.                                |
| [5]     | Low         | Some important events are missing in `Neuron` contract                                    |
| [6]     | Low         | Unsafe `transferFrom` in `Neuron` contract                                                |
| [7]     | Low         | The `attributeProbabilities` mapping is initialized twice in the `AiArenaHelper` contract |

## [1] Low

## Title

Missing two-step procedure for ownership transfer

## Links

https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/AiArenaHelper.sol#L61-L64
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/FighterFarm.sol#L120-L123
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/GameItems.sol#L108-L111
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/MergingPool.sol#L89-L92
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Neuron.sol#L85-L88
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/RankedBattle.sol#L167-L170
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/Vol

    function transferOwnership(address newOwnerAddress) external {
        require(msg.sender == _ownerAddress);
        _ownerAddress = newOwnerAddress;
    }

    function getBattleRecord(uint256 tokenId) external view returns(uint32, uint32, uint32) {
      return (
          fighterBattleRecord[tokenId].wins,
          fighterBattleRecord[tokenId].ties,
          fighterBattleRecord[tokenId].loses
      );
    }

AiArenaHelper.sol#L61-L64, FighterFarm.sol#L120-L123, GameItems.sol#L108-L111, MergingPool.sol#L89-L92, Neuron.sol#L85-L88, RankedBattle.sol#L167-L170

GameItems.sol, Neuron.sol, RankedBattle.sol, FighterFarm.sol, MergingPool.sol, AiArenaHelper.sol


0x6020c0 G

In `SafEth.sol` in the function `rebalanceToWeights()` putting the `ethAmountToRebalance == 0` check outside of the for loop saves gas on each loop iteration and skips loop iterations if no rebalancing is needed.

Suggested fix:
```
if (ethAmountToRebalance == 0){
  emit Rebalanced();
  return;
}
for (uint i = 0; i < derivativeCount; i++) {
  if (weights[i] == 0) continue;
   uint256 ethAmount = (ethAmountToRebalance * weights[i]) / totalWeight;  // Price will change due to slippage
   derivatives[i].deposit{value: ethAmount}();
}
```
Gas usage difference from test cases:

```
Before =  | SafEth · rebalanceToWeights · 669450  · 821670 · 727618 · 8  · -  │
After  =  | SafEth · rebalanceToWeights · 669406  · 821618 · 727570 · 8  · -  │
```

// Code block 1 (unknown):
if (ethAmountToRebalance == 0){
  emit Rebalanced();
  return;
}
for (uint i = 0; i < derivativeCount; i++) {
  if (weights[i] == 0) continue;
   uint256 ethAmount = (ethAmountToRebalance * weights[i]) / totalWeight;  // Price will change due to slippage
   derivatives[i].deposit{value: ethAmount}();
}


0xvj Q

## No event emission when funds are transferred to nodeDelegatorContract
`transferAssetToNodeDelegator()` function of LRTDepositPool contract didn't emit and event when funds are tranferred to nodeDelegatorContract.

```
function transferAssetToNodeDelegator(
        uint256 ndcIndex,
        address asset,
        uint256 amount
    )
        external
        nonReentrant
        onlyLRTManager
        onlySupportedAsset(asset)
    {
        address nodeDelegator = nodeDelegatorQueue[ndcIndex];
        if (!IERC20(asset).transfer(nodeDelegator, amount)) {
            revert TokenTransferFailed();
        }
        // @audit-issue add event emission
}
```

Important operations like this should emit events for off-chain accouting purposes

// Code block 1 (unknown):
function transferAssetToNodeDelegator(
        uint256 ndcIndex,
        address asset,
        uint256 amount
    )
        external
        nonReentrant
        onlyLRTManager
        onlySupportedAsset(asset)
    {
        address nodeDelegator = nodeDelegatorQueue[ndcIndex];
        if (!IERC20(asset).transfer(nodeDelegator, amount)) {
            revert TokenTransferFailed();
        }
        // @audit-issue add event emission
}


ihtishamsudo G

# [G-01]

## Use double IF Statements instead of &&

if the IF Statement has a logical AND (&&) Operation but is not followed by the else statement, it can be replaced with 2 if statements to reduce gas cost

###### Before

```
if (block.timestamp > deadline && deadline != 0)
{
    revert DeadlinePassed();
}
```

**It consumes more gas than**

###### After

```
if (block.timestamp > deadline) {
    if (deadline != 0) {
        revert DeadlinePassed();
    }
}
```

##### References

[EthRouter.sol#L101](https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/EthRouter.sol#L101)
[EthRouter.sol#L154](https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/EthRouter.sol#L154)
[EthRouter.sol#L228](https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/EthRouter.sol#L228)
[EthRouter.sol#L256](https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/EthRouter.sol#L256)

# [G-02]

## x += y costs more gas than x = x + y & same for x -= y

##### References

[PrivatePool.sol#L230](https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/PrivatePool.sol#L230)
[PrivatePool.sol#L231](https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/PrivatePool.sol#L231)
[PrivatePool.sol#L247](https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/PrivatePool.sol#L247)
[PrivatePool.sol#L252](https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/PrivatePool.sol#L252)
[PrivatePool.sol#L324](https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/PrivatePool.sol#L324)
[PrivatePool.sol#L341](https://github.com/code-423n4/2023-04-caviar/blob/cd8a92667bcb6657f70657183769c244d04c015c/src/PrivatePool.sol#L341)
[PrivatePool.sol#L678](https://github.

// Code block 1 (unknown):
if (block.timestamp > deadline && deadline != 0)
{
    revert DeadlinePassed();
}

// Code block 2 (unknown):
if (block.timestamp > deadline) {
    if (deadline != 0) {
        revert DeadlinePassed();
    }
}

EthRouter.sol#L101, EthRouter.sol#L154, EthRouter.sol#L228, EthRouter.sol#L256, PrivatePool.sol#L230, PrivatePool.sol#L231, PrivatePool.sol#L247, PrivatePool.sol#L252, PrivatePool.sol#L324, PrivatePool.sol#L341


BRONZEDISC Q

## QA
---

### Layout Order [1]

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

---

### Function Visibility [2]

- Order of Functions: Ordering helps readers identify which functions they can call and to find the constructor and fallback definitions easier. Functions should be grouped according to their visibility and ordered: constructor, receive function (if exists), fallback function (if exists), public, external, internal, private. Within a grouping, place the view and pure functions last.

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

```solidity
// these external functions should come before private and internal functions
119:    function startNewDistributionPeriod() external override returns (uint24 newDistributionId_) {
236:    function claimDelegateReward(
300:    function updateSlate(
343:    function executeStandard(
366:    function proposeStandard(
519:    function fundingVote(
572:    function screeningVote(
917:    function getDelegateReward(
928:    function getDistributionId() external view override returns (uint24) {
933:    function getDistributionPeriodInfo(
947:    function getFundedProposalSlate(
954:    function getFundingPowerVotes(
961:    function getFundingVotesCast(uint24 distributionId_, address account_) external view override returns (FundingVoteParams[] memory) {
966:    function getProposalInfo(
980:    function getSlateHash(
987:    function getTopTenProposals(
994:    function getVoterInfo(
1006:    function getVotesFunding(
1019:    function getVotesScreening(

// private functions should come last
197:    function _updateTreasury(
227:    function _setNewDistributionId() private returns (uint24 newId_) {
```

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

```solidity
// internal functions coming before external ones
404:    function _getAndInc

// internal functions coming before external ones
404:    function _getAndIncrementNonce(
416:    function _isAjnaPool(
436:    function _bucketBankruptAfterDeposit(

// public function coming after all the other ones
517:    function tokenURI(

// Code block 1 (solidity):
// these external functions should come before private and internal functions
119:    function startNewDistributionPeriod() external override returns (uint24 newDistributionId_) {
236:    function claimDelegateReward(
300:    function updateSlate(
343:    function executeStandard(
366:    function proposeStandard(
519:    function fundingVote(
572:    function screeningVote(
917:    function getDelegateReward(
928:    function getDistributionId() external view override returns (uint24) {
933:    function getDistributionPeriodInfo(
947:    function getFundedProposalSlate(
954:    function getFundingPowerVotes(
961:    function getFundingVotesCast(uint24 distributionId_, address account_) external view override returns (FundingVoteParams[] memory) {
966:    function getProposalInfo(
980:    function getSlateHash(
987:    function getTopTenProposals(
994:    function getVoterInfo(
1006:    function getVotesFunding(
1019:    function getVotesScreening(

// private functions should come last
197:    function _updateTreasury(
227:    function _setNewDistributionId() private returns (uint24 newId_) {


DavidGiladi G

### Gas Optimization Issues
|Title|Issue|Instances|Total Gas Saved|
|-|:-|:-:|:-:|
|[G-1] Avoid unnecessary storage updates | [Avoid unnecessary storage updates](#avoid-unnecessary-storage-updates) | 15 | 12000 |
|[G-2] Check Arguments Early | [Check Arguments Early](#check-arguments-early) | 1 | - |
|[G-3] Modulus operations that could be unchecked | [Modulus operations that could be unchecked](#modulus-operations-that-could-be-unchecked) | 1 | 85 |
|[G-4] State variables that could be declared constant | [State variables that could be declared constant](#state-variables-that-could-be-declared-constant) | 3 | 6291 |
|[G-5] State variables that could be declared immutable | [State variables that could be declared immutable](#state-variables-that-could-be-declared-immutable) | 3 | 6291 |
|[G-6] Avoid duplicate keccak256 calls | [Avoid duplicate keccak256 calls](#avoid-duplicate-keccak256-calls) | 2 | 84 |
|[G-7] Use of emit inside a loop | [Use of emit inside a loop](#use-of-emit-inside-a-loop) | 3 | 3078 |
|[G-8] Cache External Calls in Loops | [Cache External Calls in Loops](#cache-external-calls-in-loops) | 7 | 700 |
|[G-9] Optimal State Variable Order | [Optimal State Variable Order](#optimal-state-variable-order) | 1 | 5000 |
|[G-10] Redundant Bool Comparison | [Redundant Bool Comparison](#redundant-bool-comparison) | 1 | 9 |
|[G-11] Cache Frequently Called Functions in stack Variables to Reduce Gas Costs | [Cache Frequently Called Functions in stack Variables to Reduce Gas Costs](#cache-frequently-called-functions-in-stack-variables-to-reduce-gas-costs) | 3 | - |
|[G-12] Safe Subtraction Should Be Unchecked | [Safe Subtraction Should Be Unchecked](#safe-subtraction-should-be-unchecked) | 2 | 170 |
|[G-13] Unnecessary Casting of Variables | [Unnecessary Casting of Variables](#unnecessary-casting-of-variables) | 2 | - |
|[G-14] Avoid Unnecessary Computation Inside Loops | [Avoid Unnecessary Computation Inside Loops](#avoid-unnecessary-computation-inside-loops) |

Line: 33          contract RdpxV2Core is
  IRdpxV2Core,
  AccessControl,
  ContractWhitelist,
  ERC721Holder,
  Pausable


prady Q

## [L-01] SIGNATURE LENGTH VERIFICATION MISSING

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

The `execTransaction` does not verify that the parameter `signature` length is a valid signature length or not, as the signature param consists of 32 bytes `s` and 32 bytes `r` and 1 byte of `v,` which means the signature length should be equal to 65.

### Recommended mitigation step

Add this before line [SmartAccount-L198](https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L198)
```solidity
contracts/smart-contract-wallet/SmartAccount:
    require(_signature.length == 65, "invalid signature length");
```

## [L-02] INIT() FUNCTION CAN BE CALLED BY ANYBODY
The `init()` function can be called by anybody when the contract is not initialized.
```solidity
    function init(
        address _owner,
        address _entryPointAddress,
        address _handler
    ) public override initializer {
        require(owner == address(0), "Already initialized");
        require(address(_entryPoint) == address(0), "Already initialized");
        require(_owner != address(0), "Invalid owner");
        require(_entryPointAddress != address(0), "Invalid Entrypoint");
        require(_handler != address(0), "Invalid Entrypoint");
        owner = _owner;
        _entryPoint = IEntryPoint(payable(_entryPointAddress));
        if (_handler != address(0)) internalSetFallbackHandler(_handler);
        setupModules(address(0), bytes(""));
    }
```
More importantly, if someone else runs this function, they will have full authority as it sets the `owner` variable.

### Recommended mitigation step
Add a check that `init()` can only be called by the deployer.
```solidity
address internal immutable deployer;
constructor() {
       deployer = msg.sender;
}
...

function init(...) {
      if (msg.sender != DEPLOYER_ADDRESS) { revert NotDeployer(); }

// Code block 1 (solidity):
contracts/smart-contract-wallet/SmartAccount:
    require(_signature.length == 65, "invalid signature length");

// Code block 2 (solidity):
function init(
        address _owner,
        address _entryPointAddress,
        address _handler
    ) public override initializer {
        require(owner == address(0), "Already initialized");
        require(address(_entryPoint) == address(0), "Already initialized");
        require(_owner != address(0), "Invalid owner");
        require(_entryPointAddress != address(0), "Invalid Entrypoint");
        require(_handler != address(0), "Invalid Entrypoint");
        owner = _owner;
        _entryPoint = IEntryPoint(payable(_entryPointAddress));
        if (_handler != address(0)) internalSetFallbackHandler(_handler);
        setupModules(address(0), bytes(""));
    }

contracts/smart-contract-wallet/SmartAccount:
    require(_signature.length == 65, "invalid signature length");

function init(
        address _owner,
        address _entryPointAddress,
        address _handler
    ) public override initializer {
        require(owner == address(0), "Already initialized");
        require(address(_entryPoint) == address(0), "Already initialized");
        require(_owner != address(0), "Invalid owner");
        require(_entryPointAddress != address(0), "Invalid Entrypoint");
        require(_handler != address(0), "Invalid Entrypoint");
        owner = _owner;
        _entryPoint = IEntryPoint(payable(_entryPointAddress));
        if (_handler != address(0)) internalSetFallbackHandler(_handler);
        setupModules(address(0), bytes(""));
    }


Fitro Q

## [01] AiArenaHelper.sol the constructor initializes the attributeProbabilities() for generation 0 twice.
In the constructor of **`AiArenaHelper.sol`**, the initialization of **`attributeProbabilities()`** of generation 0 is duplicated.

https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/AiArenaHelper.sol#L41-L52
https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/AiArenaHelper.sol#L137
```Solidity
constructor(uint8[][] memory probabilities) {
   _ownerAddress = msg.sender;

   // Initialize the probabilities for each attribute
@> addAttributeProbabilities(0, probabilities);

   uint256 attributesLength = attributes.length;
   for (uint8 i = 0; i < attributesLength; i++) {
@>      attributeProbabilities[0][attributes[i]] = probabilities[i];
        attributeToDnaDivisor[attributes[i]] = defaultAttributeDivisor[i];
    }
}
```
```Solidity
function addAttributeProbabilities(uint256 generation, uint8[][] memory probabilities) public {
    require(msg.sender == _ownerAddress);
    require(probabilities.length == 6, "Invalid number of attribute arrays");

    uint256 attributesLength = attributes.length;
    for (uint8 i = 0; i < attributesLength; i++) {
@>       attributeProbabilities[generation][attributes[i]] = probabilities[i];
    }
}
```
Remove one of the two initializations.

// Code block 1 (Solidity):
constructor(uint8[][] memory probabilities) {
   _ownerAddress = msg.sender;

   // Initialize the probabilities for each attribute
@> addAttributeProbabilities(0, probabilities);

   uint256 attributesLength = attributes.length;
   for (uint8 i = 0; i < attributesLength; i++) {
@>      attributeProbabilities[0][attributes[i]] = probabilities[i];
        attributeToDnaDivisor[attributes[i]] = defaultAttributeDivisor[i];
    }
}

// Code block 2 (Solidity):
function addAttributeProbabilities(uint256 generation, uint8[][] memory probabilities) public {
    require(msg.sender == _ownerAddress);
    require(probabilities.length == 6, "Invalid number of attribute arrays");

    uint256 attributesLength = attributes.length;
    for (uint8 i = 0; i < attributesLength; i++) {
@>       attributeProbabilities[generation][attributes[i]] = probabilities[i];
    }
}

constructor(uint8[][] memory probabilities) {
   _ownerAddress = msg.sender;

   // Initialize the probabilities for each attribute
@> addAttributeProbabilities(0, probabilities);

   uint256 attributesLength = attributes.length;
   for (uint8 i = 0; i < attributesLength; i++) {
@>      attributeProbabilities[0][attributes[i]] = probabilities[i];
        attributeToDnaDivisor[attributes[i]] = defaultAttributeDivisor[i];
    }
}

function addAttributeProbabilities(uint256 generation, uint8[][] memory probabilities) public {
    require(msg.sender == _ownerAddress);
    require(probabilities.length == 6, "Invalid number of attribute arrays");

    uint256 attributesLength = attributes.length;
    for (uint8 i = 0; i < attributesLength; i++) {
@>       attributeProbabilities[generation][attributes[i]] = probabilities[i];
    }
}


0xm1ck Q

## Non Critical Issues

| |Issue|Instances|
|-|:-|:-:|
| [NC-1](#NC-1) | Missing checks for `address(0)` when assigning values to address state variables | 26 |
| [NC-2](#NC-2) |  `require()` / `revert()` statements should have descriptive reason strings | 10 |
| [NC-3](#NC-3) | Return values of `approve()` not checked | 5 |
| [NC-4](#NC-4) | TODO Left in the code | 2 |
| [NC-5](#NC-5) | Event is missing `indexed` fields | 91 |
| [NC-6](#NC-6) | Functions not used internally could be marked external | 2 |
### [NC-1] Missing checks for `address(0)` when assigning values to address state variables

*Instances (26)*:
```solidity
File: ActivePool.sol

96:         collateralConfigAddress = _collateralConfigAddress;

97:         borrowerOperationsAddress = _borrowerOperationsAddress;

98:         troveManagerAddress = _troveManagerAddress;

99:         stabilityPoolAddress = _stabilityPoolAddress;

100:         defaultPoolAddress = _defaultPoolAddress;

101:         collSurplusPoolAddress = _collSurplusPoolAddress;

103:         lqtyStakingAddress = _lqtyStakingAddress;

```

```solidity
File: BorrowerOperations.sol

146:         stabilityPoolAddress = _stabilityPoolAddress;

147:         gasPoolAddress = _gasPoolAddress;

152:         lqtyStakingAddress = _lqtyStakingAddress;

```

```solidity
File: LQTY/CommunityIssuance.sol

75:         stabilityPoolAddress = _stabilityPoolAddress;

```

```solidity
File: LQTY/LQTYStaking.sol

88:         troveManagerAddress = _troveManagerAddress;

89:         borrowerOperationsAddress = _borrowerOperationsAddress;

90:         activePoolAddress = _activePoolAddress;

```

```solidity
File: LUSDToken.sol

102:         troveManagerAddress = _troveManagerAddress;

106:         stabilityPoolAddress = _stabilityPoolAddress;

110:         borrowerOperationsAddress = _borrowerOperationsAddress;

114:         governanceAddress = _governanceAddress;

117:         guardianAddress = _guardianAddress;

149:         governance

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

96:         collateralConfigAddress = _collateralConfigAddress;

97:         borrowerOperationsAddress = _borrowerOperationsAddress;

98:         troveManagerAddress = _troveManagerAddress;

99:         stabilityPoolAddress = _stabilityPoolAddress;

100:         defaultPoolAddress = _defaultPoolAddress;

101:         collSurplusPoolAddress = _collSurplusPoolAddress;

103:         lqtyStakingAddress = _lqtyStakingAddress;

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

146:         stabilityPoolAddress = _stabilityPoolAddress;

147:         gasPoolAddress = _gasPoolAddress;

152:         lqtyStakingAddress = _lqtyStakingAddress;

// Code block 3 (solidity):
File: LQTY/CommunityIssuance.sol

75:         stabilityPoolAddress = _stabilityPoolAddress;

// Code block 4 (solidity):
File: LQTY/LQTYStaking.sol

88:         troveManagerAddress = _troveManagerAddress;

89:         borrowerOperationsAddress = _borrowerOperationsAddress;

90:         activePoolAddress = _activePoolAddress;

File: ActivePool.sol

96:         collateralConfigAddress = _collateralConfigAddress;

97:         borrowerOperationsAddress = _borrowerOperationsAddress;

98:         troveManagerAddress = _troveManagerAddress;

99:         stabilityPoolAddress = _stabilityPoolAddress;

100:         defaultPoolAddress = _defaultPoolAddress;

101:         collSurplusPoolAddress = _collSurplusPoolAddress;

103:         lqtyStakingAddress = _lqtyStakingAddress;

File: BorrowerOperations.sol

146:         stabilityPoolAddress = _stabilityPoolAddress;

147:         gasPoolAddress = _gasPoolAddress;

152:         lqtyStakingAddress = _lqtyStakingAddress;

File: LQTY/CommunityIssuance.sol

75:         stabilityPoolAddress = _stabilityPoolAddress;

File: LQTY/LQTYStaking.sol

88:         troveManagerAddress = _troveManagerAddress;

89:         borrowerOperationsAddress = _borrowerOperationsAddress;

90:         activePoolAddress = _activePoolAddress;


ayden G

1.Using bools for storage incurs overhead
If you don't use boolean for storage you will avoid Gwarmaccess 100 gas. In addition, state changes of boolean from true
to false can cost up to ~20000 gas rather than uint256(2) to uint256(1) that would cost significantly less.

https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol#L100
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-grants/src/grants/base/StandardFunding.sol#L106
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/RewardsManager.sol#L70

2.Multiple access to storage mapping should use local variable cache.
https://github.com/code-423n4/2023-05-ajna/blob/main/ajna-core/src/PositionManager.sol#L517#L535

```solidity
function tokenURI(
    uint256 tokenId_
) public view override(ERC721) returns (string memory) {
    require(_exists(tokenId_));

+   address poolAddress = poolKey[tokenId_];
-   address collateralTokenAddress = IPool(poolKey[tokenId_]).collateralAddress();
-   address quoteTokenAddress      = IPool(poolKey[tokenId_]).quoteTokenAddress();
+   address collateralTokenAddress = IPool(poolAddress).collateralAddress();
+   address quoteTokenAddress      = IPool(poolAddress).quoteTokenAddress();

    PositionNFTSVG.ConstructTokenURIParams memory params = PositionNFTSVG.ConstructTokenURIParams({
        collateralTokenSymbol: tokenSymbol(collateralTokenAddress),
        quoteTokenSymbol:      tokenSymbol(quoteTokenAddress),
        tokenId:               tokenId_,
-       pool:                  poolKey[tokenId_],
+       pool:                  poolAddress,
        owner:                 ownerOf(tokenId_),
        indexes:               positionIndexes[tokenId_].values()
    });

    return PositionNFTSVG.constructTokenURI(params);
}
```

3.Moving the check that verifies whether the owner of the tokenId is the same as the msg.sender to the beginning of the function could save some gas fees.
https://github.com/code-423n4/2023-05-ajna/

function stake(
    uint256 tokenId_
) external override {
+   // check that msg.sender is owner of tokenId
+   if (IERC721(address(positionManager)).ownerOf(tokenId_) != msg.sender) revert NotOwnerOfDeposit(); //@audit check should in the front of this function .
    address ajnaPool = PositionManager(address(positionManager)).poolKey(tokenId_);

-   // check that msg.sender is owner of tokenId
-   if (IERC721(address(positionManager)).ownerOf(tokenId_) != msg.sender) revert NotOwnerOfDeposit(); //@audit check should in the front of this function .

// Code block 1 (solidity):
function tokenURI(
    uint256 tokenId_
) public view override(ERC721) returns (string memory) {
    require(_exists(tokenId_));

+   address poolAddress = poolKey[tokenId_];
-   address collateralTokenAddress = IPool(poolKey[tokenId_]).collateralAddress();
-   address quoteTokenAddress      = IPool(poolKey[tokenId_]).quoteTokenAddress();
+   address collateralTokenAddress = IPool(poolAddress).collateralAddress();
+   address quoteTokenAddress      = IPool(poolAddress).quoteTokenAddress();

    PositionNFTSVG.ConstructTokenURIParams memory params = PositionNFTSVG.ConstructTokenURIParams({
        collateralTokenSymbol: tokenSymbol(collateralTokenAddress),
        quoteTokenSymbol:      tokenSymbol(quoteTokenAddress),
        tokenId:               tokenId_,
-       pool:                  poolKey[tokenId_],
+       pool:                  poolAddress,
        owner:                 ownerOf(tokenId_),
        indexes:               positionIndexes[tokenId_].values()
    });

    return PositionNFTSVG.constructTokenURI(params);
}

StandardFunding.sol#L100, StandardFunding.sol#L106, RewardsManager.sol#L70, PositionManager.sol#L517


Kaysoft Q

## [L-1] Refactor `_countVote` function to remove the unnamed parameter.

The last parameter of `_countVote` function in LibraGovernance.sol is unnamed.
Refactor code to remove unnamed parameter.

File: https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L76

```
function _countVote(uint256 proposalId, address account, uint8 support, uint256 weight, bytes memory) internal override {

        require(state(proposalId) == ProposalState.Active, "GovernorBravo::castVoteInternal: voting is closed");
        require(support <= 2, "GovernorBravo::castVoteInternal: invalid vote type");
        ProposalExtraData storage proposalExtraData = proposalData[proposalId];
        Receipt storage receipt = proposalExtraData.receipts[account];
        require(receipt.hasVoted == false, "GovernorBravo::castVoteInternal: voter already voted");

        proposalExtraData.supportVotes[support] += weight;

        receipt.hasVoted = true;
        receipt.support = support;
        receipt.votes = weight;
        proposalExtraData.totalVotes += weight;

    }
```

## [L-2] Refactor code to remove commented variable
The `proposalId` parameter of the `_execute` function in LibraGovernance.sol is commented out. Refactor code to remove commented parameter.

File: https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L106
```
function _execute(uint256 /* proposalId */,  address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) internal virtual override {
        require(GovernanceTimelock.checkOnlyRole(keccak256("TIMELOCK"), msg.sender), "not authorized");
        super._execute(1, targets, values, calldatas, descriptionHash);
        // _timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, descriptionHash);//@audit commented code.
    }
`

// Code block 1 (unknown):
function _countVote(uint256 proposalId, address account, uint8 support, uint256 weight, bytes memory) internal override {

        require(state(proposalId) == ProposalState.Active, "GovernorBravo::castVoteInternal: voting is closed");
        require(support <= 2, "GovernorBravo::castVoteInternal: invalid vote type");
        ProposalExtraData storage proposalExtraData = proposalData[proposalId];
        Receipt storage receipt = proposalExtraData.receipts[account];
        require(receipt.hasVoted == false, "GovernorBravo::castVoteInternal: voter already voted");

        proposalExtraData.supportVotes[support] += weight;

        receipt.hasVoted = true;
        receipt.support = support;
        receipt.votes = weight;
        proposalExtraData.totalVotes += weight;

    }


CodingNameKiki Q

### Issues Template
| Letter | Name | Description |
|:--:|:-------:|:-------:|
| L  | Low risk | Potential risk |
| NC |  Non-critical | Non risky findings |
| R  | Refactor | Changing the code |
| O | Ordinary | Often found issues |

| Total Found Issues | 22 |
|:--:|:--:|

### Low Risk Template
| Count | Explanation | Instances |
|:--:|:-------|:--:|
| [L-1] | The function `updateDistributionPeriod` should not allow distributionPeriod to be set as zero. This problem leads to the wrong calculation of rewardPerSecond in the function `fund` duo to division by zero. As rewardPerSecond is zero, this will lead to the wrong calculation of issuance in the function `issueOath` and here the function will actually issue a wrong amount of Oath to the stability pool. | 1 |
| [L-2] | The function `setAddresses` in CommunityIssuance is one time callable and the given addresses can't be changed after that, as there is no other function to change the address of the `stabilityPool` on a later plan. | 1 |

| Total Low Risk Issues | 2 |
|:--:|:--:|

### Non-Critical Template
| Count | Explanation | Instances |
|:----:|:-------|:--:|
| [N-1] | Both of the functions `transfer` and `transferFrom` does two address(0) checks on the recipient | 1 |
| [N-2] | Imported console in `LUSDToken.sol` | 1 |
| [N-3] | State variable `mintingPaused` is applied with its default value | 2 |
| [N-4] | A simple check can be applied, instead of creating a whole function doing its purpose | 2 |
| [N-5] | The function `sendOath` should check, if the contract has the balance of Oath tokens to do the transfer | 1 |
| [N-6] | The executed code in the function `setAddresses` can be moved in the constructor, as once called the function can't be called a second time | 1 |
| [N-7] | TODO applied in the contracts | 2 |
| [N-8] | Constructor lacks address(0) check | 2 |

| Total Non-Critical Issues | 8 |
|:--:|:--:|

### Refactor Issues Template
| Count | Explanation | Instances |
|:--:|:-------|:--:|
| [R-1] | U

Ethos-Core/contracts/LQTY/CommunityIssuance.sol

120:  function updateDistributionPeriod(uint256 _newDistributionPeriod) external onlyOwner {
121:        distributionPeriod = _newDistributionPeriod;
122:    }

Ethos-Core/contracts/LQTY/CommunityIssuance.sol

101:  function fund(uint amount) external onlyOwner {
102:        require(amount != 0, "cannot fund 0");
103:        OathToken.transferFrom(msg.sender, address(this), amount);
104:
105:        // roll any unissued OATH into new distribution
106:        if (lastIssuanceTimestamp < lastDistributionTime) {
107:            uint timeLeft = lastDistributionTime.sub(lastIssuanceTimestamp);
108:            uint notIssued = timeLeft.mul(rewardPerSecond);
109:            amount = amount.add(notIssued);
110:        }
111:
112:        rewardPerSecond = amount.div(distributionPeriod);
113:        lastDistributionTime = block.timestamp.add(distributionPeriod);
114:        lastIssuanceTimestamp = block.timestamp;
115:
116:        emit LogRewardPerSecond(rewardPerSecond);
117:    }


bin2chen Q

1.
SmartAccount._validateSignature()
According to protocol eip-4337, the _validateSignature() signature error should return "sigFailure", not the current direct revert.
```solidity
    function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash, address)
    internal override virtual returns (uint256 deadline) {
...
require(owner == hash.recover(userOp.signature) || tx.origin == address(0), "account: wrong signature");
...
```

https://eips.ethereum.org/EIPS/eip-4337
"""
The return value is packed of sigFailure, validUntil and validAfter timestamps.
sigFailure is 1 byte value of “1” the signature check failed (should not revert on signature failure, to support estimate)
validUntil is 8-byte timestamp value, or zero for “infinite”. The UserOp is valid only up to this time.
validAfter is 8-byte timestamp. The UserOp is valid only after this time.
"""

2.
SmartAccount.execute()/executeBatch（）has been limited to onlyOwner, no need to verify _requireFromEntryPointOrOwner();
SmartAccount.sol suggest remove onlyOwner:
```solidity
-   function execute(address dest, uint value, bytes calldata func) external onlyOwner{
+   function execute(address dest, uint value, bytes calldata func) external {
        _requireFromEntryPointOrOwner();
        _call(dest, value, func);
    }

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

// Code block 1 (solidity):
function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash, address)
    internal override virtual returns (uint256 deadline) {
...
require(owner == hash.recover(userOp.signature) || tx.origin == address(0), "account: wrong signature");
...

// Code block 2 (solidity):
-   function execute(address dest, uint value, bytes calldata func) external onlyOwner{
+   function execute(address dest, uint value, bytes calldata func) external {
        _requireFromEntryPointOrOwner();
        _call(dest, value, func);
    }

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

function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash, address)
    internal override virtual returns (uint256 deadline) {
...
require(owner == hash.recover(userOp.signature) || tx.origin == address(0), "account: wrong signature");
...

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

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


P7N8ZK Q

#

# [1] Function `adjustWeight` should check if the derivative corresponding to the index exists

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

165:    function adjustWeight(
166:        uint256 _derivativeIndex,
167:        uint256 _weight
168:    ) external onlyOwner {
169:        weights[_derivativeIndex] = _weight;
170:        uint256 localTotalWeight = 0;
171:        for (uint256 i = 0; i < derivativeCount; i++)
172:            localTotalWeight += weights[i];
173:        totalWeight = localTotalWeight;
174:        emit WeightChange(_derivativeIndex, _weight);
175:    }
```
https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L165-L175

```
diff --git forkSrcPrefix/contracts/SafEth/SafEth.sol forkDstPrefix/contracts/SafEth/SafEth.sol
index ebadb4bbf2b55e7a28b0334c5dd3ea40aa163456..b26b68119acd1ecbfe7294bf050423d77e361799 100644
--- forkSrcPrefix/contracts/SafEth/SafEth.sol
+++ forkDstPrefix/contracts/SafEth/SafEth.sol
@@ -166,6 +166,7 @@ contract SafEth is
         uint256 _derivativeIndex,
         uint256 _weight
     ) external onlyOwner {
+        require(_derivativeIndex < derivativeCount, "Invalid derivativeIndex");
         weights[_derivativeIndex] = _weight;
         uint256 localTotalWeight = 0;
         for (uint256 i = 0; i < derivativeCount; i++)
```

# [2] Function `setMaxSlippage` should check if the derivative corresponding to the index exists
```
File: contracts/SafEth/SafEth.sol

202:    function setMaxSlippage(
203:        uint _derivativeIndex,
204:        uint _slippage
205:    ) external onlyOwner {
206:        derivatives[_derivativeIndex].setMaxSlippage(_slippage);
207:        emit SetMaxSlippage(_derivativeIndex, _slippage);
208:    }
```
https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L202-L208

```
diff --git forkSrcPrefix/contracts/SafEth/SafEth.sol forkDstPrefix/contracts/SafEth/SafEth.sol
index ebadb4bbf2b55e7a28b0334c5dd3ea40aa163456..0c579a70b83d225448f66d3e9323aa0ea

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

165:    function adjustWeight(
166:        uint256 _derivativeIndex,
167:        uint256 _weight
168:    ) external onlyOwner {
169:        weights[_derivativeIndex] = _weight;
170:        uint256 localTotalWeight = 0;
171:        for (uint256 i = 0; i < derivativeCount; i++)
172:            localTotalWeight += weights[i];
173:        totalWeight = localTotalWeight;
174:        emit WeightChange(_derivativeIndex, _weight);
175:    }

// Code block 2 (unknown):
diff --git forkSrcPrefix/contracts/SafEth/SafEth.sol forkDstPrefix/contracts/SafEth/SafEth.sol
index ebadb4bbf2b55e7a28b0334c5dd3ea40aa163456..b26b68119acd1ecbfe7294bf050423d77e361799 100644
--- forkSrcPrefix/contracts/SafEth/SafEth.sol
+++ forkDstPrefix/contracts/SafEth/SafEth.sol
@@ -166,6 +166,7 @@ contract SafEth is
         uint256 _derivativeIndex,
         uint256 _weight
     ) external onlyOwner {
+        require(_derivativeIndex < derivativeCount, "Invalid derivativeIndex");
         weights[_derivativeIndex] = _weight;
         uint256 localTotalWeight = 0;
         for (uint256 i = 0; i < derivativeCount; i++)

// Code block 3 (unknown):
File: contracts/SafEth/SafEth.sol

202:    function setMaxSlippage(
203:        uint _derivativeIndex,
204:        uint _slippage
205:    ) external onlyOwner {
206:        derivatives[_derivativeIndex].setMaxSlippage(_slippage);
207:        emit SetMaxSlippage(_derivativeIndex, _slippage);
208:    }


Kaysoft Q

## [NC-1] Use more descriptive and related variable names instead of `_foo` and `_bar`
Variable names `_foo` and `_bar` are used in the `_getRate` function of the AMPHClaimer.sol contract.
File: https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/AMPHClaimer.sol#L195

```
function _getRate(uint256 _distributedAmph) internal pure returns (uint256 _rate) {
    uint256 _foo = (_TWENTY_FIVE_THOUSANDS * BASE_SUPPLY_PER_CLIFF) / Math.max(_distributedAmph, _FIFTY_MILLIONS);
    uint256 _bar = (_distributedAmph * 1e12) / (BASE_SUPPLY_PER_CLIFF * _FIFTY); //@audit div before mul.
//@audit use meaningful variable name.
    _rate = 1e6 + (_foo - _bar);
  }
```

#### Recommended Mitigation Steps
Use more descriptive variable names other than `_foo` and `_bar`.

## [NC-2] Admin can mint large amount of AmphoraProtocolToken since there is no maximum cap

The mint function has no maximum totalsupply cap, so admin can mint large amount of token.

```
function mint(address _dst, uint256 _rawAmount) public onlyOwner {
    _mint(_dst, _rawAmount);
  }//@audit totalsupply should have a cap.
```
#### Recommended Mitigation Step
implement the max supply cap

// Code block 1 (unknown):
function _getRate(uint256 _distributedAmph) internal pure returns (uint256 _rate) {
    uint256 _foo = (_TWENTY_FIVE_THOUSANDS * BASE_SUPPLY_PER_CLIFF) / Math.max(_distributedAmph, _FIFTY_MILLIONS);
    uint256 _bar = (_distributedAmph * 1e12) / (BASE_SUPPLY_PER_CLIFF * _FIFTY); //@audit div before mul.
//@audit use meaningful variable name.
    _rate = 1e6 + (_foo - _bar);
  }

// Code block 2 (unknown):
function mint(address _dst, uint256 _rawAmount) public onlyOwner {
    _mint(_dst, _rawAmount);
  }//@audit totalsupply should have a cap.


nirlin Q

## NC 1 : Use the uniswap multicall implementation that returns that exact error code, instead of the error code of multicall contract itself
Ondo use the following implementation of multicall in factory and source bridge:

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

which simply returns the `Call Failed` error on !success, but use the uniswap impementation which returns the exact error code. Implementation is as follow:
https://github.com/Uniswap/v3-periphery/blob/b13f9d9d9868b98b765c4f1d8d7f486b00b22488/contracts/base/Multicall.sol#L11-L28

```solidity
    function multicall(bytes[] calldata data) public payable override returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(data[i]);

            if (!success) {
                // Next 5 lines from https://ethereum.stackexchange.com/a/83577
                if (result.length < 68) revert();
                assembly {
                    result := add(result, 0x04)
                }
                revert(abi.decode(result, (string)));
            }

            results[i] = result;
        }
    }
}
```

## NC 2 : No need to use this much assembly in _rpow
https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/rwaOracles/RWADynamicOracle.sol#L345-L398
`_rpow` function us copied from the following repositery,

https://github.com/makerdao/dss/blob/master/src/jug.sol

which is written in very old solidity ve

## NC 2 : No need to use this much assembly in _rpow
https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/rwaOracles/RWADynamicOracle.sol#L345-L398
`_rpow` function us copied from the following repositery,

https://github.com/makerdao/dss/blob/master/src/jug.sol

which is written in very old solidity version 0.6.12 when there was no native way to take power in solidity but now that is not the case.

So as the _rpow represents the following formula given by dev:

result = (prevRangeClose * [(numerator/ ONE) ** (elapsedDays + 1)])

This can be easily done using simple solidity instead use that.

## NC 3:  Use the mul functions copied as it is
`_rmul` and `_mul` function have been copied from following file:

https://github.com/makerdao/dss/blob/master/src/jug.sol

But developers have split it instead for which there is no need to do so, instead use it as or not use it at all. Making changing is susceptible to error

## NC 4 : No need for underflow check in _mul function
The codebase from where the following function is copied

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

// Code block 2 (solidity):
function multicall(bytes[] calldata data) public payable override returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(data[i]);

            if (!success) {
                // Next 5 lines from https://ethereum.stackexchange.com/a/83577
                if (result.length < 68) revert();
                assembly {
                    result := add(result, 0x04)
                }
                revert(abi.decode(result, (string)));
            }

            results[i] = result;
        }
    }
}

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

function multicall(bytes[] calldata data) public payable override returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(data[i]);

            if (!success) {
                // Next 5 lines from https://ethereum.stackexchange.com/a/83577
                if (result.length < 68) revert();
                assembly {
                    result := add(result, 0x04)
                }
                revert(abi.decode(result, (string)));
            }

            results[i] = result;
        }
    }
}


Giorgio Q

## the `MergingPools::getFighterPoints` will revert when input is > 0

## Vulnerability details

The function attempts to fetch the points of fighters 0-maxId, but can actually only fetch the points of fighter id 0, because the length of the points array is set to 0. So if we input 1 it will revert with array out of bonds error

## Impact

The impact is not severe as this function is a view function that doesn't impact any logic in the contracts. The function will not display the different fighter points as expected

## POC

https://github.com/code-423n4/2024-02-ai-arena/blob/5b2ab9f9fadd0b91268ff6f22b4ae0fd5b79ec09/src/MergingPool.sol#L207-L211

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

To prove this I slightly modified the `testGetFighterPoints()` in MegingPool.t.sol.

```
    function testGetFighterPoints() public {
        // owner mints a fighter by claiming
        _mintFromMergingPool(_ownerAddress);
        _mintFromMergingPool(_ownerAddress);
        _mintFromMergingPool(_ownerAddress);
        _mintFromMergingPool(_ownerAddress);
        _mintFromMergingPool(_ownerAddress);
        _mintFromMergingPool(_ownerAddress);
        _mintFromMergingPool(_ownerAddress);
        _mintFromMergingPool(_ownerAddress);
        address owner = _fighterFarmContract.ownerOf(0);
        assertEq(owner, _ownerAddress);

        // rankedeBattle contract adds points
        vm.startPrank(address(_rankedBattleContract));
        _mergingPoolContract.addPoints(0, 100);
        _mergingPoolContract.addPoints(1, 100);
        _mergingPoolContract.addPoints(2, 100);
        _mergingPoolContract.addPoints(3, 100);
        _mergingPoolContract.addPoints(4, 100);
        _mergingPoolContract.addPoints(5, 100);
        _mergingPoolContract.addPoints(6, 100);
        _mergingP

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

        // rankedeBattle contract adds points
        vm.startPrank(address(_rankedBattleContract));
        _mergingPoolContract.addPoints(0, 100);
        _mergingPoolContract.addPoints(1, 100);
        _mergingPoolContract.addPoints(2, 100);
        _mergingPoolContract.addPoints(3, 100);
        _mergingPoolContract.addPoints(4, 100);
        _mergingPoolContract.addPoints(5, 100);
        _mergingPoolContract.addPoints(6, 100);
        _mergingPoolContract.addPoints(7, 100);
        assertEq(_mergingPoolContract.totalPoints(), 100);
        // getFighterPoints for owners fighter
        uint256[] memory fighterPoints = _mergingPoolContract.getFighterPoints(8);
        // assertEq(fighterPoints.length >= 1 && fighterPoints[0] == 100, true);
        // getFighterPoints for non existent fighter
        // vm.expectRevert(stdError.indexOOBError);
        // _mergingPoolContract.getFighterPoints(1000);
    }

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


Rickard Q

## [L-01] The `@dev` NatSpec comment in `UtilLib.checkNonZeroAddress` is incorrect
The NatSpec for the `checkNonZeroAddress()` function should indicate that it is a function, not a modifier.
````diff
src/utils/UtilLib.sol
-   /// @dev zero address check modifier
+   /// @dev zero address check function
    /// @param address_ address to check
    function checkNonZeroAddress(address address_) internal pure {
        if (address_ == address(0)) revert ZeroAddressNotAllowed();
    }
````
## [L-02] Use underscore prefix for internal functions
For functions such as [checkNonZeroAddress](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/utils/UtilLib.sol#L11), it is more readable to have this function be named `_checkNonZeroAddress` so readers know it is an internal function. A similarly opinionated recommendation is to use `s_` for storage variables and `i_` for immutable variables.
````solidity
11:    function checkNonZeroAddress(address address_) internal pure {
12:        if (address_ == address(0)) revert ZeroAddressNotAllowed();
13:    }
````
[https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/utils/UtilLib.sol#L11-L13](https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/utils/UtilLib.sol#L11-L13)

// Code block 1 (diff):
src/utils/UtilLib.sol
-   /// @dev zero address check modifier
+   /// @dev zero address check function
    /// @param address_ address to check
    function checkNonZeroAddress(address address_) internal pure {
        if (address_ == address(0)) revert ZeroAddressNotAllowed();
    }

// Code block 2 (solidity):
11:    function checkNonZeroAddress(address address_) internal pure {
12:        if (address_ == address(0)) revert ZeroAddressNotAllowed();
13:    }


ZanyBonzy Q

# 1. Consider checking for similarities in current and proposed wallets
Links to affected code *
https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/ManagedWallet.sol#L42
## Impact
Improves decentralization, prevents loss of funds needed to accept proposals in case same wallet updates (Updating wallets to the same addresses requires sending ether to accept, or else new wallet proposals cannot be made).

## Recommended Mitigation Steps
Consider including checks
proposedMainWallet != proposedConfirmationWallet
mainWalllet != proposedMainWallet
confirmationWallet != proposedConfirmationWallet

***

# 2. Protocol is highly vulnerable to WBTC pausable property.
Links to affected code *
https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/stable/CollateralAndLiquidity.sol#L70
https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/stable/CollateralAndLiquidity.sol#L140
https://etherscan.io/token/0x2260fac5e5542a773aa44fbcfedf7c193bc2c599#code
## Impact

The protocol relies in WBTC as one of the main collateral tokens for the protocol. Users looking to repay their USDS debt, or improve their collateral share, might need to deposit more WBTC/WETH collateral.

This process fails if WBTC is paused as transfers will not be executable thus causing such borrowers to fall below the required liquidation threshold.

At the other end, liquidators will also not be able to liquidate these users as the wbtc liquidity removal from the pools will fail. This will cause a host of bad debt to be accrued up in the protocol.

Whenever the token gets unpaused, liquidators using MEV bots can also frontrun the borrowers' repayments leading to a host of unfair liquidations.

## Recommended Mitigation Steps
Recommend introducing support for other types of tokens, to serve as collateral for USDS in the `CollateralAndLiquidity` contract. A more standard ERC20 token can be us

// Convert the 8 decimals from the Chainlink price to 18 decimals
		return uint256(price) * 10**10;


Nyxaris G

## Title:
Potential Gas Optimization in [`createPhysicalAttributes`](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/AiArenaHelper.sol#L83) Function.

## Description:
The  [`createPhysicalAttributes`](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/AiArenaHelper.sol#L83) function currently uses a dynamic array to store attribute probability indexes. While this does not incur gas costs when called externally due to its view modifier, it is a point of gas inefficiency because  the function is  used internally by state-changing functions.

## Recommendation:
 Consider refactoring the function to use a fixed-size array if the maximum size of the array is known and unchanging. This would preemptively optimize the function for any future internal use within transactions, potentially reducing gas costs.

```javascript
finalAttributeProbabilityIndexes
uint256[6] memory finalAttributeProbabilityIndexes;
```

// Code block 1 (javascript):
finalAttributeProbabilityIndexes
uint256[6] memory finalAttributeProbabilityIndexes;


0x11singh99 G

## Gas Optimizations
| Number |Issue|Instances|
|-|:-|:-:|
| [[G-01](#g-01-structs-can-be-packed-into-fewer-storage-slots)] | `Structs` can be packed into fewer storage slots. | 1 |
| [[G-02](#g-02-cache-state-variables-outside-of-loop-to-avoid-readingwriting-storage-on-every-iteration)] | Cache `state variables` outside of loop to avoid reading/writing storage on every iteration. | 1 |
| [[G-03](#g-03-using-storage-instead-of-memory-for-structsarrays-saves-gas)] | Using `storage` instead of memory for structs/arrays saves gas. | 3 |
| [[G-04](#g-04-use-calldata-instead-of-memory-for-function-arguments-that-do-not-get-mutated)] | Use `calldata` instead of memory for function arguments that do not get mutated. | 3 |
| [[G-05](#g-05-state-variables-can-be-cached-instead-of-re-reading-them-from-storage)] | State variables can be cached instead of re-reading them from storage. | 17 |
| [[G-06](#g-06-multiple-accesses-of-a-mappingarray-should-use-a-local-variable-cache)] | Multiple accesses of a mapping/array should use a local variable cache. | 5 |
| [[G-07](#g-07-state-variables-only-set-during-construction-should-be-declared-constant)]| State variables only set during construction should be declared `constant`. | 2 |
| [[G-08](#g-08-state-variables-can-be-packed-into-fewer-storage-slots)] | State variables can be `packed` into fewer storage slots. | 3 |
| [[G-09](#g-09-use-constants-instead-of-typeuintxmax)] | Use `constants` instead of type(uintx).max. | 17 |
| [[G-10](#g-10-use-hardcode-address-instead-addressthis)] | Use `hardcode address` instead address(this). | 40 |
| [[G-11](#g-11-do-not-calculate-constants-to-save-gas)] | Do not calculate `constants` to save gas. | 2 |
| [[G-12](#g-12-amounts-should-be-checked-for-0-before-calling-a-transfer)] | Amounts should be checked for 0 before calling a transfer. | 3 |
| [[G-13](#g-13-do-not-initialize-state-variables-with-their-default-value)] | Do not initialize state variables with their default value. | 1 |
| [[G-1

## [G-02] Cache state variables outside of loop to avoid reading/writing storage on every iteration.

Reading from storage should always try to be avoided within loops. In the following instances, we are able to cache state variables outside of the loop to save a Gwarmaccess (100 gas) per loop iteration. In addition, update the storage variable outside the loop to save 1 SSTORE per loop iteration.

**Note: These are instances missed by the Bot Race.**

**_1 Instances - 1 File_**

### Cache `totalActiveOptions` outside of the loop to save 1 SSTORE and 1 SLOAD per iteration, update it's state variable after the loop ended.


DavidGiladi Q

### Low Issues
|Title|Issue|Instances|
|-|:-|:-:|
|[L-1] Burn functions must be protected with a modifier | [Burn functions must be protected with a modifier](#burn-functions-must-be-protected-with-a-modifier) | 1 |
|[L-2] Missing contract-existence checks before low-level calls | [Missing contract-existence checks before low-level calls](#missing-contract-existence-checks-before-low-level-calls) | 1 |
|[L-3] Direct `supportsInterface()` calls | [Direct `supportsInterface()` calls](#direct-supportsinterface-calls) | 3 |
|[L-4] Fee/Rate Caps Missing in Smart Contracts | [Fee/Rate Caps Missing in Smart Contracts](#feerate-caps-missing-in-smart-contracts) | 1 |
|[L-5] Reentrancy vulnerabilities | [Reentrancy vulnerabilities](#reentrancy-vulnerabilities) | 18 |
|[L-6] Solmate SafeTransferLib Usage Detection | [Solmate SafeTransferLib Usage Detection](#solmate-safetransferlib-usage-detection) | 1 |
|[L-7] Unsafe Cast Unsigned to Signed | [Unsafe Cast Unsigned to Signed](#unsafe-cast-unsigned-to-signed) | 2 |

Total: 7 issues

### Non-Critical Issues
|Title|Issue|Instances|
|-|:-|:-:|
|[N-1] Do not calculate constants | [Do not calculate constants](#do-not-calculate-constants) | 2 |
|[N-2] Contract Ordering Violation Style Guide | [Contract Ordering Violation Style Guide](#contract-ordering-violation-style-guide) | 1 |
|[N-3] Control structures do not follow the Solidity Style Guide | [Control structures do not follow the Solidity Style Guide](#control-structures-do-not-follow-the-solidity-style-guide) | 29 |
|[N-4] Avoid double casting | [Avoid double casting](#avoid-double-casting) | 2 |
|[N-5] Consider move Msg.sender checks to modifier | [Consider move Msg.sender checks to modifier](#consider-move-msgsender-checks-to-modifier) | 1 |
|[N-6] Redundant Inheritance | [Redundant Inheritance](#redundant-inheritance) | 4 |
|[N-7] Should Declare as View | [Should Declare as View](#should-declare-as-view) | 6 |
|[N-8] Variable names too similar | [Variable names too similar](

Line: 98          (bool success, ) = to.call{ value: amount, gas: gas }("")

Line: 197          rdpxFeePercentage = _rdpxFeePercentage


csanuragjain Q

## Funds can stuck

Contract:
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/StakeManager.sol#L35

Issue:
Funds can stuck if withdraw address is contract itself

POC:

1. User calls `withdrawTo` function with `withdrawAddress` as StakeManager.sol contract itself

```
function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external {
        DepositInfo storage info = deposits[msg.sender];
        require(withdrawAmount <= info.deposit, "Withdraw amount too large");
        info.deposit = uint112(info.deposit - withdrawAmount);
        emit Withdrawn(msg.sender, withdrawAddress, withdrawAmount);
        (bool success,) = withdrawAddress.call{value : withdrawAmount}("");
        require(success, "failed to withdraw");
    }
```

2. This transfer all User deposited ETH to the contract which process it via `receive` function

```
receive() external payable {
        depositTo(msg.sender);
    }
```

3. Since in this case msg.sender is contract itself so deposit is made for StakeManager.sol contract

4. Now there is no way to withdraw these funds

Recommendation:
Kindly revise the receive function to disallow deposit by contract itself

```
receive() external payable {
require(msg.sender!=address(this), "Incorrect sender");
        depositTo(msg.sender);
    }
```

## Stake condition can be revised to allow type(uint112).max

Contract:
https://github.com/code-423n4/2023-01-biconomy/blob/main/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/StakeManager.sol#L65

Issue:
It seems that currently Staking amount is capped to `type(uint112).max` even though deposit cap is set to `type(uint112).max`. This means the Staking cap could be revised to also allow `type(uint112).max`

Recommendation:
Kindly revise the `addStake` function

```
function addStake(uint32 _unstakeDelaySec) public payable {
...
        require(stake <= type(uint112).max, "stake overflow");
...
}
```

## No way

// Code block 1 (unknown):
function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external {
        DepositInfo storage info = deposits[msg.sender];
        require(withdrawAmount <= info.deposit, "Withdraw amount too large");
        info.deposit = uint112(info.deposit - withdrawAmount);
        emit Withdrawn(msg.sender, withdrawAddress, withdrawAmount);
        (bool success,) = withdrawAddress.call{value : withdrawAmount}("");
        require(success, "failed to withdraw");
    }

// Code block 2 (unknown):
receive() external payable {
        depositTo(msg.sender);
    }

// Code block 3 (unknown):
receive() external payable {
require(msg.sender!=address(this), "Incorrect sender");
        depositTo(msg.sender);
    }

// Code block 4 (unknown):
function addStake(uint32 _unstakeDelaySec) public payable {
...
        require(stake <= type(uint112).max, "stake overflow");
...
}


Timenov Q

# Lybra Finance report by Timenov

## Summary
I-01 Empty lines should be removed for better code readability.
I-02 Incorrect naming of interfaces.
I-03 Incorrect naming of modifiers.
I-04 Incorrect naming of event.
I-05 Incorrect naming of function.
I-06 Wrong contract address in comment.
I-07 Use functions instead of modifiers.

### [I-01] Empty lines should be removed for better code readability.
*There are 7 instances of this issue.*

In the `LybraGovernance` contract there are some places where unnecessary empty lines are left. They should be removed for better code readability.

https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L25C5-L25C5
https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L34-L36
https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L54C1-L54C1
https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L77C7-L77C7
https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L85
https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L91C9-L91C9
https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L204-L205

### [I-02] Incorrect naming of interfaces.
*There is 1 instance of this issue.*

Some of the interfaces do not use to correct naming convention for interfaces. I have included only 1, because it is the only one is scope, however there is also one with wrong naming in `contracts/lybra/interfaces/Iconfigurator`

```solidity
File: contracts/lybra/pools/LybraStETHVault.sol

8: int

File: contracts/lybra/pools/LybraStETHVault.sol

8: interface Ilido // should be ILido

File: contracts/lybra/token/EUSD.sol

83: modifier MintPaused() // should be mintPaused()

LybraGovernance.sol#L25-L5, LybraGovernance.sol#L34-L36, LybraGovernance.sol#L54-L1, LybraGovernance.sol#L77-L7, LybraGovernance.sol#L85, LybraGovernance.sol#L91-L9, LybraGovernance.sol#L204-L205


invitedtea Q

#  L1. Dynamic array used in `LRTConfig.sol`
## Title
Unbounded loops used in `LRTConfig.sol`
## Impact
Description: The `getSupportedAssetList` function in the provided smart contract returns a dynamic array containing the list of supported assets. This function currently does not limit the number of assets it can return. In scenarios where the number of supported assets grows large, calling this function could require more gas than is available in a block. This situation would make the function fail and could potentially make parts of the contract unusable or cause issues for interfaces and other contracts that depend on this data.

Line Number: Not directly present but implied in functions that may iterate over `getSupportedAssetList`.
Recommended Fix: Consider implementing a pattern to limit the size of this list or handle large lists in a gas-efficient manner. https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTConfig.sol#L135
```
function getSupportedAssetList() external view override returns (address[] memory) {
        return supportedAssetList;
    }
```

## Proof of Concept
With amount array length of 15 and above, it is highly likely to hit the gasLimit.
## Tools Used
Manual Review

## Recommended Mitigation Steps
Pagination: Modify the getSupportedAssetList function to return a subset of the supported assets based on pagination parameters (e.g., start index and count). This approach allows callers to retrieve all assets in smaller, manageable chunks.

Example Implementation:

```solidity
function getSupportedAssetList(uint start, uint count) external view returns (address[] memory) {
    uint totalAssets = supportedAssetList.length;
    if (start >= totalAssets) {
        return new address[](0);
    }

    uint end = start + count;
    if (end > totalAssets) {
        end = totalAssets;
    }

    address[] memory assets = new address[](end - start);
    for (uint i = start; i < end; i++) {
        assets[i - start] = supportedAssetList[i];

function getSupportedAssetList(uint start, uint count) external view returns (address[] memory) {
    uint totalAssets = supportedAssetList.length;
    if (start >= totalAssets) {
        return new address[](0);
    }

    uint end = start + count;
    if (end > totalAssets) {
        end = totalAssets;
    }

    address[] memory assets = new address[](end - start);
    for (uint i = start; i < end; i++) {
        assets[i - start] = supportedAssetList[i];
    }
    return assets;
}

// Code block 1 (unknown):
function getSupportedAssetList() external view override returns (address[] memory) {
        return supportedAssetList;
    }


tofunmi Q

(1) :- `transferShares` implemented but `transferSharesFrom` isn't like lido's stEth in rUSDY.sol https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code#F27#L353
-> this would make $rUSDY's shares easy to use in dapps in the future, that's why there's is a _transferShares() internal function in the first place
```solidity
    function transferSharesFrom(
        address _sender, address _recipient, uint256 _sharesAmount
    ) external returns (bool) {
        uint256 currentAllowance = allowances[_sender][msg.sender];
        require(currentAllowance >= _amount, "TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE");
        _transferShares(_sender, _recipient, _sharesAmount);
        emit TransferShares(_sender, _recipient, _sharesAmount);
        uint256 tokensAmount = getRUSDYByShares(_sharesAmount);
        emit Transfer(msg.sender, _recipient, tokensAmount);
        _approve(_sender, msg.sender, currentAllowance - _amount);
        return true;
    }
```

// Code block 1 (solidity):
function transferSharesFrom(
        address _sender, address _recipient, uint256 _sharesAmount
    ) external returns (bool) {
        uint256 currentAllowance = allowances[_sender][msg.sender];
        require(currentAllowance >= _amount, "TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE");
        _transferShares(_sender, _recipient, _sharesAmount);
        emit TransferShares(_sender, _recipient, _sharesAmount);
        uint256 tokensAmount = getRUSDYByShares(_sharesAmount);
        emit Transfer(msg.sender, _recipient, tokensAmount);
        _approve(_sender, msg.sender, currentAllowance - _amount);
        return true;
    }


0x6980 Q

# Report

## Low Risk Issues

| |Issue|Instances|
|-|:-|:-:|
| [L-01](#L-01) | Using zero as a parameter | 1 |
| [L-02](#L-02) | Re-org attack | 3 |
| [L-03](#L-03) | `require()` should be used instead of `assert()` | 1 |
| [L-04](#L-04) | TransferOwnership Should Be Two Step | 2 |

Total: 2 instances over 2 issues.

## Non-critical Issues

| |Issue|Instances|
|-|:-|:-:|
| [N-01](#N-01) | Adding a `return` statement when the function defines a named return variable, is redundant | 1 |
| [N-02](#N-02) | `assembly` blocks should have extensive comments | 1 |
| [N-03](#N-03) | Do not calculate constants | 9 |
| [N-04](#N-04) | Function can be declared as `pure` | 1 |
| [N-05](#N-05) | Named imports of parent contracts are missing | 20 |
| [N-06](#N-06) | Not using the named return variables anywhere in the function is confusing | 4 |
| [N-07](#N-07) | Strings should use double quotes rather than single quotes | 9 |
| [N-08](#N-08) | Some contract names don't follow the Solidity naming conventions | 2 |
| [N-09](#N-09) | Unused structs | 2 |
| [N-10](#N-10) | Functions not used internally could be marked external | 14 |
| [N-11](#N-11) | OpenZeppelin libraries should be upgraded to a newer version | 13 |
| [N-12](#N-12) | Non-usage of specific imports | 32 |

Total: 841 instances over 94 issues.

## Low Risk Issues

### [L-01] Using zero as a parameter
Taking `0` as a valid argument in Solidity without checks can lead to severe security issues. A historical example is the infamous `0x0` address bug where numerous tokens were lost. This happens because `0` can be interpreted as an uninitialized `address`, leading to transfers to the `0x0` `address`, effectively burning tokens. Moreover, `0` as a denominator in division operations would cause a runtime exception. It's also often indicative of a logical error in the caller's code. It's important to always validate input and handle edge cases like `0` appropriately. Use `require()` state

File: contracts/bridge/DestinationBridge.sol

/// @audit 1 parameter
139:           new address[](0)

File: contracts/usdy/rUSDYFactory.sol

82:     rUSDYImplementation = new rUSDY();

83:     rUSDYProxyAdmin = new ProxyAdmin();

84:     rUSDYProxy = new TokenProxy(
85:          address(rUSDYImplementation),
86:          address(rUSDYProxyAdmin),
87:          ""
88:        );


slvDev Q

## Low Findings

|    | Issue | Instances |
|----|-------|:---------:|
| [L-01] | Centralization risk for privileged functions | 15 |
| [L-02] | Subtraction may underflow if multiplication is too large | 1 |
| [L-03] | `decimals()` is not part of the ERC20 standard | 4 |
| [L-04] | `type(uint256).max` Approvals Aren't Universal in All Tokens | 2 |
| [L-05] | Some tokens may revert on large transfers | 23 |
| [L-06] | Code does not follow the best practice of check-effects-interaction | 5 |
| [L-07] | Use `abi.encodeCall()` instead of `abi.encodeWithSignature()`/`abi.encodeWithSelector()` | 2 |
| [L-08] | `internal/private` Function calls within for loops | 2 |
| [L-09] | Upgradable contracts not taken into account | 94 |
| [L-10] | Lack of index element validation in external/public function | 31 |
| [L-11] | Consider checking that transfer to `address(this)` is disabled | 1 |
| [L-12] | Use `forceApprove/safeIncreaseAllowance` from SafeERC20 instead of `approve/safeApprove` | 7 |
| [L-13] | Potential Gas Griefing Due to Non-Handling of Return Data in External Calls | 3 |
| [L-14] | Low Level Calls to Custom Addresses | 3 |
| [L-15] | Prevent Division by Zero | 4 |
| [L-16] | Solidity version 0.8.20 may not work on other chains due to `PUSH0` | 11 |
| [L-17] | Missing checks for `address(0x0)` when updating address state variables | 2 |
| [L-18] | Lack of Parameter Validation in Constructor/Initializer | 10 |
| [L-19] | Owner can renounce Ownership | 4 |
| [L-20] | State variables are not limited to a reasonable range | 11 |
| [L-21] | Missing Contract-Existence Checks Before Low-Level Calls | 3 |
| [L-22] | Events may be emitted out of order due to reentrancy | 13 |
| [L-23] | External calls in an un-bounded `for-`loop may result in a DOS | 1 |
| [L-24] | For loops in public or external functions should be avoided due to high gas costs and possible DOS | 2 |
| [L-25] | Critical functions should be a two step procedure | 16 |
| [L-26] | Deprecated Function `safeAppr

File: src/V3Vault.sol

765: function withdrawReserves(uint256 amount, address receiver) external onlyOwner
788: function setTransformer(address transformer, bool active) external onlyOwner
837: function setReserveFactor(uint32 _reserveFactorX32) external onlyOwner
844: function setReserveProtectionFactor(uint32 _reserveProtectionFactorX32) external onlyOwner
856: function setTokenConfig(address token, uint32 collateralFactorX32, uint32 collateralValueLimitFactorX32)
        external
        onlyOwner
870: function setEmergencyAdmin(address admin) external onlyOwner

File: src/V3Oracle.sol

185: function setMaxPoolPriceDifference(uint16 _maxPoolPriceDifference) external onlyOwner
201: function setTokenConfig(
        address token,
        AggregatorV3Interface feed,
        uint32 maxFeedAge,
        IUniswapV3Pool pool,
        uint32 twapSeconds,
        Mode mode,
        uint16 maxDifference
    ) external onlyOwner
265: function setEmergencyAdmin(address admin) external onlyOwner


cryptostellar5 Q

### 01. UPGRADEABLE CONTRACT IS MISSING A `__GAP[50]` STORAGE VARIABLE TO ALLOW FOR NEW STORAGE VARIABLES IN LATER VERSIONS

*Number of Instances Identified: 2*

See [this](https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps) link for a description of this storage variable. While some contracts may not currently be sub-classed, adding the variable now protects against forgetting to add it in the future.

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

```
19-21: contract ReaperStrategyGranarySupplyOnly is ReaperBaseStrategyv4, VeloSolidMixin {
    using ReaperMathUtils for uint256;
    using SafeERC20Upgradeable for IERC20Upgradeable;

```

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol

```
14-18: contract ReaperBaseStrategyv4 is
    ReaperAccessControl,
    IStrategy,
    UUPSUpgradeable,
    AccessControlEnumerableUpgradeable
```

### 02. NOW IS DEPRECATED

*Number of Instances Identified: 1*

Use `block.timestamp` instead

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

```
282: require(deadline >= now, 'LUSD: expired deadline');
```

### 03. CONSTANTS SHOULD BE DEFINED RATHER THAN USING MAGIC NUMBERS

*Number of Instances Identified: 7*

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

```
127: require(_bps <= 10_000, "Invalid BPS value");
133: require(_driftBps <= 500, "Exceeds max allowed value of 500 BPS");
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.p

// Code block 1 (unknown):
19-21: contract ReaperStrategyGranarySupplyOnly is ReaperBaseStrategyv4, VeloSolidMixin {
    using ReaperMathUtils for uint256;
    using SafeERC20Upgradeable for IERC20Upgradeable;

// Code block 2 (unknown):
14-18: contract ReaperBaseStrategyv4 is
    ReaperAccessControl,
    IStrategy,
    UUPSUpgradeable,
    AccessControlEnumerableUpgradeable

// Code block 3 (unknown):
282: require(deadline >= now, 'LUSD: expired deadline');

ReaperStrategyGranarySupplyOnly.sol, ReaperBaseStrategyv4.sol, LUSDToken.sol, ActivePool.sol

LUSDToken.sol, ReaperStrategyGranarySupplyOnly.sol, ReaperBaseStrategyv4.sol, ActivePool.sol


0x3b G

| *Issue*    | *Description*                                                                                |
|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **[G-01]** | Call functions directly                                                                                |
| **[G-02]** | Save strike in memory earlier                                                                                |
| **[G-03]** | Save equation in memory earlier                                                                                |
| **[G-04]** | Instead of calling it multiple times [nextFundingPaymentTimestamp](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/perp-vault/PerpetualAtlanticVault.sol#L563-L569) save it in memory |
| **[G-05]** | [_curveSwap](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L515-L542) input parameter `validate` is useless                                                     |
| **[G-06]** | Check is not need                                                                                |

### **[G-01]** Call functions directly
Under [deposit](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/perp-vault/PerpetualAtlanticVaultLP.sol#L118-L135) you can skip [previewDeposit](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/perp-vault/Per

### **[G-03]** Save equation in memory earlier
Under [updateFunding](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/perp-vault/PerpetualAtlanticVault.sol#L462-L496) this equation bellow is used 3 times in a row.

This is not needed as the result can be saved in memory. and accessed at will for a minimum gas cost.

### **[G-04]** Instead of calling it multiple times [nextFundingPaymentTimestamp](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/perp-vault/PerpetualAtlanticVault.sol#L563-L569) save it in memory
Under [_updateFundingRate](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/perp-vault/PerpetualAtlanticVault.sol#L594-L614) you can save [nextFundingPaymentTimestamp](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/perp-vault/PerpetualAtlanticVault.sol#L602) before the `if` or `else`, saving a few calls to this function. After it you can use the variable [endTime](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/perp-vault/PerpetualAtlanticVault.sol#L602) in the calculations much more cheaply than doing multiple function calls.

### **[G-05]** [_curveSwap](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L515-L542) input parameter `validate` is useless
[_curveSwap](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L515-L542) is used in 2 places ( [upperDepeg](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L1051-L1070) and [lowerDepeg](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L1080-L1124) ), where they each input `validate` as true, meaning that there is no need for this parameter as it can be hard-coded to constantly validate.

### **[G-06]** Check is not need
[_transfer](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L624-L685) currently checks if [msg.sender matches the owner of the bondID](https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L638-L641), unfortunately this is done in the gas expensive way as the previous call to [IRdpxDecayingBonds.bonds(bondID)](https://github.com/code-423n4/2

PerpetualAtlanticVault.sol#L563-L569, RdpxV2Core.sol#L515-L542, PerpetualAtlanticVaultLP.sol#L118-L135, PerpetualAtlanticVault.sol#L462-L496, PerpetualAtlanticVault.sol#L594-L614, PerpetualAtlanticVault.sol#L602, RdpxV2Core.sol#L1051-L1070, RdpxV2Core.sol#L1080-L1124, RdpxV2Core.sol#L624-L685, RdpxV2Core.sol#L638-L641


fouzantanveer Analysis

## Any comments for the judge to contextualize your findings
Kelp DAO is actively developing rsETH, a Liquid Restaked Token (LRT) designed to provide seamless liquidity and flexibility within the DeFi landscape. The project, already live on the testnet, introduces a novel approach to Ethereum staking and restaking rewards while preserving liquidity for active participation in DeFi protocols.

*Key Components and Functionality:*

1. *Deposit Pool:* The deposit pool acts as a streamlined vault for restakers, facilitating the transfer of liquid staked tokens to receive rsETH tokens based on the current exchange rate. It abstracts complexities related to rewards and validator delegation, simplifying the overall process.

2. *Node Delegator:* This module is pivotal in managing the movement of deposited liquid staked assets. Each node delegator is responsible for delegating assets to a specific operator, ensuring economic security across nodes operated by that operator for various Adaptive Validator Sets (AVSes). It also automates reward redemption through prescribed strategies, leading to substantial gas savings for restakers.

3. *Reward Market:* Governed by the DAO through governance mechanisms, the reward market offers diverse strategies tailored to different rewards. This strategic flexibility allows AVSes to optimize returns for restakers while avoiding undesirable token activities.

4. *Withdrawal Manager:* The Withdrawal Manager module facilitates rsETH holders in converting their tokens into a share of all assets managed by the protocol. Redeemers can expect to receive a comprehensive set of rewards accrued by Node Delegators, reflecting the rewards from operators subscribed to various AVSes.

By integrating these components, rsETH seeks to bridge the gap between staking rewards and DeFi liquidity, providing users with a comprehensive solution for maximizing their returns while actively participating in decentralized finance.

## Approach taken in evaluating the

// Consider adding an event for role changes in LRTConfigRoleChecker
event RoleUpdated(bytes32 indexed role, address indexed account, bool indexed granted);

modifier onlyLRTManager() {
    if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.MANAGER, msg.sender)) {
        emit RoleUpdated(LRTConstants.MANAGER, msg.sender, false);
        revert ILRTConfig.CallerNotLRTConfigManager();
    }
    emit RoleUpdated(LRTConstants.MANAGER, msg.sender, true);
    _;
}


catellatech Q

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

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

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

| Total Found Issues | 34 |
|:--:|:--:|

### Low Risk
| Count | Explanation | Instances |
|:--:|:-------|:--:|
| [L-01] | USER FACING BORROWEROPERATIONS AND TROVEMANAGER MISS EMERGENCY LEVER | 2 |
| [L-02] | MULTIPLE ADDRESS MAPPINGS CAN BE COMBINED INTO A SINGLE MAPPING OF AN ADDRESS TO A STRUCT, WHERE APPROPRIATE | 19 |
| [L-03] | PRAGMA EXPERIMENTAL ABIECODERV2 IS DEPRECATED | 2 |
| [L-04] | ERC20UPGRADEABLE SAFEAPPROVE() IS DEPRECATED | 1 |
| [L-05] | Open TODOs | 2 |
| [L-06] | DIVISION BEFORE MULTIPLICATION CAN LEAD TO PRECISION ERRORS | 2 |
| [L-07] | IMMUTABLE ADDRESSES LACK ZERO-ADDRESS CHECK | 1 |
| [L-08] | USE OF FLOATING PRAGMA | 17 |
| [L-09] | CRITICAL CHANGES SHOULD USE TWO-STEP PROCEDURE | 3 |

| Total Low Risk Issues | 9 | Total Instances | 49 |
|:--:|:--:|:--:|--:|

### Non-Critical
| Count | Explanation | Instances |
|:--:|:-------|:--:|
| [N-01] | TOO MANY BITS TO DESCRIBE SMALL QUANTITIES | MULTIPLE INSTANCES |
| [N-02] | MANDATORY CHECKS FOR EXTRA SAFETY IN THE SETTERS | 1 |
| [N-03] | RACE CONDITION ON ERC20 APPROVAL | 1 |
| [N-04] | CREATE YOUR O

Ethos-Core/contracts/ActivePool.sol

41: mapping (address => uint256) internal collAmount;
42: mapping (address => uint256) internal LUSDDebt;
44: mapping (address => uint256) public yieldingPercentage;
45: mapping (address => uint256) public yieldingAmount;
46: mapping (address => address) public yieldGenerator;
47: mapping (address => uint256) public yieldClaimThreshold;

Ethos-Vault/contracts/libraries/DistributionTypes.sol

3: pragma experimental ABIEncoderV2;

Ethos-Vault/contracts/interfaces/IRewardsController.sol

3: pragma experimental ABIEncoderV2;

Ethos-Vault/contracts/interfaces/IRewardsDistributor.sol

3: pragma experimental ABIEncoderV2;