CertiK reviewed Derify protocol (Derify Protocol v2) on 7 Dec 2023: 18 findings, 0 critical; 3 marked fixed, 6 acknowledged, 9 open.
Report hosted on skynet.certik.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 3 | 1 |
| Medium | 0 | 3 | 2 |
| Low | 9 | 0 | 0 |
"Calling a `nonReentrant` function from another `nonReentrant` function is not supported." See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.2/contracts/security/ReentrancyGuard.sol.
According to the Derify Protocol’s [insurance pool mechanism](https://derify.medium.com/how-does-the-insurance-pool-in-derify-works-c8887ceda8c5), when users withdraw their funds but the system is in a net loss, funds from the insurance pool will be used as a supplement to ensure the normal settlement of the fund withdrawal; when users withdraw their funds but the system is in a net profit, funds from the liquidity pool will be transferred to the insurance pool. See the code snippet provided below: ```solidity function withdraw(uint256 amount) external override nonReentrant whenNotPaused { ... if (compensation > 0) { uint256 profitCompensation = uint256(compensation); if (insuranceFundPool >= profitCompensation) { _transferPoolFrom( PoolUpdateType.ProfitCompensation, AccountType.InsuranceFundPool, AccountType.LiquidityPool, profitCompensation ); } else { // handle the case that InsuranceFundPool not enough to pay => pay bond uint256 pnlBond = profitCompensation - insuranceFundPool; executeAmount = amount - pnlBond; _transferPoolFrom( PoolUpdateType.ProfitCompensation, AccountType.InsuranceFundPool, AccountType.LiquidityPool, insuranceFundPool ); IDerifyRewards(rewards).payBond(trader, pnlBond); } } else if (compensation < 0){ uint256 lossCompensation = uint256(compensation * -1); _transferPoolFrom( PoolUpdateType.LossCompensation, AccountType.LiquidityPool, AccountType.InsuranceFundPool, lossCompensation ); } } ``` However, the smart contract's deposit function possesses a logical inconsistency in the compensation mechanism. When the system is in a net loss, funds from the liquidity pool will be transferred to the insurance pool. This misalignment in fund transfer logic could create discrepancies in compensation, affecting the protocol's reliability.
The function `deposit()` is called by the user to deposit assets. When the `sysNetPnl` of the system is positive and the user attempts to deposit more assets, and the number of assets in the current pool `LiquidityPool` is less than `profitCompensation`, then the function will fail due to the underflow of `uint256`. In other words, the user cannot deposit more assets at that time. File:DerifyExchange.sol ```solidity=80 uint256 public override liquidityPool; ``` ```solidity=149 _transferPoolFrom( PoolUpdateType.ProfitCompensation, AccountType.LiquidityPool, AccountType.InsuranceFundPool, profitCompensation ); ``` ```solidity=161 liquidityPool += amount; ``` Since the amount of `liquidityPool` is accrued on line 161, there may be insufficient assets when transferring the token on line 149 of the contract.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (17)
1,044 projects reviewed · 1,375 reports · latest May 2025
See CertiK’s auditsSomething 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