xanoutas/solidity-security-findings huggingface dataset:
The onlyOwner modifier is being incorrectly used in the fund() function
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#L101


# Vulnerability details

## Impact

This breaks the interaction with fund() function

 Pool looses the OATH Tokens  

 The depositors in stability pool can't get any time based emissions from community pool

 The OATH depositor can't stake OATH and looses his rewards even he is having enough OATH in his account

EOAs and other users can't stake their OATH LP in the LPs in this pool. Then the over all revenue-share pool affects .

If the community issuance contract not getting enough OATH then its not possible to send OATH when stability pool request OATH when needed. Then depositors can't get receive time-based emissions of OATH. The over all revenue-share pool process affected.

## Proof of Concept

function fund(uint amount) external onlyOwner {

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

This fund() function is created to stake other users OATH token in pool and users getting rewards. But the fund() function wrongly use the onlyOwner Modifier. The meaning is only owner can access the fund() function. As per documentation this is wrong .

POC :

1) Bob have 100 OATH LP tokens he wants to stake this tokens in this pool to receive ERN rewards from 
issuance fees

2) He initiate the call fund(100 OATH) this function reverts because as per community issuance contract fund() function is only possible to call by owner because of the onlyOwner Modifier.

3) So the function reverts Bob unbale to stake his 100 OATH LP tokens in pool

4) So Bob unable to earn rewards even after he having enough OATH LP in his account

Internal call also not possible because fund() declared as external function.

So over all fund() function uses onlyOwner function in wrongly.As per documentation fund() function is created because the EOA or others Stake their OATH tokens in poll and getting rewards 

Similar finding in other contest:

