NaviToken Smart Contracts Security Audit

In this report we consider the security of the NaviAddress token. Our task is to find and describe security issues in the smart contracts.


Procedure

In our audit, we consider the following crucial features of the smart contract code:

  1. Whether the code is secure.
  2. Whether the code corresponds to the documentation (including whitepaper).
  3. Whether the code meets ​best​ ​practices​ ​in​ ​efficient​ ​use​ ​of​ ​gas,​ ​code readability, etc.

We perform our audit according to the following procedure:

Automated analysis

  • we scan project’s smart contracts with our own Solidity static code analyzer SmartCheck
  • we scan project’s smart contracts with several publicly available automated Solidity analysis tools such as Remix, Oyente, Securify and Solhint
  • we manually verify (reject or confirm) all the issues found by tools

Manual audit

  • we manually analyze smart contracts for security vulnerabilities
  • we check smart contracts logic and compare it with the one described in the whitepaper
  • we run tests and check code coverage

Report

  • we reflect all the gathered information in the report

Disclaimer

The audit does not give any warranties on the security of the code. One audit can not be considered enough. We always recommend proceeding with several independent audits and a public bug bounty program to ensure the security of smart contracts. Besides, security audit is not an investment advice.



About the project

In our analysis we consider NaviToken whitepaper (version on 2017–12–28_v2) and smart contracts code (version on commit 9ab694e).

Project architecture

For the audit, we have been provided with the following set of files:

  • NaviTokem.sol inherits the Ownable and StandardToken contracts from the OpenZeppelin library of version ^1.5.0. 
    At the time of the audit up-to-date version is 1.7.0.
  • Migrations.sol

The files are the part of the truffle project. The project also contains tests, deploy scripts, and several files that are beyond the scope of the audit.

The total volume of the Solidity code that has been audited is 102 lines of code.

The project compiles successfully with truffle compile command.

The project successfully passes the tests (truffle test command, tests output).

Code logic

The NaviToken contract implements the ERC20 token logic (StandardToken contract from OpenZeppelin library of version 1.5.0) with some modifications and violations described below. The token parameters:

  • name: “NaviToken”
  • symbol: “NVT”
  • decimals: 18
  • total supply: 1,000,000,000

The NaviToken contract is ownable (Ownable from OpenZeppelin library of version 1.5.0).

The owner of the contract is the address from which the contract is deployed. When the contract is deployed, 10% of tokens are transferred to the owner’s address, while other tokens are not assigned to anyone.

The owner of the contract could call the batchAssignTokens function to add address for future defrost of tokens until the stopBatchAssign function is called by the owner. Addresses could be of three kinds: investors, reserve and team, and advisors. Each kind has different requirements of defrosting.

All investors receive tokens immediately during call of the batchAssignTokens function.

All reserve and team addresses receive tokens after calling defrostReserveAndTeamTokens function by owner after DEFROST_AFTER_MONTHS (set to 6 month) after ICO starts START_ICO_TIMESTAMP. Desired address receives its amount of tokens limited to current possible unfrosted amount equal to 1/DEFROST_FACTOR_TEAMANDADV (30 parts) part each month from defrosting time.

All Advisors receive tokens after calling the defrostAdvisorsTokens function by owner after DEFROST_AFTER_MONTHS (set to 6 month) after ICO starts START_ICO_TIMESTAMP.

The owner of the contract can call stopBatchAssign any time to stop the batchAssignTokens function.

The NaviToken smart contract does not cover process of receiving ETH or any other currency. Neither it covers token distribution according to the amount received during the tokensale.


Automated analysis

We used several publicly available automated Solidity analysis tools.

Here are the combined results of SmartCheck, Solhint, and Remix. Securify (beta-version) and Oyente have found no issues.

All the issues found by tools were manually checked (rejected or confirmed).

Cases when these issues lead to actual bugs or vulnerabilities are described in the next section.


Manual analysis

Contracts were completely manually analyzed, their logic was checked and compared with the one described in the whitepaper. Besides, the results of automated analysis were manually verified. All confirmed issues are described below.


Critical issues

