DittoETH - foxb868's results

A decentralized stablecoin protocol with an order book design for supercharged staking yield.

General Information

Platform: Code4rena

Start Date: 15/03/2024

Pot Size: $60,500 USDC

Total HM: 16

Participants: 43

Period: 21 days

Judge: hansfriese

Total Solo HM: 5

Id: 348

League: ETH

DittoETH

Findings Distribution

Researcher Performance

Rank: 27/43

Findings: 2

Award: $91.81

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Infect3d

Also found by: Evo, LinKenji, XDZIBECX, falconhoof, foxb868, ilchovski, klau5, nonseodion

Labels

bug
2 (Med Risk)
satisfactory
sufficient quality report
:robot:_211_group
duplicate-114

Awards

67.2468 USDC - $67.25

External Links

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

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

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 orderbook. The bidMatchAlgo function updates the oracle price and startingShortId if the price difference between the incoming bid and the cached oracle price exceeds a threshold. The sellMatchAlgo function adds the incoming ask order to the orderbook if its price is below the cached oracle price.

Vulnerability Details

The edge case arises from the combination of the 0.5% buffer, backwards matching logic, and the use of stale prices due to the 15-minute caching window.

The conditions that enable this

  • The system allows for a 0.5% buffer when matching orders, considering prices within this range as valid matches.
  • The backwards matching logic is employed to find a valid match in case of a price mismatch.
  • The 15-minute caching window can lead to the use of stale prices if market conditions change significantly within that time frame.

The codes responsible are:

The actual behavior of the system deviates from the expected behavior in the following ways:

  • Exploitation of the 0.5% buffer and backwards matching logic:
    • An attacker can place orders with prices just within the 0.5% buffer of the cached oracle price.
    • The attacker's orders can get matched with existing orders based on the cached price, even if the actual market price has diverged.
    • The attacker can profit from the price discrepancy between the cached price and the real-time market price.
  • Use of stale prices:
    • The 15-minute caching window can lead to the use of stale prices if market conditions change significantly within that time frame.
    • Orders can be matched based on stale prices, resulting in trades that do not align with the current market conditions.
    • Users may end up buying or selling assets at prices that are no longer favorable or accurate.

These behaviors deviate from the intended fair and accurate matching of orders based on up-to-date price information.

Impact

  • Users may suffer financial losses if their orders are matched at prices that are not reflective of the current market conditions.
    • Buying or selling assets based on stale prices can lead to unfavorable trades and potential losses.

Proof of Concept

Scenario:

  1. The current market price of the asset is $100.
  2. The cached oracle price for the asset is $100, which was updated 14 minutes ago.
  3. The orderbook has the following existing orders:
    • Sell orders:
      • 1000 tokens at $100.50
      • 500 tokens at $101
    • Buy orders:
      • 800 tokens at $99.50
      • 1200 tokens at $99
  4. The market price suddenly drops to $95 due to external factors.

Steps:

  1. An attacker observes the market conditions and identifies an opportunity to exploit the vulnerability.

  2. The attacker places a buy order for 1500 tokens at $99.75, which is within the 0.5% buffer of the cached oracle price ($100).

   function placeBuyOrder(address asset, uint256 amount, uint256 price) external {
       STypes.Order memory order = STypes.Order({
           addr: msg.sender,
           price: price,
           ercAmount: amount,
           id: nextOrderId,
           orderType: O.LimitBid,
           creationTime: block.timestamp
       });
       
       MTypes.OrderHint[] memory orderHintArray;
       uint16[] memory shortHintArray;
       
       (uint88 ethFilled, uint88 ercAmountLeft) = bidMatchAlgo(asset, order, orderHintArray, shortHintArray);
       
       // Update user's balance and order state
       // ...
   }
  1. The bidMatchAlgo function is called with the attacker's buy order.

    • The cached oracle price is still $100, as it hasn't been updated within the 15-minute window.
    • The _getLowestSell function returns the sell order with the price of $100.50 as the lowest sell order.
    • The condition if (incomingBid.price >= lowestSell.price) is satisfied since the attacker's buy price of $99.75 is within the 0.5% buffer of the sell order price.
    • The updateOracleAndStartingShortViaThreshold function is called, but since the price difference is within the threshold, no update occurs.
  2. The bidMatchAlgo function proceeds to match the attacker's buy order with the existing sell orders.

    • The sell order of 1000 tokens at $100.50 is matched with the attacker's buy order at the price of $100.50, even though the current market price has dropped to $95.
    • The remaining 500 tokens of the attacker's buy order are matched with the sell order of 500 tokens at $101, also at the stale price.
  3. The attacker successfully buys 1500 tokens at an average price of $100.67, which is significantly higher than the current market price of $95.

