DerivaDEX 2

QuantstampFiles named in the report

Quantstamp reviewed DerivaDEX 2 on 22 Jul 2022: 23 findings, 0 critical; 12 marked fixed, 8 acknowledged, 3 open.

No open critical findings
Open the reportOpen DerivaDEX 2’s security record

Report hosted on certificate.quantstamp.com.

Trustblock does not review code.

Findings23

Statuses are the security firm’s own, from its report.

SeverityOpenAcknowledgedFixed
Critical000
High002
Medium111
Low279
HighMinority Jailing Majority of SignersFixed

The `Checkpoint.sol:checkpoint` function will first jail the minority submitters before verifying the consensus rule. Those jailed signers will decrease the `dsRegistration.validSignersCount` counted in the `LibCheckpoint.sol:getConsensusThreshold` function. The ability to jail others brings a potential attack where the smaller group of signers tries to jail the larger group of singers. And then, since the minority group jail the counter-parties, they can easily pass the validation as long as the smaller group of signers exceeds the `quorum` requirement.

HighSingle Signer Failing the ConsensusFixed

The function `Reject.sol:reject` (L56-126) checks whether there is consensus failure or not with the checkpoint `_submissions` input data. The calculation is based on the number of `custodians` in L96-97 retrieved from the `_submissions[i]`. However, the `reject` function does not check whether it counts the specific custodian multiple times. Thus, a single signer can fake several submissions and pretend that there are several groups.

MediumOver-Casting of `safe128`Fixed

The `MathHelpers.sol:safe128` function casts the input `n` to `uint96` instead of `uint128`. This will return an over-casted value if the `n` is in the range of `[2^96, 2^128)`. The `safe128` function is used in `block.number` calculations and also the function `LibCollateral.sol:scaleAmountForToken`. It is unlikely the `block.number` will exceed `uint96`, but `LibCollateral.sol:scaleAmountForToken` function is of risk. Inside the `LibCollateral.sol:scaleAmountForToken` function, it will apply the `safe128` to `10^(abs(decimals - OPERATOR_DECIMALS))`. Although most ERC20s use practical decimals like 18, it is not impossible to have an ERC20 token with decimal more than usual. If the are more than 47 decimals, the calculation of `10^(48-18)` will exceed `2^96-1` and be over-casted after the `safe128` function. The `LibCollateral.sol:scaleAmountForToken` function is used inside the `Collateral.sol` and `FundedInsuranceFund.sol` contracts. It would be risky when depositing and withdrawing tokens if the DEX were to list any tokens with abnormal decimals

Low`ReentrancyGuard` Not Using Diamond StorageFixed