(https://github.com/code-423n4/2023-01-biconomy-findings/issues/390)

## Tools Used

Manual Audit 

## Recommended Mitigation Steps

Remove the "onlyOwner" modifier from the "fund()" function

function fund(uint amount) external {
The vault could possibly burn user's shares even though s/he received less than the expected amount of underlying token when withdrawing
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#L366


# Vulnerability details

## Impact
When withdrawing from a vault, the user passes the amount of shares to be burnt, and in return the user receives the corresponding assets as follows:
```sh
value = (_freeFunds() * _shares) / totalSupply();
```

If there is not enough balance in the vault, then it withdraws from strategies in the order they were added in `withdrawalQueue`. However, in case the strategies don't have enough balance, the vault burns all user's shares even though s/he hasn't received all of the corresponding assets for it.

In other words, if the user should receive **Y** tokens when passing **X** shares and the issue occurs, then **X** shares will be burnt even though the user receives less than **Y** which is not fair.



## Proof of Concept

Let's break down `_withdraw`'s flow:

1. Calculate how many tokens the user should receive
```sh
   value = (_freeFunds() * _shares) / totalSupply();
```
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L365

2. Burn the shares
```sh
   _burn(_owner, _shares);
```
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L366

3. Assume there’s not enough fund in the vault then it will loop through `withdrawalQueue` and withdraw what's required to cover the gap.
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L372-L397

4. Assume the tokens the user should receive is still lower than the balance then update it to the balance
```sh
vaultBalance = token.balanceOf(address(this));
	if (value > vaultBalance) {
		value = vaultBalance;
	}
```
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L399-L402

5. Finally transfer the tokens to the user
```sh
 token.safeTransfer(_receiver, value);
```
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L410

As you can notice, no matter how many tokens the user receives, s/he will always get his/her shares burnt. 

## Tools Used
Manual analysis

## Recommended Mitigation Steps

1. Move the burning logic to the end.
2. In case, there's still not enough fund then recalculate how many shares should be burnt based on the new value of `value`

For example:

```sh
	vaultBalance = token.balanceOf(address(this));
	if (value > vaultBalance) {
		value = vaultBalance;
		=> recalculate the shares to be burnt
	}
	
  _burn(_owner, _shares);
	token.safeTransfer(_receiver, value);
```
Destruction of the ReaperStrategyGranarySupplyOnly implementation
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact

Complete freezing of all functionality in ReaperStrategyGranarySupplyOnly


Functions from the logic contract (ReaperStrategyGranarySupplyOnly) shouldn't be called directly. a bad actor can take the ownership by calling initialize directly then destroy it making all proxies (Smart Contract Wallets) pointing to a non-existing contract.

One could argue that admin can call init after deploying it. However, there is still a risk of front-runing it.

If the ReaperStrategyGranarySupplyOnly implementation contract is not initialized, it can be destroyed using the following attack scenario:

1.Initialize the ReaperStrategyGranarySupplyOnly implementation contract using the init function.
2.Execute a transaction that contains a single delegatecall to a contract that executes the selfdestruct opcode on any incoming call, such as:
```
contract Destructor {
    fallback() external {
        selfdestruct(payable(0));
    }
}
```


The destruction of the implementation contract would result in the freezing of all functionality of the wallets that point to such an implementation. It would also be impossible to change the implementation address, as the Singleton functionality and the entire contract would be destroyed, leaving only the functionality from the Proxy contract accessible.

In the deploy script there is the following logic:
```
const SmartWallet = await ethers.getContractFactory("ReaperStrategyGranarySupplyOnly");
const baseImpl = await SmartWallet.deploy();
await baseImpl.deployed();
console.log("base wallet impl deployed at: ", baseImpl.address);
```
So, in the deploy script there is no enforce that the ReaperStrategyGranarySupplyOnly contract implementation was initialized.



## Proof of Concept
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L62-L67

## Tools Used

Manual reading

## Recommended Mitigation Steps

Add to the ReaperStrategyGranarySupplyOnly contract the following constructor that will prevent implementation contract from the initialization:

```
// Constructor ensures that this implementation contract can not be initialized
constructor() public {
    owner = address(1);
}
```
User could lose the whole stake on vault withdrawal
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L359-L412
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L399-L407


# Vulnerability details

## Impact
When there are locked funds in the strategy, the withdrawMaxLoss feature of ReaperVaultV2 is not respected. Locked funds refer to a situation where the requested amount and the returned amount differ from the loss reported. This behavior is acceptable for a strategy, but in this scenario, the _withdraw() function calculates the realized loss incorrectly, and a user who withdraws their funds will receive less than expected while having their shares burned.

In situations where a strategy experiences a liquidity squeeze, users may lose their entire asset amount as all their requested shares may be burned, with only a small amount transferred to them. The amount transferred can be arbitrarily low and this behavior is not affected by the withdrawMaxLoss limit.

## Proof of Concept
In this code snippet: 
```solidity 
            vaultBalance = token.balanceOf(address(this));
            if (value > vaultBalance) {
                value = vaultBalance;
            }
```
The function withdraw will reset the `value` and set it to the `token.balanceOf(address(this));` if the balance is not enough for withdraw. As an impact, some funds can get frozen.

In ReaperVaultV2's _withdraw() function, a situation may arise where lockedAmount = _amountNeeded - (liquidatedAmount + loss) >= 0. This amount cannot be withdrawn at the moment and is neither considered a loss. The _withdraw() function updates the value per if (value > vaultBalance) {value = vaultBalance;}, which means that the totalLoss check for the rebased value <= ((value + totalLoss) * withdrawMaxLoss) / PERCENT_DIVISOR does not accurately control for the real loss. As a result, a user may lose their entire amount because _withdraw() first burns the full amount of the requested _shares and this total loss check is the only protection in place.

Consider the scenario where there is only one strategy, and 90 out of the 100 requested tokens are currently locked due to a temporary liquidity squeeze, and there is no loss involved. Suppose there are no tokens in the vault balance before the strategy's withdrawal.

In this case, if a user initiates a withdrawal using ReaperBaseStrategyv4's withdraw() function, only 10 tokens will be transferred, and there will be no reported loss. The check for total loss, i.e., 0 = totalLoss <= ((value + totalLoss) * withdrawMaxLoss) / PERCENT_DIVISOR, will be satisfied for any withdrawMaxLoss setting.

As a result, the user, will receive only 10 tokens, and the remaining 100 tokens worth of shares will be burned.

## Tools Used
Manual review.

## Recommended Mitigation Steps
I would recommend to slightly adapt the logic as following: 

```diff
re
`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-Vault/contracts/ReaperVaultV2.sol#L356, https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L426


# Vulnerability details

# [H-01] `ReaperVaultV2.sol` is not EIP-4626 compliant

## Lines of code
[https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L356](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L356)     
[https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L426](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L426)

## Vulnerability details
### Impact
Other protocols that integrate with the Ethos Reserve may mistakenly use the following code with no trace of a `mint()` and `redeem()` function.     
Judging this as High Risk. EIP4626 is aimed to create a consistent and robust implementation patterns for Tokenized Vaults. A slight deviation from 4626 would break composability and potentially lead to loss of funds.       
       
The missing functions are the most problematic; one expects the `mint()` and `redeem()` to be present, but they’re absent instead.      
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).    
The following functions are missing but should be present:   
1. `mint(uint256, address) returns (uint256)`
2. `redeem(uint256, address, address) returns (uint256)`   
### Tools Used
VS Code
### Recommended Mitigation Steps
Consider implementing the two functions listed above to meet the specifications of EIP-4626.
ReaperVaultV2._withdraw might lost depositor's token
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L359-L412


# Vulnerability details

## Impact
Function ReaperVaultV2._withdraw first call [_burn](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L366) to burn depositor's share, then call [token.safeTransfer](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L410) to transfer **value** of token to msg.sender, however there are some cases that __value__ doesn't conform with **_shares**, which cause depositor's loss

## Proof of Concept
[if (value > token.balanceOf(address(this)))](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L368), the vault first checks if balanceOf(this) is larger than __value__, if not, the vault will withdraw token from [withdrawQueue](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L372-L397). After that, the vault will [check again](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L399-L402), if the vault's balance is still smaller than __value__, it will change __value__ to it's [current balance](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L401), in such case, vault [_burn](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L366) more share than it sends to depositor

Say depositor calls __withdraw__ with **_shares** equaling to 100, [in line365](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L365) the __value__ is 10000, and in [line366](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L366), vault burns depositor 100 shares
Then the Vault doesn't have enough token, so it [withdraws token from its strategies](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L372-L397)
After that, it get 1000 as [vaultBalance](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L399), in such case, __value__ is set to __vaultBalance__ in [line401](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L400-L402)
Finally, [line410](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts
loss of funds to user when withdrawing from ReaperVaultERC4626 if withdrawal from strategies is needed
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#L364-L367
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L368-L408
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L399-L411


# Vulnerability details

## Impact
When withdrawing, a calculation error in `_withdraw` for `ReaperVaultV2`, parent class of ReaperVaultERC4626 causes user to withdraw less than their share value when withdrawal from strategies is needed.

## Proof of Concept
In `_withdraw`, notice how user share value is calculated.  
```solidity
        require(_shares != 0, "Invalid amount");
        value = (_freeFunds() * _shares) / totalSupply();
        _burn(_owner, _shares);

```

The next part in `_withdraw` checks if user is withdrawing more than what vault has. If it's more, vault will have to withdraw from strategies. Notice `value -= loss;` when ` if (loss != 0)` which means assets is withdrawn out from strategy. This works when checking against vaultBalance which is the initial balance before withdrawing from strategies. Hence with `if (value <= vaultBalance)`, once withdrawn amount + initial vaultBalance is enough for user withdrawal, `break` exits the for loop and stops withdrawing from remaining strategies.

```solidity
        if (value > token.balanceOf(address(this))) {
            uint256 totalLoss = 0;
            uint256 queueLength = withdrawalQueue.length;
            uint256 vaultBalance = 0;
            for (uint256 i = 0; i < queueLength; i = i.uncheckedInc()) {
                vaultBalance = token.balanceOf(address(this));
                if (value <= vaultBalance) {
                    break;
                }


                address stratAddr = withdrawalQueue[i];
                uint256 strategyBal = strategies[stratAddr].allocated;
                if (strategyBal == 0) {
                    continue;
                }


                uint256 remaining = value - vaultBalance;
                uint256 loss = IStrategy(stratAddr).withdraw(Math.min(remaining, strategyBal));
                uint256 actualWithdrawn = token.balanceOf(address(this)) - vaultBalance;


                // Withdrawer incurs any losses from withdrawing as reported by strat
                if (loss != 0) {
                    value -= loss;
                    totalLoss += loss;
                    _reportLoss(stratAddr, loss);
                }


                strategies[stratAddr].allocated -= actualWithdrawn;
                totalAllocated -= actualWithdrawn;
            }


            vaultBalance = token.balanceOf(address(this));
            if (value > vaultBalance) {
                value = vaultBalance;
            }


            require(
                totalLoss <= ((value + totalLoss) * withdrawMaxLoss) / PERCENT_DIVISOR,
                "Withdraw loss exceeds slippage"
            );
        }
```

The problem comes
Upgraded Q -> 2 from #773 [1679568911031]
Audit: 2023-02-ethos-findings
Severity: MEDIUM

Judge has assessed an item in Issue #773 as 2 risk. The relevant finding follows:

 LACK OF SLIPPAGE PROTECTIONS FOR EOA IN FUNCTIONS LIKE ReaperVaultERC4626.deposit, ReaperVaultERC4626.mint, ReaperVaultERC4626.withdraw, AND ReaperVaultERC4626.redeem
Depositors might not be able to withdraw from `StabilityPool` if any collateral's price drops significantly
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L1278-L1282
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L1538-L1540


# Vulnerability details

In the `TroveManager` contract, the `_closeTrove()` function contains a check to ensure there is more than one trove, as shown below.

[`TroveManager.sol#L1278-L1282`](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L1278-L1282):
```solidity
function _closeTrove(address _borrower, address _collateral, Status closedStatus) internal {
    assert(closedStatus != Status.nonExistent && closedStatus != Status.active);

    uint TroveOwnersArrayLength = TroveOwners[_collateral].length;
    _requireMoreThanOneTroveInSystem(TroveOwnersArrayLength, _collateral);
```

[`TroveManager.sol#L1538-L1540`](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L1538-L1540):
```solidity
function _requireMoreThanOneTroveInSystem(uint TroveOwnersArrayLength, address _collateral) internal view {
    require (TroveOwnersArrayLength > 1 && sortedTroves.getSize(_collateral) > 1);
}
```

This means that functions that call `_closeTrove()`, such as `liquidate()`, `batchLiquidateTroves()`, `liquidateTroves()` in the `TroveManager` contract, and `closeTrove()` in the `BorrowerOperations` contract, will revert if there is only one trove remaining.

Additionally, the `withdrawFromSP()` function in the `StabilityPool` contract reverts whenever there is an undercollateralized trove belonging to **any** type of collateral, as shown below:

[`StabilityPool.sol#L367-L368`](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/StabilityPool.sol#L367-L368):
```solidity
function withdrawFromSP(uint _amount) external override {
    if (_amount !=0) {_requireNoUnderCollateralizedTroves();}
```

[`StabilityPool.sol#L856-L867`](https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/StabilityPool.sol#L856-L867):
```solidity
function _requireNoUnderCollateralizedTroves() internal {
    address[] memory collaterals = collateralConfig.getAllowedCollaterals();
    uint numCollaterals = collaterals.length;
    for (uint i = 0; i < numCollaterals; i++) {
        address collateral = collaterals[i];
        uint price = priceFeed.fetchPrice(collateral);
        address lowestTrove = sortedTroves.getLast(collateral);
        uint256 collMCR = collateralConfig.getCollateralMCR(collateral);
        uint ICR = troveManager.getCurrentICR(lowestTrove, collateral, price);
        require(ICR >= collMCR, "StabilityPool: Cannot withdraw while there are troves with ICR < MCR");
    }
}
```

As seen from above, so long as the ICR of any trove is below its collateral's MCR, `withdrawFromSP()` will revert.

The combination of these restrictions could cause the protocol to end up in a situation where `withdrawFromSP()` is non-functional for a