Critical issues seriously endanger smart contracts security. We highly recommend fixing them.

Gas limit and loops

Consider tokens distribution via the batchAssignTokens function. If owner adds more than 120–150 addresses of the ReserveAndTeam type, or more than 200 addresses of the Advisor type, the owner will not be able to unfrost token by calling defrostReserveAndTeamTokens and defrostAdvisorsTokens respectively. This will happen due to gas limit of block. We recommend rewriting logic of defrosting or adding batch defrosting functionality.


Medium severity issues

Medium issues can influence smart contracts operation in current implementation. We highly recommend addressing them.

Modularity

It is undesirable to implement both token and non-trivial logic in one contract. If issues are found in logic after deploy and the developer has to update the contract, he/she might encounter migration problems with NVT token.

We highly recommend making the system more modular. In this particular case, we recommend implementing two separate contracts: one of them should implement the token, and the other should implement the platform logic.


Low severity issues

Low severity issues can influence smart contracts operation in future versions of code. We recommend to take them into account.

Non-release code

The contract code contains code that must be removed or changed before deployment for production use.

  • NaviToken.sol, line 22
uint256 public START_ICO_TIMESTAMP;
  • NaviToken.sol, line 54
START_ICO_TIMESTAMP = now;

We highly recommend not to use temporary code for contracts and use constructor parameters and proper deploy scripts.

Discrepancies with the whitepaper

The audit showed the discrepancy within the whitepaper. According to the whitepaper, section 5, 1,000,000,000 NVT tokens will be created during the tokensale and distributed accordingly:

“Of the Company NVT, 1,000,000,000 NVT will be issued in connection with the deployment and the development of the Platform, of which:
- 500,000,000 NVT will be allocated for distribution during sale procedures as per Section 6 below;
- 200,000,000 NVT will be allocated to Platform Growth Fund, which we will administer to incentivize use of the Platform;
- 200,000,000 NVT will be retained by the Company (*subject to NVT lock-up restrictions); and
- 100,000,000 NVT will be allocated to the Company’s management team and advisors (*subject to NVT lock-up restrictions).”

However, the contract only have distribution limitations for 100,000,000 NVT token (NaviToken.sol, line 48

uint256 amountReserve = MAX_NUM_NAVITOKENS.mul(10).div(100);

ERC20 standard violation

The audit showed some deviations from the ERC20 specifications.

  1. During the contract creation, constructor should emit the Transfer event with _from set to 0x0 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer-1)
  2. In the batchAssignTokens, defrostReserveAndTeamTokens, defrostAdvisorsTokens functions, token transfer or token minting should emit the Transfer event.
  3. The decimals constant should be uint8

We recommend minting all tokens during the contract construction and then using the transfer function of StandardToken in other places without accessing internal balances.

Pragmas version

Solidity source files indicate the versions of the compiler they can be compiled with. Example:

pragma solidity ^0.4.18; // bad: compiles w 0.4.18 and above
pragma solidity 0.4.18; // good : compiles w 0.4.18 only

We recommend following the latter example, as future compiler versions may handle certain language constructions in a way the developer did not foresee. Besides, we recommend using the latest compiler version (0.4.20 at the moment).

OpenZeppelin version

The package.json does not specify the exact version of the OpenZeppelin library (line 29):

“zeppelin-solidity”: “^1.5.0”

There are some changes in the OpenZeppelin library of version 1.7.0 (it came out at the time of the audit).

For example, the location of the ERC20 token related files has changed in version 1.6.0 (compared to version 1.5.0).

However, the 1.5.0 version is used due of the package-lock.json limitations.

We recommend specifying the exact versions of the OpenZeppelin library in package.json.


Conclusion

In this report we have considered the security of NaviToken smart contracts. We performed our audit according to the procedure described above.

The audit showed one critical issue, one medium, as well as five lower issues. We highly recommend addressing them.

This audit was performed by SmartDec, a security team specialized in static code analysis, decompilation and secure development.
Feel free to use SmartCheck, our smart contract security tool for Solidity language, and follow us on Medium. We are also available for smart contract development and auditing work.