Helper Coin - Audit

CertiKFiles named in the report

CertiK reviewed Helper Coin (Helper Coin - Audit) on 12 Jan 2023: 16 findings, 0 critical; 12 marked fixed, 4 open.

No open critical findings
Open the reportOpen Helper Coin’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings16

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

SeverityOpenAcknowledgedFixed
Critical000
High201
Medium104
Low107
HighFlawed Reward Distribution MechanismFixed

Function `rewardPrimeHolders()` is used to distribute `prime_holders_balance` amount of tokens to token holders based on their holding time. Since the distribution does nothing with the holders' balances, the more accounts a user controls, the larger part of the total rewards he can get. This distribution mechanism would introduce unfair competition, and too many accounts would make the function costly.

MediumIncorrect Transfer EventFixed

The function `rewardUsersDaily()` mints tokens as rewards for token holders. However, it emits incorrect events indicating that the tokens are transferred from `prime_holders_address` to holders. ```solidity=774 emit Transfer(prime_holders_address, _holdersArray[i], _daily_reward_amount); ```

MediumInsufficient Check for New HolderFixed

```solidity=270 if ( holdersMap[to].start_hold_timestamp == 0 && holdersMap[to].last_daily_reward_timestamp == 0 ) { holdersArray.push(to); holdersMap[to].start_hold_timestamp = block_timestamp; holdersMap[to].last_daily_reward_timestamp = block_timestamp; ``` The token recipient may be added to `holdersArray` and `holdersMap` even if the transfer amount is zero.

MediumInvalid Restriction on Withdrawing Tokens from PrFixed

```solidity=252 modifier onlyWithdrawer( WithdrawInfo storage _withdrawInfo, uint256 _withdrawAmount, address _fundAddress ) { uint256 curFundBalance = _balances[_fundAddress]; if (msg.sender != _withdrawInfo.WithdrawerAddress) { revert NotAuthorised(); } if (_withdrawInfo.lastWithdrawTime + 30 days > block.timestamp) { revert RequiredTimeNotElapsed(); } if (_withdrawAmount > (curFundBalance * _withdrawInfo.allowedPercentage) / denominator) { revert AmountNotAuthorised(); } _withdrawInfo.lastWithdrawTime = block.timestamp; _; } ``` ```solidity=955 function withdrawDevelopmentBalance(address _to, uint256 _amount) external onlyWithdrawer(developmentWithdrawInfo, _amount, development_address) { _withdrawBalance(development_address, _to, _amount); } /** * @dev withdraw Marketing balance with amount equal to _amount, recipient is the _to address. */ function withdrawMarketingBalance(address _to, uint256 _amount) external onlyWithdrawer(marketingWithdrawInfo, _amount, marketing_address) { _withdrawBalance(marketing_address, _to, _amount); } /** * @dev withdraw LegalAndBackup balance with amount equal to _amount, recipient is the _to address. */ function withdrawLegalAndBackupBalance(address _to, uint256 _amount) external onlyWithdrawer(legalAndBackupWithdrawInfo, _amount, legal_and_backup_address) { _withdrawBalance(legal_and_backup_address, _to, _amount); } ``` The modifier `onlyWithdrawer` is used to restrict three privileged addresses `development_address`, `legal_and_backup_address`, and `marketing_address` from arbitrarily transferring tokens. The intended design is that only the corresponding withdrawers can withdraw their tokens. However, The three accounts can directly call transfer functions like `transfer()` in the parent contract `ERC20` to transfer tokens.

MediumNo Upper Limits for FeesFixed

There are no upper limits restricting parameters of `setBurnFee()` and `setTransferFee()`, potentially enabling up to 100% of fees on transactions.

LowInconsistency between Comment and CodeFixed

```solidity=1014 /** * @dev helper withdraw function for the above four functions. */ function _withdrawBalance( address _from, address _to, uint256 _amount ) private { _transfer(_from, _to, _amount); _isExemptFromFee[_to] = true; _isExemptFromReward[_to] = true; } ``` The comment says "helper withdraw function for the above four functions", but only three functions call the private function.

LowMissing Emit EventsFixed

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

LowMissing Input ValidationFixed

```solidity=590 reward_array_info = RewardArrayInfo( _arrayData[0], _arrayData[1], _arrayData[2], _arrayData[3], _arrayData[4], _arrayData[5] ); length_info = LengthInfo( _arrayLengthData[0], _arrayLengthData[1], _arrayLengthData[2], _arrayLengthData[3], _arrayLengthData[4], _arrayLengthData[5] ); ``` Function `rewardPrimeHoldersWithInput()` does not check that the length of each array in `reward_array_info` is equal to the corresponding element in `length_info`, which may lead to incorrect reward distribution.

LowMissing Multiplier `days`Fixed

```solidity=303 holdTime >= _slotDaysInfo.slot2Days * 1 ``` The statement misses the multiplier `days` and should be `holdTime >= _slotDaysInfo.slot2Days * 1 days`.

LowMissing Zero Address ValidationFixed

Addresses should be checked before assignment or external call to make sure they are not zero addresses. ```solidity=155 development_address = _development_address; ``` - `_development_address` is not zero-checked before being used. --- ```solidity=161 management_address = _management_address; ``` - `_management_address` is not zero-checked before being used. --- ```solidity=167 marketing_address = _marketing_address; ``` - `_marketing_address` is not zero-checked before being used. --- ```solidity=173 prime_holders_address = _prime_holders_address; ``` - `_prime_holders_address` is not zero-checked before being used. --- ```solidity=179 core_holders_address = _core_holders_address; ``` - `_core_holders_address` is not zero-checked before being used.

Show 2 more
LowRedundant CodeFixed

```solidity=295 if (holdTime < _slotDaysInfo.slot1Days * 1 days) { sell_fee = (amount * _slotDaysFeeInfo.feeBeforeDaysSlot1) / denominator; } else if ( holdTime >= _slotDaysInfo.slot1Days * 1 days && holdTime < _slotDaysInfo.slot2Days * 1 days ) ``` 1. In the function `_transfer()`, the operand `holdTime >= _slotDaysInfo.slot1Days * 1 days` is always true because it is under the condition `else if`. The code at lines 302 - 320, 422 - 462, and 1021 - 1061 share the same issue. 2. In the internal functions `_distribute()` and `_withdrawBalance()`, the modifier `onlyCaller` is redundant because their callers already have the same modifier. 3. In the function `filterUsers()`, the variable `reward_info` is not used.

LowRepeated StatementsFixed

```solidity=1140 function _withdrawBalance( address _from, address _to, uint256 _amount ) private onlyCaller { _transfer(_from, _to, _amount); _isExemptFromFee[_to] = true; _isExemptFromFee[_to] = true; } ``` The statements `_isExemptFromFee[_to] = true;` at lines 1146 and 1147 are repeated.

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

  • contracts/IERC20Metadata.sol
  • contracts/HELPERCOIN.sol
  • contracts/IERC20.sol
  • contracts/ERC20.sol
  • contracts/Ownable.sol
  • contracts/Context.sol

Part of Helper Coin’s security record

Helper Coin
Audits1 audit by 1 firmLast audit Jan 2023, by CertiK.
Critical findingsNo open critical findingsIn 1 report.
Open Helper Coin’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