The developers of the Tokenlock Contract contracted byterocket to conduct a smart contract audit. The functionality is mainly contained in the ITokenlock.sol file, with ERC20 and DateTime related imports.
The team of byterocket reviewed and audited the above smart contracts in the course of this audit on the 3rd of May 2021.
The audit included the following services:
byterocket gained access to the code via a private Google Drive link. The shasum hash of the repository contents (which is the base for this audit on the 3rd of May 2021) is 0b4f5e2aed885ead226d47155263007f352712c3. The hash has been retrieved with the following command on Linux:
The shasum hash of the ITokenlock.sol contract itself is 7c6097221466fd7cad71122540e6d2ce8542e283
The developers of the Tokenlock Contract have updated their contracts according to our recommendations. The shasum hash of the Tokenlock.sol contract is now cefb63f50147aa43db83de42a8f7060e40f818e3.
We conducted a manual code review of the smart contracts mentioned in section (1). Two different people went through the smart contract independently and compared their results in a concluding discussion.
The contract is mostly written according to the latest standards used within the Ethereum community and the Solidity community’s best practices. The naming of variables is very logical and understandable, which results in the contract being easy to understand. The documentation of the code is lacking in some places, which could be improved.
On the code level, we found one medium severity and six no severity bugs or flaws. A further check with multiple automated reviewing tools (MythX, Slither, Manticore, and different fuzzing tools) did not find any additional bugs besides some common false positives.
The developers have since updated their smart contracts according to our recommendations, which fixed the vulnerabilities and bugs that we found. Consequently we have found no bugs or flaws in the updated code.
The initial percentage value is being used in unlockedMonths() to determine the correct amount of tokens that are being vested on a monthly basis in contrast to the initial amount. However, the initial percentage of tokens is never sent to the user. This either needs to happen in the release() function or in the calling contract (in this example case FriendsTokenlock), which is not the case.
We would recommend to either handle the token transfer of the initial amount in the calling contract or within the release() function like so (new part in bold font):
The developers have implemented a function which distributes the initial percentage of the allocated tokens to the user in lines 87 to 96. We also checked this new function and tested it and we were not able to find any problems or vulnerabilities that were introduced by this change.
Within the Solidity community, a prepended I in front of a contract name indicates an interface. However, ITokenlock is a contract, hence the name is slightly misleading and should be renamed to Tokenlock.
The developers have renamed the smart contract to Tokenlock.
The percentage decimals are inconsistent, which makes the code a bit harder to read for outsiders. E.g. in line 59 a percentage value with 2 decimal places is being used:
While in line 66 a percentage value with zero decimal places is used:
This has no implications for the functionality, as long as this is kept in mind for the deployment. However, to improve readability, we would advise to use the same schema for every percentage value if possible.
It is a common practice to write decimal-based and 1018-based values as
to greatly improve readability and to directly base it off the decimals.
The developers have changed the corresponding line according to our recommendation.
Depending on the final implementation within the calling contract, some of the functions like release() could be changed from public to external to save some gas if they are not called within the Tokenlock contract itself.
The developers have changed the corresponding function visabilities according to our recommendation.
A slightly outdated version of solidity (0.8.0) is being used. The newest version is 0.8.4. We are not aware of any bugs in 0.8.0 that might affect you, but we would still advise to use the newest version, since no bugs are known for the newest version.
The developers have changed the Solidity version according to our recommendation.
SafeMath is being imported but not used. Overflow and underflow checks are part of the Solidity compiler since version 0.8.0, which makes SafeMath obsolete in this case. We would advise to remove this import.
The developers have removed the unnecessary SafeMath import according to our recommendation.
During our code review (which was done manually and automated), we found one medium severity and six no severity bugs or flaws. Our automated systems and review tools also did not find any additional ones. The developers have since updated their smart contracts according to our recommendations, which fixed the vulnerabilities and bugs that we found. Consequently we have found no bugs or flaws in the updated code.
The protocol review and analysis did neither uncover any game-theoretical nature problems nor any other functions prone to abuse. All of the state-changing public/external functions can only be called by a token holder and will only modify their own state.
In general, we are happy with the overall quality of the code, while a bit more documentation of the code in-line could be helpful to improve its readability.
We store our public audit reports on IPFS; a peer-to-peer network called the "Inter Planetary File System". This allows us to store our reports in a distributed network instead of just a single server, so even if our website is down, every report is still available.
The IPFS Hash, a unique identifier of the report, is signed on-chain by both the client and us to prove that both sides have approved this audit report. This signing mechanism allows users to verify that neither side has faked or tampered with the audit.