xanoutas/solidity-security-findings huggingface dataset:
`FeeManager::totalBadDebtETH` variable manipulation can prevent incentive distribution to owner A and B and DoS `claimFeesBeneficial`
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/FeeManager/FeeManagerHelper.sol#L86-L100


# Vulnerability details

## Impact
When someone liquidates a position in `WiseLending` contract, if it had bad debt, it is accounted in `FeeManager`. This action is executed as follows:

```
    /**
     * @dev Checks for bad debt logic. Compares
     * total ETH of borrow and collateral.
     */
    function checkBadDebtLiquidation(
        uint256 _nftId
    )
        external
        onlyWiseLending
    {
        uint256 bareCollateral = overallETHCollateralsBare(
            _nftId
        );

        uint256 totalBorrow = overallETHBorrowBare(
            _nftId
        );

        if (totalBorrow < bareCollateral) {
            return;
        }

        unchecked {
            uint256 diff = totalBorrow
                - bareCollateral;

            FEE_MANAGER.increaseTotalBadDebtLiquidation(
                diff
            );

            FEE_MANAGER.setBadDebtUserLiquidation(
                _nftId,
                diff
            );
        }
    }
```
As we can see, when the liquidation is executed inside the `WiseLending` contract, it checks for the total collateral value of the position and the value borrowed. If the value borrowed exceeds the collateral, means that the position has bad debt and it needs to be accounted in the `FeeManager` contract. To do that, it calls 2 functions: `setBadDebtUserLiquidation` and `increaseTotalBadDebtLiquidation`.

The behavior of each function is related with their names, in the case of the first function, it sets the bad debt to the position overriding the value it previously had, but for the second, it increments the bad debt to the previous value that `totalBadDebtETH` variable had. Since liquidating a position does not ensure that it ends to a healthy state, someone can increment a lot of `totalBadDebtETH` almost for free just by liquidating a position that has bad debt and repaying just 1 unit of borrowed share. Thus, the `totalBadDebtETH` can be easily manipulated and this can harm the following actions:

1. When someone would call `FeeManager::claimWiseFees` to claim the fees from the lending component, the incentives for owner A and B would receive nothing. That is because the accounting of bad debt would be broken and it would always be greater than 0.

```
    function claimWiseFees(
        address _poolToken
    )
        public
    {
        ...
        // @audit this state will never be reached if someone manipulates the total bad debt

        if (totalBadDebtETH == 0) {

            tokenAmount = _distributeIncentives(
                tokenAmount,
                _poolToken,
                underlyingTokenAddress
            );
        }

        ...
    }
```

2. The function `FeeManager::claimFeesBeneficial` will not work again for the same reason, because if there is any bad debt, the function call reverts.

```
    function claimFeesBeneficial(
Total bad debts are overstated and can affect access and distribution of benefits
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseLending.sol#L1306
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseCore.sol#L665-L667
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseSecurity/WiseSecurity.sol#L423-L435
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/FeeManager.sol#L494-L508
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/FeeManagerHelper.sol#L89-L100


# Vulnerability details

## Impact
The total debt is overstated, which can result in fees earned under the protocol not being reutilized

## Proof of Concept
When a position has more than 100% debt, it can be liquidated via the
method [liquidatePartiallyFromTokens](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseLending.sol#L1250-L1309) to liquidate the position. The amount to be liquidated is fine as long as it does not exceed the maximum liquidatable shares. When liquidating, the total bad debt incurred and the bad debt of the position will be recorded separately.The code is as follows:
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseSecurity/WiseSecurity.sol#L405-L436
```solidity
    function checkBadDebtLiquidation(
        uint256 _nftId
    )
        external
        onlyWiseLending
    {
        uint256 bareCollateral = overallETHCollateralsBare(
            _nftId
        );

        uint256 totalBorrow = overallETHBorrowBare(
            _nftId
        );

        if (totalBorrow < bareCollateral) {
            return;
        }

        unchecked {
            uint256 diff = totalBorrow
                - bareCollateral; // @aduit The total bad debt amount of the position

            FEE_MANAGER.increaseTotalBadDebtLiquidation(
                diff
            ); // @audit The total bad debt keeps increasing

            FEE_MANAGER.setBadDebtUserLiquidation(
                _nftId,
                diff
            );
        }
    }
