As we continuously strive for excellence, we ran a fresh independent sanity-check audit of our existing ICO smart-contract last week and discovered the following three critical potential flaws that could be abused. Accordingly, we are moving our ICO from a smart-contract managed one, to a traditional model where we’ll deploy a new smart-contract for token distribution only and not for asset escrow.

Critical 1 / distributeSupply breaks token decentralization

The token contract owner is always able to destroy user tokens by using distributeSupply(address,0)

This kind of power from the contract owner is not expected in decentralized tokens.

Since a two-step ownership replacement is used, it is not possible to deactivate this function in a standard way (setting ownership to an address without known private key like 0x0). Nonetheless, there is a very specific technical trick that can be used to generate addresses for only one transaction:

  1. Generate the transaction to call acceptOwnership() with nonce=0
  2. Do an ecrecover for the transaction data, but using zeros for the signature. The ecrecover result will be the unique signature address for this transaction addrUnique
  3. With the current owner, generate a transferOwnership (addrUnique) call
  4. Top-up the addrUnique address and send the previous generated transaction in 1


Critical 2 / distributeSupply is not etherscan-safe

distributeSupply does not generate a Transfer event, so Etherscan is not able to detect and update the token holders. A realistic visualization in Etherscan today is a must because it is a proof for token users.

(L) Current token, with two distributeSupply transactions; (R) Modified token, that generates the Transfer event, generating two distributeSupply

Since this concept of anonymous holders is used, it is complicated to generate the Transfer event, because the EIP20 specification does not have the concept of anonymous holders. It does support the concept of minting (Transfer(0x0,<destination>, <amount>)), but minting should increase the total supply, which does not happen.

Critical 3 / tokenAmount does not compute the token amount properly

The tokenAmount function does not properly compute the token amount values:

function tokenAmount(uint value, uint bonusAllocation)
public constant returns (uint countedAmount, uint givenAmount) {
countedAmount = value / tokenPrice * (10**18);
givenAmount = countedAmount * bonusAllocation / 100;

The precedence of operators makes the expression compiled as countedAmount = (value / tokenPrice) * (10**18). So all the remaining amounts of < tokenPrice are trimmed off the value for the calculation.

With the current values, it means that by sending 1.001 ethers in round 1, 125.000000000000000000 tokens will be assigned; while the correct value should be 125.125000000000000000 tokens.

Note that in this wrong calculation, the error is propagated to the token transfer amount and to the newSupply variable.

In the light of the aforementioned, our culture of maximum transparency and our history of sheer dislike of bugs in software, we have decided to;

  1. Gracefully shutdown the ongoing token distribution and terminate the current smart-contract, effective immediately;
  2. Deploy a new robust smart-contract that corrects the aforementioned flaws;
  3. Re-issue newly minted Multicoins (MTC) to all existing contributors with a 30% bonus;
  4. Re-start the Multiven ICO crowdsale on July 1, 2018.

Multiven would like to thank Senior Security and Ethereum developer, Adrià Massanet of codecontext for helping to identify these issues and the AmaZix team for their support.

We thank you all for your support.

Kind regards,

Sacha Ott, CTO, Multiven ICO.


Photo credits: Multiven