ERC20 decimals, specifying a big number

I followed the conversation here to see if it would answer my question, but no it didn’t.

I understand that i have to use amount *= (amount ** tokenDecimal) before sending transactions with ERC20 transfer method, but when i do that i get an error.

I’m not sure what’s wrong because alot of articles have used this for examples.
Thanks for your help.

1 Like

Hi @sirphemmiey,

You can use a Big Number library.
The test below uses BN from @openzeppelin/test-helpers

SimpleToken.test.js

const { accounts, contract } = require('@openzeppelin/test-environment');

const {
  BN,           // Big Number support
  constants,    // Common constants, like the zero address and largest integers
  expectEvent,  // Assertions for emitted events
  expectRevert, // Assertions for transactions that should fail
} = require('@openzeppelin/test-helpers');

const [ creator, other ] = accounts;

const { expect } = require('chai');

const SimpleToken = contract.fromArtifact('SimpleToken'); // Loads a compiled contract

describe('SimpleToken', function () {
  it('transfer', async function () {
    const token = await SimpleToken.new({ from: creator });
    const amount = new BN("1000000000000000000000");
    await token.transfer(other, amount, {from: creator});
    expect(await token.balanceOf(other)).to.be.bignumber.equal(amount);
  });
});

SimpleToken.sol

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";

/**
 * @title SimpleToken
 * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
 * Note they can later distribute these tokens as they wish using `transfer` and other
 * `ERC20` functions.
 */
contract SimpleToken is Context, ERC20, ERC20Detailed {

    /**
     * @dev Constructor that gives _msgSender() all of existing tokens.
     */
    constructor () public ERC20Detailed("SimpleToken", "SIM", 18) {
        _mint(_msgSender(), 10000 * (10 ** uint256(decimals())));
    }
}

Hi @abcoathup, thanks for your reply.

I have tried a number of different big number libraries, the problem still persist.
This is what i’m trying to do;

let amount = withdrawObj.amount;
const TokenDecimals = await this.getDecimal(symbol); // get the decimal of a token
amount *= (10 ** TokenDecimals);
Let's say the token decimal function returns 18 obviously, and i pass2as the amount to transfer, it gives me2000000000000000000` which appears too large for the ERC20 transfer function to process. I have tried the big number library, OZ test helper, bing interger, ethers, web3 etc all to no avail.

Thanks for your help once again.

1 Like

Hi @sirphemmiey,

We need to use the big number libraries multiply and power functions to do the calculation as the number is too big for JavaScript.

    const tokenbits = (new BN(10)).pow(decimals); 
    const amount = (new BN(100)).mul(tokenbits); 

See the following test for the SimpleToken contract above:

SimpleToken.test.js

const { accounts, contract } = require('@openzeppelin/test-environment');

const {
  BN,           // Big Number support
  constants,    // Common constants, like the zero address and largest integers
  expectEvent,  // Assertions for emitted events
  expectRevert, // Assertions for transactions that should fail
} = require('@openzeppelin/test-helpers');

const [ creator, other ] = accounts;

const { expect } = require('chai');

const SimpleToken = contract.fromArtifact('SimpleToken'); // Loads a compiled contract

describe('SimpleToken', function () {
  it('transfer', async function () {
    const token = await SimpleToken.new({ from: creator });
    const decimals = await token.decimals.call();
    const tokenbits = (new BN(10)).pow(decimals);
    const amount = (new BN(100)).mul(tokenbits);

    console.log(`Amount: ${amount}`);

    await token.transfer(other, amount, {from: creator});
    expect(await token.balanceOf(other)).to.be.bignumber.equal(amount);
  });
});

Thanks for your reply.
It still displays the same error “(arg=”_value", coderType=“uint256”, value=10000000000000000)"
But when i changed the amount value after the bigNumber conversions to amount.toString(), the transaction went successfully.
Could there be any issue with this way at the long run?

1 Like

Hi @sirphemmiey,

I assume it depends on the JavaScript library that you use to handle big numbers.
Just ensure that you have appropriate testing that you are transferring the required amount of tokens.