xanoutas/solidity-security-findings huggingface dataset:
Double Claiming of Collateral in claimRedemption
Audit: 2024-03-dittoeth-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
the redeemer can claim collateral that has already been claimed by the shorter, it could lead to a financial loss for the platform or other users due to the depletion of the collateral pool.


## Proof of Concept
1. A shorter has a position that is eligible for redemption.
2. The redeemer proposes a redemption, which includes the shorter's position.
3. After the dispute period, the shorter uses `claimRemainingCollateral` 
to retrieve their collateral, which deletes the shortRecord.
4. The redeemerAssetUser.SSTORE2Pointer is not updated to reflect the change, and the slate of proposals remains unchanged.
5. The redeemer then calls claimRedemption and, due to the lack of state validation, is able to claim collateral based on the stale proposal data.
6. The platform's collateral pool is reduced by the amount of collateral that has now been claimed twice.


## Tools Used
Manual review 

## Recommended Mitigation Steps
The `redeemerAssetUser.SSTORE2Pointer` should be deleted if the redeemer didn't claim and the shorter claims their asset before them.


## Assessed type

Other
Mitigating Protocol Losses in Flash Crash Scenarios: Safeguarding ERC Amounts and Bid Matching
Audit: 2024-03-dittoeth-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact

Based on the vulnerability of the code line 578 in Lib Order.sol IN case of a sudden down move a market order can be affected if prices swiftly touches zero.  

A flash crash refers to a very rapid, deep, and volatile fall in stock prices within a very short period of time, typically in minutes or even seconds. These events are often characterized by a sharp decline followed by a swift recovery. Flash crashes can happen in various financial markets, including stock markets, currency markets, and commodity markets.

Characteristics:
Rapid Decline: Prices can drop by a significant percentage in a matter of minutes, or even seconds.

High Volatility: The market becomes extremely volatile, with large price swings occurring in a short time frame.

Lack of Liquidity: During a flash crash, there can be a sudden lack of liquidity in the market, making it difficult for traders to execute trades at desired prices.

Swift Recovery: After the rapid decline, prices often recover quickly, although not always to their previous levels. 

This kind of events have been noted even in centralized exchanges, there have been reports from binance,kucion,bitmex,okx and others. 

## Proof of Concept
 A quick price drop can make this assertion (incomingAsk.ercAmount.mul(highestBid.price) == 0) holds true eventhough the incomingAsk.ercAmount is greater than 0 the contract automatically sets the incomingAsk.ercAmount to zero without confirming if a price change in the highestBid.price lead to this. 

```solidity
while (true) {
    STypes.Order memory highestBid = s.bids[asset][startingId];
    if (incomingAsk.price <= highestBid.price) {
        // Consider ask filled if only dust amount left
        if (incomingAsk.ercAmount.mul(highestBid.price) == 0) {
            updateBidOrdersOnMatch(s.bids, asset, highestBid.id, false);
            incomingAsk.ercAmount = 0;
            matchIncomingSell(asset, incomingAsk, matchTotal);
            return;
```

 This could potentially lead to a loss for the protocol since the `incomingAsk.ercAmount` is credited the corresponsding ETH AMOUNT BEFORE IT enters for matching and before the check is performed.


```solidity
function matchIncomingAsk(address asset, STypes.Order memory incomingAsk, MTypes.Match memory matchTotal) private {
    AppStorage storage s = appStorage();
    uint256 vault = s.asset[asset].vault;
    address asker = incomingAsk.addr;
    s.assetUser[asset][asker].ercEscrowed -= matchTotal.fillErc;
    s.vaultUser[vault][asker].ethEscrowed += matchTotal.fillEth;
    s.vault[vault].dittoMatchedShares += matchTotal.dittoMatchedShares;
}
```



Here's a breakdown of the potential issue:

1. **Check Order**: The code checks if the product of `incomingAsk.ercAmount` and `highestBid.price` is zero.
    ```javascript
    if (incomingAsk
Incorrect Collateral Value and Ratio Assessment in the Contract Due to Unbound Frozen Collateral  
Audit: 2024-03-dittoeth-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/ExitShortFacet.sol#L131-L211


# Vulnerability details

## Impact
### Detailed description of the impact of this finding.

Based on the documentation : A user can decrease their ercDebt, and potentially leave the shortRecord position entirely to get back the underlying collateral. In summary, the statement implies that in order to get back the underlying collateral, the user needs to either fully repay their debt or reduce their ercDebt and potentially exit the shortRecord position.
 1. decrease and get back the underlying collateral for the exit, and  
2. potentially leave the shortRecord position entirely  the underlying collateral. 

for every exit in position user should get back the corresponding collateral locked up. According to the developer a users collateral is tied up based on the Collateral Ratio, But based on the code logic, using Primary Exit Short as reference which is the main and only primary exit  where the user pays for his loan from the available dethcollateral but in this instance  unused collateral 
(collateral not bound by the CR Ratio) are still frozen in the loan after repayment  
hence he won't get a dime if his position is in PROFIT or LOSE unless he repays all,
 which a user in profit might not want to do, he might want to exit a few percentage of his debt , this might lead to some unexpected behaviour leaving his debt in Solvency meaning he has more than enough collateral to hold the position for years.

 Specifically, users will not receive any collateral if their position is in profit or loss unless they fully repay their debt. 

An increase in dethcollateral will reduce the liquidation price of the user, the user can take on a almost risk free trade if the collateral freed from exiting is not separated from the ound/frozen based on CR Ratio.

This vulnerability can result in financial losses for users and may lead to a higher risk of system insolvency( caused by less or no bid since all ids are all shorts that can be held for years before any risk of liquidation), especially when multiple users are affected by this issue. Moreover, the existing limitations in the contract, such as hintid and counter and many more, can exacerbate the impact of this vulnerability, making it become more pronounced and potentially affecting a large number of users.

---

## Proof of Concept

1. Abass enters a short with a CR ratio of 2:1, with a collateral of 20,000 USDC and a debt collateral of 30,000 USDC for a debt of 100 ETH, price was 100 USDC per ETH on short.

```solidity
CR Ratio = 2:1
Collateral = 20,000 USDC
Deth Collateral = 30,000 USDC
Debt = 100 ETH
Price = 100 USDC per ETH
```

A. Scenario when Abass is in profit but decides to lessen his debt profile/position.

 1. checkCancelShortOrder will return false because the order has been filled, matched. 

2   short.updateErcDebt(e.asset);
3.  e.buyback
transferShortRecord succeeds even if no transfer is performed
Audit: 2024-03-dittoeth-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Many real-world NFT tokens may support both ERC721 and ERC1155 standards, which may break the protocol transffering short records as NFT, i.e., transferring less tokens than expected.


## Proof of Concept
If an NFT is sold that does not specify support for the ERC-721 or ERC-1155 standard interface, the sale will still succeed. In doing so, the seller will receive funds from the buyer, but the buyer will not receive any NFT from the seller. This could happen in the following cases:

A token or order that claims to be ERC-721/1155 compliant, but fails to implement the supportsInterface() function properly.
An NFT that follows a standard other than ERC-721/1155 and does not implement their EIP-165 interfaces.
A malicious contract that is deployed to take advantage of this behavior.


## Recommended Mitigation Steps
If neither the ERC-721 nor the ERC-1155 interface is supported the function should revert. An alternative approach would be to attempt a transferFrom and check the balance before and after to ensure that it succeeded.


## Assessed type

ERC721
DOS if shorter claims collateral before redeemer
Audit: 2024-03-dittoeth-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-03-dittoeth/blob/main/contracts%2Ffacets%2FRedemptionFacet.sol#L368


# Vulnerability details

After shorters claim their remaining collateral, redeemers can still call `claimRedemption`,  leading to a denial-of-service (DoS) attack. 

`claimRedemption`function is called by the redeemer after the dispute period is ended, however if the redeemer doesn't call the function quick enough before the shorter calls `claimRemainingCollateral` they won't be able to claim any collateral. `claimRemainingCollateral` deletes the short record but the redeemer `SSTORE2Pointer` remains intact indicating unclaimed redemptions.

The issues arises because the redeemer's `redeemerAssetUser.SSTORE2Pointer` remains intact even after the collateral is refunded to the shorter and the short record is deleted.

## Impact
Malicious users could exploit this loophole to prevent redeemers from successfully claiming their assets, causing financial losses and preventing future proposals 
## Proof of Concept
A user redeems but doesn't call `claimRedemption` before the shorter claim their collateral back.
Here the `claimRedemption` call only be call if the dispute time is ended and if the `SSTORE2Pointer` of the redeemer is not empty

https://github.com/code-423n4/2024-03-dittoeth/blob/main/contracts%2Ffacets%2FRedemptionFacet.sol#L314-L315 
```solidity
if (redeemerAssetUser.SSTORE2Pointer == address(0)) revert Errors.InvalidRedemption();
        
        if (LibOrders.getOffsetTime() < redeemerAssetUser.timeToDispute) revert Errors.TimeToDisputeHasNotElapsed();
