xanoutas/solidity-security-findings huggingface dataset:
logic error state variable already initialize in contract ActivePool
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/ActivePool.sol#L49-L54
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/ActivePool.sol#L132-L136
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/ActivePool.sol#L144-L150


# Vulnerability details

## Impact
The functions ``setYieldingPercentageDrift`` and ``setYieldDistributionParams`` can't be set(re-initialize).
because the storage has saved the values of the state variables in lines 49-54.

## Proof of Concept
look at this code:
```
    uint256 public yieldingPercentageDrift = 100; // rebalance iff % is off by more than 100 BPS

    // Yield distribution params, must add up to 10k
    uint256 public yieldSplitTreasury = 20_00; // amount of yield to direct to treasury in BPS
    uint256 public yieldSplitSP = 40_00; // amount of yield to direct to stability pool in BPS
    uint256 public yieldSplitStaking = 40_00; // amount of yield to direct to OATH Stakers in BPS
```

```

    function setYieldingPercentageDrift(uint256 _driftBps) external onlyOwner {
        require(_driftBps <= 500, "Exceeds max allowed value of 500 BPS");
        yieldingPercentageDrift = _driftBps;
        emit YieldingPercentageDriftUpdated(_driftBps);
    }
```

```
function setYieldDistributionParams(uint256 _treasurySplit, uint256 _SPSplit, uint256 _stakingSplit) external onlyOwner {
        require(_treasurySplit + _SPSplit + _stakingSplit == 10_000, "Splits must add up to 10000 BPS");
        yieldSplitTreasury = _treasurySplit;
        yieldSplitSP = _SPSplit;
        yieldSplitStaking = _stakingSplit;
        emit YieldDistributionParamsUpdated(_treasurySplit, _SPSplit, _stakingSplit);
    }
```
 **1.** The function ``setYieldingPercentageDrift`` aims to change the value of the variable ``yieldingPercentageDrift`` with a maximum value limit of 500 bps, as we see that the state variable ``yieldingPercentageDrift`` has been initialised with the value ``100`` in line 49 (https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/ActivePool.sol#L49). 
```
uint256 public yieldingPercentageDrift = 100; // rebalance if % does not match more than 100 BPS
```
so if the owner call ``setYieldingPercentageDrift`` function and set ``_driftBps`` = 200, the storage still read value is ``100`` because the storage already saved the value ``yieldingPercentageDrift = 100`` from line 49 (https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/ActivePool.sol#L49).

 **2.** The ``setYieldDistributionParams`` function aims to set the yield share distribution parameters and has three input parameters to fill in: ``_treasurySplit``, ``_SPSplit``, and ``_stakingSplit``. and validates the input parameters to ensure that the sum of the thr
It's possible to steal rewards by front running
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/LQTY/LQTYStaking.sol#L177-L195


# Vulnerability details

## Impact
When a user wants to earn collateral gains, typically they need to stake their funds. However, there is a way to earn collateral gains without staking funds by front-running the increaseF_Collateral function call.

By front-running, the user is able to anticipate a transaction before it is confirmed on the blockchain by placing their own transaction ahead of it. By doing this, the user can gain collateral without staking their funds.

It's important to note that the amount of time the user stakes is not a factor in their ability to earn collateral gains through front-running. This is because front-running allows the user to bypass the need for staking entirely.

However, timing is crucial when front-running. If the user executes the front-running at the correct time, they can earn collateral gains without having to stake their funds. But if they mistime the front-running, they could potentially lose money.

## Proof of Concept
Flow:
1. User rebalances with the `manualRebalance` function.
2. This internally calls `increaseF_Collateral`
3. Malicious actor frontrun this request and call the `stake` function with a big `_LQTYamount` [X]
4. This 3) request will run first, and increases the attacker stakes
5. Owner request to rebalance then
6. -> This increases the collateral `F_Collateral[_collateral]`
7. Attacker can directly call the `unstake` function.
8. `_sendCollGainToUser` will then send the gains to the Malicious actor balance ( = [X] ).

## Tools Used
Manual review.

## Recommended Mitigation Steps
When calculating gains, it's important to take into account the duration for which the user has staked their funds before rewarding them for that amount.
ACTIVEPOOL.SOL, REAPERVAULTERC4626.SOL, REAPERVAULTV2.SOL IS NOT EIP-4626 COMPLIANT
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/ActivePool.sol#L26
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L12
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L21


# Vulnerability details

## Impact
Other protocols that integrate with Ethos may wrongly assume that the functions are EIP-4626 compliant. Thus, it might cause integration problems in the future that can lead to wide range of issues for both parties.

## Proof of Concept
All official EIP-4626 requirements can be found on it’s official [page](https://eips.ethereum.org/EIPS/eip-4626#methods).

In ActivePool.sol non-compliant functions are listed below along with the reason they are not compliant. The following functions are missing but should be present:
[ ] asset() is missing
[ ] totalAssets() is missing
[ ] convertToShares(uint256) is missing
[ ] convertToAssets(uint256) is missing
[ ] maxDeposit(address) is missing
[ ] previewDeposit(uint256) is missing
[ ] deposit(uint256,address) is missing
[ ] maxMint(address) is missing
[ ] previewMint(uint256) is missing
[ ] mint(uint256,address) is missing
[ ] maxWithdraw(address) is missing
[ ] previewWithdraw(uint256) is missing
[ ] withdraw(uint256,address,address) is missing
[ ] maxRedeem(address) is missing
[ ] previewRedeem(uint256) is missing
[ ] redeem(uint256,address,address) is missing
[ ] totalSupply() is missing
[ ] balanceOf(address) is missing
[ ] transfer(address,uint256) is missing
[ ] transferFrom(address,address,uint256) is missing
[ ] approve(address,uint256) is missing
[ ] allowance(address,address) is missing

The following events are missing but should be present:
[ ] Deposit(address,address,uint256,uint256) is missing
[ ] Withdraw(address,address,address,uint256,uint256) is missing

In ReaperVaultERC4626.sol non-compliant functions are listed below along with the reason they are not compliant. The following functions are missing but should be present:

[ ] totalSupply() is missing
[ ] balanceOf(address) is missing
[ ] transfer(address,uint256) is missing
[ ] transferFrom(address,address,uint256) is missing
[ ] approve(address,uint256) is missing
[ ] allowance(address,address) is missing

The following events are missing but should be present:
[ ] Deposit(address,address,uint256,uint256) is missing
[ ] Withdraw(address,address,address,uint256,uint256) is missing

In ReaperVaultV2.sol non-compliant functions are listed below along with the reason they are not compliant. The following functions are missing but should be present:
[ ] asset() is missing
[ ] totalAssets() is missing
[ ] convertToShares(uint256) is missing
[ ] convertToAssets(uint256) is missing
[ ] maxDeposit(address) is missing
[ ] previewDeposit(uint256) is missing
[ ] deposit(uint256,address) is missing
[ ] maxMint(address) is missing
[ ] previewMint(uint256) is missing
[ ] mint(uint256,address) is missing
[ ] m
Large deposit can cause freeze of funds for all vault depositors
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L334
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L365
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L53
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L68
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L141
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L185


# Vulnerability details

## Impact
Large deposit can cause freeze of funds and the vault won't allow withdrawals or deposits.

## Proof of Concept

The links to the affected code point to instances where multiplications can overflow in certain circumstances depending on the vault's values of `totalSupply()` and `balance()`.

In `ReaperVaultV2._withdraw`
```solidity
value = (_freeFunds() * _shares) / totalSupply();
```

In `ReaperVaultV2._deposit`
```solidity
shares = (_amount * totalSupply()) / freeFunds; // use "freeFunds" instead of "pool"
```

This is the relevant test to demonstrate the sequence of events leading to frozen funds -

```solidity
  function testRevert() public {
    address actor;

    // some initial small deposit
    actor = 0x000000000000000000000000000000005F3d3a0e;
    _deposit(actor, 1 ether, false);

    // a very large deposit
    actor = 0x0000000000000000000000000000000000000308;
    _deposit(actor, (mockERC20.balanceOf(admin) - 100 ether) / vault.totalSupply(), false);

    // no longer able to make small deposits and this call will revert
    actor = 0x0000000000000000000000000000000000004950;
    _deposit(actor, 1 ether, true);

    // no longer able to withdraw small amounts and this call will revert
    actor = 0x000000000000000000000000000000005F3d3a0e;
    _withdraw(actor, 1 ether, true);

    // funds are effectively stuck in the contract
  }
```

Full details can be found here -
https://gist.github.com/alpeware/7899913cd2000a9877f1f00135655c20#file-vault-invariants-t-sol-L168

## Invariant Testing

Inspired by horsefact's recent post [0], I've come across this issue while adding a basic invariant test in Foundry.

The invariant test can be found here
https://gist.github.com/alpeware/7899913cd2000a9877f1f00135655c20#file-vault-invariants-t-sol-L124

## Tools Used

Foundry Invariant Testing

## Recommended Mitigation Steps

Use OZ's `Math.mulDiv` [1] to prevent overflow. It also supports the ability to specify rounding direction so can also replace the custom `ReaperVaultERC4626.roundUpDiv` function.

In `ReaperVaultV2._deposit`

```solidity
shares = Math.mulDiv(_amount, totalSupply(), freeFunds); // use "freeFunds" instead of "pool"
```

In `ReaperVaultV2._withdraw`

```solidity
value = Math.mulDiv(_freeFunds(), _shares, totalSupply());
```

In `ReaperVaultERC4626.previewMint`

```solidity
as
Possible Conditions That May Cause the sendOath External Function to Revert and the transfer failure
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/StabilityPool.sol#L840-L844
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/LQTY/CommunityIssuance.sol#L124-L128


# Vulnerability details

## Impact

The transfer function fails, the OATH rewards may not be distributed as expected, and the msg.sender may not receive the rewards as expected. The msg.sender may lose his rewards. 

## Proof of Concept

     function _payOutLQTYGains(ICommunityIssuance _communityIssuance, address _depositor) internal {
        uint depositorLQTYGain = getDepositorLQTYGain(_depositor);
        _communityIssuance.sendOath(_depositor, depositorLQTYGain);
        emit LQTYPaidToDepositor(_depositor, depositorLQTYGain);
     }

      function sendOath(address _account, uint _OathAmount) external override {
        _requireCallerIsStabilityPool();

        OathToken.transfer(_account, _OathAmount);
      }

POC :

"sendOath(address, 1000)" has been called from the stability pool using these input values

The caller is checked to ensure it is the stability pool. Since the caller is from the stability pool, this condition is true 

The transfer function is called without checking the contract balance. However, assume that the communityIssuance contract only has 700 OATH tokens. As a result, this transfer function will fail due to insufficient balance in the communityIssuance contract. The call is sent to the stability pool, which is not aware of the status of the sendOath() function

So this tranfer function fails because of not enough balance communityIssunace contract. the call is sent to Stabilty pool . The stability pool don't know the status of the sendOath() function .

If any failures occur due to external causes, they are not checked in the _payOutLQTYGains() function. Therefore, all external call statuses should be checked before proceeding to the next steps. There is a possibility of failure in external calls. 

So the transfer is not successful and depositor may lose his rewards. Because of transfer failure the depositor reward balance is not updated .

## Tools Used

Manual Audit

## Recommended Mitigation Steps

Rewrite sendOath() like bellow. This returns the status of the sendOath() function

function sendOath(address _account, uint _OathAmount) external override returns (bool) {
        _requireCallerIsStabilityPool();
        
        if (OathToken.balanceOf(address(this)) >= _OathAmount && _OathAmount > 0) {
            return OathToken.transfer(_account, _OathAmount);
        } else {
            return false;
        }
    }

Check the status of sendOath() in stability pools _payOutLQTYGains() function like bellow 

require(_communityIssuance.sendOath(_depositor, depositorLQTYGain),"The transfer is failed")
No accountability maintained when send OATH gains  to stability pool
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/LQTY/CommunityIssuance.sol#L124-L128
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/StabilityPool.sol#L840-L844


# Vulnerability details

## Impact

When the sendOath() function is used to transfer OATH gains to the StabilityPool, there is currently no mechanism in place to maintain accountability within the contract. Although the function transfers the requested _OathAmount to the _account address if the caller is the StabilityPool contract, there is no record of the transfer being made within the contract. The _OathAmount is not deducted from the contract balance

If the _OathAmount is not accounted for in the contract, it means that the balance of OathToken in the contract will be incorrect. This can potentially cause issues in the functioning of the contract and affect the overall system stability

 it is important to ensure that the _OathAmount is properly accounted for in the contract, such as by deducting it from the contract's balance or tracking the amount separately in a data structure

## Proof of Concept

        function _payOutLQTYGains(ICommunityIssuance _communityIssuance, address _depositor) internal {
        uint depositorLQTYGain = getDepositorLQTYGain(_depositor);
        _communityIssuance.sendOath(_depositor, depositorLQTYGain);
        emit LQTYPaidToDepositor(_depositor, depositorLQTYGain);
        }

(https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/LQTY/CommunityIssuance.sol#L124-L128)

After the sendOath(_depositor, depositorLQTYGain) function is called, the call is transferred to the communityIssuance contract

      function sendOath(address _account, uint _OathAmount) external override {
        _requireCallerIsStabilityPool();

        OathToken.transfer(_account, _OathAmount);
      }

(https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/StabilityPool.sol#L840-L844)

The CommunityIssuance contract checks if the caller is the StabilityPool contract. If the caller is the StabilityPool contract, then the requested _OathAmount is transferred to _account. However, there is no record of the transfer maintained within the contract. The _OathAmount is not reduced from the contract balance using any state variables

Maintaining contract balance in state variables provides a secure and reliable way for contracts to manage their own funds and perform financial transactions

## Tools Used

Manual Audit

## Recommended Mitigation Steps

Track the OATH amount send and received with separate state variable
SWC-101 The arithmetic operation can overflow.ActivePool.setYieldDistributionParams()
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
```
The arithmetic operation can overflow.
It is possible to cause an arithmetic overflow. Prevent the overflow by constraining inputs using the require() statement or use the OpenZeppelin SafeMath library for integer arithmetic operations. Refer to the transaction trace generated for this issue to reproduce the overflow.
```

## Proof of Concept
```
# Vulnerable Lines
    function setYieldDistributionParams(uint256 _treasurySplit, uint256 _SPSplit, uint256 _stakingSplit) external onlyOwner {
        require(_treasurySplit + _SPSplit + _stakingSplit == 10_000, "Splits must add up to 10000 BPS");
        yieldSplitTreasury = _treasurySplit;
        yieldSplitSP = _SPSplit;
        yieldSplitStaking = _stakingSplit;
        emit YieldDistributionParamsUpdated(_treasurySplit, _SPSplit, _stakingSplit);
    }
```

```
# Test
1. Create Account and add money
{
  "address": "",
  "gasLimit": "0x2ffffff",
  "gasPrice": "0x3b9aca000",
  "input": "0x608060405260008060146101000a81548160ff0219169083151502179055506064600f556107d0601055610fa0601155610fa060125534801561004157600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3614982806100ec6000396000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c8063761ab22c1161010f578063a3f4df7e116100a2578063c5f956af11610071578063c5f956af14610a02578063c707f62514610a4c578063eb13cd1014610bc6578063fc08a27814610c14576101f0565b8063a3f4df7e14610893578063aac1846f14610916578063b7f8cf9b14610960578063c0835ed8146109aa576101f0565b80638fca46f4116100de5780638fca46f4146107775780639b56d6c9146107c55780639e6ed1281461081d5780639f7d525714610875576101f0565b8063761ab22c146106a35780638c943115146106ed5780638da5cb5b1461070b5780638f32d59b14610755576101f0565b806346a8044111610187578063622c070711610156578063622c07071461052b57806362782a2f146105af5780636dc85da814610607578063715aa61b14610635576101f0565b806346a80441146103f95780634b14fa871461043b5780635a4d28bb146104935780635fc7b5e8146104dd576101f0565b806331585161116101c357806331585161146102f557806336c855df146103435780633aacc8151461038d5780633de2e098146103db576101f0565b8063015933de146101f55780630b622ab2146102135780632a9043ec1461025d5780632bc75d35146102a7575b600080fd5b6101fd610c36565b6040518082815260200191505060405180910390f35b61021b610c3c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610265610c62565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6102f36004803603604081101
sending collateral is executed before burning ` LUSD ` or repaying ` LUSD` and funds loss.
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
sending collateral is executed before burning LUSD or repaying LUSD, it's lead to funds loss.

## Proof of Concept
The `closeTrove` function performs  burning LUSD, repaying LUSD to the user, and sending collateral back to the user. These operations is not properly handled. For instance, if the sending of collateral is executed before burning LUSD or repaying LUSD, it can lead to funds loss. 

```solidity

function closeTrove(address _collateral) external override {
        ITroveManager troveManagerCached = troveManager;
        IActivePool activePoolCached = activePool;
        ILUSDToken lusdTokenCached = lusdToken;

        _requireTroveisActive(troveManagerCached, msg.sender, _collateral);
        uint256 collCCR = collateralConfig.getCollateralCCR(_collateral);
        uint256 collDecimals = collateralConfig.getCollateralDecimals(_collateral);
        uint price = priceFeed.fetchPrice(_collateral);
        _requireNotInRecoveryMode(_collateral, price, collCCR, collDecimals);

        troveManagerCached.applyPendingRewards(msg.sender, _collateral);

        uint coll = troveManagerCached.getTroveColl(msg.sender, _collateral);
        uint debt = troveManagerCached.getTroveDebt(msg.sender, _collateral);

        _requireSufficientLUSDBalance(lusdTokenCached, msg.sender, debt.sub(LUSD_GAS_COMPENSATION));

        uint newTCR = _getNewTCRFromTroveChange(_collateral, coll, false, debt, false, price, collDecimals);
        _requireNewTCRisAboveCCR(newTCR, collCCR);

        troveManagerCached.removeStake(msg.sender, _collateral);
        troveManagerCached.closeTrove(msg.sender, _collateral, 2); // 2 = closedByOwner

        emit TroveUpdated(msg.sender, _collateral, 0, 0, 0, BorrowerOperation.closeTrove);

        // Burn the repaid LUSD from the user's balance and the gas compensation from the Gas Pool
        _repayLUSD(activePoolCached, lusdTokenCached, _collateral, msg.sender, debt.sub(LUSD_GAS_COMPENSATION));
        _repayLUSD(activePoolCached, lusdTokenCached, _collateral, gasPoolAddress, LUSD_GAS_COMPENSATION);

        // Send the collateral back to the user
        activePoolCached.sendCollateral(_collateral, msg.sender, coll);
    }

```
## Tools Used
Manual
## Recommended Mitigation Steps

Need to burn  LUSD first then sending collateral.