xanoutas/solidity-security-findings huggingface dataset:
isolateRepay() Lack of check onBehalf == nftOwner
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/libraries/logic/ValidateLogic.sol#L478


# Vulnerability details

## Vulnerability details
When call `isolateRepay()` we can specify `nftTokenIds` and `onBehalf`.
The current implementation just restricts `onBehalf!=address(0)` and does not restrict `onBehalf == nftOwner`.
```solidity
  function validateIsolateRepayBasic(
    InputTypes.ExecuteIsolateRepayParams memory inputParams,
    DataTypes.PoolData storage poolData,
    DataTypes.AssetData storage debtAssetData,
    DataTypes.AssetData storage nftAssetData
  ) internal view {
    validatePoolBasic(poolData);

    validateAssetBasic(debtAssetData);
    require(debtAssetData.assetType == Constants.ASSET_TYPE_ERC20, Errors.ASSET_TYPE_NOT_ERC20);

    validateAssetBasic(nftAssetData);
    require(nftAssetData.assetType == Constants.ASSET_TYPE_ERC721, Errors.ASSET_TYPE_NOT_ERC721);

@>  require(inputParams.onBehalf != address(0), Errors.INVALID_ONBEHALF_ADDRESS);

    require(inputParams.nftTokenIds.length > 0, Errors.INVALID_ID_LIST);
    require(inputParams.nftTokenIds.length == inputParams.amounts.length, Errors.INCONSISTENT_PARAMS_LENGTH);
    validateArrayDuplicateUInt256(inputParams.nftTokenIds);

    for (uint256 i = 0; i < inputParams.amounts.length; i++) {
      require(inputParams.amounts[i] > 0, Errors.INVALID_AMOUNT);
    }
  }


```

This way we can maliciously specify `onBehalf!=nftOwner` and when the method is executed `userScaledIsolateBorrow[onBehalf]` will be maliciously reduced.

When the victim makes a real repayment or is liquidated, it will not be repaid or liquidated due to insufficient `userScaledIsolateBorrow[onBehalf]` resulting in an `underflow`

Example:
1. alice depositERC721(NFT_1)
2. bob depositERC721(NFT_2)
3. alice isolateBorrow(NFT_1, 100)
   - userScaledIsolateBorrow[alice]=100
   - loanData[NFT_1].scaledAmount = 100
4. bob isolateBorrow(NFT_2, 100)
   - userScaledIsolateBorrow[bob]=100
   - loanData[NFT_2].scaledAmount = 100
5. alice malicious repay , isolateRepay(NFT_1,amounts =1, onBehalf = bob)
    - userScaledIsolateBorrow[bob]= 99
6.  when NFT_2 be liquidated , isolateLiquidate(NFT_2)
    - userScaledIsolateBorrow[bob] -= loanData[NFT_2].scaledAmount  = 99 -100   =====> underflow

note: isolateRedeem()  similar

## Impact

Maliciously prevent being liquidated or repaid

## Recommended Mitigation

limit `onBehalf==owner`

```diff
  function validateIsolateRepayBasic(
    InputTypes.ExecuteIsolateRepayParams memory inputParams,
    DataTypes.PoolData storage poolData,
    DataTypes.AssetData storage debtAssetData,
    DataTypes.AssetData storage nftAssetData
  ) internal view {
    validatePoolBasic(poolData);

    validateAssetBasic(debtAssetData);
    require(debtAssetData.assetType == Constants.ASSET_TYPE_ERC20, Errors.ASSET_TYPE_NOT_ERC20);

    validateAssetBasic(nftAssetData);
    require(nftAssetData.assetType == Constants.ASSET_TYPE_ERC72
erc721DecreaseIsolateSupplyOnLiquidate() Missing clear lockerAddr
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/libraries/logic/VaultLogic.sol#L627


# Vulnerability details

## Vulnerability details
When `isolateLiquidate(supplyAsCollateral=false)` is executed
Finally `erc721DecreaseIsolateSupplyOnLiquidate()` will be executed and the NFT will be transferred to the user
```solidity
  function erc721DecreaseIsolateSupplyOnLiquidate(
    DataTypes.AssetData storage assetData,
    uint256[] memory tokenIds
  ) internal {
    for (uint256 i = 0; i < tokenIds.length; i++) {
      DataTypes.ERC721TokenData storage tokenData = assetData.erc721TokenData[tokenIds[i]];
      require(tokenData.supplyMode == Constants.SUPPLY_MODE_ISOLATE, Errors.INVALID_SUPPLY_MODE);

      assetData.userScaledIsolateSupply[tokenData.owner] -= 1;

      tokenData.owner = address(0);
      tokenData.supplyMode = 0;
@>  //missing tokenData.lockerAddr = address(0);
    }

    assetData.totalScaledIsolateSupply -= tokenIds.length;
  }