```
The problem occurs when the total bad debt is recorded. We can see the logic of the bad debt, which is calculated in full. 
For example, the bad debt value of a position bad debt is 5ETH.
The first liquidation is not liquidated, the repayment of 1ETH, then the total bad debt record is 4ETH, the bad debt of the position record is 4ETH. the second user made another repayment of 1ETH, then the bad debt of the position record is 3ETH, the total bad debt continues to increase, the record is 7ETH.In fact, the total bad debt should only be 3ETH.the remaining bad debt even if the call to the Even if the [updatePositionCurrentBadDebt](https://github.com/code-423n4/2024-02-wise-lending/b
The Fee Manager NFT Shares can be drained
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/PowerFarms/PendlePowerFarm/PendlePowerManager.sol#L274


# Vulnerability details

## Impact
Loss of protocol funds

## Proof of Concept

The users having positions at the Power Farms can withdraw their shares by calling [manuallyWithdrawShares](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/PowerFarms/PendlePowerFarm/PendlePowerManager.sol#L274).

The function is below;

```solidity
Contract: PendlePowerManager.sol

274:     function manuallyWithdrawShares(
275:         uint256 _keyId,
276:         uint256 _withdrawShares
277:     )
278:         external
279:         updatePools
280:         onlyKeyOwner(_keyId)
281:     {
282:         uint256 wiseLendingNFT = farmingKeys[
283:             _keyId
284:         ];
285: 
286:         _manuallyWithdrawShares(
287:             wiseLendingNFT,
288:             _withdrawShares
289:         );
290: 
291:         if (_checkDebtRatio(wiseLendingNFT) == false) {
292:             revert DebtRatioTooHigh();
293:         }
294: 
295:         emit ManualWithdrawShares(
296:             _keyId,
297:             wiseLendingNFT,
298:             _withdrawShares,
299:             block.timestamp
300:         );
301:     }
```

Accordingly, the users should pass their `_keyId` and amount of shares that they want to withdraw.

The `updatePools` modifier syncs the pools and the `onlyKeyOwner` modifier validates the caller being the key owner.

Accordingly, the function continues with converting `PENDLE_CHILD` shares to tokens by calling [_manuallyWithdrawShares](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/PowerFarms/PendlePowerFarm/PendlePowerFarm.sol#L157C14-L157C37) and the shares are cashed out accordingly in Wiselending Contract as below.
```solidity
Contract: PendlePowerFarm.sol

157:     function _manuallyWithdrawShares(
158:         uint256 _nftId,
159:         uint256 _withdrawShares
160:     )
161:         internal
162:     {
163:         uint256 withdrawAmount = WISE_LENDING.cashoutAmount(
164:             PENDLE_CHILD,
165:             _withdrawShares
166:         );
167: 
168:         withdrawAmount = WISE_LENDING.withdrawExactShares(
169:             _nftId,
170:             PENDLE_CHILD,
171:             _withdrawShares
172:         );
173: 
174:         _safeTransfer(
175:             PENDLE_CHILD,
176:             msg.sender,
177:             withdrawAmount
178:         );
179:     }
```

L: 168 withdraws the tokens using shares and the tokens are transferred afterward.

Finally, in the `PendlePowerManager.manuallyWithdrawShares` function, a debt ratio is checked, accordingly, the call is finalized and the caller receives the funds.

--- 
Scenario;

1. MEV Bot calls `manuallyWithdrawShares` with `_keyId = 0` 
2. The pools are synched by the `updatePools` modif
The position of the aaveHub  can be liquidate if aave contract is in pause
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WrapperHub/AaveHelper.sol#L101


# Vulnerability details

One of the known issues is the issue presented below:

"
If Aave freezes pools where we use the underlying as a pool new aTokens can't be minted and thus open borrow positions can't pay it back. If Aave unfreezes the pool the functionality is restored. This can be mitigated in the future by wrapping the aTokens into new tokens which also accept the underlying. Then after adding that to a pool this is mitigated. So the risk is known and not considered a bug and can be migrated after launch while its still not frozen.
"

The problem is that is user can not payback, but they can get liquidate.

## Impact
Users can not pay back his borrow If Aave freezes pools, but the contract is not taking in consideration that they are still open to liquidation which is no fair for users.

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

## Tools Used
As you can see the entry point of the liquidation is:

```
file:/contracts/WiseLending.sol

