xanoutas/solidity-security-findings huggingface dataset:
Issues Arising from Liquidation Reward Misvaluation/Miscalculation
Audit: 2024-06-size-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L98
https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L90-L92
https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L100
https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L119


# Vulnerability details

## Impact

The liquidation mechanism currently utilizes the `BorrowAtoken` for calculating the liquidator's fee instead of the collateral's actual value. This incorrect valuation can lead to significant issues in the liquidation process:

1. **Inaccurate Liquidation Rewards**: Using `BorrowAtoken` (which has a decimal value of 6) instead of the actual collateral token (which typically has a decimal value of 18) results in an underestimation of the liquidator's reward. This discrepancy causes the calculated liquidator profit to be consistently lower than it should be.

2. **Failed Liquidations**: Liquidators aiming for profitability set minimum values for rewards. Because of the underestimation, these liquidations often revert and fail, particularly when the reward calculated using `BorrowAtoken` is less than the expected threshold for profitable liquidation.

3. **Financial Inefficiency**: Liquidators who do not adjust for this discrepancy receive less collateral than they should, reducing the financial incentives to participate in liquidations. This could lead to fewer liquidations being performed, potentially causing issues in maintaining protocol health and debt positions.

## Proof of Concept

**1. Code Reference**: The calculation of the liquidator's fee using `BorrowAtoken` can be found in the liquidation process logic.

- **GitHub Link**: [Liquidation Code in libraries]
https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L98

```solidity
Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT);
```
The debtPosition.futureValue is in BorrowAtoken which is a 6 decimal place, instead of the collateral value which is what we are interested in.

**2. Incorrect Calculation Example**:

- Liquidation calculation using `BorrowAtoken`:
```solidity
uint256 liquidatorReward = Math.min(
    assignedCollateral - debtInCollateralToken,
    Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
);
```
The value gotten will always be 
>> Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT) 

since it is in decimal 6 and thus always will be lesser than the difference between collateral value available which is in 18 decimals . 


using the following values to point out these impact 

A borrower has a loan of  future value =
Incorrect calculation of swapFees in `getCreditAmountIn` function
Audit: 2024-06-size-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/AccountingLibrary.sol#L248-L249
https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/AccountingLibrary.sol#L253-L256
https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/actions/BuyCreditMarket.sol#L195-L196
https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/actions/SellCreditMarket.sol#L201-L202
https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/actions/SellCreditMarket.sol#L173-L175


# Vulnerability details

## Vulnerability Details

In the `getCreditAmountIn` function, the swap fee is incorrectly accounted for, leading to an underestimation of fees. The issue arises from how the swap fee is deducted and then recalculated in the formula.

### Problem Explanation

Reference document for the original formula.

