xanoutas/solidity-security-findings huggingface dataset:
The clock extension doesn't work correctly when the depth of the move is SPLIT_DEPTH - 1
Audit: 2024-07-optimism-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-07-optimism/blob/70556044e5e080930f686c4e5acde420104bb2c4/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol#L783-L784
https://github.com/code-423n4/2024-07-optimism/blob/70556044e5e080930f686c4e5acde420104bb2c4/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol#L377-L382


# Vulnerability details

## Impact
Users are grouped into different teams, and each team has its own `chess clock`.

If the remaining `clock` time is less than `CLOCK_EXTENSION` seconds, grant the `potential grandchild`'s `clock` a `CLOCK_EXTENSION` seconds. 
This ensures that even if a player inherits another team's `clock` to counter a freeloader claim, they will always have enough time to respond.
If the `potential grandchild` is an `execution trace bisection root`, the `clock` extension is doubled. 
This provides extra time for the off-chain challenge agent to generate the initial instruction trace on the native `FPVM`. 
This step is crucial.

In other words, if a player wants to create an `execution trace bisection root`, they should have at least `2 * CLOCK_EXTENSION` seconds. 
However, this process doesn't work correctly.

## Proof of Concept
When a player makes a `move`, the `time limit` for this player is calculated as the sum of the `grandparent's duration` and the `elapsed time` from the creation of the `move` being countered by this `move`.
```
function getChallengerDuration(uint256 _claimIndex) public view returns (Duration duration_) {
    ClaimData storage subgameRootClaim = claimData[_claimIndex];

    Clock parentClock;
    if (subgameRootClaim.parentIndex != type(uint32).max) {
        parentClock = claimData[subgameRootClaim.parentIndex].clock;
    }

    uint64 challengeDuration =
        uint64(parentClock.duration().raw() + (block.timestamp - subgameRootClaim.clock.timestamp().raw())); // @audit, here
    duration_ = challengeDuration > MAX_CLOCK_DURATION.raw() ? MAX_CLOCK_DURATION : Duration.wrap(challengeDuration);
}
```
If the current `move` is made at `SPLIT_DEPTH - 1`, the potential grandchildren will use the `duration` of this `move`. 
That player at `SPLIT_DEPTH + 1` should have at least `2 * CLOCK_EXTENSION` seconds to generate the initial instruction trace on the native `FPVM`. 
However, this doubling of the extension doesn't work correctly.

For example, if the `MAX_CLOCK_DURATION` is `100 days` and `CLOCK_EXTENSION` is `10 days`, and the calculated challenge duration for this `move` is `89 days`, the doubling of the extension doesn't occur because the condition of the `if` block isn't satisfied. 
```
function move(Claim _disputed, uint256 _challengeIndex, Claim _claim, bool _isAttack) public payable virtual {
    Duration nextDuration = getChallengerDuration(_challengeIndex); // @audit, 89 days

    if (nextDuration.raw() > MAX_CLOCK_DURATION.raw() - CLOCK_EXTENSION.raw()) { // @audit, 89 days < 100 days - 10 days
        uint64 extensionPeriod =
            nextPositionDepth
MIPS: `sc` does not write a 0 to `rt` if the write is non-atomic
Audit: 2024-07-optimism-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-07-optimism/blob/main/packages/contracts-bedrock/src/cannon/MIPS.sol#L793-L796


# Vulnerability details

As per the MIPS ISA, `sc` will write a 1 to `rt` if a write is atomic and a 0 to `rt` is non-atomic. A write is atomic if the value of the memory address pointed to by the `sc` instruction has not been changed since the value of the same memory address has been loaded by the `ll` instruction.

However, the `sc` implementation in the MIPS code will always write a 1 regardless of whether the write is atomic or non-atomic.

[MIPS.sol#L793-L796](https://github.com/code-423n4/2024-07-optimism/blob/main/packages/contracts-bedrock/src/cannon/MIPS.sol#L793-L796)
```solidity
            // stupid sc, write a 1 to rt
            if (opcode == 0x38 && rtReg != 0) {
                state.registers[rtReg] = 1;
            }