function liquidatePartiallyFromTokens(
        uint256 _nftId,
        uint256 _nftIdLiquidator,
        address _paybackToken,
        address _receiveToken,
        uint256 _shareAmountToPay
    )
        external
        syncPool(_paybackToken)
        syncPool(_receiveToken)
        returns (uint256)
    {
        CoreLiquidationStruct memory data;

        data.nftId = _nftId;
        data.nftIdLiquidator = _nftIdLiquidator;

        data.caller = msg.sender;

        data.tokenToPayback = _paybackToken;
        data.tokenToRecieve = _receiveToken;
        data.shareAmountToPay = _shareAmountToPay;

        data.maxFeeETH = WISE_SECURITY.maxFeeETH();
        data.baseRewardLiquidation = WISE_SECURITY.baseRewardLiquidation();

        (
            data.lendTokens,
            data.borrowTokens
        ) = _prepareAssociatedTokens(
            _nftId,
            _receiveToken,
            _paybackToken
        );

        data.paybackAmount = paybackAmount(
            _paybackToken,
            _shareAmountToPay
        );

        _checkPositionLocked(
            _nftId,
            msg.sender
        );

        _checkLiquidatorNft(
            _nftId,
            _nftIdLiquidator
        );

        WISE_SECURITY.checksLiquidation(
            _nftId,
            _paybackToken,
            _shareAmountToPay
        );

        return _coreLiquidation(
            data
        );
    }
```
[[Link]](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseLending.sol#L1250C5-L1309C6)

This function is not taking in consideration is the aave lending is in paused, so User can't pay back his borrow but they still can be liquidate.

## Recommended Mitigation Steps
Consider don't allow
The first deposit of each pool token will revert
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/MainHelper.sol#L33-L45


# Vulnerability details

when deposit in wise lending,beacuse of the initial number of  lendingPoolData[_poolToken].pseudoTotalPool is zero，so it will revert in _calculateShares function

## Impact

all token can't deposit in wise lending in unsolely model.

## Proof of Concept

Use depositExactAmount function as example：

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseLending.sol#L469-L474

```solidity
    function depositExactAmount(
        uint256 _nftId,
        address _poolToken,
        uint256 _amount
    )
        public
        syncPool(_poolToken)
        returns (uint256)
    {
        uint256 shareAmount = _handleDeposit(
            msg.sender,
            _nftId,
            _poolToken,
            _amount
        );

        _safeTransferFrom(
            _poolToken,
            msg.sender,
            address(this),
            _amount
        );

        return shareAmount;
    }
```

it will call _handleDeposit:

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseCore.sol#L115-L121

```solidity
function _handleDeposit(
        address _caller,
        uint256 _nftId,
        address _poolToken,
        uint256 _amount
    )
        internal
        returns (uint256)
    {
        uint256 shareAmount = calculateLendingShares(
            {
                _poolToken: _poolToken,
                _amount: _amount,
                _maxSharePrice: false
            }
        );
...
}
```

And call calculateLendingShares to calculate share:

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/MainHelper.sol#L17C14-L45

```solidity
    function calculateLendingShares(
        address _poolToken,
        uint256 _amount,
        bool _maxSharePrice
    )
        public
        view
        returns (uint256)
    {
        return _calculateShares(
            lendingPoolData[_poolToken].totalDepositShares * _amount,
            lendingPoolData[_poolToken].pseudoTotalPool,
            _maxSharePrice
        );
    }