[https://docs.size.credit/technical-docs/contracts/3.3-market-orders](https://docs.size.credit/technical-docs/contracts/3.3-market-orders)

1. **Formula for Cash Amount Out (`cashAmountOut`)**:
   
   The formula for the amount of credit (`A`) before fees:
   $$A = \frac{(V + f) (1 + r)}{1 - k\Delta T}$$

   Here, `k` is the swap fee percentage, `ΔT` is the remaining time to maturity, `V` is the cash amount out, `f` is the fragmentation fee, and `r` is the rate per tenor. This formula correctly charges the swap fee by deducting the credit by `k%`.

   Explanation

   - The $$\frac{A}{1 + r}$$ is the amount of cash the credit buyer values the amount of credit he is buying, before fees
   - Then fees are applied and
      - `KΔT` is charged since the swap fee is a function of the remaining lifetime of the loan and is applied to the cash side of the trade
      - The higher `K` and `ΔT` and the higher the amount `A` to be sold to get the desired amount out
   - `f` is charged to cover the gas costs related to credit fragmentation
      - The higher `f` and the higher the amount `A` to be sold to get the desired amount out

2. **Current Implementation Issues**:

   ```solidity
   maxCashAmountOut: Math.mulDivDown(creditPosition.credit, PERCENT - state.getSwapFeePercent(tenor), PERCENT + ratePerTenor),
   ```
   
   In scenarios where `cashAmountOut` is equal to `maxCashAmount`:

   ```solidity
   creditAmountIn = maxCredit;
   fees = Math.mulDivUp(cashAmountOut, swapFeePercent, PERCENT);
   ```

[https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/AccountingLibrary.sol#L248-L249](https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/AccountingLibrary.sol#L248-L249)


   In scenarios where `cashAmountOut` is less than `maxCashAmountOutFragmentation`:

   ```solidity
   creditAmountIn = Math.mulDivUp(
       cashAmountOut + state.feeConfig.fragmentationFee, PERCENT + ratePerTenor, PERCENT - swapFeePercent
   );
   fees = Math.mulDivUp(cashAmountOut, swapFeePercent, PERCENT) + state.feeConfig.fragmentationFee;
   ```

[https://github.com/code-423n4/2024-06-size/blob/main/src/li
Unexpected reverts or no incentives during liquidation due to wrong liquidatorReward calculation.
Audit: 2024-06-size-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L95-L100


# Vulnerability details

## Impact
* Unexpected DOS in every ```executeLiquidate``` function call even when the liquidator set a valid ```minimumCollateralProfit```.
* Incase the liquidator doesn't set any ```minimumCollateralProfit``` he only gets dust amount of collaterlTokens as reward. 
* No incentives leads to less competition which increases the risk of protocol incurring bad debt or lenders taking a loss. So, the protocol bots are the only entity that will likely call ```executeLiquidate``` in this case. And they will be forced to spend more than the rewards earned to keep up with every liquidation. 
* this will also affect the ```liquidateWithReplacement```.

## Proof of Concept
During liquidations we see that the ```liquidatorReward``` is calculated and added to ```liquidatorProfitCollateralToken``` and then sent to the liquidator as an award for calling ```executeLiquidate```. :
```javascript
// profitable liquidation
        if (assignedCollateral > debtInCollateralToken) {
            uint256 liquidatorReward = Math.min(
                assignedCollateral - debtInCollateralToken,
                Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
            );
            liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;
```

```javascript
 state.data.collateralToken.transferFrom(debtPosition.borrower, msg.sender, liquidatorProfitCollateralToken);
```

But if we look closely at ```Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)```, it uses ```debtPosition.futureValue``` to calculate the reward and sent it as ```collateralToken```. This is wrong because ```debtPosition.futureValue``` is in 1e6 precision and the ```collateralToken``` is in 1e18 precision which means we are basically sending dust amount of collateralTokens as a reward everytime a liquidation is done. 


Also, the ```liquidatorReward``` is assigned by choosing the minimum value between, ```assignedCollateral - debtInCollateralToken``` and ```Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)```.
Comparing them will always give us ```liquidatorReward``` = ```Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)``` because the first one is in 1e18 precision and the second one is in 1e6 precision. Obviously the second one will always be chosen over the first one, even when the first value is very less.




Example, a position with 1_000_000 debt is liquidated;

```liquidatorReward``` = ```1_000_000e6 * 0.05e18 * 1e18``` = ```50000e6```.
This seems like a valid reward for liquidating a position with 1 million ```debtToken``` but this is added to ```liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;``` and is sent as ``
Incorrect Reward Calculation in `executeLiquidate`
Audit: 2024-06-size-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L98


# Vulnerability details

## Impact
Liquidators will receive less reward which will disincentivize them to maintain the health of the system. 

## Proof of Concept

Liquidation should calculate the reward in the denomination of the collateral token, which is 18 decimals. However, if we examine the reward calculation from L94-L97, it's calculated using a future value that is only 6 decimals, which is incorrect.

```solidity

 function executeLiquidate(State storage state, LiquidateParams calldata params)
        external
        returns (uint256 liquidatorProfitCollateralToken)
    {
      ...SNIP...

        // profitable liquidation
        if (assignedCollateral > debtInCollateralToken) {
  L96:          uint256 liquidatorReward = Math.min(
  L97:          assignedCollateral - debtInCollateralToken,
  L98:          Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
  L99:          );
  L100:       liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;

            // split the remaining collateral between the protocol and the borrower, capped by the crLiquidation
            uint256 collateralRemainder = assignedCollateral - liquidatorProfitCollateralToken;

            // cap the collateral remainder to the liquidation collateral ratio
            //   otherwise, the split for non-underwater overdue loans could be too much
            uint256 collateralRemainderCap =
                Math.mulDivDown(debtInCollateralToken, state.riskConfig.crLiquidation, PERCENT);

            collateralRemainder = Math.min(collateralRemainder, collateralRemainderCap);

            protocolProfitCollateralToken = Math.mulDivDown(collateralRemainder, collateralProtocolPercent, PERCENT);
        } else {
            // unprofitable liquidation
            liquidatorProfitCollateralToken = assignedCollateral;
        }

        state.data.borrowAToken.transferFrom(msg.sender, address(this), debtPosition.futureValue);
        state.data.collateralToken.transferFrom(debtPosition.borrower, msg.sender, liquidatorProfitCollateralToken);
        state.data.collateralToken.transferFrom(
            debtPosition.borrower, state.feeConfig.feeRecipient, protocolProfitCollateralToken
        );

        debtPosition.liquidityIndexAtRepayment = state.data.borrowAToken.liquidityIndex();
        state.repayDebt(params.debtPositionId, debtPosition.futureValue);
    }
```

For instance:

- If the future value of the loan is 1100e6, the assignedCollateral is 10e18, the debtInCollateral is 7e18, and the liquidationRewardPercent is 0.05e18 (5%).
- Now, according to the calculation in the code, the minimum of two values will be 1100e6 * 0.05e18 / 1e18 = **55000000**.
- As we can see, `55e6` in terms of WETH is too small for the liquidation rewards.

If we have a console log of the
LiquidatorReward is not properly calculated
Audit: 2024-06-size-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L96-L99


# Vulnerability details

## Impact

High, zero liquidation incentive as the liquidation reward is practically zero.

## Proof of Concept

in `liquidate::executeLiquidate` function the  `liquidatorReward` is calculated as ![image](https://gist.github.com/assets/133224432/25f8f62c-d48d-41d4-86ec-ad8bb08fae48)
The issue is that `assignedCollateral` and `dabtInCollateralToken` have 18 decimals(as collateral is weth), whereas `debtPosition.futureValue` is in Usdc hence 6 decimals. That means the `liquidatorReward` will definitely always equal the rhs(`Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)`) i.e 5% of futureValue in 6 decimals.

## Tools Used

Manual Review

## Recommended Mitigation Steps

Replace `debtPosition.futureValue` with `debtInCollateralToken` as it's the equivalent amount in collateral

```diff
 function executeLiquidate(State storage state, LiquidateParams calldata params)
        external
        returns (uint256 liquidatorProfitCollateralToken)
    {
        //...code...

        uint256 assignedCollateral = state.getDebtPositionAssignedCollateral(debtPosition);
@>      uint256 debtInCollateralToken = state.debtTokenAmountToCollateralTokenAmount(debtPosition.futureValue);
        uint256 protocolProfitCollateralToken = 0;

        // profitable liquidation
        if (assignedCollateral > debtInCollateralToken) {
            uint256 liquidatorReward = Math.min(
                assignedCollateral - debtInCollateralToken,
-               Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
+               Math.mulDivUp(debtInCollateralToken, state.feeConfig.liquidationRewardPercent, PERCENT)
            );
            liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;

        //...code...
        }
    }
```



## Assessed type

Decimal
Liquidator's reward are wrongly computed because they are not converted to its value worth in collateral.
Audit: 2024-06-size-findings
Severity: HIGH

# Lines of code

 https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/actions/Liquidate.sol#L98


# Vulnerability details

## Impact
Liquidators will be under-rewarded, and, liquidated borrowers will keep more collateral because of incorrectly rewarding the liquidators.

## Proof of Concept
When executing a profitable liquidation, [the `liquidationReward` is computed](https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/actions/Liquidate.sol#L96-L99) to be the minimum between the leftover collateral after covering a 100% of the debt (`assignedCollateral - debtInCollateralToken`), or, a percentage (`liquidationRewardPercent`) of the amount of liquidated debt.

The computed value based on the `liquidationRewardPercent` is nominated in the Debt Value (USDC), which is scaled by 6 decimals, and, the Collateral value is scaled by 18 decimals, apart from the different market values of each of those two assets, Debt is nominated in USDC, and Collateral is nominated in ETH/WETH.

**The problem is caused due to not converting the computed value to its worth in Collateral Token.** For example:
- If the `liquidationReward` is computed to be 1k USDC. 1k USDC is expressed as 1000e6, but, because the `liquidationReward` is paid in collateral, `1000e6` in collateral value is not worth the 1k USDC that the liquidator should receive.
  - For example, if ETH is worth 2k USDC. Assume a liquidationReward of 1k USDC. **The liquidator should receive 0.5 ETH (5e17) of collateral**, ***but instead, it would receive 1000e6 === 1e9 of collateral***

As explained in the previous example, the liquidators are under-rewarded by orders of magnitude, and the liquidated borrower benefits from this because the liquidators are going to seize less collateral than they should be able to.

```
function executeLiquidate(State storage state, LiquidateParams calldata params)
    ...
{
    ...

    // profitable liquidation
    if (assignedCollateral > debtInCollateralToken) {
        uint256 liquidatorReward = Math.min(
            assignedCollateral - debtInCollateralToken,
            //@audit-issue => Value is not computed to its worth in Collateral.
            Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
        );
        //@audit => Liquidators are paid with collateral, including their rewards
        liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;

        ...
    } else {
        ..
    }

    ...

    //@audit => Liquidators are paid with collateral, including their rewards
    state.data.collateralToken.transferFrom(debtPosition.borrower, msg.sender, liquidatorProfitCollateralToken);

    ...
}
```

## Tools Used
Manual Audit

## Recommended Mitigation Steps
Convert the computed `liquidationReward` based on the `liquidationRewardPercent` to its equivalent in collateral using the [`AccountingLibrary.debtTokenAmountToCollateralTokenAmount() function`](https://github.com/code-42
Wrong `liquidatorReward` in a profitable liquidation.
Audit: 2024-06-size-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L98


# Vulnerability details

The `liquidatorReward` is a variable used to calculate the `liquidatorProfitCollateralToken` (see second arrow below)and the collateral tokens took it from the liquidatee and send it to the msg.sender (see the last arrow below).

```solidity

  function executeLiquidate(State storage state, LiquidateParams calldata params)
        external
        returns (uint256 liquidatorProfitCollateralToken)
    {
        DebtPosition storage debtPosition = state.getDebtPosition(params.debtPositionId);
        LoanStatus loanStatus = state.getLoanStatus(params.debtPositionId);
        uint256 collateralRatio = state.collateralRatio(debtPosition.borrower);


       ...

        // profitable liquidation
        if (assignedCollateral > debtInCollateralToken) {
            uint256 liquidatorReward = Math.min(
                assignedCollateral - debtInCollateralToken,
                Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
            );   <-----------
            liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;  <-----------

         ...

        state.data.borrowAToken.transferFrom(msg.sender, address(this), debtPosition.futureValue); 
        state.data.collateralToken.transferFrom(debtPosition.borrower, msg.sender, liquidatorProfitCollateralToken); <-----------
       ...
    }


```
[[Link]](https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L75C3-L126C6)

the  `liquidatorReward` is been wrongly set it because the logic is taking the min value between a collateral token and cash token(borrow token). and you can not just compere two different things is like compere apple with watermelon.


## Impact
`liquidatorReward` is been wrongly set it leading to not the correct amount of rewards sent to liquidators.

## Proof of Concept

As we can see below the functions is trying to cap the liquidator reward with ` Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)` the problem is that the comparation is wrong because is taking the min value between collateral token which is ether and borrow token which is usd. 

```solidity

 uint256 liquidatorReward = Math.min(
                assignedCollateral - debtInCollateralToken,
                Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
            );   

```


if the min value is `Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)` then you will be summing collateral token (ether) with  borrow token(usd):

```solidity

liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward; 

```


## Tools Used
Manual

## Recommended Mitigation Steps
Consider convert the c
Liquidator reward is incorrectly calculated during liquidation
Audit: 2024-06-size-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L96-#L99


# Vulnerability details

## Impact
The Size protocol measures risk using a collateralization ratio (collateral/debt). If this ratio falls below 130%, the position becomes eligible for liquidation. Liquidators are incentivized to liquidate debt positions by receiving percentage of the future value as reward. According to the docs, [`liquidationRewardPercent`](https://docs.size.credit/technical-docs/governance-variables-and-fees#:~:text=liquidationRewardPercent) is 5% of the debt's future value. However, an issue in [`executeLiquidate()`](https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L75) function results in incorrect reward calculation for liquidators, reducing their incentive to liquidate positions. 


## Proof of Concept
Consider a debt position with future value of 10,000 USDC, starting price - `$1000` per ETH and 15 ETH placed as collateral (150% collateral ratio). If the price drops to `$850` per ETH, the collateral ratio becomes approximately 127%, making the position eligible for liquidation. [Liquidator's reward is calculated as the minimum of two values](https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L96-#L99):

```solidity
uint256 liquidatorReward = Math.min(
                assignedCollateral - debtInCollateralToken,
                Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
            ); 
```
The first value is the difference between `assignedCollateral` and `debtInCollateralToken` where:
* `assignedCollateral` is the collateral assigned to current debtPosition.
* `debtInCollateralToken` is debtPosition future value converted to collateral token amount based on the current price of ETH

The second value is liquidation reward percent of the debtPosition future value. In our case it should be 500 USDC (5% of 10,000 USDC).  



So far, so good, but we have a problem: the two compared values have different decimal places. The first value is in 1e18, while the second is in 1e6.

Specifically the second value: `(10_000e6 * 0.05e18) / 1e18` result in `500e6`. 

After that `liquidatorReward` is added to `debtInCollateralToken` to form `liquidatorProfitCollateralToken`:
```solidity
                                            1e18        +      1e6
liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;
```
`debtInCollateralToken = (10_000e18 * 1e18) / 850e18 = 11764705882352941177`, to this value we are adding `500e6`. 
Since the liquidator receives their profit in collateral token (1e18), this results in significanly smaller reward than the intended 5%.

Paste the following test in `Liquidate.t.sol`:

```solidity
// @note you need to import : `forge-std/console.sol` 
func