```


## Impact
Although both the on-chain and off-chain MIPS VM contain the same error, if the L2 STF converted to MIPS contains a `sc` instruction, then it is possible that the result for both the on-chain and off-chain MIPS VM to return a result that will be egregiously wrong (for instance, not knowing where to return to after the function call) and lead to unintended consequences leading to unintended consequences (such as leading to a correct output root not being able to be confirmed because the MIPS program will report an invalid VM status)

## Tools Used

Manual Review

## Recommended Mitigation Steps

Check whether the write is non-atomic and write a 0 to the `rt` register instead if it is.








## Assessed type

Other
Attacker can continuously create games for not yet safe l2 blocks to prevent the update of anchor state
Audit: 2024-07-optimism-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-07-optimism/blob/70556044e5e080930f686c4e5acde420104bb2c4/packages/contracts-bedrock/src/dispute/DisputeGameFactory.sol#L119-L123


# Vulnerability details

### Brief

When creating a dispute game, the output root should be one of the safe l2 block's. However, attacker can continuously create games for not yet safe l2 blocks. Honest party can no longer propose the root after it becomes safe, since UUID must be unique. As a result, no root can be sucessfully defended, the anchor state can no longer be updated and the fund on L2 will be frozen.

### Proof of Concept

When creating a dispute game, the output root should be one of the safe l2 block's. Otherwise, the claim can be attacked.

However, function create needs uuid to be unique.

        // Compute the unique identifier for the dispute game.
        Hash uuid = getGameUUID(_gameType, _rootClaim, _extraData);

        // If a dispute game with the same UUID already exists, revert.
        if (GameId.unwrap(_disputeGames[uuid]) != bytes32(0)) revert GameAlreadyExists(uuid);

If an attacker has already made the claim of this block earlier, when the block is still unsafe, the correct claim can no longer be made.

### Cost and Impact

Attacker can avoid losing the bond by making a attack move in the same transaction, needing 0.08 (create) + 0.08 (attack) = 0.16eth once. The fund will be withdrawable after 3.5 (game clock) + 7 (weth delay) = 10.5 days. Assume block time is 2s, the capital needed is 0.16 × 10.5 × 24 × 3600 ÷ 2 = 72576eth ≈ 237 million dollars. Assume interest rate is 3%, to freeze l2 fund for **one year**, the cost would be 237 million × 3% = **7.11 million dollars**, while the loss would be 13.54 billion (Optimism + Base TVL) × 3% = **406.2 million dollars**.




### Fix

Include parentHash in uuid calculation.





## Assessed type

Context
MIPS: `jalr` will not write to `r31` if `rd = 0`
Audit: 2024-07-optimism-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-07-optimism/blob/main/packages/contracts-bedrock/src/cannon/MIPS.sol#L767-L770


# Vulnerability details

`jalr` with 1 operand is valid and represents an implied `rd` value of 0.

As per the MIPS ISA (consult [link](https://www.cs.cmu.edu/afs/cs/academic/class/15740-f97/public/doc/mips-isa.pdf)), if `rd = 0`, then `jalr` MUST write the return address `PC + 8 ` to `r31`, which would make it functionally equivalent to the `jal` instruction.

However, in both the on-chain and off-chain MIPS VM, the `jalr` instruction does not convert `rdReg` to 31 if `rdReg` is 0.

[MIPS.sol#L767-L770](https://github.com/code-423n4/2024-07-optimism/blob/main/packages/contracts-bedrock/src/cannon/MIPS.sol#L767-L770)
```solidity
                if (func == 8 || func == 9) {
                    // jr/jalr
                    return handleJump(func == 8 ? 0 : rdReg, rs);
                }
