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
Rank: 16/43
Findings: 1
Award: $307.67
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: popeye
Also found by: 0xbrett8571, JcFichtner, LinKenji, Rhaydden, SAQ, Sathish9098, albahaca, clara, emerald7017, fouzantanveer, foxb868, hunter_w3b, kaveyjoe, roguereggiant
307.6743 USDC - $307.67
DittoETH
is a decentralized pegged asset issuance protocol built on the Ethereum blockchain. The protocol aims to create a platform for users to mint and trade pegged assets, known as DittoAssets
, which are collateralized by liquid staked ETH (LST)
such as rETH
and stETH
. DittoETH
draws inspiration from the original Bitshares implementation of polymorphic digital assets (PMDA)
and utilizes an orderbook model for asset exchange.
At its core, DittoETH
allows users to deposit LSTs
or ETH
into vaults, which serve as collateral for minting DittoAssets. The protocol introduces the concept of dETH
, an internal representation of the deposited collateral that enables users to earn staking rewards. When a user deposits LSTs
or ETH
, they receive an equivalent amount of dETH
, which is escrowed within the protocol.
The minting of DittoAssets
occurs through a unique orderbook mechanism. Users can place bids to purchase DittoAssets using their dETH
collateral, while shorters can place asks to mint and sell DittoAssets. When a bid and an ask are matched, the DittoAsset
is minted and transferred to the bidder, while the shorter receives the dETH
collateral from the bidder. This collateral is added to the shorter's existing collateral, allowing them to earn additional staking rewards.
To ensure the stability and solvency of the system, DittoETH
requires shorters to maintain a minimum collateralization ratio, typically set at 170% (initialCR
). If a shorter's collateralization ratio falls below the liquidation threshold, their position can be liquidated by liquidators, who are incentivized to maintain the health of the protocol.
The protocol also incorporates various mechanisms to handle edge cases and maintain the peg of DittoAssets
. These include a dynamic tithe system that adjusts fees based on market conditions, a redemption mechanism that allows DittoAsset holders to redeem their assets for the underlying collateral, and a Treasury Asset Protection Pool (TAPP
) that acts as a stability fund to absorb potential losses.
DittoETH shares similarities with other decentralized finance (DeFi) protocols like MakerDAO and Synthetix in terms of collateralized debt positions and pegged asset issuance. However, it distinguishes itself through its use of LSTs as collateral, the orderbook-based minting mechanism, and the incentive structure for shorters to earn additional rewards.
The protocol's smart contracts are organized into a modular structure using the Diamond standard, allowing for flexibility and upgradability. The core contracts include:
VaultFacet
: Handles the management of vaults, deposits, and withdrawals of collateral.BridgeRouterFacet
: Facilitates the interaction with external LST bridges for depositing and withdrawing collateral.BidOrdersFacet
and ShortOrdersFacet
: Manage the creation and matching of bid and short orders on the orderbook.PrimaryLiquidationFacet
: Handles the liquidation of undercollateralized short positions.RedemptionFacet
: Enables the redemption of DittoAssets for the underlying collateral.The protocol also relies on external price oracles, such as Chainlink and Uniswap V3 TWAPs, to determine asset prices and ensure the accuracy of the system.
Here's a diagram that provides an overview of the DittoETH protocol:
If the diagram is not visible, please CLICK HERE
In the DittoETH protocol, there are several key roles and actors, each with their own privileges and responsibilities. These roles include:
DittoETH
protocol.Here's a diagram in Mermaid code that illustrates the roles and actors in the DittoETH
protocol:
If the diagram is not visible, please CLICK HERE
This diagram shows the relationships and interactions between the different roles and actors in the DittoETH
protocol. The arrows indicate the actions and privileges associated with each role, such as depositing collateral, placing orders, maintaining collateralization ratios, liquidating positions, redeeming DittoAssets
, governing the protocol, and providing price feeds.
The diagram aims to provide a clear visual representation of the roles and their respective privileges within the DittoETH
ecosystem. It highlights the interdependencies and the flow of assets and information among the various actors.
DittoETH is built on a robust and modular architecture that adheres to the Diamond standard, enabling the protocol to achieve a high degree of flexibility, upgradability, and separation of concerns. The architecture is meticulously designed to support the core functionalities of minting, trading, and redeeming pegged assets, known as DittoAssets, which are collateralized by liquid staked ETH (LSTs) such as rETH and stETH.
At the heart of the DittoETH architecture lies the AppStorage
contract, which serves as the central repository for all the critical state variables and data structures of the protocol. The AppStorage
contract employs a well-organized system of mappings and structs to efficiently store and manage information pertaining to vaults, assets, users, orders, and short records.
The vault
mapping associates a unique identifier (uint256
) with a Vault
struct, which encapsulates the essential properties and state of each vault within the protocol. This includes data such as the total dETH balance, collateral composition, and yield rates.
The asset
mapping establishes a relationship between an asset address and its corresponding Asset
struct, which holds asset-specific information like the associated vault, oracle address, and various parameters governing the asset's behavior within the protocol.
User-related data is maintained through the vaultUser
and assetUser
mappings. The vaultUser
mapping links a vault identifier and a user address to a VaultUser
struct, storing user-specific data within the context of a particular vault, such as the user's dETH balance and bridge credit. Similarly, the assetUser
mapping connects an asset address and a user address to an AssetUser
struct, capturing user-specific information pertaining to a specific asset, like the user's escrowed DittoAsset balance.
The bids
, asks
, and shorts
mappings are used to store and manage the orderbook data. Each mapping associates an asset address and an order identifier (uint16
) with an Order
struct, representing the details of a specific bid, ask, or short order, respectively. This structure allows for efficient retrieval and manipulation of order data.
Lastly, the shortRecords
mapping provides a multi-level mapping that links an asset address, a user address, and a short record identifier (uint8
) to a ShortRecord
struct. This mapping enables the protocol to keep track of the individual short positions of users, including collateral, debt, and yield information.
The centralized state management approach employed by the AppStorage
contract offers several advantages. It ensures data consistency across the various components of the protocol, reduces the complexity of inter-contract interactions, and provides a single source of truth for the protocol's state. Moreover, it allows for efficient querying and updating of state variables, optimizing gas costs and improving overall performance.
If the Sequence flow diagram is not clearly visible, please CLICK HERE
The sequence flow diagram shows the interactions between the various components and actors involved in the protocol's operations.
The VaultFacet
contract is responsible for managing the vaults within the DittoETH protocol. A vault serves as a secure container for the deposited LSTs and ETH collateral, and the VaultFacet
provides a range of functions to interact with these vaults.
Users can deposit their LSTs or ETH into a vault through the depositAsset
and depositEth
functions, respectively. When a user deposits collateral, the VaultFacet
contract mints an equivalent amount of dETH, an internal representation of the deposited collateral. The minted dETH is then escrowed within the vault, effectively locking the collateral and allowing the user to participate in the protocol's functionalities.
The VaultFacet
contract also enables users to withdraw their collateral from the vault using the withdrawAsset
function. Upon withdrawal, the escrowed dETH is burned, and the corresponding collateral is released back to the user. This process ensures that the collateral remains securely stored within the vault until the user initiates a withdrawal.
In addition to deposit and withdrawal operations, the VaultFacet
contract plays a crucial role in updating the yield rates associated with the vaults. The updateYield
function is responsible for recalculating and updating the yield rates based on the current state of the vault and the underlying collateral. This functionality ensures that users receive accurate and up-to-date yield information on their deposited collateral.
The vault management component of the DittoETH architecture serves as the foundation for the secure storage and accounting of collateral assets. By providing a robust and reliable mechanism for depositing, withdrawing, and tracking collateral, the VaultFacet
contract contributes to the overall stability and integrity of the protocol.
The BridgeRouterFacet
contract is a critical component of the DittoETH architecture, facilitating seamless interaction with external LST bridges. This contract acts as an intermediary between the protocol and the supported LST bridges, such as the rETH and stETH bridges, enabling users to deposit and withdraw LSTs through these bridges.
When a user wants to deposit LSTs into the protocol, they can interact with the BridgeRouterFacet
contract through the deposit
function. This function takes the address of the specific LST bridge and the amount of LSTs to be deposited. Internally, the contract communicates with the corresponding LST bridge contract, initiating the deposit process. The deposited LSTs are then converted into dETH, the internal representation of collateral within the DittoETH protocol.
Similarly, when a user wishes to withdraw their LSTs from the protocol, they can invoke the withdraw
function of the BridgeRouterFacet
contract. This function takes the address of the LST bridge and the amount of dETH to be withdrawn. The contract interacts with the specified LST bridge to facilitate the withdrawal process, converting the dETH back into the corresponding LSTs and transferring them to the user's wallet.
The BridgeRouterFacet
contract also incorporates a credit system to handle scenarios where users deposit and withdraw different types of LSTs. When a user deposits LSTs through a specific bridge, they receive a bridge credit associated with that particular LST. This credit is tracked and managed within the BridgeRouterFacet
contract. When a user withdraws LSTs, the contract first checks if they have sufficient bridge credit for the requested LST. If the credit is available, the withdrawal is processed using the credited LSTs. This mechanism ensures that users can only withdraw the LSTs they have previously deposited, preventing potential arbitrage opportunities.
The bridge interaction component of the DittoETH architecture serves a vital purpose by expanding the range of collateral options available to users. By integrating with multiple LST bridges, the protocol offers users the flexibility to deposit and withdraw different types of LSTs, enhancing the overall liquidity and accessibility of the platform. The BridgeRouterFacet
contract abstracts away the complexities of interacting with individual LST bridges, providing a unified and user-friendly interface for collateral management.
Moreover, the bridge interaction functionality enables the protocol to adapt and evolve as new LST bridges emerge in the ecosystem. The modular design of the BridgeRouterFacet
contract allows for easy integration of additional LST bridges, ensuring that the protocol remains compatible and interoperable with a wide range of collateral assets.
The orderbook is a fundamental component of the DittoETH architecture, facilitating the matching of buyers and sellers of DittoAssets. The orderbook functionality is implemented through two key contracts: BidOrdersFacet
and ShortOrdersFacet
.
The BidOrdersFacet
contract handles the placement and management of bid orders on the orderbook. Users can place bids by specifying the desired DittoAsset, the price they are willing to pay, and the amount of dETH collateral they wish to use. The contract validates the input parameters, checks the user's available dETH balance, and creates a new bid order on the orderbook. Bid orders are stored in the bids
mapping within the AppStorage
contract, allowing for efficient retrieval and matching.
On the other hand, the ShortOrdersFacet
contract is responsible for managing short orders on the orderbook. Shorters can place asks by specifying the DittoAsset they want to mint and sell, the price they are willing to sell at, and the amount of DittoAssets they wish to create. The contract verifies the shorter's collateral adequacy, ensures compliance with the protocol's collateralization requirements, and creates a new short order on the orderbook. Short orders are stored in the shorts
mapping within the AppStorage
contract.
The orderbook component of the DittoETH architecture employs a sophisticated matching algorithm to efficiently match bid and short orders. When a new bid or short order is placed, the contracts traverse the orderbook to find the best matching counterparty. The matching algorithm takes into account the price, quantity, and order type to determine the optimal match. If a match is found, the contracts execute the trade, transferring the DittoAssets from the shorter to the bidder and the dETH collateral from the bidder to the shorter.
To optimize gas costs and improve the performance of the orderbook, the DittoETH architecture incorporates a hint system. When placing an order, users can provide hints in the form of order IDs that indicate the expected position of their order in the orderbook. These hints help the contracts quickly locate the appropriate position for the new order, reducing the number of iterations required to find a match. If the provided hints are inaccurate or outdated, the contracts fall back to a more exhaustive search to ensure the correct placement and matching of orders.
The orderbook component also includes mechanisms to handle partial fills and order cancellations. If an order is only partially filled, the remaining quantity is updated, and the order remains active on the orderbook for future matches. Users have the ability to cancel their outstanding orders, which removes them from the orderbook and releases the associated collateral.
The BidOrdersFacet
and ShortOrdersFacet
contracts work together to create a decentralized and efficient market for minting and trading DittoAssets. The orderbook model promotes price discovery, liquidity, and fair market dynamics. By enabling users to place bids and asks at their desired prices, the architecture fosters a competitive and transparent trading environment.
Moreover, the orderbook component is designed to be flexible and extensible. The modular structure of the contracts allows for the integration of additional order types, such as limit orders or market orders, as well as the incorporation of advanced trading features like order expiration or fill-or-kill orders. This adaptability ensures that the DittoETH protocol can evolve and meet the changing needs of its users over time.
The PrimaryLiquidationFacet
contract plays a crucial role in maintaining the stability and solvency of the DittoETH protocol by facilitating the liquidation of undercollateralized short positions. Liquidation is a critical risk management mechanism that ensures the protocol remains adequately collateralized and protects against potential defaults.
When a shorter opens a short position by minting and selling DittoAssets, they are required to provide sufficient collateral to meet the protocol's collateralization requirements. The collateralization ratio is defined as the ratio of the collateral value to the minted DittoAsset value. If the collateralization ratio of a short position falls below the liquidation threshold, it becomes eligible for liquidation.
The PrimaryLiquidationFacet
contract allows liquidators to identify and liquidate undercollateralized short positions. Liquidators continuously monitor the collateralization ratios of short positions and can initiate the liquidation process by calling the liquidate
function. This function takes the address of the DittoAsset, the address of the shorter, and the ID of the short position to be liquidated.
Upon receiving a liquidation request, the contract verifies the eligibility of the short position for liquidation. It calculates the current collateralization ratio based on the latest price information from the oracle and compares it against the liquidation threshold. If the short position is indeed undercollateralized, the liquidation process proceeds.
During liquidation, the contract forcefully closes the short position by executing a series of steps. First, it determines the amount of DittoAssets that need to be repurchased to bring the position back to a safe collateralization level. The contract then places a forced bid on the orderbook to buy back the necessary DittoAssets using the shorter's collateral. If the forced bid is successful and the required DittoAssets are acquired, the contract burns the repurchased DittoAssets, effectively reducing the supply and stabilizing the collateralization ratio.
The liquidation process also involves the distribution of liquidation penalties and incentives. The shorter whose position is liquidated incurs a liquidation penalty, which is a percentage of their collateral that is forfeited. This penalty serves as a deterrent against reckless borrowing and encourages responsible collateral management. On the other hand, liquidators who successfully liquidate undercollateralized positions are rewarded with a portion of the liquidation penalty as an incentive for their efforts in maintaining the protocol's stability.
The PrimaryLiquidationFacet
contract interacts closely with other components of the DittoETH architecture, such as the orderbook and the price oracle, to execute liquidations accurately and efficiently. It relies on real-time price data from the oracle to calculate collateralization ratios and determine the eligibility of positions for liquidation. The contract also leverages the orderbook to place forced bids and acquire the necessary DittoAssets during the liquidation process.
The liquidation mechanism implemented in the PrimaryLiquidationFacet
contract is essential for mitigating the risk of undercollateralized positions and ensuring the overall health and stability of the DittoETH protocol. By promptly liquidating positions that fall below the required collateralization threshold, the contract prevents the accumulation of bad debt and maintains the integrity of the collateral backing the minted DittoAssets.
Moreover, the liquidation functionality acts as a self-regulating mechanism within the protocol. It incentivizes shorters to actively manage their collateral and maintain sufficient collateralization levels to avoid liquidation. At the same time, it encourages liquidators to actively monitor the protocol and participate in the liquidation process, contributing to the decentralized governance and risk management of the platform.
The RedemptionFacet
contract is an essential component of the DittoETH architecture, enabling DittoAsset holders to redeem their assets for the underlying collateral. Redemption is a fundamental feature that ensures the convertibility and stability of DittoAssets, allowing users to exit their positions and retrieve the collateral value locked within the protocol.
When a user holds DittoAssets and wishes to redeem them, they can interact with the RedemptionFacet
contract through the redeemAssets
function. This function takes the address of the DittoAsset and the amount to be redeemed as input parameters. Upon receiving a redemption request, the contract verifies the validity of the request and checks the user's DittoAsset balance to ensure they have sufficient funds to complete the redemption.
Once the redemption request is validated, the RedemptionFacet
contract initiates the redemption process. It calculates the corresponding amount of collateral that needs to be released based on the current redemption rate. The redemption rate is determined by the protocol's governance mechanism and takes into account factors such as the overall collateralization ratio, market conditions, and redemption demand.
After determining the collateral amount to be released, the contract burns the redeemed DittoAssets, effectively removing them from circulation. This burning process helps maintain the stability and integrity of the DittoAsset supply, as it ensures that the total supply of DittoAssets remains in sync with the underlying collateral.
Next, the RedemptionFacet
contract interacts with the vault management component to release the collateral to the user. It communicates with the VaultFacet
contract to withdraw the appropriate amount of collateral from the vault and transfer it to the user's wallet address. The contract ensures that the collateral is securely and accurately released, updating the relevant state variables and balances within the AppStorage
contract.
The redemption process implemented in the RedemptionFacet
contract is designed to be efficient, transparent, and user-friendly. It provides a seamless way for DittoAsset holders to convert their assets back into the underlying collateral, enabling them to exit their positions and access the value they have stored within the protocol.
The redemption functionality plays a crucial role in maintaining the stability and credibility of the DittoAsset ecosystem. By offering a reliable and accessible redemption mechanism, the DittoETH protocol instills confidence in its users and promotes the widespread adoption of DittoAssets as a stable and trustworthy medium of exchange.
Moreover, the RedemptionFacet
contract incorporates various security measures and checks to prevent unauthorized or fraudulent redemption attempts. It validates the authenticity
If the diagram is not visible, please CLICK HERE
The DittoETH codebase demonstrates a high level of maintainability and reliability. The contracts are well-structured, modular, and adhere to the Diamond standard, which promotes separation of concerns and allows for easy upgradability. The use of libraries, such as LibOrders
, LibAsset
, and LibShortRecord
, encapsulates complex logic and improves code reusability. The contracts are also designed to handle edge cases and potential errors gracefully, with appropriate error handling and revert messages using the Errors
library. The use of SafeMath operations ensures that arithmetic operations are protected against overflow and underflow vulnerabilities. Overall, the codebase exhibits a strong emphasis on maintainability and reliability, making it easier for developers to understand, modify, and extend the functionality of the protocol.
The DittoETH codebase features extensive and informative code comments throughout the contracts. Each contract, function, and important code block is accompanied by clear and concise comments that explain the purpose, functionality, and any relevant considerations. The comments provide valuable insights into the intended behavior of the code, making it easier for developers to understand and navigate the codebase. The use of NatSpec-style comments, such as @notice
, @dev
, and @param
, further enhances the documentation and helps in generating comprehensive documentation for the protocol. The comments also highlight any potential risks, assumptions, or dependencies associated with specific functions or variables. The thoroughness and quality of the code comments demonstrate a commitment to maintainability and facilitating collaboration among developers.
The DittoETH codebase follows a consistent and well-organized code structure and formatting. The contracts are logically grouped and separated into different files based on their functionality, such as VaultFacet
, BridgeRouterFacet
, BidOrdersFacet
, and ShortOrdersFacet
. The use of the Diamond standard ensures a clear separation of concerns and promotes modularity. The code is properly indented, and the use of white space enhances readability. The naming conventions for variables, functions, and events are descriptive and follow a consistent pattern, making it easier to understand their purpose and usage. The codebase also makes effective use of Solidity's inheritance and interface mechanisms to promote code reuse and abstraction. Overall, the code structure and formatting of the DittoETH codebase contribute to its maintainability, readability, and ease of understanding.
One of the key strengths of the DittoETH codebase is its modular and extensible architecture. The use of the Diamond standard allows for the separation of concerns and enables the protocol to evolve and adapt over time. New functionality can be added through the creation of additional facets without modifying the existing contracts, promoting upgradability and reducing the risk of introducing bugs or vulnerabilities. The codebase also demonstrates a strong focus on security, with the use of well-established libraries, such as SafeMath, and the implementation of access control mechanisms to prevent unauthorized access to critical functions. The extensive test suite provided with the codebase instills confidence in the correctness and robustness of the protocol. The tests cover various scenarios, edge cases, and potential vulnerabilities, ensuring that the contracts behave as expected and can handle different conditions. The comprehensive documentation, both in the form of code comments and external documentation, is another strength of the DittoETH codebase. The documentation provides a clear and detailed explanation of the protocol's architecture, functionality, and usage, making it easier for developers and users to understand and interact with the system.
The DittoETH protocol benefits from a comprehensive and well-structured documentation. The provided whitepaper offers a high-level overview of the protocol's design, architecture, and key components. It explains the core concepts, such as vaults, collateral management, orderbook matching, liquidation, and redemption, in a clear and accessible manner. The whitepaper also discusses the economic model, incentive structures, and potential use cases of the protocol. In addition to the whitepaper, the codebase itself is thoroughly documented using in-code comments and NatSpec annotations. These comments provide detailed explanations of each contract, function, and important code block, making it easier for developers to understand the purpose and functionality of the code. The documentation also includes usage examples, parameter descriptions, and any relevant considerations or assumptions. The combination of the whitepaper and in-code documentation provides a solid foundation for understanding the DittoETH protocol and facilitates its adoption and integration by developers and users alike.
Here's a diagram illustrating the key components of the DittoETH codebase:
If the diagram is not visible, please CLICK HERE
This diagram highlights the key components of the DittoETH codebase, including the Diamond standard architecture, the various facets responsible for different functionalities, the libraries that encapsulate complex logic, the centralized storage contract (AppStorage
), the extensive test suite, and the comprehensive documentation in the form of the whitepaper and in-code comments.
Before diving into the actual audit of the DittoETH protocol, it was essential to establish a solid foundation and understanding of the project. The first step involved reviewing the provided documentation, including the Litepaper and any available technical specifications. This initial review helped gain a high-level understanding of the protocol's architecture, key components, and intended functionality.
In addition to the project-specific documentation, the audit approach also leveraged prior knowledge and experience in auditing similar DeFi protocols. Familiarity with common vulnerabilities, best practices, and security patterns in the DeFi space provided a valuable starting point for the audit process. This background knowledge allowed for a more targeted and efficient analysis of the DittoETH codebase.
The audit of the DittoETH codebase followed a systematic and thorough approach to ensure comprehensive coverage of all critical components. The codebase was reviewed file by file, focusing on the core functionalities and technical characteristics of each contract. The following table provides an overview of the key contracts audited, along with their importance and management:
File Name | Core Functionality | Technical Characteristics | Importance and Management |
---|---|---|---|
VaultFacet.sol | Manages vaults, deposits, and withdrawals | Vault management, collateral accounting, yield updates | Critical component for secure collateral management and accurate accounting |
BridgeRouterFacet.sol | Facilitates interaction with external LST bridges | Bridge integration, credit system, deposit/withdrawal | Essential for seamless integration with LST bridges and proper handling of bridge interactions |
BidOrdersFacet.sol | Handles the placement and matching of bid orders | Orderbook management, bid matching, order settlement | Crucial for accurate order matching, settlement, and maintaining market integrity |
ShortOrdersFacet.sol | Manages the creation and matching of short orders | Short order placement, collateralization checks | Vital for ensuring proper collateralization and risk management of short positions |
PrimaryLiquidationFacet.sol | Facilitates the liquidation of undercollateralized positions | Liquidation process, incentives, collateral management | Critical for maintaining protocol solvency and stability through efficient liquidations |
RedemptionFacet.sol | Enables the redemption of DittoAssets for collateral | Redemption process, collateral release, asset burning | Essential for ensuring the convertibility and stability of DittoAssets |
Before conducting the audit, it was important to review any publicly known issues or vulnerabilities associated with the DittoETH protocol on the README. This involved examining the project's GitHub repository, issue tracker, and any relevant public forums or communication channels. By considering publicly known issues, the audit could prioritize the review of potentially affected areas and ensure that known vulnerabilities were adequately addressed. I also explored Solodit for similar protocols to understand what types of bugs are usually occurs on tese types of protocol.
Testing played a crucial role in the audit process of DittoETH. The protocol's codebase included an extensive test suite. The test suite covered various scenarios, edge cases, and potential vulnerabilities, providing valuable insights into the behavior and correctness of the smart contracts. I also wrote some tests to analyse and dive deep into the codebase. During the audit, the existing test cases were reviewed and analyzed to assess their comprehensiveness and effectiveness in detecting potential issues. Additional test cases were developed to further explore edge cases, boundary conditions, and specific attack vectors. The tests were executed using the Foundry framework, which provided a robust and efficient testing environment. The test coverage was examined to ensure that all critical functionalities and code paths were adequately tested. The tests proved to be highly valuable in understanding the functionality of each function and the underlying logic of the protocol. They served as a reliable baseline for verifying the expected behavior of the contracts and identifying any deviations or vulnerabilities.
In addition to manual code review and testing, the audit process also involved the use of static analysis tools like Slither. Slither is a popular open-source static analysis framework for Solidity smart contracts. It helps identify potential vulnerabilities, code quality issues, and best practice violations. The DittoETH codebase was analyzed using various Bots to supplement the manual review process. Slither's analysis and Bots results provided valuable insights into potential security risks. Analysis and Testing Insights:
The analysis and testing of the DittoETH codebase revealed a high level of robustness in the design and implementation of the smart contracts. The contracts demonstrated a strong adherence to best practices and security principles. The use of well-established libraries, such as SafeMath, and the proper handling of edge cases and error conditions contributed to the overall robustness of the protocol.
During the audit, attention was also given to the gas efficiency of the DittoETH contracts. The codebase was analyzed for opportunities to optimize gas consumption without compromising functionality or security. The use of efficient data structures, such as mappings and arrays, and the avoidance of unnecessary computations and storage operations were observed in several instances. However, there were a few areas identified where further gas optimizations could be explored, such as reducing the number of storage reads and writes or using more efficient algorithms for certain computations.
The security posture of the DittoETH protocol was carefully evaluated during the audit. The codebase demonstrated a strong commitment to security, with the implementation of various security measures and best practices. Access control mechanisms were properly implemented to restrict access to critical functions and state variables. The use of modifiers and role-based access control helped ensure that only authorized entities could perform specific actions. The contracts also included appropriate error handling and input validation to prevent unexpected behavior and mitigate potential attack vectors.
Throughout the audit process, it was evident that the DittoETH team was committed to continuous improvement and receptive to feedback and recommendations. The team actively engaged in discussions and addressed any findings or concerns raised during the audit. They demonstrated a willingness to iterate on the codebase and incorporate suggested improvements to enhance the protocol's security and functionality. This collaborative approach and openness to feedback contributed to the overall quality and robustness of the DittoETH protocol.
The audit of the DittoETH protocol followed a comprehensive approach that involved a combination of manual code review, testing, static analysis, and consideration of publicly known issues. The codebase was systematically analyzed, focusing on the core functionalities and technical characteristics of each contract. The extensive test suite provided valuable insights into the behavior and correctness of the smart contracts, while tools like Slither complemented the manual review process.
VaultFacet.sol
):The VaultFacet
contract is responsible for managing the vaults within the DittoETH protocol. It provides functions for depositing and withdrawing collateral, minting dETH (an internal representation of the deposited collateral), and updating yield rates. The vault management component ensures the secure storage and accounting of collateral assets.
Concerns:
The depositAsset
and depositEth
functions allow users to deposit collateral into the vault. However, there is no explicit check to ensure that the deposited amount is greater than zero. While the addDeth
function in LibBridgeRouter
does check for a minimum deposit amount, it would be safer to include this check directly in the deposit functions to prevent any potential edge cases.
The withdrawAsset
function enables users to withdraw their collateral from the vault. The function calls the assessDeth
function in LibBridgeRouter
to determine the amount of dETH that can be withdrawn based on the user's bridge credit. However, there is no explicit validation to ensure that the returned value from assessDeth
does not exceed the user's total dETH balance. While this scenario is unlikely given the current implementation, adding an explicit check would provide an extra layer of safety.
Recommendations:
depositAsset
and depositEth
functions to ensure that the deposited amount is greater than zero. This can help prevent any unintended behavior or potential issues arising from zero-value deposits.function depositAsset(address bridge, uint88 amount) external nonReentrant { if (amount == 0) revert Errors.ZeroAmountDeposit(); // Rest of the function logic }
withdrawAsset
function, consider adding an explicit validation to ensure that the amount returned from assessDeth
does not exceed the user's total dETH balance. This can be done by comparing the returned value with the user's ethEscrowed
balance in the VaultUser
struct.function withdrawAsset(address bridge, uint88 dethAmount) external nonReentrant { // Rest of the function logic uint88 withdrawableAmount = LibBridgeRouter.assessDeth(vault, bridgePointer, dethAmount, rethBridge, stethBridge); if (withdrawableAmount > s.vaultUser[vault][msg.sender].ethEscrowed) revert Errors.InsufficientDethBalance(); // Rest of the function logic }
BridgeRouterFacet.sol
):The BridgeRouterFacet
contract facilitates the interaction with external LST bridges, such as the rETH and stETH bridges. It allows users to deposit and withdraw LSTs through the bridges, converting them to dETH and vice versa. The bridge interaction component enables seamless integration with different LST protocols and expands the collateral options for users.
Concerns:
The deposit
and depositEth
functions interact with external bridge contracts to deposit LSTs or ETH. While the contract does handle the case when the bridge deposit fails (e.g., by checking the returned dethAmount
), there is no explicit validation of the bridge addresses. If an invalid or malicious bridge address is provided, it could lead to unexpected behavior or loss of funds.
The withdraw
function calculates the withdrawal fee percentage based on the market premium/discount between rETH and stETH using a 30-minute TWAP. However, there is no check to ensure that the TWAP values are not stale or manipulated. In case of external oracle failures or price manipulations, the withdrawal fee calculation could be affected, potentially leading to incorrect fees being charged.
Recommendations:
mapping(address => bool) private validBridges; function deposit(address bridge, uint88 amount) external nonReentrant { if (!validBridges[bridge]) revert Errors.InvalidBridge(); // Rest of the function logic }
function withdrawalFeePct(uint256 bridgePointer, address rethBridge, address stethBridge) internal view returns (uint256 fee) { // Rest of the function logic uint256 rethTwapTimestamp = OracleLibrary.getTwapTimestamp(VAULT.RETH_WETH); uint256 stethTwapTimestamp = OracleLibrary.getTwapTimestamp(VAULT.WSTETH_WETH); if (block.timestamp - rethTwapTimestamp > 30 minutes || block.timestamp - stethTwapTimestamp > 30 minutes) { revert Errors.StaleTwapData(); } uint256 priceDeviationThreshold = 0.1 ether; // 10% deviation threshold if (factorReth > factorSteth * (1 + priceDeviationThreshold) || factorSteth > factorReth * (1 + priceDeviationThreshold)) { revert Errors.PriceDeviationExceeded(); } // Rest of the function logic }
BidOrdersFacet.sol
and ShortOrdersFacet.sol
):The orderbook component of the DittoETH protocol is implemented through the BidOrdersFacet
and ShortOrdersFacet
contracts. These contracts handle the placement and management of bid and short orders on the orderbook. The orderbook facilitates the matching of buyers and sellers of DittoAssets, enabling efficient price discovery and liquidity.
Concerns:
The createBid
and createLimitShort
functions allow users to place bid and short orders on the orderbook. While the functions do perform various validations and checks, there is a potential concern regarding the handling of dust amounts. If a bid or short order results in a very small (dust) amount after matching, it could lead to inefficiencies and increased gas costs for subsequent operations on those orders.
The orderbook matching algorithm implemented in the bidMatchAlgo
and sellMatchAlgo
functions is complex and involves multiple loops and conditions. While the code is well-structured and documented, the complexity of the matching logic increases the potential for unintended behavior or edge cases. Thorough testing and validation of the matching algorithm is crucial to ensure its correctness and robustness.
Recommendations:
uint256 constant DUST_THRESHOLD = 1e15; // Adjust the threshold as needed function bidMatchAlgo(/* ... */) private returns (uint88 ethFilled, uint88 ercAmountLeft) { // Rest of the function logic if (incomingBid.ercAmount < DUST_THRESHOLD) { // Cancel the remaining bid order and refund the user cancelBid(asset, incomingBid.id); return (matchTotal.fillEth, 0); } // Rest of the function logic }
PrimaryLiquidationFacet.sol
):The PrimaryLiquidationFacet
contract enables the liquidation of undercollateralized short positions. It allows liquidators to identify and liquidate positions that fall below the required collateralization ratio, helping to maintain the stability and solvency of the DittoETH protocol.
Concerns:
The liquidate
function performs the liquidation of undercollateralized short positions. During the liquidation process, the contract calculates the liquidation penalty and the caller's fee based on the penaltyCR
and callerFeePct
values, respectively. However, there is no explicit check to ensure that these values are within reasonable ranges. If the penalty or caller fee percentages are set too high, it could discourage liquidations and negatively impact the protocol's stability.
The liquidation process involves the transfer of collateral and fees between the liquidated short position, the liquidator, and the TAPP (Treasury Asset Protection Pool). While the contract does handle various scenarios and edge cases, there is a potential concern regarding the accuracy and correctness of the accounting logic. Any discrepancies or errors in the accounting could lead to incorrect distributions of collateral and fees.
Recommendations:
penaltyCR
and callerFeePct
values used in the liquidation process. Ensure that these values are within reasonable ranges and do not exceed certain thresholds. Consider adding checks in the liquidation function to verify that the penalty and caller fee percentages are valid and do not disincentivize liquidations.function liquidate(/* ... */) external returns (uint88, uint88) { // Rest of the function logic uint256 maxPenaltyCR = 0.5 ether; // Maximum penalty collateralization ratio uint256 maxCallerFeePct = 0.1 ether; // Maximum caller fee percentage if (m.penaltyCR > maxPenaltyCR) revert Errors.InvalidPenaltyCR(); if (m.callerFeePct > maxCallerFeePct) revert Errors.InvalidCallerFeePct(); // Rest of the function logic }
RedemptionFacet.sol
):The RedemptionFacet
contract enables DittoAsset holders to redeem their assets for the underlying collateral. It provides functionalities for proposing redemptions, disputing redemptions, and claiming the redeemed collateral. The redemption component ensures the convertibility and stability of DittoAssets.
Concerns:
The proposeRedemption
function allows users to propose a set of short positions for redemption. The function processes the proposed positions and updates the collateral and debt balances accordingly. However, there is a potential concern regarding the gas cost of this function, especially if a large number of positions are proposed in a single transaction. Processing a large redemption proposal could exceed the block gas limit, making it infeasible to execute.
The redemption process involves a dispute period during which other users can challenge the proposed redemptions. The dispute logic implemented in the disputeRedemption
function relies on the accuracy and correctness of the provided dispute data. If the dispute data is maliciously crafted or incorrect, it could lead to invalid disputes and potentially disrupt the redemption process.
Recommendations:
uint256 constant MAX_POSITIONS_PER_PROPOSAL = 100; // Adjust the limit as needed function proposeRedemption(/* ... */) external { // Rest of the function logic if (proposalInput.length > MAX_POSITIONS_PER_PROPOSAL) revert Errors.TooManyPositionsInProposal(); // Rest of the function logic }
disputeRedemption
function to ensure the integrity of the dispute process. Verify the authenticity and correctness of the provided dispute data before processing a dispute. Consider implementing additional checks and safeguards to prevent malicious or invalid disputes from disrupting the redemption process.function disputeRedemption(/* ... */) external { // Rest of the function logic if (!isValidDisputeData(disputeData)) revert Errors.InvalidDisputeData(); // Rest of the function logic } function isValidDisputeData(bytes memory disputeData) internal pure returns (bool) { // Implement logic to validate the structure and contents of the dispute data // Return true if the dispute data is valid, false otherwise }
Additionally, consider implementing a reputation system or staking mechanism for disputers to discourage frivolous or malicious disputes. Require disputers to stake a certain amount of tokens, which can be slashed if their disputes are found to be invalid or malicious. This can help maintain the integrity of the redemption process and deter bad actors from disrupting it.
The DittoETH protocol demonstrates a well-designed and thoughtfully implemented architecture for enabling the minting, trading, and redemption of pegged assets. The codebase exhibits a strong commitment to security, modularity, and extensibility. However, as with any complex system, there are certain areas that require careful consideration and additional safeguards to ensure the protocol's robustness and reliability.
The concerns and recommendations highlighted in this overview aim to address potential vulnerabilities, optimize gas efficiency, and enhance the overall security and usability of the DittoETH protocol. Implementing additional validations, safeguards, and error handling mechanisms can help mitigate risks and ensure the smooth operation of the protocol.
It is crucial to conduct thorough fuzz and invariant testing, auditing, and validation of the codebase, especially for critical components such as the orderbook matching algorithm and the liquidation process. Engaging the community, external auditors, and leveraging formal verification techniques can provide additional assurance and help identify any potential issues or vulnerabilities.
The vault management component, implemented in the VaultFacet
contract, plays a crucial role in the DittoETH protocol by ensuring the secure storage and accounting of collateral assets. It provides functions for depositing and withdrawing collateral, minting dETH (an internal representation of the deposited collateral), and updating yield rates.
One of the key strengths of the vault management system is its ability to handle multiple types of collateral, including LSTs (Liquid Staking Tokens) and ETH. The depositAsset
and depositEth
functions allow users to seamlessly deposit their collateral into the vault, while the withdrawAsset
function enables them to withdraw their collateral when needed.
The vault management component maintains accurate accounting of the deposited collateral through the use of the VaultUser
struct, which keeps track of each user's dETH balance. The addDeth
function in the LibBridgeRouter
library ensures that the deposited collateral is properly credited to the user's account and updates the vault's total dETH balance.
To ensure the security and integrity of the collateral, the vault management system incorporates various checks and validations. For example, the withdrawAsset
function verifies that the user has sufficient dETH balance before allowing a withdrawal and updates the user's balance accordingly.
Overall, the vault management component provides a robust and flexible foundation for the DittoETH protocol, enabling users to securely deposit and withdraw their collateral while maintaining accurate accounting and yield calculations.
If the diagram is not visible, please CLICK HERE
The bridge interaction component, implemented in the BridgeRouterFacet
contract, is responsible for facilitating the integration of external LST bridges into the DittoETH protocol. It allows users to deposit and withdraw LSTs through supported bridges, such as the rETH and stETH bridges, and seamlessly converts them to dETH and vice versa.
The deposit
and depositEth
functions in the BridgeRouterFacet
contract enable users to deposit LSTs or ETH through the specified bridge. The contract interacts with the corresponding bridge contract to initiate the deposit process and converts the deposited assets into dETH, which is then credited to the user's account.
Similarly, the withdraw
function allows users to withdraw their LSTs from the protocol by specifying the bridge and the amount of dETH to be withdrawn. The contract communicates with the bridge contract to facilitate the withdrawal process, converting the dETH back into the corresponding LSTs and transferring them to the user's wallet.
One of the notable features of the bridge interaction component is the credit system, which handles scenarios where users deposit and withdraw different types of LSTs. When a user deposits LSTs through a specific bridge, they receive a bridge credit associated with that particular LST. The credit is tracked and managed within the BridgeRouterFacet
contract, ensuring that users can only withdraw the LSTs they have previously deposited.
The bridge interaction component also incorporates a withdrawal fee mechanism, which calculates the fee based on the market premium/discount between rETH and stETH using a 30-minute TWAP (Time-Weighted Average Price). This fee serves to prevent arbitrage opportunities and ensure fair pricing for LST withdrawals.
Overall, the bridge interaction component enhances the flexibility and interoperability of the DittoETH protocol by enabling seamless integration with external LST bridges. It provides users with a convenient way to deposit and withdraw different types of LSTs while maintaining accurate accounting and credit tracking.
If the diagram is not visible, please CLICK HERE
The orderbook component, implemented in the BidOrdersFacet
and ShortOrdersFacet
contracts, is a critical part of the DittoETH protocol as it facilitates the matching of buyers and sellers of DittoAssets. It provides a decentralized and efficient mechanism for price discovery and liquidity provision.
The BidOrdersFacet
contract handles the placement and management of bid orders on the orderbook. Users can place bids by specifying the desired DittoAsset, the price they are willing to pay, and the amount of dETH collateral they wish to use. The contract validates the input parameters, checks the user's available dETH balance, and creates a new bid order on the orderbook.
Similarly, the ShortOrdersFacet
contract manages the creation and matching of short orders on the orderbook. Shorters can place asks by specifying the DittoAsset they want to mint and sell, the price they are willing to sell at, and the amount of DittoAssets they wish to create. The contract verifies the shorter's collateral adequacy, ensures compliance with the protocol's collateralization requirements, and creates a new short order on the orderbook.
The orderbook component employs a sophisticated matching algorithm to efficiently match bid and short orders. The bidMatchAlgo
and sellMatchAlgo
functions traverse the orderbook to find the best matching counterparty based on price, quantity, and order type. When a match is found, the contracts execute the trade, transferring the DittoAssets from the shorter to the bidder and the dETH collateral from the bidder to the shorter.
To optimize gas costs and improve performance, the orderbook utilizes a hint system, where users can provide hints in the form of order IDs to indicate the expected position of their order in the orderbook. These hints help the contracts quickly locate the appropriate position for new orders, reducing the number of iterations required for matching.
The orderbook component also handles partial fills and order cancellations. If an order is only partially filled, the remaining quantity is updated, and the order remains active on the orderbook for future matches. Users have the flexibility to cancel their outstanding orders, which removes them from the orderbook and releases the associated collateral.
If the diagram is not visible, please CLICK HERE
The liquidation component, implemented in the PrimaryLiquidationFacet
contract, is essential for maintaining the stability and solvency of the DittoETH protocol. It enables the liquidation of undercollateralized short positions, ensuring that the protocol remains adequately collateralized and protects against potential defaults.
When a shorter opens a short position by minting and selling DittoAssets, they are required to provide sufficient collateral to meet the protocol's collateralization requirements. The collateralization ratio, defined as the ratio of the collateral value to the minted DittoAsset value, must be maintained above a certain threshold. If the collateralization ratio falls below the liquidation threshold, the short position becomes eligible for liquidation.
The PrimaryLiquidationFacet
contract allows liquidators to identify and liquidate undercollateralized short positions. Liquidators continuously monitor the collateralization ratios of short positions and can initiate the liquidation process by calling the liquidate
function, specifying the DittoAsset, the shorter's address, and the ID of the short position to be liquidated.
Upon receiving a liquidation request, the contract verifies the eligibility of the short position for liquidation by calculating the current collateralization ratio based on the latest price information from the oracle. If the short position is indeed undercollateralized, the liquidation process proceeds.
During liquidation, the contract forcefully closes the short position by executing a series of steps. It determines the amount of DittoAssets that need to be repurchased to bring the position back to a safe collateralization level. The contract then places a forced bid on the orderbook to buy back the necessary DittoAssets using the shorter's collateral. If the forced bid is successful and the required DittoAssets are acquired, the contract burns the repurchased DittoAssets, effectively reducing the supply and stabilizing the collateralization ratio.
The liquidation process also involves the distribution of liquidation penalties and incentives. The shorter whose position is liquidated incurs a liquidation penalty, which is a percentage of their collateral that is forfeited. This penalty serves as a deterrent against reckless borrowing and encourages responsible collateral management. On the other hand, liquidators who successfully liquidate undercollateralized positions are rewarded with a portion of the liquidation penalty as an incentive for their efforts in maintaining the protocol's stability.
If the diagram is not visible, please CLICK HERE
The redemption component, implemented in the RedemptionFacet
contract, enables DittoAsset holders to redeem their assets for the underlying collateral. It provides a mechanism for users to exit their positions and retrieve the value locked within the protocol, ensuring the convertibility and stability of DittoAssets.
The redemption process begins with a user proposing a set of short positions for redemption by calling the proposeRedemption
function. The user specifies the DittoAsset, the proposed redemption amount, and the maximum redemption fee they are willing to pay. The contract validates the proposal, checks the user's DittoAsset balance, and verifies that the proposed positions meet the redemption criteria.
Once a redemption proposal is submitted, it enters a dispute period during which other users can challenge the proposed redemptions. The dispute mechanism, implemented in the disputeRedemption
function, allows users to provide evidence and dispute the validity of the proposed redemptions. If a dispute is successful, the challenged positions are removed from the redemption proposal, and the remaining positions proceed to the redemption process.
After the dispute period has passed, the redeemer can claim the redeemed collateral by calling the claimRedemption
function. The contract verifies that the dispute period has elapsed and processes the approved redemption positions. It calculates the corresponding amount of collateral to be released based on the redemption rate and burns the redeemed DittoAssets, effectively removing them from circulation.
The redemption component also includes a mechanism for shorters to claim any remaining collateral from their redeemed positions. If a shorter's position is fully redeemed and the redeemer fails to claim the collateral, the shorter can call the claimRemainingCollateral
function to retrieve their remaining collateral.
To ensure fair pricing and prevent abuse, the redemption process incorporates a dynamic redemption fee mechanism. The fee is calculated based on factors such as the total collateral redeemed, the redemption amount, and the time elapsed since the last redemption. The fee serves to discourage excessive redemptions and maintain the stability of the DittoAsset ecosystem.
If the diagram is not visible, please CLICK HERE
The DittoETH protocol relies on accurate and reliable price oracles to determine the value of assets and ensure the proper functioning of various components, such as collateralization checks, liquidations, and redemptions. The price oracle component is implemented in the LibOracle
library and utilizes both Chainlink price feeds and Uniswap V3 TWAPs (Time-Weighted Average Prices).
The getOraclePrice
function in the LibOracle
library is responsible for retrieving the price of an asset from the configured oracle. It supports two types of oracles: the base oracle (e.g., ETH/USD) and asset-specific oracles (e.g., BTC/ETH). The function first checks the availability and validity of the price data from the primary oracle (Chainlink). If the primary oracle price is unavailable or outdated, it falls back to using the TWAP price from Uniswap V3.
The oracle component includes circuit breaker mechanisms to handle situations where the oracle price deviates significantly from the protocol's stored price or if the price data is stale. The baseOracleCircuitBreaker
function compares the Chainlink price with the protocol's stored price and the TWAP price. If the deviation exceeds a certain threshold (e.g., 50%), it falls back to using the TWAP price to ensure the integrity of the price data.
The twapCircuitBreaker
function is used as a fallback mechanism when the primary oracle price is unavailable or invalid. It retrieves the TWAP price from Uniswap V3 based on a specified time interval (e.g., 30 minutes) and verifies the liquidity of the trading pair to ensure the reliability of the price data.
The price oracle component also includes functions for setting and retrieving the stored oracle price and timestamp. The setPriceAndTime
function allows the protocol to update the stored price and timestamp, while the getPrice
and getTime
functions provide access to the stored values.
If the diagram is not visible, please CLICK HERE
The DittoETH protocol implements a robust access control and permissions system to ensure the security and integrity of the platform. The protocol follows the principle of least privilege, granting specific roles and permissions to different entities based on their responsibilities and requirements.
The access control mechanism is primarily implemented through the use of modifiers and role-based checks within the smart contracts. The Modifiers
contract defines a set of modifiers that restrict access to certain functions based on the caller's role or privileges. For example, the onlyDAO
modifier ensures that only the designated DAO (Decentralized Autonomous Organization) address can execute specific functions, such as
VaultFacet.sol
):Potential Weakness
: The depositAsset
and depositEth
functions allow users to deposit any amount of collateral, including zero amounts. While the addDeth
function in LibBridgeRouter
does check for a minimum deposit amount, allowing zero deposits in the VaultFacet
could lead to unnecessary transactions and potential confusion for users.
Example Scenario
: A user accidentally calls the depositAsset
function with an amount of zero. Although the transaction will not have any effect on the user's balance, it will still consume gas and clutter the transaction history.
Complexity:
The vault management component interacts with multiple other contracts and libraries, such as LibBridgeRouter
and LibVault
, which adds complexity to the overall system. Ensuring the correctness and security of these interactions requires careful auditing and testing.
BridgeRouterFacet.sol
):Potential Weakness:
The deposit
and depositEth
functions rely on the addDeth
function in LibBridgeRouter
to update the user's balance and the vault's total dETH. However, there is no explicit validation to ensure that the addDeth
function executed successfully. If the addDeth
function fails silently, it could lead to inconsistencies in the user's balance and the vault's total dETH.
Example Scenario:
If the addDeth
function encounters an error or fails to update the user's balance correctly, the user's deposit may not be properly credited, leading to a loss of funds or incorrect accounting.
Complexity:
The bridge interaction component involves complex logic for handling different types of collateral (LSTs and ETH) and interacting with external bridge contracts. The withdraw
function, in particular, has a significant level of complexity due to the various checks and calculations involved, such as assessing the user's bridge credit and calculating withdrawal fees based on market prices.
BidOrdersFacet.sol
and ShortOrdersFacet.sol
):Potential Weakness
The orderbook matching algorithm implemented in the bidMatchAlgo
and sellMatchAlgo
functions is complex and involves multiple loops and conditions. This complexity increases the potential for errors or unintended behavior, especially when dealing with edge cases or extreme market conditions.
Example Scenario:
If there is a bug in the matching algorithm that causes incorrect order matching or settlement, it could lead to financial losses for users or even exploitation by malicious actors.
Complexity:
The orderbook component is one of the most complex parts of the DittoETH protocol. It involves intricate logic for order placement, matching, and settlement, as well as the management of the underlying data structures. The use of a hint system to optimize gas costs and performance adds another layer of complexity to the orderbook implementation.
PrimaryLiquidationFacet.sol
):Potential Weakness:
The liquidation process relies on the accuracy and reliability of the price oracle to determine the collateralization ratio of short positions. If the price oracle is manipulated or provides incorrect data, it could lead to improper liquidations or allow undercollateralized positions to remain open.
Example Scenario:
An attacker manipulates the price oracle to falsely report a lower price for a collateral asset. This manipulation could cause the liquidation threshold to be breached, triggering unnecessary liquidations and causing financial losses for shorters.
Complexity:
The liquidation component involves complex calculations and interactions with multiple parts of the protocol, such as the orderbook and the Treasury Asset Protection Pool (TAPP). The liquidate
function has to handle various scenarios, such as calculating liquidation penalties, placing forced bids on the orderbook, and distributing incentives to liquidators. This complexity makes the liquidation process prone to errors and requires thorough testing and auditing.
RedemptionFacet.sol
):Potential Weakness
: The redemption process allows users to propose a set of short positions for redemption, which can be disputed by other users during a specified dispute period. However, the dispute mechanism relies on the accuracy and honesty of the disputers. If a malicious user submits false or fabricated evidence to dispute a legitimate redemption proposal, it could delay or prevent the redemption process.
Example Scenario:
A malicious user deliberately submits invalid dispute evidence to challenge a valid redemption proposal. This action could cause the redeemer to lose their opportunity to redeem their assets and potentially incur financial losses.
Complexity:
The redemption component involves a multi-step process that includes proposal submission, dispute handling, and claim processing. The complexity lies in managing the state transitions, handling disputes, and ensuring the correct distribution of collateral and burning of redeemed DittoAssets. The redemption fee calculation also adds complexity, as it takes into account various factors such as the total collateral redeemed and the time elapsed since the last redemption.
LibOracle.sol
):Potential Weakness:
The price oracle component relies on external data sources, such as Chainlink price feeds and Uniswap V3 TWAPs, to provide accurate and up-to-date price information. However, if these external data sources are compromised, manipulated, or experience downtime, it could lead to incorrect price data being used by the protocol, resulting in improper liquidations, redemptions, or other critical operations.
Example Scenario:
If the Chainlink price feed for an asset is manipulated to report an artificially low price, it could trigger unnecessary liquidations of short positions, causing financial losses for shorters.
Complexity:
The price oracle component has to handle various scenarios and fallback mechanisms to ensure the availability and reliability of price data. The getOraclePrice
function has to navigate through different oracle types (base oracle and asset-specific oracles), handle circuit breakers, and fallback to TWAP prices when necessary. This complexity increases the potential for errors and requires careful testing and monitoring.
Modifiers.sol
):Potential Weakness:
The access control and permissions system relies on the correct configuration and management of roles and privileges. If the roles are not properly assigned or if there are vulnerabilities in the access control mechanisms, it could lead to unauthorized access to critical functions or sensitive data.
Example Scenario:
If the DAO role is accidentally assigned to an untrusted address, it could allow that address to execute privileged functions, such as modifying protocol parameters or withdrawing funds from the TAPP.
Complexity:
The access control and permissions system is implemented using modifiers and role-based checks scattered throughout the codebase. While this approach provides flexibility and granularity, it also increases the complexity of the system and makes it harder to reason about the overall security posture. Ensuring the correctness and consistency of access control requires careful auditing and testing.
LibVault.sol
):Potential Weakness:
The yield management component calculates and distributes the dETH yield based on the vault's total collateral and the elapsed time since the last yield update. However, if the yield calculation formula is incorrect or if there are rounding errors, it could lead to incorrect yield distribution or potential exploits.
Example Scenario:
If the yield calculation formula has a vulnerability that allows an attacker to manipulate the yield rate, they could potentially earn more yield than intended, leading to an unfair distribution of rewards.
Complexity:
The yield management component involves complex mathematical calculations and interactions with other parts of the protocol, such as the vault and the dETH token. The updateYield
function has to handle various edge cases, such as when the vault's collateral is zero or when there is a significant time gap since the last yield update. This complexity increases the potential for errors and requires thorough testing and auditing.
LibShortRecord.sol
):Potential Weakness:
The short record management component is responsible for creating, updating, and deleting short records, which represent a user's short position. However, if there are bugs or inconsistencies in the short record management logic, it could lead to incorrect accounting of short positions or potential exploits.
Example Scenario:
If the fillShortRecord
function has a bug that allows a user to increase their collateral without increasing their debt proportionally, it could lead to an undercollateralized short position and potential loss of funds for the protocol.
Complexity:
The short record management component interacts with various other parts of the protocol, such as the orderbook, the liquidation component, and the vault. It has to handle complex calculations and state transitions, such as updating the ercDebtRate and dethYieldRate, and ensuring the consistency of short records across different operations. This complexity increases the potential for errors and requires thorough testing and auditing.
Potential Weakness:
The TAPP is a critical component of the DittoETH protocol that acts as a safety net to absorb potential losses and ensure the stability of the system. However, if the TAPP is not adequately funded or if there are vulnerabilities in the TAPP management logic, it could lead to insufficient protection against black swan events or potential exploits.
Example Scenario:
If the TAPP is drained due to a vulnerability or an unexpected market event, it may not have enough funds to cover the losses incurred by the protocol, leading to a loss of confidence and potential collapse of the system.
Complexity:
The TAPP involves complex interactions with various components of the protocol, such as the liquidation process, the redemption process, and the yield management system. It requires careful management of funds, accurate accounting, and robust security measures to ensure its effectiveness. The complexity of the TAPP increases the potential for errors and vulnerabilities and requires thorough testing and auditing.
Errors.sol
):Potential Weakness:
The Errors.sol
contract defines a set of custom error types used throughout the DittoETH codebase. However, if the error handling and exception mechanisms are not properly implemented or if there are inconsistencies in error reporting, it could lead to incorrect error messages or potential exploits.
Example Scenario:
If an error condition is not properly checked or if the wrong error type is used, it could lead to misleading error messages or even allow an attacker to bypass certain validations and exploit the system.
Complexity:
The error handling and exception mechanism is spread across the entire codebase, with different contracts and functions using custom error types defined in the Errors.sol
contract. Ensuring the consistency and correctness of error handling requires careful auditing and testing of all the contracts and functions that use these error types.
Events.sol
):Potential Weakness:
The Events.sol
contract defines a set of event types used for logging important actions and state changes in the DittoETH protocol. However, if the event logging is not comprehensive or if there are missing events for critical actions, it could hinder the ability to properly monitor and audit the system.
Example Scenario:
If a critical action, such as a liquidation or a redemption, is not properly logged with the relevant event, it could make it difficult to track and investigate any issues or discrepancies in the system.
Complexity:
The event logging mechanism is spread across the entire codebase, with different contracts and functions emitting events defined in the Events.sol
contract. Ensuring the completeness and accuracy of event logging requires careful auditing and testing of all the contracts and functions that emit these events.
It's important to note that the weaknesses and complexities mentioned above are potential areas of concern and may not necessarily represent actual vulnerabilities or exploits. However, they highlight the need for thorough testing, auditing, and continuous monitoring of the DittoETH protocol to ensure its security, reliability, and robustness.
The DittoETH protocol aims to be a decentralized platform for minting and trading pegged assets. However, there are certain aspects of the protocol that may introduce centralization risks.
Governance:
The protocol is governed by a DAO (Decentralized Autonomous Organization), which has the power to make critical decisions, such as adjusting protocol parameters, managing the TAPP (Treasury Asset Protection Pool), and upgrading the protocol. If the DAO is not sufficiently decentralized or if there is a concentration of voting power among a few entities, it could lead to centralized decision-making and potential conflicts of interest.
Oracles:
The protocol relies on external price oracles, such as Chainlink and Uniswap V3 TWAPs, to provide accurate price data for various assets. If these oracles are compromised or controlled by a centralized entity, it could lead to manipulation of price feeds and affect the integrity of the protocol.
Liquidity Provision:
The liquidity of the DittoAssets and the underlying collateral assets is crucial for the proper functioning of the protocol. If there is a concentration of liquidity provision among a few entities, it could lead to centralization risks and potential market manipulation.
The DittoETH protocol operates within the broader context of the cryptocurrency and DeFi ecosystem, which exposes it to various systematic risks.
Market Volatility:
The protocol's collateral assets, such as LSTs (Liquid Staking Tokens) and ETH, are subject to market volatility. Sudden and significant price fluctuations of these assets could impact the collateralization ratios of short positions and trigger liquidations, potentially causing cascading effects on the protocol.
Regulatory Uncertainty:
The regulatory landscape for cryptocurrencies and DeFi is still evolving, and there is uncertainty regarding the legal and compliance requirements for protocols like DittoETH. Changes in regulations or legal actions could have a significant impact on the protocol's operations and adoption.
Interoperability and Composability:
The DittoETH protocol interacts with other DeFi protocols and platforms, such as LST bridges and DEXes. Any vulnerabilities or failures in these external systems could have a ripple effect on the DittoETH protocol and its users.
graph TD A[DittoETH Protocol] --> B[Market Volatility] A --> C[Regulatory Uncertainty] A --> D[Interoperability and Composability] B --> E{Systematic Risk} C --> E D --> E
The DittoETH protocol is a complex system that involves multiple smart contracts, libraries, and external dependencies. This complexity introduces various technical risks.
Smart Contract Vulnerabilities:
The protocol's smart contracts may contain vulnerabilities or bugs that could be exploited by malicious actors. These vulnerabilities could lead to loss of funds, unauthorized access, or disruption of the protocol's functionalities.
Upgradability and Governance:
The protocol's upgradability mechanism, such as the Diamond standard, allows for the addition of new features and improvements. However, if the governance process for upgrades is not secure or if there are vulnerabilities in the upgrade mechanism itself, it could introduce technical risks.
Scalability and Performance:
As the adoption and usage of the DittoETH protocol grow, scalability and performance issues may arise. If the protocol is not able to handle increased transaction volumes or if there are bottlenecks in the system, it could lead to delays, higher gas costs, and poor user experience.
graph LR A[DittoETH Protocol] --> B[Smart Contract Vulnerabilities] A --> C[Upgradability and Governance] A --> D[Scalability and Performance] B --> E{Technical Risk} C --> E D --> E
The DittoETH protocol integrates with various external systems and dependencies, which introduces integration risks.
Oracle Integration:
The protocol relies on price oracles, such as Chainlink and Uniswap V3 TWAPs, for accurate price data. If there are issues with the integration of these oracles, such as delays, inconsistencies, or vulnerabilities, it could affect the protocol's functionality and security.
Bridge Integration:
The protocol integrates with LST bridges to enable the deposit and withdrawal of collateral assets. Any failures or vulnerabilities in the bridge contracts or the integration mechanism could lead to loss of funds or disruption of the protocol's operations.
DEX Integration:
The protocol utilizes DEXes (Decentralized Exchanges) for liquidity provision and trading of DittoAssets. If there are issues with the integration of these DEXes, such as front-running, slippage, or liquidity crises, it could impact the protocol's efficiency and user experience.
graph TD A[DittoETH Protocol] --> B[Oracle Integration] A --> C[Bridge Integration] A --> D[DEX Integration] B --> E{Integration Risk} C --> E D --> E
Non-Standard Token Risks:
The DittoETH protocol supports the minting and trading of pegged assets, which are essentially synthetic tokens. These tokens may not adhere to standard token interfaces or behaviors, which could lead to compatibility issues or unexpected behavior when interacting with other DeFi protocols or wallets.
User Errors:
The protocol's user interface and user experience play a crucial role in ensuring the safe and correct usage of the platform. If users make errors while interacting with the protocol, such as inputting incorrect amounts, selecting wrong assets, or not understanding the implications of their actions, it could lead to financial losses or unintended consequences.
graph LR A[DittoETH Protocol] --> B[Non-Standard Token Risks] A --> C[User Errors] B --> D{Other Risks} C --> D
Overall Risk Diagram:
If the diagram is not visible, please CLICK HERE
This diagram provides an overview of the various risks associated with the DittoETH protocol. It highlights the main risk categories and their corresponding sub-risks, illustrating the complex and interconnected nature of these risks.
Managing and mitigating these risks requires a comprehensive risk management framework that includes:
The DittoETH protocol follows a modular architecture using the Diamond standard, which promotes the separation of concerns and allows for extensibility and upgradability. The codebase is organized into multiple facets, each responsible for a specific functionality, such as vault management (VaultFacet
), bridge interaction (BridgeRouterFacet
), orderbook management (BidOrdersFacet
, ShortOrdersFacet
), liquidation (PrimaryLiquidationFacet
), and redemption (RedemptionFacet
).
This modular approach enhances code maintainability, as each facet can be developed, tested, and deployed independently. It also enables the protocol to evolve and adapt over time by adding new facets or upgrading existing ones without disrupting the entire system.
For example, the VaultFacet
contract focuses solely on managing vaults and handling collateral deposits and withdrawals:
function depositAsset(address bridge, uint88 amount) external nonReentrant { // ... uint88 dethAmount = uint88(IBridge(bridge).deposit(msg.sender, amount)); vault.addDeth(bridgePointer, dethAmount); // ... }
This separation of concerns allows for a cleaner and more focused codebase, making it easier to understand, maintain, and extend.
The DittoETH protocol makes extensive use of libraries to encapsulate complex logic and promote code reusability. Libraries such as LibOrders
, LibAsset
, LibShortRecord
, and LibVault
contain utility functions and common operations that are used across multiple contracts.
For instance, the LibOrders
library contains functions for managing orders on the orderbook, such as adding, canceling, and matching orders:
function addBid(address asset, STypes.Order memory order, MTypes.OrderHint[] memory orderHintArray) internal { // ... addOrder(s.bids, asset, order, hintId); // ... }
By leveraging libraries, the codebase avoids duplication and ensures consistency in the implementation of common functionalities. This approach also improves code readability and maintainability, as the core logic is abstracted away into reusable units.
The DittoETH protocol incorporates robust error handling and validation mechanisms to ensure the integrity and security of the system. The Errors
library defines a set of custom error types that are used consistently throughout the codebase to provide meaningful and informative error messages.
Functions in the protocol's contracts perform necessary validations and checks to prevent invalid or malicious inputs. For example, the createBid
function in the BidOrdersFacet
contract verifies the asset validity and checks for sufficient ETH balance before creating a bid order:
function createBid(/* ... */) external isNotFrozen(asset) onlyValidAsset(asset) nonReentrant returns (uint88 ethFilled, uint88 ercAmountLeft) { // ... if (eth < LibAsset.minBidEth(asset)) revert Errors.OrderUnderMinimumSize(); if (s.vaultUser[Asset.vault][sender].ethEscrowed < eth) revert Errors.InsufficientETHEscrowed(); // ... }
These error handling and validation practices help in catching and preventing potential issues early in the execution flow, improving the overall robustness and reliability of the protocol.
The DittoETH protocol places a strong emphasis on testing and code coverage to ensure the correctness and reliability of the smart contracts. The codebase includes a comprehensive test suite that covers various scenarios, edge cases, and potential vulnerabilities.
The tests are written using the Foundry framework, which provides a powerful and efficient testing environment for Solidity contracts. The tests cover unit testing of individual functions, integration testing of contract interactions, and scenario-based testing to simulate real-world usage patterns.
function testCreateBid() public { // ... (uint88 ethFilled, uint88 ercAmountLeft) = bidOrdersFacet.createBid(/* ... */); // ... assertEq(ethFilled, expectedEthFilled, "Incorrect ethFilled amount"); assertEq(ercAmountLeft, expectedErcAmountLeft, "Incorrect ercAmountLeft amount"); }
The extensive test coverage helps in identifying and fixing bugs, ensuring the expected behavior of the contracts, and maintaining a high level of code quality. It also provides confidence in the protocol's functionality and security.
The DittoETH codebase follows good documentation practices, with comprehensive comments and NatSpec annotations providing clear explanations of the purpose, functionality, and usage of each contract, function, and important code block.
/** * @notice Creates bid order in market * @dev IncomingBid created here instead of BidMatchAlgo to prevent stack too deep * * @param asset The market that will be impacted * @param price Unit price in eth for erc * @param ercAmount Amount of erc to buy * @param isMarketOrder Boolean for whether the bid is limit or market * @param orderHintArray Array of hint ID for gas-optimized sorted placement on market * @param shortHintArray Array of hint ID for gas-optimized short matching above oracle price * * @return ethFilled Amount of eth filled * @return ercAmountLeft Amount of erc not matched */ function createBid(/* ... */) external { // ... }
The provided whitepaper and technical documentation offer a high-level overview of the protocol's architecture, components, and functionalities. This documentation helps developers, auditors, and users understand the protocol's design and behavior, facilitating code review, integration, and adoption.
Currently, the DittoETH protocol relies on centralized price oracles, such as Chainlink and Uniswap V3 TWAPs, for obtaining asset prices. While these oracles provide reliable price data, they introduce a level of centralization risk into the system. If these oracles were to fail or be compromised, it could significantly impact the protocol's functionality and security.
Recommendation:
Consider transitioning to a more decentralized oracle solution, such as a decentralized oracle network or a multi-oracle approach. Decentralized oracle networks, like Tellor or UMA's Oracle, leverage the power of decentralized networks to provide secure and tamper-resistant price data. A multi-oracle approach involves using multiple independent oracles and aggregating their data to reduce the reliance on a single oracle provider.
Example:
function getOraclePrice(address asset) internal view returns (uint256) { // ... uint256 tellorPrice = ITellorOracle(tellorOracleAddress).getPrice(asset); uint256 umaPrice = IUMAOracle(umaOracleAddress).getPrice(asset); uint256 chainlinkPrice = AggregatorV3Interface(chainlinkOracleAddress).latestAnswer(); // Aggregate prices from multiple oracles uint256 aggregatedPrice = (tellorPrice + umaPrice + chainlinkPrice) / 3; // ... }
By diversifying the oracle sources and using decentralized solutions, the protocol can reduce its reliance on centralized oracles and enhance its overall security and resilience.
The current access control mechanism in the DittoETH protocol relies on the onlyDAO
modifier to restrict access to certain critical functions. While this provides a basic level of access control, it may not be granular enough to handle the diverse roles and permissions required in a complex system like DittoETH.
Recommendation:
Implement a more granular access control system, such as role-based access control (RBAC), to provide finer-grained control over different functionalities and permissions. This can be achieved by defining specific roles, such as VAULT_MANAGER
, BRIDGE_OPERATOR
, LIQUIDATOR
, etc., and assigning these roles to different addresses or contracts.
Example:
contract AccessControl { mapping(address => mapping(bytes32 => bool)) private _roles; modifier onlyRole(bytes32 role) { require(_roles[msg.sender][role], "AccessControl: sender lacks role"); _; } function grantRole(bytes32 role, address account) public onlyRole(DEFAULT_ADMIN_ROLE) { _roles[account][role] = true; } // ... } contract VaultFacet is AccessControl { // ... function depositAsset(address bridge, uint88 amount) external nonReentrant onlyRole(VAULT_MANAGER_ROLE) { // ... } // ... }
By implementing a more granular access control system, the protocol can ensure that only authorized entities can perform specific actions, reducing the risk of unauthorized access and enhancing the overall security posture.
The DittoETH protocol relies on external actors, such as liquidators and redeemers, to perform certain critical tasks, such as liquidating undercollateralized positions and processing redemption proposals. However, relying solely on external actors may lead to delays or inefficiencies in the execution of these tasks.
Recommendation:
Introduce a keeper system that automates the execution of certain repetitive and time-sensitive tasks. Keepers are external entities that are incentivized to perform specific actions on behalf of the protocol. They can be implemented as standalone contracts or off-chain bots that monitor the protocol's state and trigger the necessary actions when conditions are met.
Example:
contract LiquidationKeeper { // ... function performLiquidation(address asset, address shorter, uint8 id) external { // Check if the position is eligible for liquidation bool isUndercollateralized = PrimaryLiquidationFacet(primaryLiquidationFacetAddress).isUndercollateralized(asset, shorter, id); if (isUndercollateralized) { // Trigger the liquidation PrimaryLiquidationFacet(primaryLiquidationFacetAddress).liquidate(asset, shorter, id); // Claim keeper reward // ... } } // ... }
By introducing a keeper system, the protocol can ensure the timely execution of critical tasks, reduce the reliance on manual interventions, and improve the overall efficiency and reliability of the system.
In the event of unexpected market conditions or potential vulnerabilities, it is crucial for the DittoETH protocol to have mechanisms in place to quickly respond and mitigate risks. Currently, the protocol lacks explicit circuit breakers or emergency pause functionality.
Recommendation:
Implement circuit breakers and emergency pause functionality to allow the protocol to halt certain operations or freeze assets in case of extreme market volatility or potential security threats. Circuit breakers can be triggered automatically based on predefined thresholds, such as excessive price fluctuations or abnormal trading volumes. Emergency pause functionality can be controlled by a multisig or a decentralized governance mechanism.
Example:
contract EmergencyPause is AccessControl { bool private _paused; modifier whenNotPaused() { require(!_paused, "Paused"); _; } function pause() external onlyRole(PAUSE_ROLE) { _paused = true; } function unpause() external onlyRole(PAUSE_ROLE) { _paused = false; } // ... } contract VaultFacet is EmergencyPause { // ... function depositAsset(address bridge, uint88 amount) external nonReentrant whenNotPaused { // ... } // ... }
By implementing circuit breakers and emergency pause functionality, the protocol can quickly respond to adverse situations, protect users' assets, and maintain the stability and integrity of the system.
Given the complexity and critical nature of the DittoETH protocol, it is essential to ensure the highest level of security and correctness of the smart contracts. While the codebase includes extensive testing and follows best practices, regular security audits and formal verification can provide additional assurance.
Recommendation:
Conduct regular security audits by reputable third-party auditors who specialize in smart contract security. These audits can help identify potential vulnerabilities, suggest improvements, and validate the overall security posture of the protocol. Additionally, consider applying formal verification techniques, such as model checking or theorem proving, to mathematically prove the correctness of critical components and invariants.
Example:
// Invariant: The total collateral in the system should always be greater than or equal to the total debt invariant totalCollateral() >= totalDebt() function totalCollateral() public view returns (uint256) { // ... } function totalDebt() public view returns (uint256) { // ... }
By subjecting the protocol to regular security audits and applying formal verification techniques, the DittoETH team can demonstrate their commitment to security, build trust among users and stakeholders, and ensure the long-term resilience and reliability of the protocol.
The DittoETH protocol presents a sophisticated and innovative approach to pegged asset issuance and trading on the Ethereum blockchain. By leveraging the power of liquid staked ETH (LSTs) as collateral and introducing an orderbook-based minting mechanism, DittoETH aims to provide a decentralized and efficient platform for creating and exchanging a wide range of pegged assets. The protocol's modular architecture, based on the Diamond standard, promotes separation of concerns, extensibility, and upgradability. The codebase demonstrates a strong commitment to code quality, with extensive testing, comprehensive documentation, and adherence to best practices in smart contract development.
However, the complexity of the DittoETH protocol also introduces various risks and challenges that need to be carefully addressed. The reliance on centralized price oracles, the potential for centralization risks in governance and liquidity provision, and the exposure to systematic risks in the broader DeFi ecosystem are notable concerns that require ongoing monitoring and mitigation strategies. To further enhance the protocol's security, resilience, and long-term viability, several architectural improvements and recommendations have been proposed. These include transitioning to a more decentralized oracle solution, implementing a granular access control system, introducing a keeper system for automated tasks, incorporating circuit breakers and emergency pause functionality, and conducting regular security audits and formal verification.
By addressing these recommendations and continuously iterating on the protocol's design and implementation, the DittoETH team can strengthen the protocol's foundation, mitigate potential risks, and establish DittoETH as a leading platform for pegged asset issuance and trading in the DeFi landscape. However, it is important to acknowledge that the success and adoption of the DittoETH protocol also depend on factors beyond the technical implementation. Building a robust ecosystem of partnerships, attracting liquidity and user adoption, and navigating the evolving regulatory landscape will be critical challenges that the DittoETH team must address to ensure the protocol's long-term growth and sustainability.
In conclusion, the DittoETH protocol represents a significant step forward in the realm of pegged asset issuance and trading on the Ethereum blockchain. With its innovative design, modular architecture, and commitment to security and code quality, DittoETH has the potential to revolutionize the way pegged assets are created and exchanged. However, the protocol's success will depend on the team's ability to address the identified risks, implement the recommended improvements, and foster a thriving ecosystem around the protocol.
41 Hours
41 hours
#0 - c4-pre-sort
2024-04-07T20:36:34Z
raymondfam marked the issue as high quality report
#1 - c4-judge
2024-04-17T07:17:40Z
hansfriese marked the issue as grade-a
#2 - c4-judge
2024-04-17T07:21:09Z
hansfriese marked the issue as selected for report