CertiK reviewed dbXEN on 17 Feb 2023: 4 findings, 0 critical; all marked fixed.
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 | 0 | 1 |
| Medium | 0 | 0 | 0 |
| Low | 0 | 0 | 3 |
The "DBXen" Contract enables the deposit of `DXN` tokens to participate in the sharing of native token fees. The `cycleFeesPerStakeSummed` value acts as an accumulated index to determine the reward earned by the user between the time of staking and the time the reward is issued. However, there is a concern with the current implementation, as the `cycleFeesPerStakeSummed` value is discrete and only updates for `lastStartedCycle + 1`. This means that if multiple cycles occur without a batch burn, the `lastStartedCycle` will remain unchanged, and the `cycleFeesPerStakeSummed` value for the remaining cycles will be 0. ```solidity=469 cycleFeesPerStakeSummed[lastStartedCycle + 1] = cycleFeesPerStakeSummed[previousStartedCycle] + feePerStake; ``` For instance, if the new cycle starts at 0, then `cycleFeesPerStakeSummed[1]` will have a value, but cycles 2 and 3 will be 0.  This will lead to an incorrect calculation in the `accAccruedFees` update. If the user stakes in an inactive cycle, such as cycle 2 or 3, the value of `cycleFeesPerStakeSummed[accFirstStake[account]]` will always be 0. ```solidity=548 if (lastStartedCycle + 1 > accFirstStake[account]) { accAccruedFees[account] = accAccruedFees[account] + ( (accStakeCycle[account][accFirstStake[account]] * (cycleFeesPerStakeSummed[lastStartedCycle + 1] - cycleFeesPerStakeSummed[accFirstStake[account]] ) ) ) / SCALING_FACTOR; } ```
The execution of the function `setUpNewCycle()` is required to set up values such as `summedCycleStakes[]` for the current cycle. Since `setUpNewCycle()` is called by function `onTokenBurned()`, it means that these values will be set when XENCrypto.burn() is executed for the first time in each cycle. If there is no token burning, the function will not be run. If unstaking and reward retrieval occurs during this period, `summedCycleStakes[currentCycle]` will not be updated and will remain overestimated until the function is executed. ```solidity=414 if (lastStartedCycle == currentStartedCycle) { pendingStakeWithdrawal += amount; } else { summedCycleStakes[currentCycle] -= amount; } ``` In summary, if there is no token burning during a cycle or multiple cycles, `summedCycleStakes[]` and new stakes/rewards will not be updated until the next time tokens are burned and setUpNewCycle() is executed.
When the `burnBatch` function is invoked, the user will pay a protocol fee to complete the process. And there is a discount on the protocol fee based on the batch number. ```solidity=251 uint256 discount = (batchNumber * (1000000 - 50 * batchNumber)); ``` However, the base number presenting 100 percent is 1000000 instead of the value for `MAX_BPS` (which is `10000`).
The return value of the transfer()/transferFrom() call is not checked. ```solidity=390 dxn.transferFrom(_msgSender(), address(this), amount); ``` --- ```solidity=423 dxn.transfer(_msgSender(), amount); ```
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (1)
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