Solidity – Metamask web3js ERC20 Token Transfer Error for Amounts Less Than 1

erc-20metamasksoliditytruffle-contractweb3js

I'm working on a Dapp that allows users to pay with an ERC20 token. I made a standard ERC20 token and deployed the contract to a testrpc node with truffle, and I was able to get an instance of the token contract in with truffle contract.

I can call the token transfer function with an amount that's greater than 1, and after signing the transaction with metamask, everything works properly, I get the transaction receipt, and the token balance gets deducted.

tokenContract.deployed().then(async token => {
      token.transfer(toAddress, amount, {
        from: web3.eth.accounts[0],
        gas: 4612388
      });
    });

However, when the amount parameter is less than one, I get an error in the chrome console:

errors.js:35 Uncaught (in promise) Error: Error: [ethjs-rpc] rpc error
with payload
{"id":7447005951567,"jsonrpc":"2.0","params":["0xf8b0178504a817c8008346612494e7194e2016d5454d5791d94d8a6aff6c1ead645780b844a9059cbb00000000000000000000000000d1ae0a6fc13b9ecdefa118b94cf95ac16d4ab000000000000000000000000000000000000000000000000000000000000000008602c0d0e327cba0a30d94d6e74e0e2f602c5fba9ea677f5d81d99e52acde754bbbe65b9dd295d9fa01e5d09addbdcd9f5cd311f06790406b69d92b162386789277bdde2de6d18cb13"],"method":"eth_sendRawTransaction"}
Error: VM Exception while processing transaction: revert

At first I thought that you can't send floats into truffle contract instances because solidity doesn't handle floats, but calling the amount with 1.1 works just fine. I also tried to convert the float into a BigNumber by setting the amount to new BigNumber(0.1), and the same error still persists.

Am I missing something here? Being able to send less than 1 token seems to be a very typical use case.

Best Answer

Solidity doesn't support floating-point numbers, so when you are dealing with tokens that is why you have the decimals state variable.

When you created your token, you might have specified 18 decimals, which is the most common number, but could be even 0 (in which case they wouldn't be divisible).

So, actually, one unit of your token would not be "1", but it would be 1000000000000000000 or 1 * (10 ** 18).

If you wanted to transfer less than 1 unit of your token, you would transfer 5 * (10 ** 17) -> That would be 0.5 (or half) a token.

Then, on the front end you would have to know how many decimals the token is using and divide the balance of the user by the decimals, so you get the correct amount of tokens someone holds.

For example, if I have a balance of 240000000000000000000 (240 * 10 ** 18) my real token balance would be 240 tokens.

Related Topic