CertiK reviewed Onyx Protocol (Chain Staking) on 28 Mar 2022: 14 findings, 0 critical; 7 marked fixed, 7 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 | 2 | 0 | 2 |
| Medium | 1 | 0 | 1 |
| Low | 4 | 0 | 4 |
```solidity=36 function grantDAO(address user, uint256 amount) public onlyOwner { rewardToken.safeTransfer(user, amount); emit GrantDAO(user, amount); } ``` The role `_owner` can send arbitrary amount of reward token to any address through the function `grantDAO()`. If the private key of the owner is compromised, reward token can be completely drained from the contract, and users might not be able to call the `claimReward()` function due to insufficient balance.
In the contract `CHNReward` the role `_owner` has authority over the function `changeStakingAddress()`. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and change the address of staking contract. In the contract `CHNStaking` the role `_owner` has authority over the functions shown in the diagram below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and manipulate critical functions. 
If the token being deposited is a deflationary token implementing the ERC20 standard, the input `_amount` may not be equal to the received amount due to the charged transaction fee. In this case, if a user stakes `_amount` deflationary tokens (with a non-zero transaction fee) into a pool, fewer than `_amount` tokens actually arrive in the contract. The contract calculates the amount the user is able to withdraw to be `user.amount = user.amount.add(_amount).sub(depositFee);`, which could be larger than the amount actually received. The user's rewards calculated for the deposit also use the entered `_amount`, not the actual amount received, which can lead to inconsistencies.
There should always be events emitted in the sensitive functions that are controlled by centralization roles.
Contract `CHNStaking` should inherit from `CHNStakingInterface` in`CHNReward.sol`
```solidity=46 function initialize( IERC20 _rewardToken, uint256 _rewardPerBlock, uint256 _startBlock, uint256 _bonusEndBlock, uint256 _multiplier, address _rewardVault ) public initializer { __Ownable_init(); rewardToken = _rewardToken; rewardPerBlock = _rewardPerBlock; startBlock = _startBlock; bonusEndBlock = _bonusEndBlock; BONUS_MULTIPLIER = _multiplier; rewardVault = _rewardVault; } ``` Function `initialize()` lacks input validation: - Zero-address checks on `rewardVault` and `rewardToken` - Upper boundaries on `rewardPerBlock` and `BONUS_MULTIPLIER` - Lower boundaries on `startBlock` and `bonusEndBlock`
The return values of functions `safeTransfer()` and `safeTransferFrom()` are not handled.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (3)
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