```

This makes it such that the return address, `PC + 8`, is not written to any register because the `_linkReg` variable which is the `rdReg` will be 0.

[MIPS.sol#L477-L480](https://github.com/code-423n4/2024-07-optimism/blob/main/packages/contracts-bedrock/src/cannon/MIPS.sol#L477-L480)
```solidity
            // Update the link-register to the instruction after the delay slot instruction.
            if (_linkReg != 0) {
                state.registers[_linkReg] = prevPC + 8;
            }
```

## Impact

Although both the on-chain and off-chain MIPS VM contain the same error, if the L2 STF converted to MIPS contains a `jalr` instruction with 1 operand (which is still valid), then it is possible that the result for both the on-chain and off-chain MIPS VM to return a result that will be egregiously wrong (for instance, not knowing where to return to after the function call) and lead to unintended consequences leading to unintended consequences (such as leading to a correct output root not being able to be confirmed because the MIPS program will report an invalid VM status)


## Tools Used

Manual Review

## Recommended Mitigation Steps

For `jalr` instruction, check if `rdReg` is 0. If it is then set it to 31 instead.


























## Assessed type

Other
DoSed `YieldSavingsDai`  withdrawals due to passing in `DAI` amount to `redeem()`, which accepts shares
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/sdai/YieldSavingsDai.sol#L105
https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/YieldStakingBase.sol#L340
https://github.com/makerdao/sdai/blob/master/src/SavingsDai.sol#L354


# Vulnerability details

## Impact

DoSed withdrawals in `YieldSavingsDai` as it will be impossible to withdraw the yield in `YieldSavingsDie::unstake()`.

## Proof of Concept

`YieldSavingsDai::protocolClaimWithdraw()` calls the redeem function specifying `sd.withdrawAmount` as the amount. However, `SavingsDai::redeem()` accepts a [shares](https://github.com/makerdao/sdai/blob/master/src/SavingsDai.sol#L354) argument, not `DAI` itself, which will make it revert with insufficient amount as the `DAI` amount is bigger than the corresponding shares.

`sd.withdrawAmount` is the `DAI` amount as it is fetched [here](https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/YieldStakingBase.sol#L340) using `convertToYieldAssets(address(vars.yieldAccout), sd.yieldShare);`, which returns the DAI amount as the total assets are [fetched](https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/sdai/YieldSavingsDai.sol#L133) as `sdai.balanceOf(account);`

## Tools Used

Vscode

Foundry

## Recommended Mitigation Steps

`SavingsDai::withdraw()` can be used instead which [accepts](https://github.com/makerdao/sdai/blob/master/src/SavingsDai.sol#L340) a `DAI` argument.


## Assessed type

Other
Mismatch between yield amount deposited in shares calculation and `getAccountYieldBalance()`
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/YieldStakingBase.sol#L250-L255
https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/etherfi/YieldEthStakingEtherfi.sol#L120-L122
https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/lido/YieldEthStakingLido.sol#L120-L122


# Vulnerability details

## Impact

Mismatch between the return amount in all yield Etherfi and Lido assets and the `getAccountYieldBalance()` call causes the yield amount of each staked nft to the same `YieldAccount` to be incorrect, leading to the possibility of withdrawing the excess for some nfts while being closer to liquidation on others

## Proof of Concept

The issue stems from the fact that in `YieldStakingBase::stake()`, on deposit of the borrowed amount to the corresponding yield source (Etherfi or Lido), it returns the minted shares of each integration [Etherfi](https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L529C25-L529C48) and [Lido](https://github.com/lidofinance/lido-dao/blob/master/contracts/0.4.24/Lido.sol#L946). As all these integrations shares increase in value over time, on each deposit, less shares than the deposited `ETH` are minted. This will be problematic because `YieldStakingBase` uses the returned shares value from depositing as if they were assets, [here](https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/YieldStakingBase.sol#L253). But then, it calculates `totalAssets` to compute the yield using the actual ETH balance of the positions [Etherfi](https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/etherfi/YieldEthStakingEtherfi.sol#L121), [Lido](https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/lido/YieldEthStakingLido.sol#L121).

Due to this, if more than 1 nft is deposited, the borrowed amount and the yield amount will differ significantly. The first staked nft will have a bigger yield amount that can be claimed immediately and the following nfts will have instant losses that may end up being liquidated.

Replace the `MockEtherfiLiquidityPool` deposit logic to mimic the real behaviour. It is the same as having an assets/shares ratio in Etherfi of 0.9:
```solidity
function deposit() external payable override returns (uint256) {
  require(msg.value > 0, 'msg value is 0');

  MockeETH(payable(eETH)).mint(msg.sender, msg.value);
  return msg.value * 9 / 10;
}
```

Place the following test in `YieldEthStakingEtherfi.t.sol`. The yield amount of each staked nft is different, but the borrowed amounts are the same.
```solidity
function test_POC_Incorrect_Yield_tracking() public {
  YieldTestVars memory testVars;

  prepareWETH(tsDepositor1);

  uint256[] memory tokenIds = prepareIsolateBAYC(tsBorrower1);

  uint256 stakeAmount = tsYieldEthStakingEtherfi.getNftValueInUnderlyingAsset(address(tsBAYC));
  stakeAmount = (stakeAmount * 80) / 100;

  tsHEVM.prank(address(tsBorrower1));
  address yieldAccount = tsYieldEthStak
Missing ERC721Receiver in YieldAccount leading to DoSed withdrawals in `YieldEthStakingEtherfi`
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/YieldAccount.sol#L15
https://github.com/etherfi-protocol/smart-contracts/blob/master/src/WithdrawRequestNFT.sol#L63


# Vulnerability details

## Impact
Withdrawals of YieldEthStakingEtherfi are permanently DoSed. 

## Proof of Concept

`YieldEthStakingEtherfi::protocolRequestWithdrawal()` calls `LiquidityPool::requestWithdrawal()`, which in turn calls [WithdrawRequestNFT.requestWithdraw](https://github.com/etherfi-protocol/smart-contracts/blob/master/src/LiquidityPool.sol#L209). [Here](https://github.com/etherfi-protocol/smart-contracts/blob/master/src/WithdrawRequestNFT.sol#L63), it calls `_safeMint()` to the receiver, which is the `YieldAccount`; however, the `YieldAccount` does not implement the `ERC721Receiver` contract, which means it will revert when receiving the nft with error `ERC721: transfer to non ERC721Receiver implementer".

Replace the mock contract function `MockEtherfiWithdrawRequestNFT::requestWithdraw()`, the `_mint()` call with `_safeMint()` and run `forge test --mt test_Should_unstake`, it will revert with the mentioned error.

## Tools Used

Vscode

Foundry

## Recommended Mitigation Steps

Implement `ERC721Receiver` in the `YieldAccount`.





## Assessed type

ERC721
unstake / repay will always revert when called by botAdmin, due to implementation error, unstakeFine will be lost
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#L84
https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/yield/lido/YieldEthStakingLido.sol#L82
https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/yield/etherfi/YieldEthStakingEtherfi.sol#L95
https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/yield/lido/YieldEthStakingLido.sol#L96
https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/yield/YieldStakingBase.sol#L312


# Vulnerability details

## Impact
`unstake` / `repay` will always revert when called by botAdmin, due to implementation error, unstakeFine will be lost.

## Proof of Concept
In `unstake()`/ `repay()`, msg.sender will always be used to fetch the user's yieldAccount. (`yieldAccounts[msg.sender]`). Flows: YieldStakingBase::unstake / repay -> protocolRequestWithdrawal/ protocolClaimWithdraw

But when the caller is botAdmin, msg.sender will still be used to fetch the user's yieldAccount, which results in address(0), causing revert. 

(1) unstake reverts, unstakeFine cannot be charged to unhealthy positions.
```solidity
//src/yield/YieldStakingBase.sol
  function _unstake(uint32 poolId, address nft, uint256 tokenId, uint256 unstakeFine) internal virtual {
    UnstakeLocalVars memory vars;
    //@audit when msg.sender is botAdmin, vars.yieldAccount is address(0), failing require check.
|>  vars.yieldAccout = IYieldAccount(yieldAccounts[msg.sender]);
    require(address(vars.yieldAccout) != address(0), Errors.YIELD_ACCOUNT_NOT_EXIST);
...
    // sender must be bot or nft owner
    if (msg.sender == botAdmin) {
      require(unstakeFine <= nc.maxUnstakeFine, Errors.YIELD_ETH_EXCEED_MAX_FINE);

      uint256 hf = calculateHealthFactor(nft, nc, sd);
      require(hf < nc.unstakeHeathFactor, Errors.YIELD_ETH_HEATH_FACTOR_TOO_HIGH);

 |>   sd.unstakeFine = unstakeFine; //@audit unstakeFine cannot be charged 
      totalUnstakeFine += unstakeFine;
    }
...
```
(https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/yield/YieldStakingBase.sol#L312)

(2) repay reverts
```solidity
//src/yield/YieldStakingBase.sol
  function _repay(uint32 poolId, address nft, uint256 tokenId) internal virtual {
    RepayLocalVars memory vars;
        //@audit when msg.sender is botAdmin, vars.yieldAccount is address(0), failing require check.
|>   vars.yieldAccout = IYieldAccount(yieldAccounts[msg.sender]);
    require(address(vars.yieldAccout) != address(0), Errors.YIELD_ACCOUNT_NOT_EXIST);
...
    //@audit both nftOwner and botAdmin are allowed to call repay.
    require(vars.nftOwner == msg.sender || botAdmin == msg.sender, Errors.INVALID_CALLER);
...
```
(https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src
executeIsolateLiquidate() totalBidAmout is not accounting correctly
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Vulnerability details
When execute `isolateLiquidate()`, we will accounting `totalBidAmout`
```solidity
  function executeIsolateLiquidate(InputTypes.ExecuteIsolateLiquidateParams memory params) internal {
...
    for (vars.nidx = 0; vars.nidx < params.nftTokenIds.length; vars.nidx++) {
...
      // transfer remain amount to borrower
      if (vars.remainBidAmounts[vars.nidx] > 0) {
        VaultLogic.erc20TransferOutBidAmount(debtAssetData, tokenData.owner, vars.remainBidAmounts[vars.nidx]);
      }
...
      vars.totalBorrowAmount += vars.borrowAmount;
      vars.totalBidAmount += loanData.bidAmount;
      vars.totalExtraAmount += vars.extraBorrowAmounts[vars.nidx];

      // delete the loan data at final
      delete poolData.loanLookup[params.nftAsset][params.nftTokenIds[vars.nidx]];
    }

    require(
      (vars.totalBidAmount + vars.totalExtraAmount) >= vars.totalBorrowAmount,
      Errors.ISOLATE_LOAN_BORROW_AMOUNT_NOT_COVER
    );

    // update interest rate according latest borrow amount (utilizaton)
    InterestLogic.updateInterestRates(poolData, debtAssetData, (vars.totalBorrowAmount + vars.totalExtraAmount), 0);

    // bid already in pool and now repay the borrow but need to increase liquidity
@>  VaultLogic.erc20TransferOutBidAmountToLiqudity(debtAssetData, vars.totalBorrowAmount);

```
```solidity
  function erc20TransferOutBidAmountToLiqudity(DataTypes.AssetData storage assetData, uint amount) internal {
@>  assetData.totalBidAmout -= amount;
    assetData.availableLiquidity += amount;
  }
```

At the end of the method, we will use `erc20TransferOutBidAmountToLiqudity(vars.totalBorrowAmount)` to reduce the `totalBidAmout`：
`assetData.totalBidAmout -= vars.totalBorrowAmount`

Using `vars.totalBorrowAmount` may be incorrect 
Over time (borrowIndex increase), `vars.totalBorrowAmount` may be greater than `vars.totalBidAmount`
This will result in `assetData.totalBidAmout` being subtracted too much




## Impact

`assetData.totalBidAmout` was incorrectly subtracted too much , which could lead to subsequent methods `underflow`

## Recommended Mitigation
1. when have remainBidAmounts, don't use erc20TransferOutBidAmount() , it will reduce `totalBidAmout`
2. erc20TransferOutBidAmountToLiqudity() use totalBidAmount
```diff
  function executeIsolateLiquidate(InputTypes.ExecuteIsolateLiquidateParams memory params) internal {
...
      // transfer remain amount to borrower
      if (vars.remainBidAmounts[vars.nidx] > 0) {
-       VaultLogic.erc20TransferOutBidAmount(debtAssetData, tokenData.owner, vars.remainBidAmounts[vars.nidx]);
+       assetData.underlyingAsset.safeTransfer(tokenData.owner,vars.remainBidAmounts[vars.nidx]);
      }
...


    // bid already in pool and now repay the borrow but need to increase liquidity
-   VaultLogic.erc20TransferOutBidAmount
isolateLiquidate() lock of check msgSender == lastBidder
Audit: 2024-07-benddao-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Vulnerability details

When the bidding ends, the user can call `isolateLiquidate()` to liquidate
```solidity
  function executeIsolateLiquidate(InputTypes.ExecuteIsolateLiquidateParams memory params) internal {
...
    for (vars.nidx = 0; vars.nidx < params.nftTokenIds.length; vars.nidx++) {
      DataTypes.IsolateLoanData storage loanData = poolData.loanLookup[params.nftAsset][params.nftTokenIds[vars.nidx]];
      DataTypes.GroupData storage debtGroupData = debtAssetData.groupLookup[loanData.reserveGroup];
      DataTypes.ERC721TokenData storage tokenData = VaultLogic.erc721GetTokenData(
        nftAssetData,
        params.nftTokenIds[vars.nidx]
      );
...
      ValidateLogic.validateIsolateLiquidateLoan(params, debtGroupData, loanData);

      vars.auctionEndTimestamp = loanData.bidStartTimestamp + nftAssetData.auctionDuration;
      require(block.timestamp > vars.auctionEndTimestamp, Errors.ISOLATE_BID_AUCTION_DURATION_NOT_END);
@>  //@audit missing check msgSender == lastBidder
```
```solidity
  function validateIsolateLiquidateLoan(
    InputTypes.ExecuteIsolateLiquidateParams memory inputParams,
    DataTypes.GroupData storage debtGroupData,
    DataTypes.IsolateLoanData storage loanData
  ) internal view {
    validateGroupBasic(debtGroupData);

    require(loanData.loanStatus == Constants.LOAN_STATUS_AUCTION, Errors.INVALID_LOAN_STATUS);
    require(loanData.reserveAsset == inputParams.asset, Errors.ISOLATE_LOAN_ASSET_NOT_MATCH);
  }
```

From the above code, we can see that this method does not restrict `msgSender == lastBidder`

It can be called by anyone, and will result in the winner of the bid, `lastBidder`, losing the corresponding bid funds.

## Impact

The winner of the auction, `lastBidder`, loses the corresponding bid funds.

## Recommended Mitigation

```diff
  function executeIsolateLiquidate(InputTypes.ExecuteIsolateLiquidateParams memory params) internal {
...
      vars.auctionEndTimestamp = loanData.bidStartTimestamp + nftAssetData.auctionDuration;
      require(block.timestamp > vars.auctionEndTimestamp, Errors.ISOLATE_BID_AUCTION_DURATION_NOT_END);
+     require(params.msgSender == loanData.lastBidder, " invald msgSender");
```


## Assessed type

Context