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.
In our audit, we consider the following crucial features of the smart contract code:
- Whether the code is secure.
- Whether the code corresponds to the documentation (including whitepaper).
- Whether the code meets best practices in efficient use of gas, code readability, etc.
We perform our audit according to the following procedure:
- 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
- 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
- we reflect all the gathered information in the report
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.
We have scanned NaviToken smart contracts for commonly known and more specific vulnerabilities. Here are some of the commonly known vulnerabilities that we considered (th full list includes them but is not limited to them):
- Timestamp Dependence
- Gas Limit and Loops
- DoS with (Unexpected) Throw
- DOS with (Unexpected) revert
- DoS with Block Gas Limit
- Transaction-Ordering Dependence
- Use of tx.origin
- Exception disorder
- Gasless send
- Balance equality
- Byte array
- Transfer forwards all gas
- ERC20 API violation
- Malicious libraries
- Compiler version not fixed
- Redundant fallback function
- Send instead of transfer
- Style guide violation
- Unchecked external call
- Unchecked math
- Unsafe type inference
- Implicit visibility level
- Address hardcoded
- Using delete for arrays
- Integer overflow/underflow
- Locked money
- Private modifier
- Revert/require functions
- Using var
- Using blockhash
- Using SHA3
- Using suicide
- Using throw
- Using inline assembly
About the project
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.
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).
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 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
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
The owner of the contract can call
stopBatchAssign any time to stop the
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.
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.
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 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
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.
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.
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.
- During the contract creation, constructor should emit the
_fromset to 0x0 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer-1)
- In the
defrostAdvisorsTokensfunctions, token transfer or token minting should emit the
decimalsconstant should be
We recommend minting all tokens during the contract construction and then using the
transfer function of StandardToken in other places without accessing internal balances.
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).
The package.json does not specify the exact version of the OpenZeppelin library (line 29):
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.
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.