xanoutas/solidity-security-findings huggingface dataset:
ReaperVaultV2 withdrawals can be frozen if Granary market has liquidity shortage
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L353-L387
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L184-L201


# Vulnerability details

## Summary

ReaperStrategyGranarySupplyOnly do not control for liquidity squeeze that is typical for lending markets and can routinely happen in Granary markets. I.e. some funds can be temporary locked just because they are lent out. This is locked funds situation ReaperBaseStrategyv4's specification accounts for, but it's ignored in ReaperStrategyGranarySupplyOnly implementation.


Due to that whenever liquidity squeeze does happen the overall ReaperVaultV2 withdrawal requests will be reverted as long as ReaperStrategyGranarySupplyOnly is next in `withdrawalQueue`. There might be plenty of funds in other ReaperVaultV2 strategies, i.e. withdrawal neither should be big, nor there should be any loss on the aggregated Vault level in order for all the users have their withdrawal calls reverted.


Suppose ReaperStrategyGranarySupplyOnly is the first strategy in `withdrawalQueue` and the Granary pool it is integrated with now has particularly high utilization and have few funds available, say it's `50000 DAI` market with `100 DAI` now available. Then all the withdrawal requests in ReaperVaultV2 for sums higher than `100 DAI` will be reverted.

## Impact

Stakers will not be able to unstake until either this particular pool liquidity squeeze abates or `withdrawalQueue` be manually renewed by Vault admin.

## Proof of Concept

Withdrawals happen according to `withdrawalQueue` and the `Math.min(remaining, strategies[stratAddr].allocated)` is requested:

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

```solidity
    function withdraw(uint256 _shares) external {
        _withdraw(_shares, msg.sender, msg.sender);
    }

    // Internal helper function to burn {_shares} of vault shares belonging to {_owner}
    // and return corresponding assets to {_receiver}. Returns the number of assets that were returned.
    function _withdraw(
        uint256 _shares,
        address _receiver,
        address _owner
    ) internal nonReentrant returns (uint256 value) {
        require(_shares != 0, "Invalid amount");
        value = (_freeFunds() * _shares) / totalSupply();
        _burn(_owner, _shares);

        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 stratA
Index of removed Trove is not updated
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#L1339


# Vulnerability details

## Impact
Detailed description of the impact of this finding.

In the function removeTroveOwner in the TroveManager contract (https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/TroveManager.sol#L1339) the Troves[borrower][collateral].arrayIndex is still equal to its previous index even though it has been removed from TroveOwners and therefore has no index in TroveOwners. 

This could be problematic if an active Trove with the same index as the removed trove had functionality based on its index. In other words, the removed trove might be able to maliciously act as the active trove because it has the same index as it.

Also, this could be problematic if the function is called again as it would lead to another Trove being removed from the TroveOwners incorrectly. 

## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

This is the additional test added in the test file:

```diff
diff --git a/TroveManagerTest.js.orig b/TroveManagerTest.js
index 4f6b03a..2e46387 100644
--- a/TroveManagerTest.js.orig
+++ b/TroveManagerTest.js
@@ -287,6 +287,7 @@ contract('TroveManager', async accounts => {
     const bob_arrayIndex = (await troveManager.Troves(bob, collaterals[0].address))[4]
     const dennis_arrayIndex = (await troveManager.Troves(dennis, collaterals[0].address))[4]
     const erin_arrayIndex = (await troveManager.Troves(erin, collaterals[0].address))[4]
+    const carol_arrayIndex = (await troveManager.Troves(erin, collaterals[0].address))[4]
 
     // [W, A, B, E, D] 
     assert.equal(whale_arrayIndex, 0)
@@ -294,6 +295,7 @@ contract('TroveManager', async accounts => {
     assert.equal(bob_arrayIndex, 2)
     assert.equal(erin_arrayIndex, 3)
     assert.equal(dennis_arrayIndex, 4)
+    assert.isFalse(carol_arrayIndex,3)
   })

Running the test case above fails because carol_arrayIndex is equal to 3.

For example, if the array is [W, A, B, C, D, E] and then C is removed, we get the final array: [W, A, B, E, D] where E now has an index = 3. However, the TroveManager removeTroveOwner code does not update the index of C, so therefore C still has index = 3. This could be problematic if handling E’s trove depended on its index. In other words, C might be able to maliciously act as E because it has the same index as E. 

If removeTroveOwner was called again, removing C, the following would happen: 

- index = 3 (the index of C)
- length of TroveOwnersArray = 5
- indexLast = 4
- addressToMove = D
- TroveOwners[collateral][index] = D
- Troves[D][collateral].arrayIndex = D
- TroveOwners = [W, A, B, D]

Therefore ‘E’ has been removed from TroveOwners when it shouldn’t have been.

## Tools Used
Hardhat test

## Recommended Mitigation Steps
Decay interval can be extended
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/TroveManager.sol#L1500-L1507


# Vulnerability details

## Impact
The half-life defined by `MINUTE_DECAY_FACTOR` can be extended from 12h up to 24h.

## Proof of Concept
[`minutesPassed`](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/TroveManager.sol#L1510) is truncated to the minute. This means that the actual time passed may be up to a minute more than calculated. [_updateLastFeeOpTime](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/TroveManager.sol#L1500-L1507) is used to only allow updates when at least one minute has passed. This indeed prevents a complete griefing halt of the decay, but still allows for almost one minute extra to be taken from each update (at most one per minute), thus enabling the decay to be slowed down to almost half.

## Recommended Mitigation Steps
Do not mix minutes and seconds in the same reference. For example, let `lastFeeOperationTime` itself be the nearest lesser whole minute, and update (as is currently done) based on whole minutes as well. This automatically also prevents a complete griefing.
ERC20 `approve` can fail for some tokens
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

ReaperBaseStrategyv4.sol#L74](https://github.com/code-423n4/2023-02-ethos/blob/34ba1e7dd2d259f06f9d5fa13f5d96be7829ff34/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L74


# Vulnerability details

## Summary

Some tokens (like `USDT`) do not work when changing the allowance from an
existing non-zero allowance value. They must first be approved by zero and then the actual allowance must be approved.

`approve` reverts for tokens like USDT if first not approved to `0`. Due to calling approve with max value always, this can fail for these tokens

## Impact

Reverting in tokens like `USDT`(Tether)

## Code Snippet

- Some ERC20 like `USDT` fail if not set first to `0`

- [ReaperBaseStrategyv4.sol#L74](https://github.com/code-423n4/2023-02-ethos/blob/34ba1e7dd2d259f06f9d5fa13f5d96be7829ff34/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L74)
`IERC20Upgradeable(want).safeApprove(vault, type(uint256).max);`

## Tool used

Manual Review

## Recommendation

- Add `approve(0)` before `approve(uint)`
pullCollateralFromBorrowerOperationsOrDefaultPool can fail on  if _amount will set to zero
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

<h3>Impact</h3>
Amount can be zero,as there is not  no check in place, while collect modules do attempt to send it in such a case anyway. Some ERC20 tokens do not allow zero value transfers, reverting such attempts.

As a result, a combination of a token set as a collect and  zero amount  will revert any collect operations, rendering collect functionality unavailable.

<h3>Proof on Concept</h3>
Amount in this function can be set to zero:
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/ActivePool.sol#L204

There is no check the amount to be send:
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/ActivePool.sol#L210

<h3>References</h3>
Some ERC20 tokens revert on zero value transfers:

https://github.com/d-xo/weird-erc20#revert-on-zero-value-transfers

<h3>Tools Used</h3>
Manual code review

<h3>Recommended Mitigation Steps</h3>

Consider checking the treasury fee amount and do transfer only when it is positive.

Now:

IERC20(_collateral).safeTransferFrom(msg.sender, address(this), _amount);

Reworked:

if (_amount > 0)
IERC20(_collateral).safeTransferFrom(msg.sender, address(this), _amount);
`setWithdrawalQueue` never removes items from the queue and can get out of gas
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/34ba1e7dd2d259f06f9d5fa13f5d96be7829ff34/Ethos-Vault/contracts/ReaperVaultV2.sol#L258-L268


# Vulnerability details

## Impact
`setWithdrawalQueue` calls delete, this sets to `0` each element of the array rather than removing elements (what it's done with `.pop()`). After that, strategies are pushed in a for loop, therefore, each time `setWithdrawalQueue` is called, length of the queue is doubled, leading at the end to an out of gas due to be so long.

## Proof of Concept

```solidity
 function setWithdrawalQueue(address[] calldata _withdrawalQueue) external {
_atLeastRole(ADMIN);
uint256 queueLength = _withdrawalQueue.length;
require(queueLength != 0, "Queue must not be empty");

delete withdrawalQueue; //@audit not voiding the queue
for (uint256 i = 0; i < queueLength; i = i.uncheckedInc()) {
        address strategy = _withdrawalQueue[i];
        StrategyParams storage params = strategies[strategy];
        require(params.activation != 0, "Invalid strategy address");
        withdrawalQueue.push(strategy); //@audit pushing more items
```


- [ReaperVaultV2.sol#L263](https://github.com/code-423n4/2023-02-ethos/blob/34ba1e7dd2d259f06f9d5fa13f5d96be7829ff34/Ethos-Vault/contracts/ReaperVaultV2.sol#L258-268)

## Tools Used

Manual analysis

## Recommended Mitigation Steps

Implement an array loop deletion with pop. [Example](https://blog.finxter.com/how-to-delete-an-element-from-an-array-in-solidity/)
Attacker contract can avoid being blocked
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/Dependencies/CheckContract.sol#L11


# Vulnerability details

## Impact

A Malicious attacker can interact with the system and selfdestruct his own contract then use CREATE2  to recreate it at same address when he needs to interact with the system again.

## Proof of Concept

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/Dependencies/CheckContract.sol#L11

## Tools Used
Manual Review

## Recommended Mitigation Steps

Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets. Infact the security can be bypassed as demonstrated above.
Consideration should be given to blacklisting addresses without checking if they are contracts.
Redemption fee increase can be thwarted
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/TroveManager.sol#L1408-L1411


# Vulnerability details







## Impact
The mechanism to increase the `baseRate` during redemptions is moot, up to gas fees. Therefore an arbitrageur can redeem more than what is healthy for the supply of LUSD. This weakens the price floor at $1, and may cause needless volatility. It further implies that an excess of troves may be closed, and impedes the growth of the protocol.

## Proof of Concept
The redemption fee is increased based on the fraction of redeemed LUSD to total supply. This is to disincentivize redemption beyond which reduces the supply more than the current price is too low, as per [QTM](https://en.wikipedia.org/wiki/Quantity_theory_of_money). For example, if LUSD trades at $0.99 then exactly 1% of the total supply should ideally be redeemed. The fee is greater the greater the fraction of the total supply is redeemed, with the intention that an arbitrageur profits maximally when redeeming just the right amount, but not when redeeming more than this.
However, this assumes that the redemption is performed in whole. The `baseRate` increases by half of the fraction of total supply redeemed in a redemption: ([TroveManager.sol#L1408-L1411](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/TroveManager.sol#L1408-L1411))
```solidity
uint redeemedLUSDFraction = 
LiquityMath._getScaledCollAmount(_collateralDrawn, _collDecimals).mul(_price).div(_totalLUSDSupply);

uint newBaseRate = decayedBaseRate.add(redeemedLUSDFraction.div(BETA));
```
The increased fee rate makes it unprofitable to redeem more than a certain amount. But nothing prevents an arbitrageur from splitting that greater amount into several smaller redemptions, whereby each constitutes only a small fraction of the total supply whence `baseRate` increases only very little. By splitting the amount into ever smaller parts the accumulated increase in `baseRate` can be made arbitrarily small (only limited by gas fee considerations), thereby bypassing the fee increase.

## Recommended Mitigation Steps
The increase in `baseRate` should not be determined by the fraction of total supply redeemed, but should be independent of the amount redeemed such that it doesn't matter how the redemptions are partitioned.
Integer Overflow
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
The owner of the ActivePool contract can set yield distribution parameters that do not add to the expected 10000 BPS. This would cause the _rebalance() function to send the incorrect number of tokens when using the splits.
 
## Proof of Concept
Calling setYieldDistributionParams with any combination of parameters such that
```(_treasurySplit + _SPSplit + _stakingSplit) % 10_000 == 0```
will succeed. Therefore, the owner could configure the contract to distribute the wrong number of tokens.

## Tools Used
Manual inspection

## Recommended Mitigation Steps
Use the Safemath library to add the parameters together in the require statement:
```require(_treasurySplit.add(_SPSplit).add(_stakingSplit) == 10_000, "Splits must add up to 10000 BPS");```
Re-entrancy inside BorrowOperations if collateral is ERC777
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
Invariant violations through re-entrancy if the collateral token is ERC777

## Proof of Concept
If the collateral token will be an ERC777 token, a malicious user could use the safeTransfer from L#231 ( https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/BorrowerOperations.sol#L231 ) to re-enter the BorrowOperations contract context and call the closeTrove function, which will pass all the sanity checks of the function as the trove is already marked as opened and the TCR & CCR are having the same values, the attacker needs to have a balance of LUSD before starting the attack because of the _repayLUSD function (L#405) inside the trove, at the end of the execution of closeTrove function, the collateral will be given back to the user and the trove will be marked as close ( status #2 ), however after that the execution will be resumed inside the openTrove back from L#231 and the _withdrawLUSD function will be called, which will mint LUSD ( the same amount he had to pay in the first place to close it's trove) however at the same time the LUSD Debt inside the Active Pool will increase but his trove is already marked as closed which will not allow to decrease the debt later unless he call the repayLUSD voluntarily 


## Tools Used
Manual Review
## Recommended Mitigation Steps
Add a non-renentrant modifier on all trove operations.
LUSDT non-compliance with the EIP-2612 standard
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact

* Inability to integrate `LUSDT` into contracts of other services where the `DOMAIN_SEPARATOR` is used or strict adherence to the `EIP2612` standard is required.

* Various network analyzers that automatically determine the type of contracts will not be able to recognize that this is a token with a Permit function.

* Websites/exchanges/tools will not recognize that this is a token with a `Permit` function, and will therefore not provide users with the ability to pay less gas or use certain functionality, as they will not have access to the `DOMAIN_SEPARATOR` and automatically obtain the data.

## Proof of Concept
The contract [LUSDT.sol](https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/LUSDToken.sol) implement the `EIP-2612` standard, but the implementation is incorrect. According to the standard described in [https://eips.ethereum.org/EIPS/eip-2612](https://eips.ethereum.org/EIPS/eip-2612#:~:text=Compliant%20contracts%20must%20implement%203%20new%20functions%20in%20addition%20to%20EIP%2D20%3A) the contract should contain a function `function DOMAIN_SEPARATOR() external view returns (bytes32)` but in reality, the contract contains  `function domainSeparator() public view override returns (bytes32)`,  which is a different function name. Therefore, we cannot say that it fully implements this standard since the mandatory `DOMAIN_SEPARATOR` method is missing
` 

## Tools Used
* Manual review
## Recommended Mitigation Steps

- Correcting according to the standard
Last good price might be not good if both Tellor and Chainlink prices are unreliable
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/BorrowerOperations.sol#L181 https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/BorrowerOperations.sol#L289 https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/BorrowerOperations.sol#L375 https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/StabilityPool.sol#L861 https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/TroveManager.sol#L524 https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/TroveManager.sol#L728


# Vulnerability details

## Impact
Calling from `Pricefeed.sol`, `fetchPrice()` returns the last good price seen by the protocol whenever both Chainlink and Tellor fail to be reliable. The protocol features multi-collateral support which eventually accepts assets that are volatile in nature, due to their own tokenomics and, known risks that might influence the asset price among others. Despite whitelisting assets, faulty prices arising from these scenarios will still be consumed by the contracts. 

## Proof of Concept
```
Scenario 1: Opening a trove using last good price from fetchPrice()
- Alice deposits collateral using the last good price @ 1
- Oracle becomes reliable and returns a price at 0.4
- Alice gets liquidated


Scenario 2: topping up collateral using last good price from fetchPrice()
- Alice topped up additional collateral using the last good price @ 1
- Oracle becomes reliable and returns a price at 0.4
- Alice's added collateral reduces in value

Scenario 3: using last good price from fetchPrice()
- Buy XYZ @0.4$ from an AMM. The state of the AMM reflects the real state of XYZ's price but PriceFeed.sol retains last good price @1$
- Alice opens a trove using XYZ as collateral mint LUSD/ERN at @1$
- Alice then stake ERN in stability pool
- Oracle becomes reliable and returns a price at 0.4
- Alice keeps deposited ERN, have a potential gain from other collateral liquidations + OATH tokens



```

## Tools Used
Manual Review

## Recommended Mitigation Steps
Don't trust prices under these conditions. Suspending core operations might be safer than hurting user positions or draining the treasury affecting the overall function of the protocol.
[NAZ-M2] `ReaperVaultERC4626.sol` doesn't fully conform to EIP4626 implementation
Audit: 2023-02-ethos-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L79
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L122


# Vulnerability details

## Impact
Specifically the two function `maxDeposit() && maxMint()` don't fully conform to EIP4626 implementation. 

## Proof of Concept
Looking at the following from [EIP4626](https://eips.ethereum.org/EIPS/eip-4626):
> This assumes that the user has infinite assets, i.e. MUST NOT rely on balanceOf of asset.

This goes for both `maxDeposit() && maxMint()`. However, looking at both functions:
```Solidity
function maxDeposit(address) external view override returns (uint256 maxAssets) {
    if (emergencyShutdown || balance() >= tvlCap) return 0;//@audit MUST NOT rely on balanceOf of asset but it does here
    if (tvlCap == type(uint256).max) return type(uint256).max;
    return tvlCap - balance();
}

function maxMint(address) external view override returns (uint256 maxShares) {
    if (emergencyShutdown || balance() >= tvlCap) return 0;//@audit MUST NOT rely on balanceOf of asset but it does here
    if (tvlCap == type(uint256).max) return type(uint256).max;
    return convertToShares(tvlCap - balance());
}

```

We see them using the `balance()` function inherited from `ReaperVaultV2.sol`:
```Solidity
function balance() public view returns (uint256) {
    return token.balanceOf(address(this)) + totalAllocated;
}   
```

Here we can see that the `balanceOf` of asset is being relied on and this would break the EIP4626 implementation.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Consider following the EIP4626 implementation as it is stated and avoid relying on `balanceOf` of assets in both `maxDeposit() && maxMint()`.