xanoutas/solidity-security-findings huggingface dataset:
Users can pay less fees for the same amount of cash, protocol losses expected income
Audit: 2024-06-size-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/AccountingLibrary.sol#L228
https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/AccountingLibrary.sol#L249
https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/AccountingLibrary.sol#L256


# Vulnerability details

# **Users can pay less fees for the same amount of cash, protocol losses expected income**

---

### **Explanation && Impact** 📌📈

On the ***PoC-1*** below you will see that for the same tenor and same APR:

|               | `OPTION 1` | `OPTION 2` |
| ------------- | ---------- | ---------- |
| cash borrowed | 99_500000  | 100_000000 |
| Swap Fees     | 0_500000   | 0_500000   |

- _OPTION 1_: Bob puts a borrow offer, then Alice uses `buyCreditMarket` action
- _OPTION 2_: Alice puts lending offer, then Bob uses `sellCreditMarket` action

The problem arises from `sellCreditMarket` where the fees are calculated on the `cashAmountOut`, which is expected to have deducted from it the fees. `cashAmountOut` is actually the result of applying the fees to some amount **X**. Yet it is treated as if it were the amount **X** inside the function `getCreditAmountIn()`. And `X > cashAmountOut`, thus the proportional fees calculated on top of **X** will be bigger than the ones calcualted on `cashAmountOut`. So, as `cashAmountOut` is used in `getCreditAmountIn()`, that is why you are charging less fees for bigger amounts of cash.