```
Also the shorter can call `claimRemainingCollateral` to claim back their collateral incase the redeemer doesn't claim.
Which also can't be called if the dispute time isn't ended or if the `SSTORE2Pointer` of the redeemer is zero 

https://github.com/code-423n4/2024-03-dittoeth/blob/main/contracts%2Ffacets%2FRedemptionFacet.sol#L352-L354
```solidity
STypes.AssetUser storage redeemerAssetUser = s.assetUser[asset][redeemer];
        if (redeemerAssetUser.SSTORE2Pointer == address(0)) revert Errors.InvalidRedemption();
        if (redeemerAssetUser.timeToDispute > LibOrders.getOffsetTime()) revert Errors.TimeToDisputeHasNotElapsed();
```

As we can see the `shorter` and the `redeemer` can both claim the functions if the dispute period is over. In this case if the shorter calls `claimRemainingCollateral` before the redeemer calls `claimRedemption` this is what happens: `_claimRemainingCollateral` gets called 

https://github.com/code-423n4/2024-03-dittoeth/blob/main/contracts%2Ffacets%2FRedemptionFacet.sol#L368
```solidity
function _claimRemainingCollateral(address asset, uint256 vault, address shorter, uint8 shortId) private {
        STypes.ShortRecord storage shortRecord = s.shortRecords[asset][shorter][shortId];

        if (shortRecord.ercDebt == 0 && shortRecord.status == SR.FullyFilled) {
            // @dev Refund shorter the remaining collateral only if fully rede
STETH can be withdrawn if the LSTs(rETH/stETH) vault of the user is empty but it will never be the exact asset deposited
Audit: 2024-03-dittoeth-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
The logic behind the assessDeth function is to allow users to assess any asset of their choice, whether it's rETH or stETH, from the LST (Liquidity Swap Tokens) Vault. In a rare or unlikely scenario where the rETH bridge contract is empty or has no remaining rETH, the user will be able to withdraw the desired amount of stETH, equivalent to the rETH, fee-free. This is because stETH is the only remaining asset in the LST Vault.

## Description
```
  function assessDeth(uint256 vault, uint256 bridgePointer, uint88 amount, address rethBridge, address stethBridge)
        internal
        returns (uint88)
    {
        AppStorage storage s = appStorage();
        STypes.VaultUser storage VaultUser = s.vaultUser[vault][msg.sender];

        uint88 creditReth;
        uint88 creditSteth;
        if (bridgePointer == VAULT.BRIDGE_RETH) {
            // Withdraw RETH
            creditReth = VaultUser.bridgeCreditReth;
            if (creditReth >= amount) {
                VaultUser.bridgeCreditReth -= amount;
                return 0;
            }

            VaultUser.bridgeCreditReth = 0;
            amount -= creditReth;
            creditSteth = VaultUser.bridgeCreditSteth;
            if (creditSteth < C.ROUNDING_ZERO) {
                // Valid withdraw when no STETH credits
                return amount;
            } else {
                if (IBridge(stethBridge).getDethValue() < C.ROUNDING_ZERO) {
                    // Can withdraw RETH using STETH credit when STETH bridge is empty
                    if (creditSteth >= amount) {
                        VaultUser.bridgeCreditSteth -= amount;
                        return 0;
                    } else {
                        VaultUser.bridgeCreditSteth = 0;
                        return amount - creditSteth;
                    }

```
***Let's consider a scenario where a user wants to withdraw 100 RETH from their vault, and the bridge pointer indicates RETH withdrawal. The user has 120 RETH credits in their vault.***
> Sufficient RETH Credits (120 RETH):

***Since the user has sufficient RETH credits (120 RETH), the function checks and confirms this condition. However, it returns 0 as per the code logic. This behavior might be intended to indicate that no additional withdrawal is necessary, as the user's RETH credits already cover the requested amount***
>Insufficient RETH Credits (80 RETH):
If the user only has 80 RETH, which is less than the requested withdrawal amount, the function will:

***Reset the user's RETH credits to 0 to adjust the withdrawal amount to 20 RETH (100 - 80).
Check if the user has any STETH credits. If there are none, it returns 20 RETH, indi
Preventing short record from being redeemed by increasing collateral
Audit: 2024-03-dittoeth-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details



## Impact
User can prevent having a low CR short record redeemed.

## Proof of Concept
Suppose Alice has the next short record in line for redemption. In order to avoid being redeemed against she can `increaseCollateral()` (1 wei per hour) in order to [set the `updatedAt` field](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/ShortRecordFacet.sol#L61) and then propose a redemption, which, except for excluding hers, which the lowest collateral ratio, is correct. Since she keeps updating her short record, [this cannot be disputed](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/RedemptionFacet.sol#L259). Since her redemption will then pass and be claimable, the redemption fee increase causes redemption to no longer be profitable and others will not propose a new redemption (immediately) against her short record.

## Recommended Mitigation Steps
Set minimum collateral increase amount.




## Assessed type

DoS
Unrestricted Access to Asset Data Modifcation in createLimitShort()
Audit: 2024-03-dittoeth-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-dittoeth/blob/main/contracts/facets/ShortOrdersFacet.sol#L35-L48


# Vulnerability details

## Impact
In the contract ShortOrdersFacet.sol, the function `createLimitShort` does not validate the roles of the function caller and it allows any user to place short orders in the market. This could be problematic if the contract is intended to be used only by certain participants, like authorized traders or the contract owner.

A potential vulnerability associated with an unrestricted-access issue like this is that it may enable an attacker to manipulate the value of the associated asset or perform malicious actions to drain the liquidity pool. The immediate impact would be reduction of the validity of the prices of the assets in question, and possibly loss of funds, since the asset's value may be artificially lowered or raised by a malicious actor.

## Proof of Concept

https://github.com/code-423n4/2024-03-dittoeth/blob/main/contracts/facets/ShortOrdersFacet.sol#L35-L48

```Solidity
function createLimitShort(
        address asset,
        uint80 price,
        uint88 ercAmount,
        MTypes.OrderHint[] memory orderHintArray,
        uint16[] memory shortHintArray,
        uint16 shortOrderCR
    ) external isNotFrozen(asset) onlyValidAsset(asset) nonReentrant {
    
    // ...
    
    // Anyone can create "empty" SR.
    incomingShort.shortRecordId = LibShortRecord.createShortRecord(asset, msg.sender, SR.Closed, 0, 0, 0, 0, 0);

    // ...

}
```
## Tools Used

Manual review

## Recommended Mitigation Steps

It's highly recommended to set role-based access control to restrict the function `createLimitShort` for security reasons. Utilize existing standards such as OpenZeppelin's Access Control library that offers a secure way to regulate which addresses can use specific operations in the contract.



## Assessed type

Access Control
Twap value is too low in the bridge router and would cause for using wrong prices which leads to wrong accounting
Audit: 2024-03-dittoeth-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details


## Proof of Concept

Take a look at https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibBridgeRouter.sol#L111-L141

```solidity
    function withdrawalFeePct(uint256 bridgePointer, address rethBridge, address stethBridge) internal view returns (uint256 fee) {
        IBridge bridgeReth = IBridge(rethBridge);
        IBridge bridgeSteth = IBridge(stethBridge);

        // Calculate rETH market premium/discount (factor)
        uint256 unitRethTWAP = OracleLibrary.estimateTWAP(1 ether, 30 minutes, VAULT.RETH_WETH, VAULT.RETH, C.WETH);
        uint256 unitRethOracle = bridgeReth.getUnitDethValue();
        uint256 factorReth = unitRethTWAP.div(unitRethOracle);
        // Calculate stETH market premium/discount (factor)
        uint256 unitWstethTWAP = OracleLibrary.estimateTWAP(1 ether, 30 minutes, VAULT.WSTETH_WETH, VAULT.WSTETH, C.WETH);
        uint256 unitWstethOracle = bridgeSteth.getUnitDethValue();
        uint256 factorSteth = unitWstethTWAP.div(unitWstethOracle);
        if (factorReth > factorSteth) {
            // rETH market premium relative to stETH
            if (bridgePointer == VAULT.BRIDGE_RETH) {
                // Only charge fee if withdrawing rETH
                return factorReth.div(factorSteth) - 1 ether;
            }
        } else if (factorSteth > factorReth) {
            // stETH market premium relative to rETH
            if (bridgePointer == VAULT.BRIDGE_STETH) {
                // Only charge fee if withdrawing stETH
                return factorSteth.div(factorReth) - 1 ether;
            }
        } else {
            // Withdrawing less premium LST or premiums are equivalent
            return 0;
        }
    }
```

This function is used to bridge fees so as to prevent free arbitrage, fee charged is the premium/discount differential, keep in mind that this function is also called whenever [BridgeRouterFacet.withdraw()](https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/facets/BridgeRouterFacet.sol#L101) is called, case here hpwever is that the `estimateTwap()` hardcodes a `secondsAgo` value of 30 minutes, but this is too much of a duration for twap, coupling this with the fact that the crypto bull run just kicked in, using a value of `30` minutes would more often than not cause for wrong prices to be used to calculate the fee, essentially breaking the accounting in `s.vaultUser[vault][address(this)].ethEscrowed += fee` that gets updated in the bridge router facet.

Considering this integration is done with uniswap and not chainlink (i.e chainlink eth feed has a heartbeat of 3600, or deviation of 0.5% so its more often than not an accurate price provider), but here having the twap duration at 30 minutes leave the