Skip links
cryptosolartech logo

Cryptosolartech Security Audit

Coinfabrik’s smart contract audit’s team was asked to audit the contracts for the Cryptosolartech sale. Firstly, we will provide a summary of our discoveries and secondly, we will show the details of our findings.

Summary

The contracts audited are from the Cryptosolartech repository. The audit is based on the commit 4a04863c1cf6ef55d89a3ed63c3e0de863efe4da and updated to reflect the changes made on commit bd4277db249d9550cea439f9044c54882c379d5d.

The audited contracts are:

  • contracts/Burnable.sol: Burnable token interface.
  • contracts/Crowdsale.sol: Deployable contract for the crowdsale.
  • contracts/CrowdsaleToken.sol: Deployable contract for the token.
  • contracts/DeploymentInfo.sol: View functions for additional information.
  • contracts/EIP20Token.sol: EIP20 Token interface.
  • contracts/GenericCrowdsale.sol: Abstract base contract for token sales.
  • contracts/Haltable.sol: Inheritable contract with modifiers for halting capabilities.
  • contracts/LostAndFoundToken.sol: Inheritable contract for securely retrieving mistakenly sent tokens.
  • contracts/Mintable.sol: Mintable token interface.
  • contracts/MintableToken.sol: Inheritable contract for minting capabilities.
  • contracts/Ownable.sol: Inheritable contract with modifiers for privilege calls.
  • contracts/ReleasableToken.sol: Inheritable contract
  • contracts/SafeMath.sol: Overflow checked arithmetic functions
  • contracts/StandardToken.sol: Standard ERC20 token implementation.
  • contracts/TokenTranchePricing.sol: Tranche pricing capabilities for the crowdsale.
  • contracts/UpgradeableToken.sol: Inheritable contract for upgrading capabilities.
  • contracts/UpgradeAgent.sol: Inheritable contract for the agent executing the upgrade.

The following analyses were performed:

  • Misuse of the different call methods: call.value(), send() and transfer().
  • Integer rounding errors, overflow, underflow and related usage of SafeMath functions.
  • Old compiler version pragmas.
  • Race conditions such as reentrancy attacks or front-running.
  • Misuse of block timestamps, assuming anything other than them being strictly increasing.
  • Contract softlocking attacks (DoS).
  • Potential gas cost of functions being over the gas limit.
  • Missing function qualifiers and their misuse.
  • Fallback functions with a higher gas cost than the one a transfer or send call allows.
  • Fraudulent or erroneous code.
  • Code and contract interaction complexity.
  • Wrong or missing error handling.
  • Overuse of transfers in a single transaction instead of using withdrawal patterns.
  • Insufficient analysis of function input requirements.

Detailed findings

Minor severity

Unintended multiplication by 0 in calculateTokenAmount()

It is possible for a user to buy tokens but receive nothing, as milieurs_per_eth isn’t updated in the constructor, which means that transfer will call calculateTokenAmount() and multiply it by 0 (being the value of tokensPerEth). The user will have sent money to the contract but received no tokens.

function calculateTokenAmount(uint weiAmount, address) internal view returns (uint     weiAllowed, uint tokenAmount)
 {
   uint tokensPerEth = getCurrentPrice(tokensSold).mul(milieurs_per_eth).div(1000);
   //...
 }

This could easily be fixed by adding the following to the function:

function calculateTokenAmount(uint weiAmount, address) internal view returns (uint     weiAllowed, uint tokenAmount)
 {
   require(milieurs_per_eth != 0);
   uint tokensPerEth = getCurrentPrice(tokensSold).mul(milieurs_per_eth).div(1000);
   //...
 }

This situation can happen only if function updateEursPerEth wasn’t called because function updateEursPerEth checks if the price is zero.

Finalize does not call burn() function

At Crowdsale.sol, in the finalize function, unsold tokens aren’t burned:

function finalize() public inState(State.Success) onlyOwner stopInEmergency
{
  //Tokens sold + bounties represent 75% of the total, the other 25% goes ti the multisig to the partners and to regulate market
  uint sold = tokensSold.add(  initial_tokens);
  uint toShare = sold.mul(25).div(75).mul(10**uint(token.decimals()));
  token.setMintAgent(address(this), true);
  token.mint(multisigWallet, toShare);
  token.setMintAgent(address(this), false);
  token.releaseTokenTransfer();
  super.finalize();
}

This means that the CrowdsaleToken contract stores the address of the Crowdsale as if it had tokens. Since they are not going to be used, it is best to simply dispose of them.

This issue in the commit 4a04863c1cf6ef55d89a3ed63c3e0de863efe4da.

Enhancements

Use of updated pragmas

In later commits, the contracts use the following pragma:

pragma solidity ^0.4.19;

We recommend updating compiler directives so that newer compiler versions are used, as the current solidity version is 0.4.21. In the same vein, events are now emitted using the emit keyword, which results in more code legibility. This also helps to differentiate between function calls and event emission.

Conclusion 

The contracts followed recommended practices and were acceptably documented. Common attacks like the EIP 20 approve/transferFrom attack were taken into account. Two errors were found for either undefined or unaccounted behavior. One was properly fixed. The other was addressed calling function updateEursPerEth during the Smart Contract deployment so the price can never be zero.

Do you want to know what is Coinfabrik Auditing Process?

Check our A-Z Smart Contract Audit Guide or you could request a quote for your project.