xanoutas/solidity-security-findings huggingface dataset:
Hardcoded Uniswap V3 fee for Arbitrum
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/PowerFarms/PendlePowerFarm/PendlePowerFarmDeclarations.sol#L95
https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/PowerFarms/PendlePowerFarm/PendlePowerFarmLeverageLogic.sol#L278


# Vulnerability details

Uniswap V3 offers 4 different [fee tiers](https://docs.uniswap.org/concepts/protocol/fees) (0,01%, 0,05%, 0,3%, 1%). The hardcoded value used to call [exactInputSingle](https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/PowerFarms/PendlePowerFarm/PendlePowerFarmLeverageLogic.sol#L273), when the chain is Arbitrum, assumes that a pool with a fee tier of 0,01 either exists or has enough liquidity. This is not the ideal case as anybody can initialize these pools at the different fee tiers.

## Impact
In case the pool is not initialized for the hardcoded fee tier, an attacker could deploy and initialize the pool with a manipulated price. 

## Proof of Concept


## Tools Used
Manual review

## Recommended Mitigation Steps
1. Don't use a hardcoded value for the fee tier and check if the pair actually exists before using that particular fee.
2. Check that the [_depositAmount](https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/PowerFarms/PendlePowerFarm/PendlePowerFarmLeverageLogic.sol#L429) is not zero before executing other functions


## Assessed type

DoS
Borrowing aToken rebase rate can compensate for the borrowing interest rate and even generate positive benefits
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#L500-L576


# Vulnerability details

before every operator of wise lending, it will call  _updatePseudoTotalAmounts to update borrow interest amount to pool.If the pool token is aToken, it will only calculate the interest generated by borrowing amount, and don't take into  the rebase increasing amount after borrowing and interest generated.In low borrow rate,increaing amount will exceed borrow interest,and borrower will get benefits from borrowing,it is unreasonable.The borrower can even use repeated deposits and borrows to add leverage and obtain more rebase increasing amounts.

## Impact

When positive rebase token (aToken) is borrowed, the amount and interest of the rebase increase are not calculated.

## Proof of Concept

before every operator of wise lending, it will call _cleanup function in _preparePool function  to add rebase amount or falsely sent amount to pool,and _updatePseudoTotalAmounts to update borrow interest amount to pool.If the pool token is aToken, it will only calculate the interest generated by borrowing amount, and don't calculate the rebase increasing amount after borrowing and interest generated.In low borrow rate,increaing amount may exceed borrow interest,and borrower will get benefits from borrowing,it is unreasonable.

It use syncPool to update lending amount and borrow amount before pool position operation, and it call _syncPoolBeforeCodeExecution to _preparePool:

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

```solidity
    modifier syncPool(
        address _poolToken
    ) {
        (
            uint256 lendSharePrice,
            uint256 borrowSharePrice
        ) = _syncPoolBeforeCodeExecution(
            _poolToken
        );

        _;

        _syncPoolAfterCodeExecution(
            _poolToken,
            lendSharePrice,
            borrowSharePrice
        );
    }
```

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

```solidity
    function _syncPoolBeforeCodeExecution(
        address _poolToken
    )
        private
        returns (
            uint256 lendSharePrice,
            uint256 borrowSharePrice
        )
    {
        _checkReentrancy();

        _preparePool(
            _poolToken
        );
    ......
    }
```

In _preparePool,it will call _cleanup to add rebase amount or falsely sent amount of pool token to gobal pool data and lending data:

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

```；solidity
    function _preparePool(
        address _poolToken
    )
        internal
    {
        _cleanUp(
            _poolToken
        );

        _updatePseudoTotalAmounts(
            _poolToken
Missing access controls in mint functions allows anyone to create unlimited position nfts
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/PositionNFTs.sol#L142-L149
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/PositionNFTs.sol#L174-L191


# Vulnerability details

## Bug Description
`mintPosition()` and `mintPositionForUser(address)` of PositionNFTs contract do not validate the authority of the minter, allowing anyone to mint unlimited position nfts.
```
 function mintPosition()
        external
        returns (uint256)
    {
        return _mintPositionForUser(
            msg.sender
        );
    }
```

```
function mintPositionForUser(
        address _user
    )
        external
        returns (uint256)
    {
        if (isApprovedForAll(
                _user,
                msg.sender
            ) == false
        ) {
            revert NotPermitted();
        }

        return _mintPositionForUser(
            _user
        );
    }
```

The attacker can mint unlimited position nfts and then call withdraw funcitions in WiseLending contract and steal raw ETH from the protocol

## Impact
Anyone can mint unlimited position nfts as a result they can then directly steal ETH from wiselending by calling ETH withdrawal functions.

## Proof of Concept
Since the bug is straightforward i think POC isn't required

## Tools Used
Manual Analysis

## Recommended Mitigation Steps
`Create a minter role and enforce that only minter can mint position nfts for users`


```
function mintPositionForUser(address _user) external onlyMinter returns (uint256) {
  ... ... ...
}
```



## Assessed type

Access Control
Incorrect Calculation of Token in Eth Price
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#L159-L167


# Vulnerability details

## Impact
The `WiseOracleHub.getTokensInEth` gets the value of given tokens in ETH using a calculation which calculates the value based on the token decimals. 
```
function getTokensInETH(
        address _tokenAddress,
        uint256 _tokenAmount
    )
        public
        view
        returns (uint256)
    {
        if (_tokenAddress == WETH_ADDRESS) {
            return _tokenAmount;
        }

        uint8 tokenDecimals = _tokenDecimals[
            _tokenAddress
        ];
@>        return _decimalsETH < tokenDecimals
            ? _tokenAmount
                * latestResolver(_tokenAddress)
                / 10 ** decimals(_tokenAddress)
                / 10 ** (tokenDecimals - _decimalsETH)
            : _tokenAmount
                * 10 ** (_decimalsETH - tokenDecimals)
                * latestResolver(_tokenAddress)
                / 10 ** decimals(_tokenAddress);
    }
```

The value of the tokens in ETH is used by very crucial functions in the protocol including `WiseOracleHub.getTokensPriceInUSD`, `FeeManager.getReceivingToken`, `WiseCore._coreLiquidation`, `PendlePowerFarmMathLogic.getTotalWeightedCollateralETH` and numerous other essential functions. In the case of incorrect value returned by this function, the impact on the entire protocol is far reaching and extremely critical.

## Proof of Concept
```
 return _decimalsETH < tokenDecimals ? 
              _tokenAmount * 
              latestResolver(_tokenAddress) 
              / 10 ** decimals(_tokenAddress)
               / 10 ** (tokenDecimals - _decimalsETH)
            : _tokenAmount
                * 10 ** (_decimalsETH - tokenDecimals)
                * latestResolver(_tokenAddress)
                / 10 ** decimals(_tokenAddress);
```

Given: _decimalsETH = 18
     tokenDecimals = 27 (Assume a token with 27 decimals)
     tokenAmount = 1 (Assume we want to convert just one token)
     latestResolver(token) = 1000000000000000000 (This is paired to ETH therefore 
                       chainlink feed would return the price in 18 decimals; 
                       Also, let us assume that the the resolver returns the price of the token as 1 ether or 1e18 i.e. 1 token = 1 ETH.
     decimals(token) = 18 (As this is paired with ETH)
Since ethDecimals < tokenDecimals in this scenario, the first calculation in the tenary is returned.

`uint256 answer = 1 * 1000000000000000000 / 10**18 / 10 ** (27-18)`

In this scenario, answer would actually return 0 due to rounding down in solidity. Therefore, in a scenario where we are trying to convert 1 token to Eth whose value is 1 ether, this should return 1 but we get 0.

## Tools Used
Manual Review

## Recommended Mitigation Steps
1. The `getTokensInEth` function calculation must be corrected to return the correct value of the tokens and also if r
PendlePowerFarm enterFarm function reverts because of redundant flashLoan call when 1x leverage provided
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/PowerFarms/PendlePowerFarm/PendlePowerManager.sol#L96
https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/PowerFarms/PendlePowerFarm/PendlePowerFarm.sol#L210


# Vulnerability details

When entering a farm, a user supplies the `_leverage` which denotes the amount of leverage to be used while opening the position. In the case the user chooses to enter farm without any leverage, the execution reverts because of the way balance flash loan is executed. This should not happen and there's no need to flash loan any amount if no additional funds are needed as leverage to open the position.

## Impact
It prevents users from opening power farm positions when neutral leverage is chosen.

## Proof of Concept
Add the snippet to PendlePowerFarmControllerBase.t.sol:
```
function test_enter_farm_no_leverage() public cheatSetup(false) {
    vm.expectRevert();

    powerFarmManagerInstance.enterFarm(
        false,
        1 ether,
        1 ether,
        entrySpread
    );
}
```

Run the following command:
```
forge test --fork-url mainnet --match-test test_enter_farm_no_leverage -vvvv
```


## Tools Used
Manual review

## Recommended Mitigation Steps
Execute the [_logicOpenPosition](https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/PowerFarms/PendlePowerFarm/PendlePowerFarmLeverageLogic.sol#L414) directly from [PendlePowerFarm](https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/PowerFarms/PendlePowerFarm/PendlePowerFarm.sol#L253) without calling the `_executeBalancerFlashLoan`. 


## Assessed type

DoS
The `paybackBadDebtForToken` function is also vulnerable to reentrancy attacks. 
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/FeeManager.sol#L730-L814


# Vulnerability details

## Impact
An attacker could potentially drain the contract's funds by repeatedly calling the function before the `badDebtPosition` mapping is updated.
Here's how the reentrancy attack could work:
1. The attacker creates a malicious contract that calls `paybackBadDebtForToken` from within its `fallback` function.
2. The attacker calls `paybackBadDebtForToken` with their malicious contract as the caller.
3. Inside the `paybackBadDebtForToken` function, the contract transfers the `receivingAmount` tokens to the attacker's malicious contract before updating the `badDebtPosition` mapping.
4. The malicious contract's fallback function is triggered by the token transfer, and it recursively calls `paybackBadDebtForToken` again.
5. Since the `badDebtPosition` mapping hasn't been updated yet, the attacker can repeatedly receive the `receivingAmount` tokens.
This attack can continue until the contract's funds are depleted or the gas limit is reached.
The severity of this vulnerability is considered high because it could lead to a complete loss of funds for the contract. An attacker could potentially drain all the tokens held by the contract, resulting in a significant financial 


## Proof of Concept
The `paybackBadDebtForToken` function is also vulnerable to reentrancy attacks. An attacker could potentially call this function recursively before the `badDebtPosition` mapping is updated, leading to multiple paybacks of the same bad debt. True or false, explain in details how this works, what is the impact ? show relevant code sections and explain proof of concept and vulnerability details. Use code to explain how it can be mitigated.
The `paybackBadDebtForToken` function is indeed vulnerable to a reentrancy attack. Here's a breakdown of the vulnerability and how it can be exploited:
1.The function updates the `badDebtPosition` mapping after transferring the `receivingAmount` and the `paybackAmount` tokens. This means that an attacker's malicious contract can re-enter the function before the `badDebtPosition` mapping is updated.
2. The attacker's malicious contract would call `paybackBadDebtForToken` and receive the `receivingAmount` token.
3. Before the `badDebtPosition` mapping is updated, the attacker's contract would recursively call `paybackBadDebtForToken` again, exploiting the fact that the `badDebtPosition` mapping has not been updated yet.
4.This recursive call would allow the attacker to receive additional `receivingAmount` tokens before the `badDebtPosition` mapping is updated, effectively draining the contract's tokens.
Here's the relevant code section that illustrates the vulnerability:

       function paybackBadDebtForToken(
            uint256 _nftId,
           address _paybackToken,
           address _receivingToken,
           uint256 _shares
       )
[H-3] Share's health factor not checked leading to wrong positions health state.
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/PendlePowerFarm.sol#L157-L179
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/InterfaceHub/IWiseLending.sol#L306-L312
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseLending.sol#L67-L90


# Vulnerability details

## Description:
Function Interface `IWiseLending::withdrawExactShares` does not apply essential modifiers and checks for `syncPool()` and `healthStateCheck()`. hence, functions inheriting the interface like `PendlePowerFarm::_manuallyWithdrawShares` are not checked to know if positions are healthy or not and might lead to wrong values in ascertaining positions that should be liquidated.

## Impact:
Break in core contract logic in asscertaining the health factor of positions

## Tools Used
Manual Review

## Proof Of Concept:
```javascript
    function _manuallyWithdrawShares(
        uint256 _nftId,
        uint256 _withdrawShares
    )
        internal
    {
        uint256 withdrawAmount = WISE_LENDING.cashoutAmount(
            PENDLE_CHILD,
            _withdrawShares
        );

        withdrawAmount = WISE_LENDING.withdrawExactShares(
            _nftId,
            PENDLE_CHILD,
            _withdrawShares
        );
        
        _safeTransfer(
            PENDLE_CHILD,
            msg.sender,
            withdrawAmount
        );
    }

```

## Recommended Mitigation Steps:
Create an interface in the `IWiseLending` with an external function for 
```javascript
    function healthStateCheck() external
```

Add additional checks to check for the health State of positions in `PendlePowerFarm::_manuallyWithdrawShares` using the `_healthStateCheck()` 
```diff
     function _manuallyWithdrawShares(
        uint256 _nftId,
        uint256 _withdrawShares
    )
        internal
    {
        uint256 withdrawAmount = WISE_LENDING.cashoutAmount(
            PENDLE_CHILD,
            _withdrawShares
        );

+       withdrawAmount = WISE_LENDING.healthStateCheck(nftId)

        withdrawAmount = WISE_LENDING.withdrawExactShares(
            _nftId,
            PENDLE_CHILD,
            _withdrawShares
        );
        
        _safeTransfer(
            PENDLE_CHILD,
            msg.sender,
            withdrawAmount
        );
    }
```


## Assessed type

Context
Bad accounting bug on `WiseSecurity::checkBadDebtLiquidation()` leads to permanently unclaimable incentives and fees
Audit: 2024-02-wise-lending-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseSecurity/WiseSecurity.sol#L427-L429
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/FeeManagerHelper.sol#L94
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseSecurity/WiseSecurity.sol#L431-L434
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/FeeManagerHelper.sol#L83
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/FeeManagerHelper.sol#L147-L149
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/FeeManagerHelper.sol#L157-L159
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/FeeManagerHelper.sol#L179-L181
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/FeeManager.sol#L663-L670
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/FeeManager.sol#L697-L699


# Vulnerability details

## Impact

The `WiseSecurity::checkBadDebtLiquidation()` got a bad accounting bug while updating the global bad debt (i.e., [`totalBadDebtETH` variable](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/DeclarationsFeeManager.sol#L117)). 

This bug can be triggered by normal liquidation events or even by an attacker who forces the liquidable position (with bad debt) to be liquidated twice (i.e., executing the [`WiseLending::liquidatePartiallyFromTokens()`](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseLending.sol#L1250) upon the target position twice). 

In addition to the attack cost, an attacker can even pay `1 wei` (in terms of the payback token) for each liquidation by specifying the [`_shareAmountToPay` parameter == 0](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseLending.sol#L1255) when invoking the `liquidatePartiallyFromTokens()`. Thus, the attack cost is very cheap.

Subsequently, this bug will permanently increment the `totalBadDebtETH` variable (global bad debt). In other words, the `totalBadDebtETH` variable will not be able to decrease to 0 anymore, even if all bad debt of that associated position is paid back in full.

As a result, the `incentiveOwnerA` and `incentiveOwnerB` will [no longer receive their incentives](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/FeeManager/FeeManager.sol#L663-L670) via the `FeeManager::claimWiseFees()` since the `_d
Potential Loss of Funds in WiseLending Contract Due to Incorrect Repayment Calculations
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#L1161-L1198
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseLending.sol#L1204-L1238


# Vulnerability details


## Impact
Borrowers could lose the excess amount of ERC20 to be paid back, as it would be stuck inside the WiseLending contract and never refunded to the borrower.

## Proof of Concept

This issue involves two scenarios where the `paybackExactAmount()` and `paybackExactShares()` functions are called with parameters that could lead to incorrect repayment calculations. The contract should include checks to ensure that the repayment amount and the corresponding shares do not exceed the borrower's current borrow shares.

**Scenario 1: paybackExactAmount() Function** https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseLending.sol#L1161-L1198

Bob has a position in the WiseLending contract with an NFT ID of `12345`. He has borrowed a token with the address `0xBorrowedToken` and has a maximum of `200` borrow shares (`maxBorrowShares`) for this token. Bob calls the `paybackExactAmount()` function with an `_amount` of `1000`, which results in `500` shares to repay. However, the contract does not include a check to ensure that `paybackShares` does not exceed `maxBorrowShares`, leading to an incorrect update of the contract's state and the loss of `800` units of the borrowed token.

**Scenario 2: paybackExactShares() Function** https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseLending.sol#L1204-L1238

Alice has a position in the WiseLending contract with an NFT ID of `67890`. She has borrowed a token with the address `0xBorrowedToken` and has a maximum of `300` borrow shares (`maxBorrowShares`) for this token. Alice calls the `paybackExactShares()` function with `_shares` of `400`, which results in `2000` units of the borrowed token to repay. However, the contract does not include a check to ensure that `repaymentAmount` does not exceed `maxBorrowShares`, leading to an incorrect update of the contract's state and the loss of `1700` units of the borrowed token.

**Detailed difference between both scenarios:**

Both issues involve incorrect repayment calculations that could lead to a loss of funds for borrowers. The first issue is related to the amount of the borrowed token being repaid, while the second issue is related to the number of shares being repaid. In both cases, the contract should include checks to ensure that the repayment amount and the corresponding shares do not exceed the borrower's current borrow shares.

## Tools Used
Manual Review

## Recommended Mitigation Steps

Include a check in the `_handlePayback()` function to ensure that the `paybackShares` do not exceed the `maxBorrowShares` when the `paybackExactAmount(