Potential Consequences:

  • Users who placed sell orders at prices above the current market price may experience opportunity costs if their orders are filled at the stale cached price.
  • The protocol may accumulate losses if the market price continues to move against the filled orders.
  • The integrity of the order matching process is compromised, as orders are being matched based on stale prices that do not reflect the current market conditions.
  • Users may lose trust in the protocol if they consistently experience losses due to the use of stale prices and the exploitation of the 0.5% buffer.
  1. Reduce the caching window:

    • Shorten the caching window to a smaller time frame (e.g., 5 minutes) to reduce the chances of using stale prices.
    • Regularly update the cached price to reflect the latest market conditions.
    function updateCachedPrice(address asset) internal { uint256 currentTime = block.timestamp; if (currentTime - lastPriceUpdateTime[asset] >= 5 minutes) { cachedPrice[asset] = fetchLatestPrice(asset); lastPriceUpdateTime[asset] = currentTime; } }
  2. Implement price deviation checks:

    • Compare the cached oracle price with the real-time market price obtained from reliable external sources.
    • If the price deviation exceeds a certain threshold (e.g., 1%), trigger a price update or halt the order matching process until the price is refreshed.
    function isValidPrice(address asset, uint256 price) internal view returns (bool) { uint256 cachedPrice = getCachedPrice(asset); uint256 realTimePrice = fetchRealTimePrice(asset); uint256 deviation = calculateDeviation(cachedPrice, realTimePrice); return deviation <= MAX_DEVIATION_THRESHOLD; }
  3. Enhance the hint system:

    • Improve the hint system to take into account the potential price changes within the caching window.
    • Incorporate additional checks and validations to ensure the accuracy and reliability of the hints provided by users.
    function validateHint(address asset, uint256 hintPrice) internal view returns (bool) { uint256 cachedPrice = getCachedPrice(asset); uint256 realTimePrice = fetchRealTimePrice(asset); uint256 deviation = calculateDeviation(hintPrice, realTimePrice); return deviation <= MAX_HINT_DEVIATION_THRESHOLD; }
  4. Implement circuit breakers:

    • Set up circuit breakers that halt trading or limit order matching when significant price deviations or unusual market activities are detected.
    • Define thresholds for price movements or trading volumes that trigger the circuit breakers.
    function checkCircuitBreaker(address asset) internal view { uint256 priceDeviation = calculatePriceDeviation(asset); uint256 tradingVolume = calculateTradingVolume(asset); if (priceDeviation >= CIRCUIT_BREAKER_PRICE_THRESHOLD || tradingVolume >= CIRCUIT_BREAKER_VOLUME_THRESHOLD) { // Halt trading or limit order matching // ... } }

Assessed type

Context

#0 - c4-pre-sort

2024-04-07T04:43:36Z

raymondfam marked the issue as sufficient quality report

#1 - c4-pre-sort

2024-04-07T04:43:45Z

raymondfam marked the issue as duplicate of #114

#2 - raymondfam

2024-04-07T04:45:20Z

Kind of unstructured in terms of POC when compared to that of #114 and #128.

#3 - c4-judge

2024-04-11T16:12:45Z

hansfriese marked the issue as satisfactory

Findings Information

Labels

analysis-advanced
grade-b
sufficient quality report
A-08

Awards

24.5635 USDC - $24.56

External Links

Overview

DittoETH is a decentralized stablecoin protocol that aims to provide stable assets backed by over-collateralized staked ETH. It utilizes an order book design to match buyers and sellers, allowing for efficient price discovery and liquidity provision. The protocol incentivizes liquidity providers with supercharged staking yields, making it attractive for users to participate in the system.

Approach Taken in Evaluating the Codebase: Day 1

1. Code Review:

  • I conducted a line-by-line review of the DittoETH code.
  • I analyzed the code for potential security vulnerabilities, such as reentrancy attacks, integer overflows/underflows, and access control issues for my understanding.
  • Also reviewed the code for adherence to best practices and coding standards.

2. Architecture Review:

  • Examined the overall design and architecture of the DittoETH protocol based on the Documentation.
  • Assessed the interaction between different components and contracts.
  • Identified potential areas of concern and complexity.

3. Mechanism Review:

  • I also analyzed the mechanisms and functionalities of the DittoETH protocol, such as order matching, oracle usage, and liquidation processes.
  • Evaluated the potential risks and vulnerabilities associated with these mechanisms.

4. Centralization and Admin Control:

  • Examined the level of centralization in the protocol's governance and admin roles.
  • Assessed the potential risks associated with admin control and abuse.

5. Systemic Risks:

  • Evaluated the potential systemic risks of the DittoETH protocol, considering factors such as market dynamics, liquidity, and external dependencies.

Codebase Quality Analysis: Day 2

Based on the Codebase, here are some of my observations regarding the codebase quality:

1. Modularization and Separation of Concerns:

  • The codebase seems to follow a modular structure, with separate contracts for different functionalities (e.g., BidOrdersFacet, ExitShortFacet).
  • This modularization helps in maintaining a clear separation of concerns and improves code readability and maintainability.

2. Use of Libraries and Interfaces:

  • The codebase utilizes libraries (e.g., LibSRUtil, LibOracle) and interfaces (e.g., IUniswapV3Pool), which promotes code reusability and abstraction.
  • The use of libraries and interfaces can enhance code organization and facilitate unit testing.

3. Error Handling and Validation:

  • The code includes error handling and validation checks, such as requiring certain conditions to be met before executing specific actions (e.g., isNotFrozen, onlyValidShortRecord).
  • These checks help in preventing invalid or unauthorized actions and improve the overall robustness of the system.

Code Documentation and Comments

  • The code snippets contain some comments and documentation, which aids in understanding the purpose and functionality of different parts of the codebase.
  • However, more comprehensive documentation, including function descriptions, parameter explanations, and high-level overviews, would further enhance the codebase's readability and maintainability.

Architecture Risks and Recommendations: Day 3

1. Complexity and Interdependencies:

  • The DittoETH protocol involves multiple contracts and mechanisms, such as order matching, margin calls, and liquidations, which can introduce complexity and interdependencies.
  • My Recommendation: Ensure the correct interaction and behavior of these components. Consider simplifying the architecture where possible to reduce complexity and potential vulnerabilities.

2. Oracle Dependency:

  • The protocol relies on oracle prices for various calculations and decision-making processes.
  • My Recommendation: Ensure the reliability and security of the oracle solution used. Implement measures to handle oracle failures or price manipulations, such as using multiple oracles, price deviation checks, and fallback mechanisms.

3. Liquidation and Margin Call Mechanisms:

  • The liquidation and margin call processes are critical components of the protocol and can have significant impact on users' positions and funds.
  • My Recommendation: Validate the liquidation and margin call mechanisms to ensure their correctness and fairness. Consider implementing safeguards, such as price thresholds and time delays, to prevent unnecessary or malicious liquidations.

4. Upgradability and Contract Migration:

  • The code do not explicitly mention upgradability or contract migration mechanisms.
  • My Recommendation: Consider implementing a robust upgradability solution, such as proxy contracts or the diamond pattern, to facilitate future updates and improvements to the protocol. Ensure that the upgradability mechanism is secure and does not introduce additional risks.

Centralization Risks and Admin Control Abuse:

1. Admin Roles and Privileges:

  • The code mention admin roles, such as onlyDAO, which grant special privileges to certain addresses.
  • My Recommendation: Clearly define and document the responsibilities and powers of admin roles. Implement multi-signature or time-locked mechanisms to prevent unilateral control and abuse of admin privileges.

2. Governance Centralization:

  • The information does not detail the governance structure of the DittoETH protocol.
  • My Recommendation: Ensure that the governance mechanism is decentralized and involves the participation of the community. Implement transparent and secure voting processes to prevent centralized control and manipulation of protocol decisions.

Mechanism Review and Explanation:

1. Order Matching:

  • The bidMatchAlgo and sellMatchAlgo functions handle the matching of incoming orders with existing orders in the orderbook.
  • The matching process considers the price and availability of orders, and executes trades accordingly.
  • Potential risks include front-running attacks, where malicious actors can manipulate the order of transactions to their advantage.
  • My Recommendation: Implement measures to prevent front-running, such as order batching, random order matching, or the use of a commit-reveal scheme.

2. Short Order Matching:

  • The protocol includes a unique mechanism for matching Short Orders only at or above the oracle price.
  • The bidMatchAlgo function updates the oracle price and the startingShortId based on certain thresholds.
  • Potential risks include oracle price manipulation and the use of stale prices, which can lead to incorrect matching and potential losses for users.
  • Recommendation: Implement robust oracle price validation, price deviation checks, and consider using multiple oracle sources to mitigate the risk of price manipulation.

3. Liquidation and Margin Calls:

  • The liquidate function in the PrimaryLiquidationFacet contract allows for the liquidation of undercollateralized short positions.
  • The liquidation process involves a forced bid on the orderbook, with the liquidator receiving a fee for their service.
  • Potential risks include insufficient incentives for liquidators, which may lead to delayed or failed liquidations, and the potential for malicious liquidations.
  • My Recommendation: Ensure that the liquidation incentives are adequate to attract liquidators and consider implementing safeguards against malicious liquidations, such as price thresholds and time delays.

Systemic Risks:

1. Dependency on External Protocols:

  • The DittoETH protocol interacts with external protocols, such as Uniswap, for price oracle functionality.
  • Potential risks include the failure or manipulation of these external protocols, which can impact the stability and security of DittoETH.
  • Recommendation: Implement fallback mechanisms and circuit breakers to handle potential failures or anomalies in these protocols.

2. Liquidity and Market Dynamics:

  • The protocol's stability and effectiveness depend on sufficient liquidity in the orderbook and the overall market dynamics.
  • Potential risks include low liquidity, which can lead to price slippage and increased volatility, and the impact of large market movements on the protocol's collateralization and stability.
  • Recommendation: Incentivize liquidity provision and implement mechanisms to manage liquidity risks, such as dynamic fees and market making strategies. Continuously monitor and assess the protocol's resilience to various market conditions.

3. Stablecoin Peg Stability:

  • The DittoETH protocol aims to maintain a stable peg for its stablecoin.
  • Potential risks include peg deviations, which can occur due to market imbalances, collateral volatility, or loss of user confidence.
  • Recommendation: Implement robust stabilization mechanisms, such as adaptive collateralization ratios, algorithmic pricing, and emergency intervention measures. Regularly monitor and assess the stablecoin's peg stability and take proactive actions to maintain its integrity.

Code Snippets a few highlight of potential issues and areas for improvement:

  1. Oracle Price Manipulation:
    • In the bidMatchAlgo function, the updateOracleAndStartingShortViaThreshold function is called to update the oracle price based on certain thresholds.
    • Potential issue: If the oracle price can be manipulated, it could lead to incorrect order matching and potential losses for users.
    • Recommendation: Implement robust oracle price validation, price deviation checks, and consider using multiple oracle sources to mitigate the risk of price manipulation.
function bidMatchAlgo(
    address asset,
    STypes.Order memory incomingBid,
    MTypes.OrderHint[] memory orderHintArray,
    MTypes.BidMatchAlgo memory b
) private returns (uint88 ethFilled, uint88 ercAmountLeft) {
    // ...
    STypes.Order memory lowestSell = _getLowestSell(asset, b);
    if (incomingBid.price >= lowestSell.price) {
        // ...
        LibOrders.updateOracleAndStartingShortViaThreshold(asset, LibOracle.getPrice(asset), incomingBid, shortHintArray);
        // ...
    }
    // ...
}

BidOrdersFacet.sol#108

2. Front-Running Vulnerability:

  • The bidMatchAlgo and sellMatchAlgo functions match incoming orders with existing orders based on price.
  • Potential issue: Malicious actors can monitor pending transactions and front-run orders by submitting their own transactions with higher gas prices, potentially manipulating the order matching process.
  • Recommendation: Implement measures to prevent front-running, such as order batching, random order matching, or the use of a commit-reveal scheme.
function bidMatchAlgo(
    address asset,
    STypes.Order memory incomingBid,
    MTypes.OrderHint[] memory orderHintArray,
    MTypes.BidMatchAlgo memory b
) private returns (uint88 ethFilled, uint88 ercAmountLeft) {
    // ...
    while (true) {
        // ...
        STypes.Order memory lowestSell = _getLowestSell(asset, b);
        if (incomingBid.price >= lowestSell.price) {
            matchlowestSell(asset, lowestSell, incomingBid, matchTotal);
            // ...
        }
        // ...
    }
}

function sellMatchAlgo(
    address asset,
    STypes.Order memory incomingAsk,
    MTypes.OrderHint[] memory orderHintArray,
    uint256 minAskEth
) internal {
    // ...
    while (true) {
        STypes.Order memory highestBid = s.bids[asset][startingId];
        if (incomingAsk.price <= highestBid.price) {
            matchHighestBid(incomingAsk, highestBid, asset, matchTotal);
            // ...
        }
        // ...
    }
}

3. Liquidation Incentives and Risks:

  • The liquidate function in the PrimaryLiquidationFacet contract allows for the liquidation of undercollateralized short positions.
  • Potential issue: If the liquidation incentives are not sufficient, it may lead to delayed or failed liquidations, putting the protocol at risk.
  • Recommendation: Ensure that the liquidation incentives (callerFee and gasFee) are adequate to attract liquidators and consider implementing safeguards against malicious liquidations, such as price thresholds and time delays.
function liquidate(address asset, address shorter, uint8 id, uint16[] memory shortHintArray, uint16 shortOrderId)
    external
    isNotFrozen(asset)
    nonReentrant
    onlyValidShortRecord(asset, shorter, id)
    returns (uint88, uint88)
{
    // ...
    _performForcedBid(m, shortHintArray);
    _liquidationFeeHandler(m);
    // ...
}

function _liquidationFeeHandler(MTypes.PrimaryLiquidation memory m) private {
    // ...
    uint88 callerFee = m.ethFilled.mulU88(m.callerFeePct) + m.gasFee;
    // ...
}

Recommendations:

  1. Implement robust oracle solutions: Ensure the reliability and security of the price oracle mechanisms used in the protocol. Consider using multiple oracle sources, implementing price deviation checks, and establishing fallback mechanisms to handle oracle failures or manipulations.

  2. Enhance front-running protection: Implement measures to prevent front-running attacks, such as order batching, random order matching, or the use of a commit-reveal scheme. Consider utilizing technologies like zero-knowledge proofs or secure multi-party computation to enhance transaction privacy.

  3. Strengthen governance and admin controls: Clearly define and document the roles and responsibilities of admin and governance functions. Implement multi-signature requirements, time-locks, and other safeguards to prevent unauthorized or malicious actions by privileged accounts.

  4. Develop comprehensive test suites, including unit tests, integration tests, and scenario-based tests, to ensure the correctness and robustness of the protocol's mechanisms. Perform regular audits and security assessments to identify and address potential vulnerabilities.

  5. Enhance the codebase documentation, including detailed comments, function descriptions, and high-level overviews. Ensure that the code is well-structured, modular, and follows best practices for readability and maintainability.

  6. Develop and document contingency plans to handle potential risks, such as market volatility, liquidity crises, or system failures. Define clear procedures for emergency interventions, including the use of circuit breakers and emergency governance actions.

Potential weaknesses, centralization risks, and improvement points in the DittoETH codebase

1. Oracle Manipulation:

  • Weakness: I see that the protocol relies heavily on the accuracy and reliability of the oracle price feeds. If the oracle is manipulated, it could lead to incorrect price information and potential exploits.
  • Code Snippet:: #L108
    function bidMatchAlgo(
        address asset,
        STypes.Order memory incomingBid,
        MTypes.OrderHint[] memory orderHintArray,
        MTypes.BidMatchAlgo memory b
    ) private returns (uint88 ethFilled, uint88 ercAmountLeft) {
        // ...
        LibOrders.updateOracleAndStartingShortViaThreshold(asset, LibOracle.getPrice(asset), incomingBid, shortHintArray);
        // ...
    }
  • Improvement Points:
    • Implement robust oracle price validation mechanisms, such as using multiple oracle sources, median pricing, and price deviation checks.
    • Consider using decentralized oracle solutions like Chainlink to reduce the risk of single point of failure.
    • Implement circuit breakers and emergency price feeds to handle situations where the primary oracle fails or is manipulated.

2. Front-Running Vulnerability:

  • Weakness: The order matching process is susceptible to front-running attacks, where malicious actors can monitor pending transactions and insert their own transactions with higher gas prices to manipulate the order execution.
  • Code Snippet: bidMatchAlgo
    function bidMatchAlgo(
        address asset,
        STypes.Order memory incomingBid,
        MTypes.OrderHint[] memory orderHintArray,
        MTypes.BidMatchAlgo memory b
    ) private returns (uint88 ethFilled, uint88 ercAmountLeft) {
        // ...
        while (true) {
            // ...
            STypes.Order memory lowestSell = _getLowestSell(asset, b);
            if (incomingBid.price >= lowestSell.price) {
                matchlowestSell(asset, lowestSell, incomingBid, matchTotal);
                // ...
            }
            // ...
        }
    }
  • Improvement Points:
    • Implement a commit-reveal scheme or a batch auction mechanism to prevent front-running attacks.
    • Use cryptographic techniques like zero-knowledge proofs or secure multi-party computation to hide the order details until the execution phase.
    • Implement a fair ordering mechanism, such as using a verifiable delay function (VDF) or a decentralized sequencer, to determine the order of transaction execution.
  1. Sandwich Attack Vulnerability:
    • Weakness: The order matching process is vulnerable to sandwich attacks, where an attacker can place orders both before and after a pending order to manipulate the price and profit from the price difference.
    • Code Snippet: sellMatchAlgo
      function sellMatchAlgo(
          address asset,
          STypes.Order memory incomingAsk,
          MTypes.OrderHint[] memory orderHintArray,
          uint256 minAskEth
      ) internal {
          // ...
          while (true) {
              STypes.Order memory highestBid = s.bids[asset][startingId];
              if (incomingAsk.price <= highestBid.price) {
                  matchHighestBid(incomingAsk, highestBid, asset, matchTotal);
                  // ...
              }
              // ...
          }
      }
    • Improvement Points:
      • Implement a random order matching mechanism to make it harder for attackers to predict and manipulate the order execution.
      • Use a time-weighted average price (TWAP) or a volume-weighted average price (VWAP) to determine the execution price, reducing the impact of short-term price manipulations.
      • Implement monitoring and detection mechanisms to identify and flag suspicious trading patterns indicative of sandwich attacks.

Susceptibility of the order matching process to sandwich attacks, where an attacker can manipulate the price by placing orders both before and after a pending order, potentially leading to financial losses for the sandwiched user.

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

bidMatchAlgo function

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

sellMatchAlgo function

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 lack of protection against sandwich attacks in the order matching process. An attacker can exploit this vulnerability by placing orders both before and after a pending order, manipulating the price in their favor.

The specific conditions that enable this vulnerability are:

  • The order matching process relies solely on price for determining the order of execution.
  • There are no mechanisms in place to detect or prevent sandwich attacks.

Lines of code responsible for the vulnerability.

  • In bidMatchAlgo, the comparison if (incomingBid.price >= lowestSell.price) matches the incoming bid with the lowest sell order based on price.
  • In sellMatchAlgo, the comparison if (incomingAsk.price <= highestBid.price) matches the incoming ask with the highest bid order based on price.

Recommendation

  1. Introduce a random order matching mechanism:

    • Instead of matching orders strictly based on price, introduce randomness in the order matching process.
    • This makes it more difficult for attackers to predict and exploit the exact order of execution.
    function matchOrders(address asset, STypes.Order memory incomingOrder) internal {
        // ... code ...
        uint256 randomValue = getRandomValue();
        uint256 orderIndex = randomValue % orders.length;
        STypes.Order memory matchingOrder = orders[orderIndex];
        // ... code ...
    }
  2. Implement a time-based order priority:

    • Assign a timestamp to each order when it is placed.
    • Prioritize orders based on their timestamp, giving preference to orders that were placed earlier.
    • This reduces the effectiveness of sandwich attacks, as the attacker's orders may not be executed immediately before and after the targeted order.
    function addOrder(STypes.Order memory order) internal {
        order.timestamp = block.timestamp;
        // ... code ...
    }
    
    function matchOrders(address asset, STypes.Order memory incomingOrder) internal {
        // ... code ...
        STypes.Order[] memory sortedOrders = sortOrdersByTimestamp(orders);
        // ... code ...
    }
  3. Use a batch auction mechanism:

    • Instead of continuous order matching, implement a batch auction mechanism.
    • Collect orders over a fixed time interval and execute them in a single batch at the end of the interval.
    • This makes it harder for attackers to sandwich specific orders, as the execution is not immediate.
    function batchAuction(address asset) external {
        // ... code ...
        STypes.Order[] memory batchedOrders = collectOrders(asset);
        // ... code ...
        executeBatchOrders(batchedOrders);
        // ... code ...
    }
  4. Implement monitoring and detection mechanisms:

    • Continuously monitor the order flow and trading activities for patterns that indicate potential sandwich attacks.
    • Utilize machine learning algorithms or heuristics to detect and flag suspicious trading behavior.
    • Investigate and take appropriate actions against accounts engaging in sandwich attacks.
    function monitorTrading(address asset) external {
        // ... code ...
        STypes.Order[] memory recentOrders = getRecentOrders(asset);
        bool isSuspicious = detectSuspiciousActivity(recentOrders);
        if (isSuspicious) {
            // Flag the suspicious activity and take appropriate actions
            // ...
        }
        // ... code ...
    }

4. Liquidity Provider Risks:

  • Weakness: Liquidity providers (LPs) who contribute assets to the DittoETH system may be exposed to impermanent loss and other risks associated with providing liquidity.
  • Improvement Points:
    • Implement mechanisms to mitigate impermanent loss, such as using dynamic fees or liquidity incentives based on market conditions.
    • Provide clear documentation and risk disclosures to LPs, highlighting the potential risks and rewards of providing liquidity.
    • Implement emergency withdrawal mechanisms for LPs to allow them to remove their liquidity in case of market disruptions or protocol issues.

5. Governance Centralization Risks:

  • Weakness: The protocol's governance mechanism may be centralized, giving excessive control to a small group of token holders or the development team.
  • Improvement Points:
    • Implement a decentralized governance model that distributes decision-making power among a diverse set of stakeholders.
    • Use token-based voting mechanisms that allow token holders to participate in governance decisions proportional to their token holdings.
    • Implement governance safeguards, such as multi-sig wallets, time-locks, and governance upgrade delays, to prevent hastily made or malicious governance decisions.

7. Upgradability Risks:

  • Weakness: The protocol may use upgradable contracts, which can introduce risks if the upgrade mechanism is not properly implemented or secured.
  • Improvement Points:
    • Follow best practices for upgradable contracts, such as using the transparent proxy pattern or the diamond standard.
    • Implement strict access controls and governance mechanisms for contract upgrades to prevent unauthorized or malicious upgrades.

8. Flash Loan Risks:

  • Weakness: The protocol may be vulnerable to flash loan attacks, where an attacker can borrow a large amount of assets, manipulate the market, and profit from the price discrepancies.
  • Improvement Points:
    • Implement flash loan protection mechanisms, such as requiring a minimum holding period for borrowed assets or imposing a flash loan fee.
    • Monitor and detect suspicious flash loan activities and implement emergency stop mechanisms to halt the protocol in case of an ongoing attack.
    • Regularly update and adapt the flash loan protection measures based on the evolving DeFi landscape and new attack vectors.

9. Code Quality and Security Best Practices:

  • Weakness: The codebase may have potential vulnerabilities or may not follow security best practices, increasing the risk of exploits and attacks.
  • Improvement Points:
    • Follow established security best practices, such as using safe math libraries, performing input validation, and avoiding common pitfalls like reentrancy and integer overflows.
    • Implement comprehensive test suites, including unit tests, integration tests, and fuzz testing, to ensure the robustness and correctness of the codebase.
    • Maintain clear and up-to-date documentation, including code comments, to facilitate code review and maintenance.

These are some of the weaknesses i may have noticed from the CodeBase, centralization risks, and improvement points identified in the DittoETH codebase.

System

The DittoETH system consists of several key components:

  1. Vaults: Vaults hold the collateral (staked ETH) and are used to mint stable assets. Each vault can support multiple stable assets.

  2. Bridges: Bridges allow users to deposit and withdraw their staked ETH (such as rETH and stETH) into and out of the vaults.

  3. Orderbook: The orderbook is a decentralized exchange mechanism that matches buy and sell orders for stable assets. It supports limit orders, market orders, and short orders.

  4. ShortRecord: ShortRecords represent the debt positions of users who have minted stable assets by providing collateral. They track the collateral ratio and allow for liquidation if the ratio falls below a certain threshold.

  5. Liquidation Mechanism: The liquidation mechanism ensures that the system remains solvent by liquidating undercollateralized ShortRecords and redistributing the collateral to maintain the stability of the stable assets.

  6. Oracle: The oracle provides price feeds for the assets in the system, enabling accurate pricing and collateralization calculations.

Functions

The DittoETH various functions that enable the core functionalities of the system:

1. Vault Functions:

  • createVault: Creates a new vault to hold collateral and mint stable assets.
  • depositAsset: Allows users to deposit stable assets into the vault.
  • withdrawAsset: Allows users to withdraw stable assets from the vault.

2. Bridge Functions:

  • deposit: Allows users to deposit staked ETH (e.g., rETH, stETH) into the vault.
  • depositEth: Allows users to deposit ETH directly into the vault, which is then converted to staked ETH.
  • withdraw: Allows users to withdraw their staked ETH from the vault.

3. Orderbook Functions:

  • createBid: Creates a buy order in the orderbook.
  • createAsk: Creates a sell order in the orderbook.
  • createLimitShort: Creates a limit short order in the orderbook.
  • cancelOrder: Cancels an existing order in the orderbook.

4. ShortRecord Functions:

  • createShortRecord: Creates a new ShortRecord when a short order is matched.
  • updateShortRecord: Updates the collateral and debt of a ShortRecord.
  • liquidateShortRecord: Liquidates an undercollateralized ShortRecord.

5. Liquidation Functions:

  • liquidate: Initiates the liquidation process for an undercollateralized ShortRecord.
  • redistributeCollateral: Redistributes the collateral of a liquidated ShortRecord to maintain system solvency.

6. Oracle Functions:

  • getPrice: Retrieves the current price of an asset from the oracle.
  • setPrice: Sets the price of an asset in the oracle (admin function).

Roles

  1. Users: Regular users who interact with the DittoETH protocol to mint stable assets, provide liquidity, or trade on the orderbook.

  2. Liquidity Providers (LPs): Users who deposit their staked ETH into the vaults to provide liquidity and earn staking yields.

  3. Shorters: Users who mint stable assets by creating short positions and providing collateral.

  4. Liquidators: Users or bots that monitor the system for undercollateralized ShortRecords and initiate the liquidation process to maintain system solvency.

  5. Oracles: External entities that provide price feeds for the assets in the system.

  6. Admin: An administrative role with privileged access to certain functions, such as setting oracle prices or managing system parameters.

Architecture

The DittoETH protocol follows a decentralized architecture, with smart contracts deployed on the Ethereum blockchain. The high-level workflow of the system is as follows:

  1. Users deposit their staked ETH (rETH, stETH) into the vaults through the bridge contracts.

  2. Shorters create short positions by minting stable assets and providing collateral. They specify the collateral ratio and the amount of stable assets they wish to mint.

  3. Buyers and sellers place orders on the orderbook, specifying the price and quantity of stable assets they want to trade.

  4. The orderbook matches buy and sell orders based on price priority. When a match occurs, the stable assets are exchanged, and the collateral is updated accordingly.

  5. If a shorter's collateral ratio falls below the liquidation threshold, liquidators can initiate the liquidation process to close the short position and redistribute the collateral.

  6. The oracle provides real-time price feeds for the assets in the system, ensuring accurate pricing and collateralization calculations.

  7. Users can withdraw their staked ETH from the vaults through the bridge contracts, subject to any applicable fees or lock-up periods.

The DittoETH protocol utilizes various mathematical models and algorithms to ensure the stability of the minted assets, calculate collateral ratios, and determine liquidation thresholds. The system is designed to be self-sustaining and resistant to market volatility and manipulation.

Overall, DittoETH aims to provide a decentralized and efficient platform for minting stable assets backed by staked ETH, while offering attractive staking yields to liquidity providers. The order book design enables price discovery and liquidity, while the liquidation mechanism ensures the solvency and stability of the system.

Time spent:

30 hours

#0 - c4-pre-sort

2024-04-07T20:25:14Z

raymondfam marked the issue as sufficient quality report

#1 - c4-judge

2024-04-17T07:11:10Z

hansfriese marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter