xanoutas/solidity-security-findings huggingface dataset:
Users will receive fewer `shares` than intended due to division before multiplication in `LibOrders::increaseSharesOnMatch`
Audit: 2024-03-dittoeth-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L47


# Vulnerability details

## Impact

The `LibOrders::increasesSharesOnMatch` function determines the number of `shares` based on the amount of `eth` and the time until a match occurs:

```javascript

    function increaseSharesOnMatch(address asset, STypes.Order memory order, MTypes.Match memory matchTotal, uint88 eth) internal {
        AppStorage storage s = appStorage();

        // @dev use the diff to get more time (2159), to prevent overflow at year 2106
        uint32 timeTillMatch = getOffsetTime() - order.creationTime;
        if (timeTillMatch > C.MIN_DURATION) {
            // shares in eth-days
    @>      uint88 shares = eth * (timeTillMatch / 1 days);
            matchTotal.dittoMatchedShares += shares;

            uint256 vault = s.asset[asset].vault;
            s.vaultUser[vault][order.addr].dittoMatchedShares += shares;
        }
    }

```

But there is a precision loss in the expression `uint88 shares = eth * (timeTillMatch / 1 days)` due to integer division before multiplication. In `Solidity`, when dividing integers, the result is truncated towards zero. If `timeTillMatch` is not a multiple of `1 days` (86400 seconds), the division will truncate any remainder leading to a loss of precision in the calculation of `shares`.
The precision loss in `shares` calculation results in users receiving fewer shares than they are entitled to, based on the time and `eth` amount.

## Proof of Concept
Link to the code:
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L47

Let's consider the following scenario:
1. The `getOffset` function returns: `return uint32(block.timestamp - C.STARTING_TIME);`. The current `block.timestamp` is `1712058842` (in seconds, 02.04.2024, 11:54:02 GMT) and the variable `C.STARTING_TIME` is `1660353637` (13.08.2022).
2. The order creatin time is: Sunday, 17 March 2024 12:00:02. Therefore, the Epoch timestamp value is 1710676802.
3. The `timeTillMatch` is calculated in the following way: `uint32 timeTillMatch = getOffsetTime() - order.creationTime;`.
4. The input parameter `eth` is `1e18`.

Now, we can write a test function that shows the difference between the calculated `shares` when division before multiplication is done and when the division is performed after the multiplication (the correct way).

```javascript

    function test_precisionLoss() external {
        //Order creation time: Sunday, 17 March 2024 12:00:02 (1710676802)
        //Current blocktimestamp: 1712058842, 02.04.2024, 11:54:02 GMT
        uint32 timeTillMatch = uint32(1712058842 - 1660353637) - uint32(1710676802 - 1660353637);
        uint88 eth = 1e18;
        uint88 shares = eth * (timeTillMatch / 1 days);
        uint88 sharesCorrect = uint88(uint256(eth * timeTillMatch) / 1 days);
        uint88 diff = sharesCorr
Attacker exploiting reentrancy can claim excessive collateral, disrupting redemption process.
Audit: 2024-03-dittoeth-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L310-L334
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L324-L329


# Vulnerability details

## Summary & Impact
`claimRedemption` allows a redeemer to claim the collateral from the verified redemption candidates after the dispute period has passed. It takes the following parameter:
- `asset`: The market that will be impacted.

**As can be seen, the function performs the following key steps:**
1. Retrieves the redeemer's asset user and vault user structs.
2. Checks if the redeemer has a valid redemption proposal and if the dispute period has elapsed.
3. Reads the redemption proposal data using SSTORE2.
4. Iterates through the redemption proposal data and calls the `_claimRemainingCollateral` function for each verified redemption candidate.
5. Updates the redeemer's vault user struct with the total redeemed collateral.
6. Deletes the redeemer's asset user struct's SSTORE2 pointer.

[RedemptionFacet.sol::claimRedemption](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L310-L334)

```solidity
function claimRedemption(address asset) external isNotFrozen(asset) nonReentrant {
    uint256 vault = s.asset[asset].vault;
    STypes.AssetUser storage redeemerAssetUser = s.assetUser[asset][msg.sender];
    STypes.VaultUser storage redeemerVaultUser = s.vaultUser[vault][msg.sender];
    if (redeemerAssetUser.SSTORE2Pointer == address(0)) revert Errors.InvalidRedemption();
    if (LibOrders.getOffsetTime() < redeemerAssetUser.timeToDispute) revert Errors.TimeToDisputeHasNotElapsed();


    MTypes.ProposalData[] memory decodedProposalData =
        LibBytes.readProposalData(redeemerAssetUser.SSTORE2Pointer, redeemerAssetUser.slateLength);


    uint88 totalColRedeemed;
    for (uint256 i = 0; i < decodedProposalData.length; i++) {
        MTypes.ProposalData memory currentProposal = decodedProposalData[i];
        totalColRedeemed += currentProposal.colRedeemed;
        _claimRemainingCollateral({
            asset: asset,
            vault: vault,
            shorter: currentProposal.shorter,
            shortId: currentProposal.shortId
        });
    }
    redeemerVaultUser.ethEscrowed += totalColRedeemed;
    delete redeemerAssetUser.SSTORE2Pointer;
    emit Events.ClaimRedemption(asset, msg.sender);
}
```

> Had it been there are proper reentrancy guards in the `claimRedemption` function. Although the function is marked with the `nonReentrant` modifier, it still calls an external function (`_claimRemainingCollateral`) before updating the redeemer's vault user struct and deleting the asset user struct's SSTORE2 pointer.

> If the `_claimRemainingCollateral` function or any other function called within the loop is malicious or can be controlled by an
Potential redemption of unintended collateral, disrupting protocol stability, risking financial loss.
Audit: 2024-03-dittoeth-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L56-L177
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L31-L43
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L87
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L31-L43
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L116-L125


# Vulnerability details

## Summary & Impact
`proposeRedemption` function allows users to propose a set of ShortRecords for redemption. It takes the following parameters:
- `asset`: The market that will be impacted.
- `proposalInput`: Array of data pertaining to the ShortRecord candidates.
- `redemptionAmount`: Total amount of ercDebt requested to be redeemed.
- `maxRedemptionFee`: Maximum fee that the redeemer is willing to pay.

_Then perform the following steps:_
1. Validates the input parameters and checks the redeemer's escrowed balance.
2. Iterates through the `proposalInput` array and validates each ShortRecord candidate.
3. Calculates the total collateral and debt to be redeemed based on the valid ShortRecords.
4. Stores the redemption proposal data using SSTORE2.
5. Updates the system's debt and the redeemer's escrowed balance.

[RedemptionFacet.sol::proposeRedemption](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L56-L177)

```solidity
function proposeRedemption(
    address asset,
    MTypes.ProposalInput[] calldata proposalInput,
    uint88 redemptionAmount,
    uint88 maxRedemptionFee
) external isNotFrozen(asset) nonReentrant {
    // ... (function body)
}
```

> There's Insufficient validation of the proposed ShortRecords in the `proposeRedemption`. The function relies on the `validRedemptionSR` function to validate each ShortRecord candidate. But, the validation checks in `validRedemptionSR` may not cover all necessary conditions to ensure the integrity of the proposed ShortRecords.

_For example, the `validRedemptionSR` function checks if the ShortRecord's status is not `SR.Closed` and if the `ercDebt` is greater than or equal to `minShortErc`. However, it does not verify other important aspects, such as the ShortRecord's collateral ratio or the validity of the associated short order._

[RedemptionFacet.sol::validRedemptionSR](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L31-L43)

```solidity
function validRedemptionSR(STypes.ShortRecord storage shortRecord, address proposer, address shorter, uint256 minShortErc)
internal
view
returns (bool)
{
// @dev Matches check in o
Orders may be matched based on stale prices, causing financial losses.
Audit: 2024-03-dittoeth-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/BidOrdersFacet.sol#L130-L204
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L556-L626
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/BidOrdersFacet.sol#L150
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L574


# Vulnerability details

## Description
`bidMatchAlgo` and `sellMatchAlgo`, which are responsible for matching incoming orders with existing orders in the orderbook based on price.

The `bidMatchAlgo` and `sellMatchAlgo` functions are expected to match incoming orders with existing orders in the orderbook based on accurate and up-to-date price information. The hint system should optimize the order placement process without compromising the integrity of the matching logic.

The expected inputs are the `asset` being traded, the `incomingBid` or `incomingAsk` order, and the `orderHintArray` for efficient order placement.

The intended outcome is to fill the incoming order as much as possible by matching it with existing orders at prices that reflect the current market conditions, ensuring fair and accurate trading for all users.

[BidOrdersFacet.sol#bidMatchAlgo](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/BidOrdersFacet.sol#L130-L204)
```solidity
function bidMatchAlgo(
    address asset,
    STypes.Order memory incomingBid,
    MTypes.OrderHint[] memory orderHintArray,
    MTypes.BidMatchAlgo memory b
) private returns (uint88 ethFilled, uint88 ercAmountLeft) {
    // ... code ...
    STypes.Order memory lowestSell = _getLowestSell(asset, b);
    if (incomingBid.price >= lowestSell.price) {
        // ... code ...
        LibOrders.updateOracleAndStartingShortViaThreshold(asset, LibOracle.getPrice(asset), incomingBid, shortHintArray);
        b.shortHintId = b.shortId = Asset.startingShortId;
        b.oraclePrice = LibOracle.getPrice(asset);
        return bidMatchAlgo(asset, incomingBid, orderHintArray, b);
    }
    // ... code ...
}
```

[LibOrders.sol#sellMatchAlgo](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L556-L626)
```solidity
function sellMatchAlgo(
    address asset,
    STypes.Order memory incomingAsk,
    MTypes.OrderHint[] memory orderHintArray,
    uint256 minAskEth
) internal {
    // ... code ...
    if (incomingAsk.price < oraclePrice) {
        LibOrders.addSellOrder(incomingAsk, asset, orderHintArray);
    } else {
        LibOrders.sellMatchAlgo(asset, incomingAsk, orderHintArray, minAskEth);
    }
}
```
These functions use the cached oracle price and the provided order hints to match incoming orders with existing orders in the or
Market manipulation, front-running, distorted prices, potential financial losses for users.
Audit: 2024-03-dittoeth-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/BidOrdersFacet.sol#L130-L204
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L556-L626


# Vulnerability details

## Description
`bidMatchAlgo` and `sellMatchAlgo`, which are responsible for matching incoming orders with existing orders in the orderbook based on price.

[BidOrdersFacet.sol#bidMatchAlgo](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/BidOrdersFacet.sol#L130-L204)
```solidity
function bidMatchAlgo(
    address asset,
    STypes.Order memory incomingBid,
    MTypes.OrderHint[] memory orderHintArray,
    MTypes.BidMatchAlgo memory b
) private returns (uint88 ethFilled, uint88 ercAmountLeft) {
    // ... code ...
    while (true) {
        // ... code ...
        STypes.Order memory lowestSell = _getLowestSell(asset, b);
        if (incomingBid.price >= lowestSell.price) {
            matchlowestSell(asset, lowestSell, incomingBid, matchTotal);
            // ... code ...
        } else {
            // ... code ...
            return matchIncomingBid(asset, incomingBid, matchTotal, b);
        }
    }
}
```

[LibOrders.sol#sellMatchAlgo](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L556-L626)
```solidity
function sellMatchAlgo(
    address asset,
    STypes.Order memory incomingAsk,
    MTypes.OrderHint[] memory orderHintArray,
    uint256 minAskEth
) internal {
    // ... code ...
    while (true) {
        STypes.Order memory highestBid = s.bids[asset][startingId];
        if (incomingAsk.price <= highestBid.price) {
            matchHighestBid(incomingAsk, highestBid, asset, matchTotal);
            // ... code ...
        } else {
            // ... code ...
            return;
        }
    }
}
```
These functions iterate through the orderbook, matching the incoming order with the lowest sell order or highest bid order, respectively, based on price.

The [bidMatchAlgo](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/BidOrdersFacet.sol#L130-L204) and [sellMatchAlgo](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L556-L626) functions are expected to match incoming orders with existing orders in the orderbook based on price, facilitating trades between buyers and sellers.

The expected inputs are the `asset` being traded, the `incomingBid` or `incomingAsk` order, and any necessary `orderHintArray` for efficient matching.

The intended outcome is to fill the incoming order as much as possible by matching it with existing orders, updating the orderbook state accordingly, and returning the filled amounts and any remaining amounts.

## Vulnerability De
Excessive gas consumption, potential denial-of-service due to slow order insertion.
Audit: 2024-03-dittoeth-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L430-L462
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L448-L449


# Vulnerability details

## Description
`getOrderId` function is responsible for finding the correct position to insert an order in the orderbook when an invalid hint is provided. It takes the following inputs:
- `orders`: The mapping representing the orderbook.
- `asset`: The address of the asset being traded.
- `direction`: The direction to search (C.PREV for previous, C.NEXT for next).
- `hintId`: The ID of the hint to start the search from.
- `_newPrice`: The price of the order being inserted.
- `orderType`: The type of the order being inserted.

[LibOrders.sol#getOrderId](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L430-L462)

```solidity
    /**
     * @notice Helper function for finding and returning id of potential order
     *
     * @param orders the order mapping
     * @param asset The market that will be impacted
     * @param direction int direction to search (PREV, EXACT, NEXT)
     * @param hintId hint id
     * @param _newPrice price of prospective order used to find the id
     * @param orderType which OrderType to verify
     */
    function getOrderId(
        mapping(address => mapping(uint16 => STypes.Order)) storage orders,
        address asset,
        int256 direction,
        uint16 hintId,
        uint256 _newPrice,
        O orderType
    ) internal view returns (uint16 _hintId) {
        while (true) {
            uint16 nextId = orders[asset][hintId].nextId;


            if (verifyId(orders, asset, hintId, _newPrice, nextId, orderType) == C.EXACT) {
                return hintId;
            }


            if (direction == C.PREV) {
                uint16 prevId = orders[asset][hintId].prevId;
                hintId = prevId;
            } else {
                hintId = nextId;
            }
        }
    }
```
_The function iterates through the order list, starting from the provided `hintId`, and compares the prices using the `verifyId` function. It continues searching in the specified direction (`C.PREV` for previous, `C.NEXT` for next) until it finds the correct position for the order._

## Vulnerability Details
When a large number of orders with invalid hints are submitted to the system. Since the `getOrderId` function falls back to a full search when an invalid hint is provided, it can lead to significant gas consumption and slow down the order insertion process.

> The issue lies in the unbounded iteration within the `getOrderId` function. The function continues to iterate through the order list until it finds the correct position, without any limit on the number of iterations or gas consumed.

The line responsible for the vulnerability i
Inconsistent orderbook state, potential loss of funds, incorrect token balances.
Audit: 2024-03-dittoeth-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L853-L866


# Vulnerability details

## Description
`cancelBid`, `cancelAsk`, and `cancelShort` functions are responsible for canceling orders from their respective ordersbooks. They take the `asset` and `id` of the order as inputs and directly remove the order from the orderbook without checking if it is currently being matched.

[cancelBid](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOrders.sol#L853-L866)

```solidity
    // Helper Functions for cancelling orders
    function cancelBid(address asset, uint16 id) internal {
        AppStorage storage s = appStorage();
        STypes.Order storage bid = s.bids[asset][id];


        O orderType = bid.orderType;
        if (orderType == O.Cancelled || orderType == O.Matched) revert Errors.NotActiveOrder();


        uint256 vault = s.asset[asset].vault;
        uint88 eth = bid.ercAmount.mulU88(bid.price);
        s.vaultUser[vault][bid.addr].ethEscrowed += eth;


        cancelOrder(s.bids, asset, id);
    }
```
This retrieves the bid order, checks if it's not already canceled or matched, updates the user's escrowed balance, and then calls the internal `cancelOrder` function to remove the order from the orderbook.

## Vulnerability Details
When an order is in the process of being matched by the `bidMatchAlgo` or `sellMatchAlgo` functions, and simultaneously, the `cancelBid`, `cancelAsk`, or `cancelShort` function is called for the same order.

> The issue lies in the fact that the cancel functions do not check whether the order is currently being matched. They directly remove the order from the orderbook without any locks or checks.

Due to the lack of checks and locks, if the cancel function is called while the order is being matched, it can lead to inconsistencies in the orderbook state. The order may be partially filled and then cancelled, resulting in an incorrect remaining amount or a discrepancy between the user's balances and the order status.

**For example, consider the following scenario:**
1. A bid order is being matched in the `bidMatchAlgo` function.
2. While the matching is in progress, the `cancelBid` function is called for the same bid order.
3. The `cancelBid` function removes the order from the orderbook, even though it is still being matched.

This can lead to a situation where the order is partially filled by the matching process, but then gets cancelled, leaving the remaining amount in an inconsistent state.

## Impact
- The orderbook may contain orders with incorrect remaining amounts or orders that should have been fully filled but are marked as cancelled.
- Users may have incorrect balances if their orders are partially filled and then cancelled, leading to discrepancies between their actual and expected balances.

## Proof of Concept
_Scenario:_
1. User A create