CertiK reviewed Chronos (Chronos Audit 2) on 21 Apr 2023: 32 findings, 0 critical; 21 marked fixed, 1 acknowledged, 10 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 | 0 | 2 |
| Medium | 0 | 1 | 6 |
| Low | 10 | 0 | 13 |
Performing integer division before multiplication truncates the low bits, losing the precision of calculation. ```solidity=235 rewardRate = reward.div(DURATION); ``` ```solidity=238 uint256 leftover = remaining.mul(rewardRate); ``` --- ```solidity=649 block_slope = (MULTIPLIER * (block.number - last_point.blk)) / (block.timestamp - last_point.ts); ``` ```solidity=679 last_point.blk = initial_last_point.blk + (block_slope * (t_i - initial_last_point.ts)) / MULTIPLIER; ``` --- ```solidity=778 _bonusPercent = minBonusPercent + ((maxBonusPercent - minBonusPercent)*(_bonusTime*PRECISSION/maxBonusTime))/PRECISSION; ``` --- ```solidity=100 uint _amountPerNFT = totalAirdrop/_totalSupply; ``` ```solidity=101 uint _amount = _ogMints * _amountPerNFT; ``` --- ```solidity=119 uint claimablePercent = (timeElapsedSinceStart*PRECISION)/VESTING_PERIOD; ``` ```solidity=121 userInfo.CHRClaimable = _totalCHR*claimablePercent/PRECISION - claimedCHR[_who]; ```
It is expected that calls of the form `transfer(recipient, amount)` and `transferFrom(from, dest, amount)` fail if the recipient address is zero address.
The contract `AirdropClaimChrNFT` imports `IERC20` interface from openzeppelin, however the contract `VotingEscrow` imports the same interface from "./interfaces/IERC20.sol". Thus, compiling contracts encounters an error: "DeclarationError: Identifier already declared.".
When transferring deflationary ERC20 tokens, the input amount may not be equal to the received amount due to the charged transaction fee. For example, if a user sends 100 deflationary tokens (with a 10% transaction fee), only 90 tokens actually arrived to the contract. However, a failure to discount such fees may allow the same user to withdraw 100 tokens from the contract, which causes the contract to lose 10 tokens in such a transaction. Reference: https://thoreum-finance.medium.com/what-exploit-happened-today-for-gocerberus-and-garuda-also-for-lokum-ybear-piggy-caramelswap-3943ee23a39f ```solidity=225 IERC20(_rewardsToken).safeTransferFrom(msg.sender,address(this),reward); ``` - Transferring tokens by `reward`. ```solidity=235 rewardData[_rewardsToken][_startTimestamp].rewardsPerEpoch = _lastReward + reward; ``` - The `reward` appears to be used for bookkeeping purposes without compensating the potential transfer fees. --- ```solidity=156 _deposit(amount, msg.sender); ``` - Transferring tokens by `amount`. - This function call executes the following operation. - In `GaugeV2._deposit`, - `TOKEN.safeTransferFrom(account, address(this), amount);` ```solidity=156 _deposit(amount, msg.sender); ``` - This function call executes the following operation. - In `GaugeV2._deposit`, - `_totalSupply = _totalSupply.add(amount);` - In `SafeMath.add`, - `return a + b;` - The `amount` appears to be used for bookkeeping purposes without compensating the potential transfer fees. --- ```solidity=232 rewardToken.safeTransferFrom(DISTRIBUTION, address(this), reward); ``` - Transferring tokens by `reward`. ```solidity=239 rewardRate = reward.add(leftover).div(DURATION); ``` - This function call executes the following operation. - In `SafeMath.add`, - `return a + b;` - The `reward` appears to be used for bookkeeping purposes without compensating the potential transfer fees. --- ```solidity=809 assert(IERC20(token).transferFrom(from, address(this), _value)); ``` - Transferring tokens by `_value`. ```solidity=819 emit Supply(supply_before, supply_before + _value); ``` - The `_value` appears to be used for bookkeeping purposes without compensating the potential transfer fees. --- ```solidity=842 _deposit_for(_tokenId, _value, 0, _locked, DepositType.DEPOSIT_FOR_TYPE); ``` - Transferring tokens by `_value`. - This function call executes the following operation. - In `VotingEscrow._deposit_for`, - `assert(IERC20(token).transferFrom(from, address(this), _value));` ```solidity=842 _deposit_for(_tokenId, _value, 0, _locked, DepositType.DEPOSIT_FOR_TYPE); ``` - This function call executes the following operation. - In `VotingEscrow._deposit_for`, - `emit Supply(supply_before, supply_before + _value);` - The `_value` appears to be used for bookkeeping purposes without compensating the potential transfer fees. --- ```solidity=860 _deposit_for(_tokenId, _value, unlock_time, locked[_tokenId], DepositType.CREATE_LOCK_TYPE); ``` - Transferring tokens by `_value`. - This function call executes the following operation. - In `VotingEscrow._deposit_for`, - `assert(IERC20(token).transferFrom(from, address(this), _value));` ```solidity=860 _deposit_for(_tokenId, _value, unlock_time, locked[_tokenId], DepositType.CREATE_LOCK_TYPE); ``` - This function call executes the following operation. - In `VotingEscrow._deposit_for`, - `emit Supply(supply_before, supply_before + _value);` - The `_value` appears to be used for bookkeeping purposes without compensating the potential transfer fees. --- ```solidity=869 return _create_lock(_value, _lock_duration, msg.sender); ``` - Transferring tokens by `_value`. - This function call executes the following operation. - In `VotingEscrow._create_lock`, - `_deposit_for(_tokenId, _value, unlock_time, locked[_tokenId], DepositType.CREATE_LOCK_TYPE);` - In `VotingEscrow._deposit_for`, - `assert(IERC20(token).transferFrom(from, address(this), _value));` ```solidity=869 return _create_lock(_value, _lock_duration, msg.sender); ``` - This function call executes the following operation. - In `VotingEscrow._create_lock`, - `_deposit_for(_tokenId, _value, unlock_time, locked[_tokenId], DepositType.CREATE_LOCK_TYPE);` - In `VotingEscrow._deposit_for`, - `emit Supply(supply_before, supply_before + _value);` - The `_value` appears to be used for bookkeeping purposes without compensating the potential transfer fees. --- ```solidity=877 return _create_lock(_value, _lock_duration, _to); ``` - Transferring tokens by `_value`. - This function call executes the following operation. - In `VotingEscrow._create_lock`, - `_deposit_for(_tokenId, _value, unlock_time, locked[_tokenId], DepositType.CREATE_LOCK_TYPE);` - In `VotingEscrow._deposit_for`, - `assert(IERC20(token).transferFrom(from, address(this), _value));` ```solidity=877
The function `createPair` can be called by anyone as it has no access restriction. This enables anyone to call this and create a swap pair. In addition, there isn't a whitelist to control swap token types. The swap pool does not support deflationary tokens, users may create a swap pool for deflationary tokens by mistake. Furthermore, malicious users may create swap pools for scam tokens.
The `_transfer` function lacks a check to ensure the token sender has sufficient balance. Therefore, if the sender's balance is insufficient, the token transfer process will be reverted with the error message "Arithmetic over/underflow", which does not accurately describe the issue.
The contract is serving as the underlying entity to interact with one or more third party protocols. The scope of the audit treats third party entities as black boxes and assume their functional correctness. However, in the real world, third parties can be compromised and this may lead to lost or stolen assets. In addition, upgrades of third parties can possibly create severe impacts, such as increasing fees of third parties, migrating to new LP pools, etc. ```solidity=38 address public gaugeRewarder; ``` - The contract `GaugeV2` interacts with third party contract with `IRewarder` interface via `gaugeRewarder`. --- ```solidity=38 IRewardsDistributor public _rewards_distributor; ``` - The contract `MinterUpgradeable` interacts with third party contract with `IRewardsDistributor` interface via `_rewards_distributor`. --- ```solidity=35 address public immutable token0; ``` - The contract `Pair` interacts with third party contract with `IERC20` interface via `token0`. --- ```solidity=36 address public immutable token1; ``` - The contract `Pair` interacts with third party contract with `IERC20` interface via `token1`.
The `SafeMath` library is used unnecessarily. With Solidity compiler versions 0.8.0 or newer, arithmetic operations will automatically revert in case of integer overflow or underflow. ```solidity=27 using SafeMath for uint256; ``` - `SafeMath` library is used for `uint256` type in `GaugeV2` contract. ```solidity=134 return rewardPerTokenStored.add(lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(_totalSupply)); ``` - `SafeMath.sub` is called in `rewardPerToken` function of `GaugeV2` contract. *Note: Only a sample of 2 `SafeMath` library usage in this contract (out of 23) are shown above.* --- ```solidity=13 using SafeMath for uint256; ``` - `SafeMath` library is used for `uint256` type in `MasterChef` contract. ```solidity=118 uint256 timeLeft = lastDistributedTime.sub(block.timestamp); ``` - `SafeMath.sub` is called in `setDistributionRate` function of `MasterChef` contract. *Note: Only a sample of 2 `SafeMath` library usage in this contract (out of 21) are shown above.*
One or more logic contracts do not protect their initializers. An attacker can call the initializer and assume ownership of the logic contract, whereby he can perform privileged operations that trick unsuspecting users into believing that he is the owner of the upgradeable contract. ```solidity=15 contract MinterUpgradeable is IMinter, OwnableUpgradeable { ``` - `MinterUpgradeable` is an upgradeable contract that does not protect its initializer. ```solidity=44 function initialize( ``` - `initialize` is an unprotected initializer function. --- ```solidity=21 contract VoterV2_1 is IVoter, OwnableUpgradeable, ReentrancyGuardUpgradeable { ``` - `VoterV2_1` is an upgradeable contract that does not protect its initializer. ```solidity=69 function initialize(address __ve, address _factory, address _gauges, address _bribes) initializer public { ``` - `initialize` is an unprotected initializer function. --- ```solidity=21 contract VotingEscrow is Initializable, IERC721Upgradeable, IERC721MetadataUpgradeable, IVotesUpgradeable { ``` - `VotingEscrow` is an upgradeable contract that does not protect its initializer. ```solidity=111 function initialize( ``` - `initialize` is an unprotected initializer function. --- ```solidity=12 contract BribeFactoryV2 is OwnableUpgradeable { ``` - `BribeFactoryV2` is an upgradeable contract that does not protect its initializer. ```solidity=17 function initialize(address _voter) initializer public { ``` - `initialize` is an unprotected initializer function. --- ```solidity=13 contract GaugeFactoryV2 is IGaugeFactory, OwnableUpgradeable { ``` - `GaugeFactoryV2` is an upgradeable contract that does not protect its initializer. ```solidity=18 function initialize() initializer public { ``` - `initialize` is an unprotected initializer function. --- ```solidity=9 contract PairFactoryUpgradeable is IPairFactory, OwnableUpgradeable { ``` - `PairFactoryUpgradeable` is an upgradeable contract that does not protect its initializer. ```solidity=40 function initialize() initializer public { ``` - `initialize` is an unprotected initializer function.
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.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (20)
1,044 projects reviewed · 1,393 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