```

```solidity
	function _calculateShares(
        uint256 _product,
        uint256 _pseudo,
        bool _maxSharePrice
    )
        private
        pure
        returns (uint256)
    {
        return _maxSharePrice == true
            ? _product / _pseudo + 1
            : _product / _pseudo - 1;
    }

```

When pseudoTotalPool is zero, _calculateShares will revert， because divide zero will revert.

So all pool token can't deposit because the initial number of  lendingPoolData[_poolToken].pseudoTotalPool is zero.

## Tool Used

foundary、vscode

## Recommended Mitigation Steps

Add the processing logic of lendingPoolData[_poolToken].pseudoTotalPool == 0


## Assessed type

Math
Malicious users can honeypot other users by  withdrawing deposit tokens
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseLending.sol#L460-L484


# Vulnerability details

accroding to website https://wisesoft.gitbook.io/wise/wiselending.com/wise-lending, it says:

`Each user mints an NFT for their account when they first interact. This allows for transferrable positions, as well as modular features to be built on top of the base protocol, such as an options market.`

So position NFT  can be used as a financial certificate and sold and purchased in the market.

If the NFT is put for sale and and it has some collateral available,anybody can submitt a transaction with price paid to buy it.But the seller can front-run before buyer,and he can withdraw all deposit token in NFT,and get all price paid.

## Impact

Malicious users can honeypot other users

## Proof of Concept

For example,If user A own Position NFT 1 with `1 ETH` deposit:

1. User A owns Position NFT 1.
2. Position NFT 1 has `1 ETH` deposit and they can be withdrawed.
3. User A lists Position NFT 1 for `3000 USDT`.
4. User B buys  Position NFT 1.
5. User A sees the transaction in the mempool and quickly front runs it in order to withdraw `1 ETH`.
6. User A withdraw `1 ETH` and get user B price paid `3000 USDT`,and user B get Position NFT 1 with no deposit.

There is an example like it: https://www.codehawks.com/report/clql6lvyu0001mnje1xpqcuvl#H-04

## Recommended Mitigation Steps

After position NFT is operated in wise lending, the timestamp of its operation need be recorded. Transfer need limit to be used after a duration after this timestamp.


## Assessed type

MEV
Infinite approvals to third parties are irrevokable and subject to be the soft belly when the dependent platform is exploited
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/PowerFarms/PendlePowerFarm/PendlePowerFarmDeclarations.sol#L274-L354


# Vulnerability details

## Impact
Loss of protocol and user funds

## Proof of Concept
Wiselending Protocol pre-approves some inter-protocol addresses in the [PendlePowerFarmDeclarations](https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/PowerFarms/PendlePowerFarm/PendlePowerFarmDeclarations.sol) contract´s constructor to provide smooth function flows and save gas.

However, this is an irreversible implementation as the approvals given to the addresses are not only the Wiselending contracts and they can´t be zeroed back.

It´s performed in the constructor by calling [_doApprovals](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/PowerFarms/PendlePowerFarm/PendlePowerFarmDeclarations.sol#L274-L354), and here´s the list of approved addresses;

```solidity
Contract: PendlePowerFarmDeclarations.sol