Several facets inherit the `ReentrancyGuard.sol` contract from the OpenZeppelin. However, the `ReentrancyGuard.sol` implementation does not integrate with the diamond storage. The `ReentrancyGuard.sol` will mutate a `_status` variable on the storage ([code](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/de99bccbfd4ecd19d7369d01b070aa72c64423c9/contracts/utils/ReentrancyGuard.sol#L36)). This brings risk to storage collision across facets if new facets access to the standard storage instead of the randomized diamond storage. Note that this is the only storage detected not following the diamond storage pattern within the current code base, so there is no exploit from this now. However, future code changes and audits should be aware of this risk.

LowClone-and-OwnFixed

DerivaDEX inherits from a Diamond Standard implementation of EIP-2535. However, it is unclear which repository and which commit hash the files are cloned from.

LowFragile `LibStack` Assumption on the MemoryFixed

The `LibStack.sol` contract strongly assumes that the implementation should allocate no memory within the stack's life cycle. If a new memory is assigned, the stack will not fail and will continue to read from those newly issued memories. Note that the team already documented this limitation inside the code. Also, we did not find an exploit from this during the audit. Still, we would like to highlight this, so future code changes or audits should be cautious.

LowIgnoring Return Value of ERC-20 TransferFixed

A few places in the code ignore the return value of the generic ERC20 transfer call. The implementation of the `transfer` and `transferFrom` functions of the ERC20 tokens can potentially return false to indicate a failed transfer instead of reverting directly. Therefore, a failed transfer might sneak through the code without checking the return value. 1. `Collateral.sol:L388` (the function `withdraw`): return value of `IERC20(...).transfer(...)` is not checked. 2. `FundedInsuranceFund.sol:L81` (the function `fund`): return value of `IERC20(_collateralAddress).transferFrom(...)` is not checked. 3. `FundedInsuranceFund.sol::L152` (the function `unfund`): return value of `IERC20(...).transfer(...)` is not checked.

LowMisleading Rate Limit ConditionFixed

The `LibCollateral.sol:commitWithdrawalAllowance` function (L251-275) has the condition of `rateLimitRemaining != uint128(-1)` in L269. However, if we look into the `LibCollateral.sol:getMaximumWithdrawal` function (L358-398), `rateLimitRemaining` is defined as `rateLimits.rateLimitForPeriod - rateLimits.consumedInPeriod` in L391. To fulfill the condition of `rateLimitRemaining != uint128(-1)`, the `rateLimits.consumedInPeriod` must be exactly `rateLimits.rateLimitForPeriod + 1` so that it can underflow and become `uint128(-1)`. There are some issues from our observation. First, the condition indicates the expectation and usage of the underflow. The use of underflow adds complexity to understanding the code and is against best practices. Aside from that, the calculation of `rateLimits.rateLimitForPeriod - rateLimits.consumedInPeriod` seems not possible to go underflow. The reason is that the `rateLimits.consumedInPeriod` is the sum of the `_unscaledWithdrawalAmount`. And the `_unscaledWithdrawalAmount` is guarded by the `maximumWithdrawalAmount` in L261 inside the function of `LibCollateral.sol:commitWithdrawalAllowance`. `maximumWithdrawalAmount` ensures that it will not be greater than the `rateLimits.rateLimitForPeriod`.

LowOld Solidity VersionFixed

DerivaDEX uses Version 0.6.12 of Solidity, whereas the latest release of Solidity is 0.8.15. Several breaking changes removing unused/unsafe features have been implemented in the intervening versions. Moreover, an antiquated version makes it impossible to use the latest version of Diamond standard files.

LowSeveral `TODO` and `FIXME` Comments on the CodebaseFixed

Codebase contains several `TODO` and `FIXME` comments. These should not appear in a production codebase.

Show 2 more
LowSpec/doc Mismatch on `FundedInsuranceFund`Fixed

There are a few places where there is a gap between the code document and the implementation: 1. The code document in `FundedInsuranceFund.sol:fund` (L65-66) claims the following: "Allows an allowed funder to deposit funds into the funded insurance fund." However, despite the implementation checking the banned status, it does not verify the `msg.sender` is in a pre-defined allow list or not. In other words, any user can create a new account and call this function. 2. The code document in `FundedInsuranceFund.sol:L25-26` states, "This capital will not grow and will not be subject ...". However, funders can deposit at any time to grow the fund. The team should rephrase the description to avoid confusion.

LowStyle Consistency on Arithmetic OperatorFixed

As the Solidity version is previous to 0.8.0, code base is vulnerable to integer overflows and underflows. The project uses libraries to avoid these problems (e.g. SafeMath), but the multiplication operator is sometimes still used: - `LibCheckpoint`: - `L35`: `dsCheckpoint.consensusThreshold * CONSENSUS_PRECISION` - `L93`: `_consensusCount * CONSENSUS_PRECISION` - `LibCollateral`: - `L71`: `TRADE_MINING_LENGTH * TRADE_MINING_EPOCH_MULTIPLIER` - `L558`: `TRADE_MINING_LENGTH * TRADE_MINING_EPOCH_MULTIPLIER` - `L575`: `TRADE_MINING_REWARD_PER_EPOCH * reward_epochs`

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (99)

  • protocol/contracts/src/tokens/DummyToken.sol
  • protocol/contracts/src/storage/LibDiamondStoragePause.sol
  • protocol/contracts/src/facets/Checkpoint.sol
  • protocol/contracts/src/facets/Custodian.sol
  • protocol/contracts/test/TestLibCheckpoint.sol
  • protocol/contracts/src/gnosis/ICreateCall.sol
  • protocol/contracts/src/libs/LibBytes.sol
  • protocol/contracts/src/facets/InsuranceFund.sol
  • protocol/contracts/test/TestFundedInsuranceFund.sol
  • protocol/contracts/src/libs/LibTraderInternal.sol
  • protocol/contracts/src/facets/Specs.sol
  • protocol/contracts/src/facets/interfaces/IInsuranceFund.sol
  • protocol/contracts/src/libs/LibClone.sol
  • protocol/contracts/test/TestLibBytes32.sol
  • protocol/contracts/src/facets/Trader.sol
  • protocol/contracts/src/libs/defs/CheckpointDefs.sol
  • protocol/contracts/src/diamond/OwnershipFacet.sol
  • protocol/contracts/src/libs/defs/SpecsDefs.sol
  • protocol/contracts/src/tokens/interfaces/IDIFundTokenFactory.sol
  • protocol/contracts/src/facets/Governance.sol
  • protocol/contracts/test/TestSolRsaVerify.sol
  • protocol/contracts/test/TestRegistrationForSnapshot.sol
  • protocol/contracts/src/libs/SafeMath128.sol
  • protocol/contracts/src/libs/LibDelegation.sol
  • protocol/contracts/test/TestRegistration.sol
  • protocol/contracts/src/libs/LibEIP712.sol
  • protocol/contracts/src/DerivaDEX.sol
  • protocol/contracts/src/libs/defs/DepositDefs.sol
  • protocol/contracts/src/storage/LibDiamondStorageDerivaDEX.sol
  • protocol/contracts/src/diamond/DiamondFacet.sol
  • protocol/contracts/src/tokens/interfaces/IDDX.sol
  • protocol/contracts/src/facets/Banner.sol
  • protocol/contracts/src/tokens/interfaces/IDIFundToken.sol
  • protocol/contracts/src/libs/MathHelpers.sol
  • protocol/contracts/src/gnosis/IGnosisSafeProxyFactory.sol
  • protocol/contracts/test/TestLibCollateral.sol
  • protocol/contracts/src/facets/Stake.sol
  • protocol/contracts/src/libs/defs/FundedInsuranceFundDefs.sol
  • protocol/contracts/src/facets/interfaces/IComptroller.sol
  • protocol/contracts/src/libs/defs/InsuranceFundDefs.sol
  • protocol/contracts/src/storage/LibDiamondStorageTrader.sol
  • protocol/contracts/src/libs/StringUtils.sol
  • protocol/contracts/test/TestCheckpointSingleNodeDeployment.sol
  • protocol/contracts/src/libs/defs/TraderDefs.sol
  • protocol/contracts/src/diamond/IERC165.sol
  • protocol/contracts/test/GasConsumer.sol
  • protocol/contracts/src/libs/LibSMT.sol
  • protocol/contracts/src/storage/LibDiamondStorageRegistration.sol
  • protocol/contracts/src/libs/LibRelease.sol
  • protocol/contracts/src/diamond/LibDiamondStorage.sol
  • protocol/contracts/src/facets/Registration.sol
  • protocol/contracts/test/TestLibSMT.sol
  • protocol/contracts/src/libs/Base64.sol
  • protocol/contracts/src/diamond/IDiamondCut.sol
  • protocol/contracts/src/storage/LibDiamondStorageDeposit.sol
  • protocol/contracts/src/libs/LibSignature.sol
  • protocol/contracts/src/libs/LibBytes32.sol
  • protocol/contracts/src/libs/defs/SharedDefs.sol
  • protocol/contracts/src/libs/LibCheckpoint.sol
  • protocol/contracts/src/libs/defs/GovernanceDefs.sol
  • protocol/contracts/src/tokens/SafeERC20Wrapper.sol
  • protocol/contracts/test/TestLibRelease.sol
  • protocol/contracts/src/diamond/LibDiamondCut.sol
  • protocol/contracts/src/libs/LibVoteCast.sol
  • protocol/contracts/src/libs/SolRsaVerify.sol
  • protocol/contracts/src/tokens/CompetitionDummyToken.sol
  • protocol/contracts/test/TestStake.sol
  • protocol/contracts/src/tokens/DIFundToken.sol
  • protocol/contracts/src/facets/interfaces/ICToken.sol
  • protocol/contracts/test/TestCollateral.sol
  • protocol/contracts/test/TestCheckpointMultiNodeDeployment.sol
  • protocol/contracts/src/gnosis/IGnosisSafe.sol
  • protocol/contracts/src/tokens/DDXWalletCloneable.sol
  • protocol/contracts/src/storage/LibDiamondStorageDepositGuarded.sol
  • protocol/contracts/src/storage/LibDiamondStorageReentrancyGuard.sol
  • protocol/contracts/src/tokens/HDUMToken.sol
  • protocol/contracts/src/libs/SafeMath96.sol
  • protocol/contracts/src/libs/LibCollateral.sol
  • protocol/contracts/src/tokens/DIFundTokenFactory.sol
  • protocol/contracts/src/tokens/interfaces/IDDXWalletCloneable.sol
  • protocol/contracts/src/facets/Pause.sol
  • protocol/contracts/src/tokens/DDX.sol
  • protocol/contracts/test/TestLibStack.sol
  • protocol/contracts/src/libs/LibStack.sol
  • protocol/contracts/src/libs/SafeMath32.sol
  • protocol/contracts/src/tokens/interfaces/IERC20Extended.sol
  • protocol/contracts/test/TestCheckpoint.sol
  • protocol/contracts/src/facets/FundedInsuranceFund.sol
  • protocol/contracts/src/libs/LibPermit.sol
  • protocol/contracts/src/storage/LibDiamondStorageGovernance.sol
  • protocol/contracts/src/diamond/IDiamondLoupe.sol
  • protocol/contracts/src/storage/LibDiamondStorageBanner.sol
  • protocol/contracts/src/libs/defs/RegistrationDefs.sol
  • protocol/contracts/src/facets/Collateral.sol
  • protocol/contracts/src/storage/LibDiamondStorageCheckpoint.sol
  • protocol/contracts/src/facets/interfaces/IAToken.sol
  • protocol/contracts/src/storage/LibDiamondStorageInsuranceFund.sol
  • protocol/contracts/src/facets/Reject.sol
  • protocol/contracts/src/libs/ReentrancyGuard.sol

Part of DerivaDEX 2’s security record

DerivaDEX 2
Audits1 audit by 1 firmLast audit Jul 2022, by Quantstamp.
Critical findingsNo open critical findingsIn 1 report.
Open DerivaDEX 2’s security record

Security firm

Quantstamp

236 projects reviewed · 332 reports · latest Oct 2026

See Quantstamp’s audits

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us