```

We know from the above code that this method does not clear the `tokenData.lockerAddr`
So, now `tokenData` is.
erc721TokenData[NFT_1].owner = 0
erc721TokenData[NFT_1].supplyMode = 0
erc721TokenData[NFT_1].lockerAddr = address(poolManager)

And user alice has NFT_1, then alice execute `BVault.depositERC721(NFT_1, supplyMode = SUPPLY_MODE_CROSS)` will succeed, `deposit()` does not check `lockerAddr`.

So `tokenData` becomes.
erc721TokenData[NFT_1].owner = alice 
erc721TokenData[NFT_1].supplyMode = SUPPLY_MODE_CROSS
erc721TokenData[NFT_1].lockerAddr = address(poolManager) -> not change


After that the user's NFT_ 1 will be locked because `withdrawERC721()` -> `validateWithdrawERC721()` will check that `lockerAddr` must be `address(0)`
```solidity
  function validateWithdrawERC721(
...
    for (uint256 i = 0; i < inputParams.tokenIds.length; i++) {
      DataTypes.ERC721TokenData storage tokenData = VaultLogic.erc721GetTokenData(assetData, inputParams.tokenIds[i]);
      require(tokenData.owner == inputParams.onBehalf, Errors.INVALID_CALLER);
      require(tokenData.supplyMode == inputParams.supplyMode, Errors.INVALID_SUPPLY_MODE);

@>    require(tokenData.lockerAddr == address(0), Errors.ASSET_ALREADY_LOCKED_IN_USE);
    }
  }
```

Other `Isolate` methods cannot be operated either

Note: erc721DecreaseIsolateSupply() similar

## Impact

Unable to retrieve NFT

## Recommended Mitigation

```diff
  function erc721DecreaseIsolateSupplyOnLiquidate(
    DataTypes.AssetData storage assetData,
    uint256[] memory tokenIds
  ) internal {
    for (uint256 i = 0; i < tokenIds.length; i++) {
      DataTypes.ERC721TokenData storage tokenData = assetData.erc721TokenData[tokenIds[i]];
      require(tokenData.supplyMode == Constants.SUPPLY_MODE_ISOLATE, Errors.INVALID_SUPPLY_MODE);

      assetData.userScaledIsolateSupply[tokenData.owner] -= 1;

      tokenData.owner = address(0);
      tokenData.supplyMode = 0;
+     tokenData.lockerAddr = address(0);
YieldEthStakingLido.protocolDeposit() returns the wrong quantity
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/yield/lido/YieldEthStakingLido.sol#L77


# Vulnerability details

## Vulnerability details
in `YieldEthStakingLido.sol`
when `stake()`, we need to compute `yieldShare`
```solidity
  function _stake(uint32 poolId, address nft, uint256 tokenId, uint256 borrowAmount) internal virtual {
...
    vars.totalYieldBeforeDeposit = getAccountTotalUnstakedYield(address(vars.yieldAccout));
    vars.yieldAmount = protocolDeposit(sd, borrowAmount);
    vars.yieldShare = _convertToYieldSharesWithTotalYield(
      address(vars.yieldAccout),
      vars.yieldAmount,
      vars.totalYieldBeforeDeposit
    );
```
1. totalYieldBeforeDeposit = getAccountTotalUnstakedYield() = getAccountYieldBalance() -> stETH.balanceOf(account)
2. yieldAmount =protocolDeposit(sd, borrowAmount);
3. yieldShare = yieldAmount * totalShares / totalYieldBeforeDeposit

Step one:
`totalYieldBeforeDeposit = stETH.balanceOf(account) = in stETH.sol => getPooledEthByShares()`

stETH is rebase , `totalYieldBeforeDeposit = stETH.balanceOf()` is `stETH.assets`, not `stETH.shares`.


But in the second step, `protocolDeposit()` returns `stETH.shares`, not `stETH.assets`.

```solidity
  function protocolDeposit(YieldStakeData storage /*sd*/, uint256 amount) internal virtual override returns (uint256) {
    IWETH(address(underlyingAsset)).withdraw(amount);

    IYieldAccount yieldAccount = IYieldAccount(yieldAccounts[msg.sender]);

    bytes memory result = yieldAccount.executeWithValue{value: amount}(
      address(stETH),
@>    abi.encodeWithSelector(IStETH.submit.selector, address(0)),
      amount
    );
    uint256 yieldAmount = abi.decode(result, (uint256));
    require(yieldAmount > 0, Errors.YIELD_ETH_DEPOSIT_FAILED);
    return yieldAmount;
  }

```

https://github.com/lidofinance/lido-dao/blob/5fcedc6e9a9f3ec154e69cff47c2b9e25503a78a/contracts/0.4.24/Lido.sol#L922

`protocolDeposit()`-> `StETH.submit`
```solidity
    /**
     * @dev Process user deposit, mints liquid tokens and increase the pool buffer
     * @param _referral address of referral.
     * @return amount of StETH shares generated
     */
    function _submit(address _referral) internal returns (uint256) {
        require(msg.value != 0, "ZERO_DEPOSIT");

        StakeLimitState.Data memory stakeLimitData = STAKING_STATE_POSITION.getStorageStakeLimitStruct();
        // There is an invariant that protocol pause also implies staking pause.
        // Thus, no need to check protocol pause explicitly.
        require(!stakeLimitData.isStakingPaused(), "STAKING_PAUSED");

        if (stakeLimitData.isStakingLimitSet()) {
            uint256 currentStakeLimit = stakeLimitData.calculateCurrentStakeLimit();

            require(msg.value <= currentStakeLimit, "STAKE_LIMIT");

            STAKING_STATE_POSITION.setStorageStakeLimitStruct(stakeLimitData.updatePrevStakeLimit(currentStakeLimit - msg.value));
        }

        uint
YieldEthStakingEtherfi.protocolRequestWithdrawal() cannot be executed because yieldAccount does not implement onERC721Received
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/yield/etherfi/YieldEthStakingEtherfi.sol#L87


# Vulnerability details

## Vulnerability details
in `YieldEthStakingEtherfi.sol`

The main processes are as follows:

1. stake() -> LiquidityPool.deposit()
2. unstake () -> LiquidityPool.requestWithdraw(recipient = yieldAccount) -> withdrawRequestNFT.requestWithdraw(recipient = yieldAccount)
3. repay() -> WithdrawRequestNFT.claimWithdraw()

When performing the second step, `withdrawRequestNFT.requestWithdraw(recipient = yieldAccount)` uses `_safeMint(to=yieldAccount)`

https://github.com/etherfi-protocol/smart-contracts/blob/master/src/WithdrawRequestNFT.sol#L58C1-L67C6
```solidity
contract WithdrawRequestNFT is ERC721Upgradeable, UUPSUpgradeable, OwnableUpgradeable, IWithdrawRequestNFT {
...
    function requestWithdraw(uint96 amountOfEEth, uint96 shareOfEEth, address recipient, uint256 fee) external payable onlyLiquidtyPool returns (uint256) {
        uint256 requestId = nextRequestId++;
        uint32 feeGwei = uint32(fee / 1 gwei);

        _requests[requestId] = IWithdrawRequestNFT.WithdrawRequest(amountOfEEth, shareOfEEth, true, feeGwei);
@>      _safeMint(recipient, requestId);

        emit WithdrawRequestCreated(uint32(requestId), amountOfEEth, shareOfEEth, recipient, fee);
        return requestId;
    }
```

`_safeMint()` checks if `to = yieldAccount` implements `IERC721Receiver.onERC721Received.selector`.
If not then `revert`

But currently `YieldAccount.sol` doesn't implement `onERC721Received`

So `protocolRequestWithdrawal()` can't be executed, causing `unstake()` to fail forever and the token is locked

## Impact

`protocolRequestWithdrawal()` is not executable, `unstake()` fails forever, token is locked

## Recommended Mitigation
YieldAccount add `ERC721Holder`
```diff
- contract YieldAccount is IYieldAccount, Initializable {
+ contract YieldAccount is IYieldAccount, Initializable , ERC721Holder{

...
```


## Assessed type

Context
YieldEthStakingEtherfi.protocolDeposit() returns the wrong quantity
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/yield/etherfi/YieldEthStakingEtherfi.sol#L68


# Vulnerability details

## Vulnerability details
in `YieldEthStakingEtherfi.sol`
when `stake()`, we need to compute `yieldShare`
```solidity
  function _stake(uint32 poolId, address nft, uint256 tokenId, uint256 borrowAmount) internal virtual {
...
    vars.totalYieldBeforeDeposit = getAccountTotalUnstakedYield(address(vars.yieldAccout));
    vars.yieldAmount = protocolDeposit(sd, borrowAmount);
    vars.yieldShare = _convertToYieldSharesWithTotalYield(
      address(vars.yieldAccout),
      vars.yieldAmount,
      vars.totalYieldBeforeDeposit
    );
```
1. totalYieldBeforeDeposit = getAccountTotalUnstakedYield() = getAccountYieldBalance() -> eETH.balanceOf(account);
2. yieldAmount =protocolDeposit(sd, borrowAmount);
3. yieldShare = yieldAmount * totalShares / totalYieldBeforeDeposit

Step one:
`totalYieldBeforeDeposit = eETH.balanceOf(account) = in eETH.sol => getTotalPooledEther() * eETH.shares(_user)) / totalShares`

eETH is rebase , `totalYieldBeforeDeposit = eETH.balanceOf()` is `eETH.assets`, not `eETH.shares`.


But in the second step, `protocolDeposit()` returns `eETH.shares`, not `eETH.assets`.

`protocolDeposit()`-> `LiquidityPool.deposit()`
```solidity
  function protocolDeposit(YieldStakeData storage /*sd*/, uint256 amount) internal virtual override returns (uint256) {
    IWETH(address(underlyingAsset)).withdraw(amount);

    IYieldAccount yieldAccount = IYieldAccount(yieldAccounts[msg.sender]);

    bytes memory result = yieldAccount.executeWithValue{value: amount}(
      address(liquidityPool),
      abi.encodeWithSelector(ILiquidityPool.deposit.selector),
      amount
    );
@>  uint256 yieldAmount = abi.decode(result, (uint256));
    require(yieldAmount > 0, Errors.YIELD_ETH_DEPOSIT_FAILED);
    return yieldAmount;
  }
```


https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L525
```solidity
contract LiquidityPool is Initializable, OwnableUpgradeable, UUPSUpgradeable, ILiquidityPool {
    function _deposit(address _recipient, uint256 _amountInLp, uint256 _amountOutOfLp) internal returns (uint256) {
        totalValueInLp += uint128(_amountInLp);
        totalValueOutOfLp += uint128(_amountOutOfLp);
        uint256 amount = _amountInLp + _amountOutOfLp;
        uint256 share = _sharesForDepositAmount(amount);
        if (amount > type(uint128).max || amount == 0 || share == 0) revert InvalidAmount();

       eETH.mintShares(_recipient, share);

@>     return share;
    }
```

So `yieldAmount` is wrong, and the returned `eETH.shares` should be converted to `eETH.assets` via `ILiquidityPool.amountForShare()`

## Impact.

`yieldAmount` is wrong it will be small, causing `yieldShare` to be small as well, and the corresponding nft's gain will be smaller
Corresponding to a vault managing all nft earnings uniformly will cause nft rewards to be d
unstake/repay ,  when botAdmin call , use yieldAccounts[msg.sender] is wrong
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/yield/YieldStakingBase.sol#L312


# Vulnerability details

## Vulnerability details

in `YieldStakingBase.unstake()` and `YieldStakingBase.repay()`

`botAdmin` can call it and is mainly used for something like forced liquidation

```solidity
  function _unstake(uint32 poolId, address nft, uint256 tokenId, uint256 unstakeFine) internal virtual {
    UnstakeLocalVars memory vars;

@>  vars.yieldAccout = IYieldAccount(yieldAccounts[msg.sender]);
    require(address(vars.yieldAccout) != address(0), Errors.YIELD_ACCOUNT_NOT_EXIST);

    YieldNftConfig storage nc = nftConfigs[nft];
    require(nc.isActive, Errors.YIELD_ETH_NFT_NOT_ACTIVE);

    // check the nft ownership
    (vars.nftOwner, vars.nftSupplyMode, vars.nftLockerAddr) = poolYield.getERC721TokenData(poolId, nft, tokenId);
@>  require(vars.nftOwner == msg.sender || botAdmin == msg.sender, Errors.INVALID_CALLER);
```
```solidity
  function _repay(uint32 poolId, address nft, uint256 tokenId) internal virtual {
    RepayLocalVars memory vars;

@>  vars.yieldAccout = IYieldAccount(yieldAccounts[msg.sender]);
    require(address(vars.yieldAccout) != address(0), Errors.YIELD_ACCOUNT_NOT_EXIST);

    YieldNftConfig memory nc = nftConfigs[nft];
    require(nc.isActive, Errors.YIELD_ETH_NFT_NOT_ACTIVE);

    YieldStakeData storage sd = stakeDatas[nft][tokenId];
    require(sd.state == Constants.YIELD_STATUS_UNSTAKE, Errors.YIELD_ETH_STATUS_NOT_UNSTAKE);
    require(sd.poolId == poolId, Errors.YIELD_ETH_POOL_NOT_SAME);

    require(protocolIsClaimReady(sd), Errors.YIELD_ETH_WITHDRAW_NOT_READY);

    // check the nft ownership
    (vars.nftOwner, vars.nftSupplyMode, vars.nftLockerAddr) = poolYield.getERC721TokenData(poolId, nft, tokenId);
@>  require(vars.nftOwner == msg.sender || botAdmin == msg.sender, Errors.INVALID_CALLER);

```

If called by `botAdmin`, `vars.yieldAccout` gets `yieldAccounts[botAdmin]` of `botAdmin`, it is wrong, should use `yieldAccounts [nftOwner]`

> Note: `yieldAccounts[botAdmin]` will not be equal to `address(0)`, because we can create it by `createYieldAccount(botAdmin)`, which requires no permissions.

An incorrect `vars.yieldAccout` will cause `sd.withdrawAmount` to be calculated incorrectly: `sd.withdrawAmount` will be calculated incorrectly:
`sd.withdrawAmount = convertToYieldAssets(address(vars.yieldAccout), sd.yieldShare);`

`accountYieldInWithdraws[address(vars.yieldAccout)] += sd.withdrawAmount;`
``accountYieldShares[address(vars.yieldAccout)] -= sd.yieldShare;`` also has an error

Note: `protocolRequestWithdrawal()/protocolClaimWithdraw()` is also using `yieldAccounts[msg.sender]` which is also wrong

## Impact
This one causes multiple issues
`botAdmin` can't execute `unstake()/repay()` properly:underflow, `accountYieldShares[address(vars.yieldAccout)] -= sd.yieldShare;`
Or take out tokens that don't belong to you: `accountYieldInWithdraws[vars.yieldAccout
Revert due to underflow error, leading to lock of the liquidated NFT 
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/main/src/libraries/logic/IsolateLogic.sol#L464
https://github.com/code-423n4/2024-07-benddao/blob/main/src/libraries/logic/IsolateLogic.sol#L269


# Vulnerability details


## Description

The `IsolateLogic.sol#executeIsolateAuction()` is triggered by liquidators to launch a new auction or just participate in an existing one for isolated lending.
each NFT token has a predefined auction duration `nftAssetData.auctionDuration`, the MAX duration is 7 days.
In the period of e.g.,7 days, the `borrowAmount` will keep increasing due to the Interest 

```solidity
File: GenericLogic.sol#calculateNftLoanLiquidatePrice()

279:     vars.borrowAmount = nftLoanData.scaledAmount.rayMul(vars.normalizedIndex);
```
If the liquidator is the first bidder, the bid price must be greater than borrowed debt and the liquidate price
Otherwise, the liquidator will just try to outbid the last bidder, by at least 1%.
At the end of `executeIsolateAuction()`, will transfer the underlying asset from the liquidator to escrow and increase the value of ` assetData.totalBidAmout` by the bid amount from the liquidator (Note: remember the last point)

```solidity
File: IsolateLogic.sol#executeIsolateAuction()

269:     VaultLogic.erc20TransferInBidAmount(debtAssetData, params.msgSender, vars.totalBidAmount);
```
After 7 days, the liquidator who wins the auction will invoke `IsolateLogic.sol#executeIsolateLiquidate()` to implement the liquidation 
It will calculate the `borrowAmount` and check for any remaining or extra amount.
```solidity
File: IsolateLogic.sol#executeIsolateLiquidate()

427:       vars.borrowAmount = loanData.scaledAmount.rayMul(vars.normalizedIndex);
```
then, because the bid is already in the pool, it will sub-call to `VaultLogic.sol#erc20TransferOutBidAmountToLiqudity()` to increase liquidity in the pool `assetData.availableLiquidity` and decrease the `assetData.totalBidAmout` value.

The issue is here, About how much `totalBidAmout` has decreased. 
In the below code snap is passing `totalBorrowAmount` to `erc20TransferOutBidAmountToLiqudity()`

```solidity
File: IsolateLogic.sol#executeIsolateLiquidate()

464:     VaultLogic.erc20TransferOutBidAmountToLiqudity(debtAssetData, vars.totalBorrowAmount);
```
The `vars.totalBorrowAmount` is just the value of `vars.borrowAmount` (in case of one NFT in the liquidation)
As we mentioned above the borrowed amount will keep increasing over time and it will exceed the saved value in `assetData.totalBidAmout` (check the above Note).
this will lead the transaction to revert 
```solidity
File: VaultLogic.sol

503:   function erc20TransferOutBidAmountToLiqudity(DataTypes.AssetData storage assetData, uint amount) internal {
504:     assetData.totalBidAmout -= amount;
505:     assetData.availableLiquidity += amount;
506:   }
```
There are multiple scenarios to reach this point (revert):
- The auction ends with only one bidder (the first bidder wins it), so the res
Bad debt is never handled which places insolvency risks on BendDAO
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/main/src/libraries/logic/LiquidationLogic.sol#L99-L105


# Vulnerability details

## Impact
Bad debt is never handled, which may happen whenever the collateral asset price crashes or the debt value spikes. Whenever this happens `ERC20` positions will be partially liquidated and `ERC721` positions will not be profitable for liquidation, which means the debt will not be repaid. When this happens, the protocol will not have enough liquidity to fulfil withdrawals, DoSing them forever or until the price comes back up again.

## Proof of Concept

`LiquidationLogic::executeCrossLiquidateERC20()` [allows](https://github.com/code-423n4/2024-07-benddao/blob/main/src/libraries/logic/LiquidationLogic.sol#L99-L105) partial, liquidations, so the likely outcome here would be liquidation of the debt corresponding to the available collateral, but some debt could be outstanding. `ERC721` liquidations don't allow partial liquidations in the same way, as the price of each collateral asset is based on the debt value only, so it could happen that these debt assets are not liquidated at all.

As withdrawing deposits depends on the protocol having liquidity, if these assets are borrowed and there is no way to repay them, users will not be able to withdraw.

## Tools Used

Vscode

Foundry

## Recommended Mitigation Steps

On liquidation, place a mechanism to handle the creation of bad debt. This could be implemented as a reserve or by decreasing the supply index or similar, so the bad debt is redistributed by the suppliers.


## Assessed type

Other