CertiK reviewed DIN on 14 Jan 2025: 19 findings, 0 critical; 4 marked fixed, 4 acknowledged, 11 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 | 1 | 1 |
| Low | 11 | 0 | 2 |
In the `claim` function, users can input multiple `stakingIds` simultaneously to claim rewards. Each `stkChoice` determines the calculation of `weightClaimed` and reward amounts based on time and staking amounts. However, when the `stkChoice` for a `stakingId` is `L30Days`, the `weightClaimed` calculation does not account for time changes, and the reward calculation remains unaffected by the last claim time, this allows users to repeatedly claim rewards at the same timestamp.
In the `claim()` function of the `CurveStaking` contract, DIN rewards are distributed base on the proportion of the `stakingId` weight relative to `poolGlobalWeightNow`. However, this may lead to unfair reward distribution due to the order of claim operations of different users. As shown in the proof of concept (PoC), Alice, Bob and Cat stake at the same time, and the `_globalStakingTime` at this time is equal to their staking timestamp. However, after a period of time, when the three users claim, Bob, who claims first, will receive rewards based solely on the proportion of his stake amount relative to `_globalStakingAmountAfterCo`, as the `_globalStakingTime` difference matches his timestamp difference. In contrast, Alice and Cat, who claim later, must account for changes in time and stake amounts, receiving rewards proportionally adjusted for these factors.
In the `claim` function of `NodeStakingConvertor` contract, the logic for distributing rewards based on the day intervals contains a **logical mismatch** due to the use of the `<=` operator. This causes certain **boundary days** (e.g., 30, 90, 120) to be treated as part of the **earlier interval**, rather than the intended **later interval**, as described in the comments. This discrepancy stems from how the boundary conditions are structured in the code versus how they are described in the comments. ```solidity function claim(uint256[] calldata claimIds) public { ... for (uint256 i = 0; i < claimIds.length; ++i) { require(userClaimId[_msgSender()].contains(claimIds[i]), "No claim"); // The following rule is hardcoded: // Day 0-29: Can not claim // Day 30-89: 25% to user, 75% to treasury // Day 90-119: 60% to user, 40% to treasury // Day 120 and after, 100% to user uint256 tmpUserAmount = 0; uint256 tmpTreasuryAmount = 0; if ((block.timestamp - claimSchedules[claimIds[i]].createTime) <= 30 days) { require(false, "Can not claim before 30 days"); } else if ((block.timestamp - claimSchedules[claimIds[i]].createTime) <= 90 days) { tmpUserAmount = claimSchedules[claimIds[i]].amount * 25 / 100; tmpTreasuryAmount = claimSchedules[claimIds[i]].amount * 75 / 100; } else if ((block.timestamp - claimSchedules[claimIds[i]].createTime) <= 120 days) { tmpUserAmount = claimSchedules[claimIds[i]].amount * 60 / 100; tmpTreasuryAmount = claimSchedules[claimIds[i]].amount * 40 / 100; } else { tmpUserAmount = claimSchedules[claimIds[i]].amount; } userClaimId[_msgSender()].remove(claimIds[i]); emit rewardClaimed(claimIds[i], tmpUserAmount, tmpTreasuryAmount); userAmount += tmpUserAmount; treasuryAmount += tmpTreasuryAmount; } ... } ```
Contracts `NFTAirdropNative` and `xDINConvertingNative` implement interface of ERC20 standard, however, the `transferFrom()` function does not correctly set a return value as required by the ERC20 standard, and the comment also states that this function needs a return value. Even though the return value of this function is not used in the actual implementation, it is still recommended to adhere to the standard by correctly implementing the function in the interface. ```solidity interface IERC20 { ... /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external; } ```
| Address | Chain | Source code |
|---|---|---|
| 0x3ab1…da4e0x3ab1a5f76e12202d1ad1548a08a799501581da4e | Chain: BNB Chain | Source code: Verified source |
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