In _OPTION-2_, you are calculating [here](https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/AccountingLibrary.sol#L249) the fees on an amount which has already fees deducted from it, thus calculating them in a smaller amount that the actual amount they should be calculated from. Which is X => `X = cashAmountOut / (1-swapFee)`.

> ℹ️ **Note** 📘 You can deduce `X = cashAmountOut / (1-swapFee)` from `X - swapFee*X = cashAmountOut`. This equation is basically answering the question, if `cashAmountOut` came from something **X** being deducted swapFee, what was that something **X**?

> ℹ️ **Note** 📘 We know that in `sellCreditMarket`, `cashAmountOut` is meant to have fees deducted as this amount is directly transfered to the borrower at the end of the function. [See here](https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/actions/SellCreditMarket.sol#L201). And the borrower pays `swapFee` due to the _cash-for-credit_ operation he is executing thus the amount he ends up receiving should be an amount with already deducted `swapFee` from.

The impact of this issue is pretty bad for the protocol as it receives less fees than the expected ones. Users can get more credit for the same amount of fees payed. This is a loss for the protocol as they are receiving less fees than they should.

Same happens when exiting loans via `sellCreditMarket` (***PoC-2***) when there is a partial exit. The lender of the position being exited can choose how much `swapFees` to be charged:

|               | `OPTION
`liquidatorReward` computation use `debtPosition.futureValue` in place of `debtInCollateralToken` in `Liquidate.sol`
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#L75
https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/actions/Liquidate.sol#L91
https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/AccountingLibrary.sol#L26-L35


# Vulnerability details

## Vulnerability details
 `debtPosition.futureValue` represent the amount of debt expressed in debt token (USDC), while `debtInCollateralToken` is the same amount [expressed in collateral tokens (WETH)](https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/actions/Liquidate.sol#L91)

 The function `Liquidate::executeLiquidate()` compute the liquidator reward expressed in collateral tokens, as proven by the `>>`in the code snippet below.

`L91` we see that `debtInCollateralToken` is `debtPosition.futureValue` converted to collateral representation by [`debtTokenAmountToCollateralTokenAmount`](https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/AccountingLibrary.sol#L26-L35)
Then `L96-98` `liquidatorReward` is equal to the minimum value between both terms the the `min` function. While the first term is expressed in collateral tokens, the second term (`L98`) is expressed in debt tokens.

If the debt token is USDC as in the state of the contest, this means `debtPosition.futureValue` is 6 decimals, meaning it will always be less than `debtInCollateralToken`, hence `liquidatorReward` will always be equal to the second term.

`L100` we see that `liquidatorProfitCollateralToken` has some dimension issues, as a collateral value is sumed with a debt value.

Finally, `L119` we see that this is the value that will be transfered to the liquidator, leading to a wrong accounting.

https://github.com/code-423n4/2024-06-size/blob/main/src/libraries/actions/Liquidate.sol#L75
```solidity
File: src/libraries/actions/Liquidate.sol
075:     function executeLiquidate(State storage state, LiquidateParams calldata params)
076:         external
077:         returns (uint256 liquidatorProfitCollateralToken)
078:     {
...:
...:		//* 	some code 		*//
...:
089: 
090:         uint256 assignedCollateral = state.getDebtPositionAssignedCollateral(debtPosition);
091: >>      uint256 debtInCollateralToken = state.debtTokenAmountToCollateralTokenAmount(debtPosition.futureValue);
092:         uint256 protocolProfitCollateralToken = 0;
093: 
094:         // profitable liquidation
095:         if (assignedCollateral > debtInCollateralToken) {
096: >>          uint256 liquidatorReward = Math.min( //*MIN(
097:                 assignedCollateral - debtInCollateralToken,
098: ❌>>			 Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
099:             );
100: >>          liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;
101:
...:
...:		//* 	some code 		*//
...:
117: 
118:         state.data.borrowAToken.transferFrom(msg.sender, address(this), debtPosition.futureValue);
119: >>
`liquidatorReward` calculation is not correct
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


# Vulnerability details

## Bug Description 
The calculation of `liquidatorReward` during the execution of `liquidate()` does not account for the fact that the `debtToken balance` for a loan which is same as `debtPosition.futureValue` will/may not be the same decimal like the collateral token or the `assignedCollateral ` and `debtInCollateralToken` values. 

If collateral token is 18 decimals for example, while the underlyingBorrowToken is 6 decimals, the debtToken will be 6 decimals too as seen initialized [here](https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Initialize.sol#L257). 

The calculation of `liquidatorReward` is like below 

https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L90-L98
```solidity
        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) 
            );
```
`getDebtPositionAssignedCollateral()` and `debtTokenAmountToCollateralTokenAmount()` will both return values already converted to 18 decimals because  [getDebtPositionAssignedCollateral()](https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/LoanLibrary.sol#L148-L159) reads collateral token balance and [debtTokenAmountToCollateralTokenAmount()](https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/AccountingLibrary.sol#L31) converts the debtToken amount to 18 decimals before converting it to collateral token amount. Lets assume `assignedCollateral` and `debtInCollateralToken` are `2e18` and `1.6e18` respectively. 

The other logic `Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)` attempts to use the raw debtToken value (because debtPosition.futureValue is the amount of debtToken minted to a borrower when a loan is taken. see [here](https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/AccountingLibrary.sol#L91) ) in the calculation of the percentage to be due as liquidation reward. So if 
- debtToken is 6 decimals,
-  debtTokenAmount (which is debtToken balance and is also same as `debtPosition.futureValue`) is 10e6, 
-  `riskConfig.liquidationRewardPercent` is 5%, 

 the calculation will result to
Aave Yield on Lender Credit Repayment Vulnerable to Griefing
Audit: 2024-06-size-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/DepositTokenLibrary.sol#L49-L65
https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Claim.sol#L23-L60


# Vulnerability details


## Summary

An attacker can grief lenders by claiming their credit repayment, thereby depriving them of potential Aave yield. When a borrower repays a debt, the repayment amount in USDC is sent to Aave, allowing the lender to earn yield until they claim it. However, due to the lack of access control on the claim function, anyone can execute this claim on behalf of the lender, disrupting the lender's yield generation.

## Description

When a borrower repays a debt, the repayment amount in USDC is transferred to the Size protocol and subsequently deposited into Aave. The deposited amount remains in Aave, earning yield, until the lender claims their credit. This process is initiated through the `deposit` function, which calls `executeDeposit` and further invokes `depositUnderlyingBorrowTokenToVariablePool`. 

The relevant code snippet is as follows:

[https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/DepositTokenLibrary.sol#L49-L65](https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/DepositTokenLibrary.sol#L49-L65)

```sol
    function depositUnderlyingBorrowTokenToVariablePool(State storage state, address from, address to, uint256 amount)
        external
    {
        state.data.underlyingBorrowToken.safeTransferFrom(from, address(this), amount);

        IAToken aToken =
            IAToken(state.data.variablePool.getReserveData(address(state.data.underlyingBorrowToken)).aTokenAddress);

        uint256 scaledBalanceBefore = aToken.scaledBalanceOf(address(this));

        state.data.underlyingBorrowToken.forceApprove(address(state.data.variablePool), amount);

        state.data.variablePool.supply(address(state.data.underlyingBorrowToken), amount, address(this), 0);
        
        uint256 scaledAmount = aToken.scaledBalanceOf(address(this)) - scaledBalanceBefore;

        state.data.borrowAToken.mintScaled(to, scaledAmount);
    }
```

Lenders can claim their credit using the `claim` function, which calls `executeClaim` and calculates the proportion of the repayment amount based on the time elapsed since the repayment. The lender can then call `withdraw` to receive their USDC. 

The claim process is outlined in the following code:

[https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Claim.sol#L23-L60](https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Claim.sol#L23-L60)

```sol
    function claim(ClaimParams calldata params) external payable override(ISize) whenNotPaused {
        state.validateClaim(params);
        st
Due to wrong calculation of liquidator Reward, unexpected financial Loss of Protocol fee Recipient and Borrower is happening 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#L98


# Vulnerability details

## Impact
Due to the wrong calculation of `liquidatorReward` Liquidator will be getting the whole `assignedCollateral` as his reward, leaving 0 collateral left for protocol `feeRecipient` and borrower, leading to a loss of protocol and borrower financially.

According to the size protocol: "The liquidator gets up to a fixed 5% reward on the loan's face value(future value).” Then, the collateral remainder is split as follows:

- *νb* collateral remainder percentage back to the liquidated borrower
- *νp* collateral remainder percentage to the protocol

Therefore this can be marked as High Vulnerability.

## Proof of Concept
Providing Real example with calculations according to Docs of Size Protocol, which is given here in docs - https://docs.size.credit/non-technical/illustrated-examples/illustration-of-borrower-liquidation-without-replacement-borrower

Note: Here all values of ETH and USDC, I’ve taken are the same according to the docs of size protocol (link I provided above) ⇒ the value of ETH drops from $3000 to $2400, causing Borrower's collateralization ratio to drop below the 130% liquidation threshold. Where the future value of the loan is $1890.

Code snippet where `liquidatorReward` calculation is getting wrong -
https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L98

```solidity
uint256 liquidatorReward = Math.min(
                assignedCollateral - debtInCollateralToken,
@>              Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
            );
```
If we put the real values according to the Docs example, with proper decimals of collateral Token, then the calculation of this code snippet should look like this -
```solidity
 // profitable liquidation -
        // 2.000000000000000000 > 1.575000000000000000 | here both values are compared in collateral tokens, so it is good!
        if (assignedCollateral > debtInCollateralToken) {
            // taking minimum value
            uint256 liquidatorReward = Math.min(
                //  2.000000000000000000 − 1.575000000000000000 = 0.425e18 szETH (in 18 decimal 0.425000000000000000)
                assignedCollateral - debtInCollateralToken,
          
                // calculation->  1890e6 * 0.05e18 / 1e18 = 94500000 (94.5e6) szaUSDC is getting calculated, but this should be converted in terms of szETH, which if calculated will be - 0.078750000000000000 (0.07875e18 szETH), so that the comparision of minimum happens between same token, which here in this case is collateralToken(szETH)
                Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
            );
```
With the above calculation token amount of `liquidatorReward` will be stored as => `0.425e18
Incorrect Handling of Decimal Places in Liquidation Reward 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#L96


# Vulnerability details

## Description
The `executeLiquidate` function is crucial for the liquidation process of debt positions within the smart contract. This function retrieves a debt position, checks loan status, calculates potential profits for the liquidator, and distributes the remaining collateral. A significant bug exists in the calculation involving the liquidator's reward due to the handling of different decimal precisions, which could mislead in determining the correct amounts to be distributed.

During a liquidation event, the contract:
1. Fetches the relevant `DebtPosition` and `LoanStatus`.
2. Determines if the position is underwater or overdue to set the appropriate protocol fee percentage.
3. Calculates the total debt in terms of the collateral token and the collateral assigned to the position.
4. Determines the liquidator's reward, which is the minimum of the excess collateral or a calculated reward percentage of the future debt value.

The critical issue arises in the liquidator's reward calculation, where `Math.min` function is used between values that represent excess collateral (`18 decimals`) and a reward calculated as a percentage of the debt (`6 decimals`). This mismatch in decimal places results in incorrect calculations.

**Example:**
- Assigned Collateral: `2 ether` (equivalent to `8000 USDC`)
- Debt in Collateral Token: `1 ether` (equivalent to `4000 USDC`)
- Calculated Reward: `200 USDC` (correctly should be in `18 decimals` but is in `6 decimals`)

The system incorrectly processes the decimal precision, treating the `200 USDC` as `200e6` in `6 decimals`, leading to a comparison between `8000e18` and `200e6`. As a result, the `Math.min` function always picks the `200e6`, and this value is improperly added to the `1 ether` amount in the subsequent calculation of `liquidatorProfitCollateralToken`.

## Impact
This bug leads to a miscalculation of the liquidator’s reward, potentially causing the liquidator to receive less than intended, which directly impacts the incentive mechanism for liquidators. Additionally, the incorrect addition of values with different decimal precisions could result in errors or unintended behavior in the smart contract, affecting the distribution of collateral between the protocol, borrower, and liquidator.

## Proof of Concept

```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);

        emit Events.Liquidate(params.debtPositionId, params.minimumCollateralProfit, collateralRatio, loanStat
Liquidators can steal borrowers collateral tokens due to wrong assumption.
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#L100-L100


# Vulnerability details

## Impact
When calculating the liquidator reward in collateral token to get how much tokens they will get in return for their liquidation, `executeLiquidate` adds the debt in collateral tokens, + the calculated liquidatorReward, which after other calculations, directly sends the amount from the borrower to the liquidator, but the liquiditorReward can either be returned in ETH or USDC which means that the calculation will return a false value allowing the liquidator to take more than they deserve.

## Proof of Concept
```solidity
if (assignedCollateral > debtInCollateralToken) {
            uint256 liquidatorReward = Math.min(
                assignedCollateral - debtInCollateralToken,
                Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
            );
```
Here as seen in this snippet above, liquidatorReward can be in both usdc(borrrowToken) and ETh(collateralToken), but this fact is not taken into accoount when the next part of the function is done, which leads to a wrong calculations
```solidity
            liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;
```
As seen here the addition here is done directly, without checking if liquidator was gotten from the future value, allowing liquidators to take from tokens than they deserve

Example Illustration

- Calculating liquidator reward, 
Math.min(5ETh, 4usdc) liquidatorReward = 4USDC

- liquidatorProfitCollateralToken calculations
debtInCollateralToken = 5eth 

wrong calculations taking place = 5 + 4 = 9ETH


## Tools Used
Manual Review

## Recommended Mitigation Steps
Assert that the liquidatorReward is in ETH before attempting The addition.


## Assessed type

Context
Liquidate & Self-Liquidate Should Have 100% Uptime
Audit: 2024-06-size-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/Size.sol#L210
https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/Size.sol#L223


# Vulnerability details

## Impact
Lenders can lose funds if the borrower's collateral drops when the protocol is paused.


## Proof of Concept

* Alice deposits 4000 USDC into the Size protocol.
* Bob deposits 1 ETH as collateral, worth approximately 4000 USD (assuming the ETH price is 4000 USD/ETH).
* Bob borrows up to 2666 USDC with a Collateral Ratio of 150%.
    * BorrowAmount = Collateral Value / crOpening
    * Collateral Value = 4000 USD worth of ETH
    * crOpening = 1.5

* ETH price drops to 3467 USD/ETH.
* Collateral Ratio is now just above the liquidation threshold of 130%.
    * Collateral Value = 3467 USD worth of ETH
    * BorrowAmount = 2666 USDC
    * Collateral Ratio = Collateral Value / Borrow Amount = 1.3004
    * crLiquidation = 1.3

* Protocol pauses the Size contract for any reason.
* Bob's collateral drops further and is open for liquidation, but his position can't be liquidated due to the modifier.

If the ETH price continues to drop and reaches 2665 USD/ETH, Bob is now undercollateralized and Alice can't call the Self-Liquidation function either.

Therefore, Bob has no incentive to repay the loan and keep the USDC value, leading to a loss of funds for Alice.

## Tools Used

Manual Review

## Recommended Mitigation Steps

* Remove the `whenNotPaused` modifier in the [liquidate](https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/Size.sol#L210) and [selfLiquidate](https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/Size.sol#L223) functions.
* Create a different modifier to pause those functions (for emergencies). This way, if the protocol is paused, liquidators can liquidate a liquidatable position and lenders can still self-liquidate before they lose too much credit


## Assessed type

Access Control