xanoutas/solidity-security-findings huggingface dataset:
Rebase (underlying ERC20) tokens would break the property of supply and lead to a loss of funds
Audit: 2023-10-wildcat-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarket.sol#L86


# Vulnerability details

## Impact
According to the docs, the lender that deposits 133.7 XYZ tokens into a market will receive 133.7 market tokens - with the market token name depending on what was selected by the borrower when the market was launched.

However, the above architecture does not handle the case when XYZ is a rebasing (or elastic) token whose supply is algorithmically adjusted. The issue might lead to a permanent loss of funds as tokens would stay locked in the contract.

The issue also breaks the following property: `The supply of the market token and assets owed by the borrower should always match.`

## Proof of Concept
[Wildcat-Gitbook#deposits](https://wildcat-protocol.gitbook.io/wildcat/using-wildcat/day-to-day-usage/lenders#deposits)
[WildcatMarket.sol#L86](https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarket.sol#L86)

## Tools Used
Manual Review

## Recommended Mitigation Steps
1. You can explicitly state in the documentation that you do not support rebasing mechanism. 
2. Alternatively, when rebasing tokens go down in value, you should have a method to update the market tokens' balances accordingly. 
And when they go up in value, you should add a method to actually transfer the excess tokens out of the protocol. This is a complex solution.


## Assessed type

ERC20
Using ``WildCatMarketController.setAnnualInterestBips()`` a borrower can set a new ``annualInterestBips`` above /below the maximum/minimum respectively
Audit: 2023-10-wildcat-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketController.sol#L67-L68
https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketController.sol#L468-L488
https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketConfig.sol#L149-L159


# Vulnerability details

## Impact
When markets are deployed using the Factory ``deployControllerAndMarket()`` or with the controller``deployMarket()``, a check is performed on the ``AnnualInterestBips``
It is ensured that the APR is always less than ``maximumAnnualInterestBips`` preset in the factory and greater than the ``MinimumAnnualInterestBips``
However, a borrower can increase or reduce the market's APR to any value using the ``WildcatMarketController.setAnnualInterestBips()``
It can be set to zero, or any amount greater than the allowed maximum from the Factory contract. 
After a discussion with the spponsor, this was confirmed to be an issue.
## Proof of Concept
The function ``setAnnualInterestBips()`` does no checks to ensure the limiters on the new ``annualInterestBips``.
```solidity
function setAnnualInterestBips(
    address market,
    uint16 annualInterestBips
  ) external virtual onlyBorrower onlyControlledMarket(market) {
    // If borrower is reducing the interest rate, increase the reserve
    // ratio for the next two weeks.
    if (annualInterestBips < WildcatMarket(market).annualInterestBips()) {
      TemporaryReserveRatio storage tmp = temporaryExcessReserveRatio[market];

      if (tmp.expiry == 0) {
        tmp.reserveRatioBips = uint128(WildcatMarket(market).reserveRatioBips());

        // Require 90% liquidity coverage for the next 2 weeks
        WildcatMarket(market).setReserveRatioBips(9000);
      }

      tmp.expiry = uint128(block.timestamp + 2 weeks);
    }

    WildcatMarket(market).setAnnualInterestBips(annualInterestBips);
  }
```
The sanity check is very important this point because there also is no check inside the market contract except the BIP value. 
## Tools Used
Manual Review
## Recommended Mitigation Steps

As discussed with the sponsor, the max and min values can be stored as an immutable in the market contract and checked directly in the ``WildCatMarket.setAnnualInterestBips()`` function. 



## Assessed type

Math
Continuous Borrowing Without Debt Reduction in borrow Function
Audit: 2023-10-wildcat-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/main/src/market/WildcatMarket.sol#L124


# Vulnerability details

## Impact
The code for the borrow function allows borrowers to repeatedly withdraw funds from the market without reducing their borrowable amount. This oversight can have several significant impacts:

Excessive Debt Accumulation: Borrowers can accumulate debt without any requirement to reduce it, potentially exceeding the collateral obligations set by the protocol.

Increased Risk: This behavior exposes lenders and the protocol to greater risk, as borrowers can accumulate larger debts that may become difficult to repay.

Market Instability: Continuous borrowing without debt reduction can lead to market instability and potential disruptions in the protocol's functioning.

## Proof of Concept


    function borrow(uint256 amount) external onlyBorrower nonReentrant {
    MarketState memory state = _getUpdatedState();
    if (state.isClosed) {
      revert BorrowFromClosedMarket();
    }
    uint256 borrowable = state.borrowableAssets(totalAssets());
    if (amount > borrowable) {
      revert BorrowAmountTooHigh();
    }
    _writeState(state);
    asset.safeTransfer(msg.sender, amount);
    emit Borrow(amount);
    }

The borrow function permits borrowers to withdraw a specified amount from the market.

There is no mechanism in place to enforce repayments or reduce the borrowing capacity of the borrower after each withdrawal as borrowable is always the same amount.

As a result, the borrower can repeatedly call the borrow function to withdraw additional funds without any reduction in their borrowing limit

## Tools Used
manual review

## Recommended Mitigation Steps
Implement a dynamic calculation for the borrowable amount that takes into account the borrower's outstanding debt and collateral obligations. This ensures that the borrowable amount decreases as debt accumulates.


## Assessed type

Access Control
Reversed order of parameters in allowance function call
Audit: 2023-10-wildcat-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/main/src/market/WildcatMarket.sol#L60
https://github.com/code-423n4/2023-10-wildcat/blob/main/src/market/WildcatMarketToken.sol#L46


# Vulnerability details

## Impact
When trying to pull assets from an approver to the allowed spender, the parameters that are used for the `allowance` function call are not in the same order that is used later in the call to `safeTransferFrom`.

## Proof of Concept
```solidity
File: src/market/WildcatMarket.sol

60:     asset.safeTransferFrom(msg.sender, address(this), amount);

```

```solidity
File: src/market/WildcatMarketToken.sol

46:     uint256 allowed = allowance[from][msg.sender];

```

## Tools Used

## Recommended Mitigation Steps
Reverse the order of parameters in `allowance` function call to fit the order that is in the `safeTransferFrom` function call.


## Assessed type

Invalid Validation
Malicious borrower can set annual interest rate to an insignificant amount without being sanctioned
Audit: 2023-10-wildcat-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketController.sol#L468-L488


# Vulnerability details

## Impact
Reducing the annual interest rate of a market results in sanctions for the borrower by increasing the reserve ratio to 90% for a span of two weeks. Currently, it is assumed that no borrower would deploy a market with a reserve ratio of such high percentage as it would not be beneficial for them.
However, a reserve ratio in the range of 90% would not only attract more lenders to deposit into the protocol but would open the door to a serious vulnerability.
A market with a reserve ratio near, equal to or higher than 90% protects the borrower from being sanctioned when decreasing the annual interest rate as it would not bring any impactful changes to the reserve ratio. In fact, decreasing the interest rate is beneficial for the borrower if the market has a reserve ratio equal to or higher than 90%. 
Consequently, a malicious borrower can exploit this the following way: after deploying the market they decrease the annual interest rate to an insignificant amount without being negatively affected and without being required to return any funds to fill in the reserve ratio(as it was 90% before the decrease of the interest rate and they would not be delinquent). After that, they make use of the funds outside of the reserve ratio, paying an insignificant amount of interest.

## Proof of Concept
1. Malicious borrower needs 1000 USDT for some purpose. Instead of deploying a market with an ordinary reserve ratio of 10% they deploy a market with a reserve ratio of 90% and a max total supply of 10,000 USDT.
2. A lender gets deceived by the good offer assuming they would be acquiring large interest safely, due to the large sum and low borrowable amount.
3. Borrower immediately decreases the interest rate to an insignificant amount, escaping from any sanctions and makes use of the 1000 USDT they initially needed without having to pay a large interest.

## Tools Used
Manual review

## Recommended Mitigation Steps
There are no clear mitigations for this issue. Perhaps limiting the maximum reserve ratio to 50%-70% could be an effective fix.


## Assessed type

Other
Potential Reversion in closeMarket due to Insufficient Borrower's Balance
Audit: 2023-10-wildcat-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/main/src/market/WildcatMarket.sol#L129
https://github.com/code-423n4/2023-10-wildcat/blob/main/src/market/WildcatMarket.sol#L154


# Vulnerability details

## Impact
The design flaw in the borrowing mechanism  in case currentlyHeld < totalDebts ,could allow a malicious or careless borrower to effectively block the market's closure. If the borrower transfers the borrowed tokens to another address, the check in closeMarket will fail, making it impossible for the controller to close the market under normal procedures.

The borrow function allows the borrower to borrow a specific amount from the market.
There's no restriction on the borrower transferring these borrowed assets elsewhere.
When the controller attempts to close the market with closeMarket, and currentlyHeld < totalDebts, the function tries to pull the remaining debts from the borrower.
If the borrower's balance is insufficient (because they transferred the assets), safeTransferFrom will revert, blocking the market's closure.

## Proof of Concept

    function borrow(uint256 amount) external onlyBorrower nonReentrant {
    MarketState memory state = _getUpdatedState();
    if (state.isClosed) {
      revert BorrowFromClosedMarket();
    }
    uint256 borrowable = state.borrowableAssets(totalAssets());
    if (amount > borrowable) {
      revert BorrowAmountTooHigh();
    }
    _writeState(state);
    asset.safeTransfer(msg.sender, amount);
    emit Borrow(amount);
    }
  
    function closeMarket() external onlyController nonReentrant {
    ..
    if (currentlyHeld < totalDebts) {
      // Transfer remaining debts from borrower
      asset.safeTransferFrom(borrower, address(this), totalDebts - currentlyHeld);
    ..
    }

## Tools Used
manual review

## Recommended Mitigation Steps
Ensure that borrowers repay their previous borrowings before borrowing again. This reduces the chances of accumulating a debt they cannot repay.


## Assessed type

DoS
OpenZeppelin's EnumerableSet data structure
Audit: 2023-10-wildcat-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/main/src/WildcatArchController.sol#L82
https://github.com/code-423n4/2023-10-wildcat/blob/main/src/WildcatArchController.sol#L125
https://github.com/code-423n4/2023-10-wildcat/blob/main/src/WildcatArchController.sol#L168
https://github.com/code-423n4/2023-10-wildcat/blob/main/src/WildcatArchController.sol#L211
https://github.com/code-423n4/2023-10-wildcat/blob/main/src/WildcatMarketController.sol#L122
https://github.com/code-423n4/2023-10-wildcat/blob/main/src/WildcatMarketController.sol#L201
https://github.com/code-423n4/2023-10-wildcat/blob/main/src/WildcatMarketControllerFactory.sol#L135
https://github.com/code-423n4/2023-10-wildcat/blob/main/src/market/WildcatMarketWithdrawals.sol#L25


# Vulnerability details

## Impact
The `WildcatArchController.sol`, `WildcatMarketController.sol`, `WildcatMarketControllerFactory.sol` and `WildcatMarketWithdrawals.sol`  contracts are vulnerable to a Denial of Service (DoS) attack due to the usage of the `values()` method from the `EnumerableSet` library. When the `values()` method is used to retrieve the entire set of addresses, it involves copying the entire storage to memory. If the set size is substantial, this operation can become gas-expensive, potentially leading to a Denial of Service (DoS) attack. An attacker can exploit this vulnerability to increase gas costs significantly, disrupting the normal operation of the affected contracts and making them uncallable if the set size becomes too large.

## Proof of Concept

According to [OpenZeppelin EnumerableSet docs](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/EnumerableSet.sol#L359-L366):

```
  /**
   * @dev Return the entire set in an array
   *
   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
   * this function has an unbounded cost, and using it as part of a state-changing function may render the function
   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
   */
```

```solidity
File: src/WildcatArchController.sol

82:     return _borrowers.values();

125:     return _controllerFactories.values();

168:     return _controllers.values();

211:     return _markets.values();

```

```solidity
File: src/WildcatMarketController.sol

122:     return _authorizedLenders.values();

201:     return _controlledMarkets.values();

```

```solidity
File: src/WildcatMarketControllerFactory.sol

135:     return _deployedControllers.values();

```

```solidity
File: src/market/WildcatMarketWithdrawals.sol

25:     return _withdrawalData.unpaidBatches.values();

```

## Tools Used
VS Code

## Recommended Mitigation Steps
Limit Data Retrieval - avoid returning entire sets of data if the set size could grow significantly.
Steal funds
Audit: 2023-10-wildcat-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketBase.sol#L163-L187


# Vulnerability details

## Impact
Steal funds
A state variable is changed after a contract uses call.value. The attacker uses a fallback function—which is automatically executed after Ether is transferred from the targeted contract—to execute the vulnerable function again, before the state variable is changed.
Reentrancy in WildcatMarketBase._blockAccount(MarketState,address) (src/market/WildcatMarketBase.sol#163-187):
External calls:
- escrow = IWildcatSanctionsSentinel(sentinel).createEscrow(accountAddress,borrower,address(this)) (src/market/WildcatMarketBase.sol#172-176)
State variables written after the call(s):
- _accounts[escrow].scaledBalance += scaledBalance (src/market/WildcatMarketBase.sol#178)
WildcatMarketBase._accounts (src/market/WildcatMarketBase.sol#68) can be used in cross function reentrancies:
- WildcatMarketBase.getAccountRole(address) (src/market/WildcatMarketBase.sol#299-301)
- WildcatMarketBase.scaledBalanceOf(address) (src/market/WildcatMarketBase.sol#292-294)
- _accounts[accountAddress] = account (src/market/WildcatMarketBase.sol#185)
WildcatMarketBase._accounts (src/market/WildcatMarketBase.sol#68) can be used in cross function reentrancies:
- WildcatMarketBase.getAccountRole(address) (src/market/WildcatMarketBase.sol#299-301)
- WildcatMarketBase.scaledBalanceOf(address) (src/market/WildcatMarketBase.sol#292-294)

Description:

Detection of the [reentrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy). Do not report reentrancies that involve Ether (see `reentrancy-eth`).



## Proof of Concept
https://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit

function splitDAO(
  uint _proposalID,
  address _newCurator
) noEther onlyTokenholders returns (bool _success) {

  ...
  // XXXXX Move ether and assign new Tokens.  Notice how this is done first!
  uint fundsToBeMoved =
      (balances[msg.sender] * p.splitData[0].splitBalance) /
      p.splitData[0].totalSupply;
  if (p.splitData[0].newDAO.createTokenProxy.value(fundsToBeMoved)(msg.sender) == false) // XXXXX This is the line the attacker wants to run more than once
      throw;

  ...
  // Burn DAO Tokens
  Transfer(msg.sender, 0, balances[msg.sender]);
  withdrawRewardFor(msg.sender); // be nice, and get his rewards
  // XXXXX Notice the preceding line is critically before the next few
  totalSupply -= balances[msg.sender]; // XXXXX AND THIS IS DONE LAST
  balances[msg.sender] = 0; // XXXXX AND THIS IS DONE LAST TOO
  paidOut[msg.sender] = 0;
  return true;
}

## Tools Used

Slither

## Recommended Mitigation Steps

bool private locked = false;

modifier noReentrancy() {
    require(!locked, "Reentrant call detected!");
    locked = true;
    _;
    locked = false;
}

function _blockAccount(MarketState memory state, address accountAddress) internal noReentrancy {
    Ac
Precision Loss in Interest Rate Calculation
Audit: 2023-10-wildcat-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/main/src/libraries/MathUtils.sol#L37


# Vulnerability details

## Impact
The calculateLinearInterestFromBips function is susceptible to precision loss when the accumulatedInterestRay is smaller than the constant SECONDS_IN_365_DAYS. The division operation can result in rounding down to zero, leading to incorrect interest rate calculations. This precision loss can have a significant impact on the accuracy of interest accrual, especially when dealing with small interest rates or short time intervals.
Users may experience unexpected financial losses or gains due to inaccurate interest rate calculations. This can affect their overall financial position and potentially result in monetary losses.


## Proof of Concept

    function calculateLinearInterestFromBips(
    uint256 rateBip,
    uint256 timeDelta
    ) internal pure returns (uint256 result) {
    uint256 rate = rateBip.bipToRay();
    uint256 accumulatedInterestRay = rate * timeDelta;
    unchecked {
      return accumulatedInterestRay / SECONDS_IN_365_DAYS;
    }
    }

## Tools Used
Manual review

## Recommended Mitigation Steps
Floating-Point Arithmetic: Use floating-point arithmetic or fixed-point representations with higher precision to perform the division, ensuring that precision is not lost.




## Assessed type

Math
Underflow Vulnerability in transferFrom Function
Audit: 2023-10-wildcat-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/main/src/market/WildcatMarketToken.sol#L50


# Vulnerability details

## Impact
The transferFrom function in the contract is susceptible to an underflow vulnerability when the allowance (allowed) is zero, and a user attempts to transfer a non-zero amount. This vulnerability can lead to an underflow in the calculation of the new allowance (newAllowance), resulting in an unintended large positive value. This, in turn, allows users to perform unauthorized transfers, bypassing the intended allowance mechanism.

for a non allowed user,  allowance is zero, a transfer of any non-zero amount can trigger an underflow. The subtraction operation (newAllowance = allowed - amount) results in newAllowance becoming an excessively large positive number.

Unintended Transfer: With the large newAllowance, the user can make unauthorized transfers of substantial amounts, bypassing the intended allowance mechanism.


## Proof of Concept



    function transferFrom(
    address from,
    address to,
    uint256 amount
    ) external virtual nonReentrant returns (bool) {
    uint256 allowed = allowance[from][msg.sender]; // this would be 0

    // Saves gas for unlimited approvals.
    if (allowed != type(uint256).max) { //check pass as 0 != (uint256).max
      uint256 newAllowance = allowed - amount; // underflow
      _approve(from, msg.sender, newAllowance);
    }

    _transfer(from, to, amount);

    return true;
    }

## Tools Used
Manual review

## Recommended Mitigation Steps
Bounds Checking: Add bounds checking to ensure that the newAllowance calculation does not result in an underflow. If allowed is zero, do not perform the subtraction.




## Assessed type

Under/Overflow