CertiK reviewed Chiliz on 23 Dec 2022: 19 findings, 1 critical; 10 marked fixed, 9 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 | 1 |
| High | 3 | 0 | 1 |
| Medium | 1 | 0 | 6 |
| Low | 5 | 0 | 2 |
The `_stakingContract.getDelegatorFee()` returns the amount of delegator rewards plus undelegated tokens in `_stakingContract`. The `validatorPool.pendingUnstake` is the total amount of undelegated tokens, which is the sum of undelegated tokens in `_stakingContract` and withdrawn undelegated tokens in current `StakingPool`. The unclaimed rewards should be `_stakingContract.getDelegatorFee()` minus undelegated tokens in `_stakingContract`, NOT `validatorPool.pendingUnstake`. The incorrect calculation may cause integer underflow and revert. The incorrect calculation is used by most functions, including `stake()`, `unstake()` and `claim()`, which means the contract may become totally useless and users' funds are locked and lost forever.
All upgradeable contracts in an inheritance chain must follow the same rules for writing upgradeable contracts. See https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#use-upgradeable-libraries. Otherwise it will malfunction and may be vulnerable and completely stop working.
A banned deployer should not be able to perform any action. The code does not check if the specified deployer is banned. Thus a banned deployer can register contracts which may be malicious.
The Governance indirectly inherits from the `EIP712` contract through the `Governor` contract. The immutables in `EIP712` contract will not work after upgrade because the runtime upgrade evm hook does not run deployment code during upgrade, so all the immutables are not initialized through constructor and are all zero values. See https://docs.soliditylang.org/en/latest/contracts.html#immutable. Thus the functions `castVoteBySig()/castVoteWithReasonAndParamsBySig()` in `Governor` will stop working after upgrade. See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.6.0/contracts/utils/cryptography/draft-EIP712.sol
The function `_stakingContract.getValidators()` returns current validator array, which is used as the parameter of subsequent call of `_stakingContract.getValidatorByOwner()`, which actually expects owners of validators as the parameter, not validators. Thus the function `activateProposerRegistry()` will malfunction or even always revert.
The function `_getVotes()` checks only actived validators' power. However, the function `_votingSupply()` lacks a check on whether the validator is active. This results in an inaccurate minimum number of votes required for a proposal to be successful.
In the modifier `onlyProposer`, only the active validator owner can be a proposer when the registry is not activated. In the function `activateProposerRegistry()`, governance can add the validator owner to the proposer list, but the function does not call the function `isValidatorActive()` to check that the owner's validator is active.
The functions `_validatorVotingPowerAt()/_validatorOwnerVotingPowerAt()` are used to get validator/owner voting power at a specific block number which may be in the past. But the function `_stakingContract.isValidatorActive()` only checks if a validator is active currently. It is possible that a validator is active at present but is inactive at that specific past block, which makes `_validatorVotingPowerAt()/_validatorOwnerVotingPowerAt()` return incorrect values.
Addresses should be checked before assignment or external call to make sure they are not zero addresses. ```solidity=19 _evmHookAddress = evmHookAddress; ``` - `evmHookAddress` is not zero-checked before being used.
It is not recommended to use Solidity's `transfer()` and `send()` functions for transferring Ether, since some contracts may not be able to receive the funds. Those functions forward only a fixed amount of gas (2300 specifically) and the receiving contracts may run out of gas before finishing the transfer. Also, EVM instructions' gas costs may increase in the future. Thus, some contracts that can receive now may stop working in the future due to the gas limitation. ```solidity=179 payable(address(msg.sender)).transfer(amount); ``` - `StakingPool.claim` uses `transfer()`. --- ```solidity=104 payableTreasury.transfer(amountToPay); ``` - `SystemReward._claimSystemFee` uses `transfer()`.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (9)
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