Dtec Audit

CertiKFiles named in the report

CertiK reviewed The Dtec World (Dtec Audit) on 12 Dec 2023: 18 findings, 0 critical; 13 marked fixed, 5 open.

No open critical findings
Open the reportOpen The Dtec World’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings18

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

SeverityOpenAcknowledgedFixed
Critical000
High201
Medium003
Low309
HighPurchased `DTEC` Stuck In the `PublicSaleLock` CoFixed

In the contract `PublicSaleLock`, users can call `claim()` function to claim the `DTEC` tokens they purchased earlier in the `DTECPublicSale` contract after a certain period. However, it is noted that in the `getClaimable()` function, the contract uses the code below to calculate the claimable amount of `DTEC`, and the value of `numerator` is always less than **10000**, which means 10% of `info.totalAmount` will be stuck in the current contract. ```solidity=70 uint256 numerator = getReleaseNumerator(periodsPassed); uint256 totalClaimableSoFar = info.totalAmount * numerator / 10000; if (totalClaimableSoFar > info.totalAmount) { totalClaimableSoFar = info.totalAmount; } return totalClaimableSoFar - info.totalClaimed; ```

MediumPotential DoS Attack on `migrateOldUsers()`Fixed

The function `migrateOldUsers` is intended to facilitate the migration of tokens from an old contract to a new one. It requires that each user's bought amount in the new contract be zero before allowing migration. ```solidity function migrateOldUsers (address[] calldata users ) external onlyOwner nonReentrant { //... for (uint256 i = 0; i < users.length; i++) { require(addressToBoughtAmt[users[i]] == 0, "User should only migrate once, no duplicate amount"); //... require(oldSaleContract.amountSold() == totalMigratedTokenAmount , "All bought amounts should be migrated"); emit MigrationMade(users, block.timestamp, totalMigratedTokenAmount); } ``` This may bring a potential DoS attack and no token can be migrated from an old contract to a new contract.

MediumPotential Incorrect Allocation AmountFixed

In the `migrateOldUsers()` function, the contract calculates the value of `allocation` via `addressToBoughtAmt`. However, it is noted that `addressToBoughtAmt` is possibly inconsistent with `allocation` in the old contract due to the `claimAllocation()` function. If a user has called `claimAllocation()` in the old contract, the `allocation` of this user is zero. But the migration incorrectly updates `allocation` to the corresponding bought amount, which causes a user can claim more tokens than bought.

MediumPotential transfer allocated tokens of usersFixed

In the contract `DTECTokenSale`, the `_owner` can transfer `_amt` amount of `DTEC` tokens away. It is noted that this function misses a sanity check for `_amt`, as a result, the allocated tokens of users may be also transferred, causing calling to `claimAllocation()` failed.

LowInconsistant Import PathFixed

The provided codebase cannot be compiled. Additionally, suppose the contracts are within the same folder. There will be inconsistency in the imports of the `ITokenLock.sol` interface between the different files. Specifically, the discrepancy lies in the paths used to import this interface: - In the file `DTECTokenSale.sol`, it is imported as ```solidity import {ITokenLock} from "./interfaces/ITokenLock.sol"; ``` - In the file `PublicSaleLock.sol` and `LinearLock.sol`, it is imported as ```solidity import {ITokenLock} from "../interfaces/ITokenLock.sol"; ```

LowLack of Zero Amount ValidationFixed

The `_owner` can modify the `period` of the contract. However, there is no validation to prevent the `period` from being set to zero. If `period` is set to zero, the lock contract will encounter a revert error when users attempt to claim their tokens. The variable `releaseRate` is also lacking the same sanity check.

LowMissing Emit EventsFixed

There should always be events emitted in the sensitive functions that are controlled by centralization roles.

LowMissing Zero Address ValidationFixed

The cited address input is missing a check that it is not `address(0)`.

LowState Variable Should Be Declared ConstantFixed

State variables that never change should be declared as `constant` to save gas. ```solidity=7 uint256 public MAX_SUPPLY = 900000000 * 10 ** 18; ``` - `MAX_SUPPLY` should be declared `constant`.

LowUnable to remove users from `wl`Fixed

In the contract `DTECPrivateSale`, only whitelisted users can buy `DTEC` via this contract. It is noted that the contract misses a functionality that remove users from whitelist.

Show 3 more
LowUnreachable If BranchFixed

The function `getReleaseNumerator` is used to calculate the released amount. ```solidity function getReleaseNumerator(uint256 _periods) internal pure returns (uint256) { if (_periods == 0) { return 0; } else if (_periods == 1) { return 2000; } else if (_periods == 2) { return 5000; } return 9000; } ``` However, if the calculated `periodsPassed` is zero, getClaimable() will be returned directly at L67 without reaching the first if branch(L50) in the function `getReleaseNumerator()`.

LowUser Could not Claim Tokens From VestingFixed

The function `getClaimable()` is used to calculate claimable tokens. ```solidity function getClaimable(address _user) public view returns (uint256) { LockInfo memory info = userToLockInfo[_user]; if (info.totalClaimed == info.totalAmount || lockStartTime == 0 || block.timestamp < lockStartTime) { return 0; } //... } ``` However, since the visit level of functions `setReleaseInfo()` and `setPeriod()` are internal, which could not be called by the owner, thus `lockStartTime` and `releaseRate` will always be zero. The function `getClaimable()` will reach condition in L46 and always return zero, no one can claim any tokens.

LowVariables That Could Be Declared as ImmutableFixed

The linked variables assigned in the constructor can be declared as `immutable`. Immutable state variables can be assigned during contract creation but will remain constant throughout the lifetime of a deployed contract. A big advantage of immutable variables is that reading them is significantly cheaper than reading from regular state variables since they will not be stored in storage.

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 (15)

  • contracts/LinearLock.sol
  • contracts/PublicSaleLock.sol
  • contracts/DTECPublicSale.sol
  • contracts/DTECPrivateSale.sol
  • contracts/DTECTokenSale.sol
  • PreSaleLock.sol
  • contracts/Vesting.sol
  • PublicSaleLock.sol
  • contracts/PreSaleLock.sol
  • Vesting.sol
  • contracts/DTEC.sol
  • contracts/PrivateSaleLock.sol
  • contracts/DTECPreSale.sol
  • LinearLock.sol
  • PrivateSaleLock.sol

Part of The Dtec World’s security record

The Dtec World
Audits2 audits by 1 firmLast audit Jul 2024, by CertiK.
Critical findingsNo open critical findingsAcross 2 reports.
Open The Dtec World’s security record

Security firm

CertiK

1,044 projects reviewed · 1,375 reports · latest May 2025

See CertiK’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