274:     function _doApprovals(
275:         address _wiseLendingAddress
276:     )
277:         internal
278:     {
279:         if (block.chainid == ETH_CHAIN_ID) {
280:             _safeApprove(
281:                 ST_ETH_ADDRESS,
282:                 address(CURVE),
283:                 MAX_AMOUNT
284:             );
285:         }
286: 
287:         if (block.chainid == ARB_CHAIN_ID) {
288:             _safeApprove(
289:                 address(ENTRY_ASSET),
290:                 address(UNISWAP_V3_ROUTER),
291:                 MAX_AMOUNT
292:             );
293: 
294:             _safeApprove(
295:                 WETH_ADDRESS,
296:                 address(UNISWAP_V3_ROUTER),
297:                 MAX_AMOUNT
298:             );
299: 
300:             _safeApprove(
301:                 WETH_ADDRESS,
302:                 _wiseLendingAddress,
303:                 MAX_AMOUNT
304:             );
305:         }
306: 
307:         _safeApprove(
308:             PENDLE_CHILD,
309:             _wiseLendingAddress,
310:             MAX_AMOUNT
311:         );
312: 
313:         _safeApprove(
314:             ENTRY_ASSET,
315:             address(PENDLE_ROUTER),
316:             MAX_AMOUNT
317:         );
318: 
319:         _safeApprove(
320:             address(PENDLE_MARKET),
321:             PENDLE_CHILD,
322:             MAX_AMOUNT
323:         );
324: 
325:         _safeApprove(
326:             address(PENDLE_MARKET),
327:             address(PENDLE_ROUTER),
328:             MAX_AMOUNT
329:         );
330: 
331:         _safeApprove(
332:             address(ENTRY_ASSET),
333:             address(PENDLE_SY),
334:             MAX_AMOUNT
335:         );
336: 
337:         _safeApprove(
338:             address(ENTRY_ASSET),
339:             _wiseLendingAddress,
340:             MAX_AMOUNT
341:         );
342: 
343:         _safeApprove(
344:             address(PENDLE_SY),
345:
Hardcoded prices are prone to be abused one day
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseOracleHub/WiseOracleHub.sol#L151-L152


# Vulnerability details

## Impact
Loss of protocol and user funds
## Proof of Concept

The protocol returns ETH value of a given token amount in order of 1E18 decimal precision by calling [getTokensInETH](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseOracleHub/WiseOracleHub.sol#L143)

Accordingly, the function gets the token address and the token amount as the input parameters, and further validations are carried out as per the input address;

```solidity
Contract: WiseOracleHub.sol

143:     function getTokensInETH(
144:         address _tokenAddress,
145:         uint256 _tokenAmount
146:     )
147:         public
148:         view
149:         returns (uint256)
150:     {
151:         if (_tokenAddress == WETH_ADDRESS) { 
152:             return _tokenAmount;
153:         }
154: 
155:         uint8 tokenDecimals = _tokenDecimals[
156:             _tokenAddress
157:         ];
158: 
159:         return _decimalsETH < tokenDecimals
160:             ? _tokenAmount
161:                 * latestResolver(_tokenAddress)
162:                 / 10 ** decimals(_tokenAddress)
163:                 / 10 ** (tokenDecimals - _decimalsETH)
164:             : _tokenAmount
165:                 * 10 ** (_decimalsETH - tokenDecimals)
166:                 * latestResolver(_tokenAddress)
167:                 / 10 ** decimals(_tokenAddress);
168:     }
```
L: 151 checks whether the input token is WETH. If true, it returns the same `_tokenAmount` as the input.

Otherwise, the function carries out internal calls depending on the token decimals with the trace below;

* `latestResolver` -> 

* Check ChainLing is dead && `_validateAnswer` in `latestResolver` -> 

* Check Uniswap TWAP price && Get ChainLink Price && Compare they don´t fall outside of the price difference ratio boundaries in `_validateAnswer` ->
 
* Return Answer in `_validateAnswer`


However, assuming WETH:ETH peg in a 1:1 ratio might cause the protocol to be used as the arbitration point and drain ETH funds when the WETH loses its peg. 

While, it may be an unreal issue for the ETH main net, the black swan events at the different chains can trigger this when the WETH is depegged at those chains. To picture this, [this article](https://pwning.mirror.xyz/RFNTSouIIlHVNmTNDThUVb1obIeN5c1LAiQuN9Ve-ok) from the Top #1 whitehat on Immunefi can provide the idea of how WETH can lose its peg on other chains.


No need to mention that, even the most trusted stables had depegged in the past.
There was a USDC depeg last year which brought the price to 0,89 USD per USDC. As a result, DAI also depegged no matter how decentralized it is:
![dai](https://gist.github.com/assets/65364747/16a375df-f789-4a71-b88c-1f024fa3833b)


## Tools Used
Manual Review

## Recommended Mitigation Steps
we rec