Fail with error 'SafeERC20: low-level call failed' (only with other decimals than 18)

Hello!
For my tests I created 3 tokens ( SimpleToken.sol - from this link: https://forum.openzeppelin.com/t/simple-erc20-crowdsale/4863/1v)
They differ only with decimal places.

  1. First token has 8 decimals - not working with SimpleCrowdsale.sol
    Token: https://ropsten.etherscan.io/token/0x67ca631789d7535fe9c68868d7d124377559e6ee
    Contract: https://ropsten.etherscan.io/address/0x95326ebc1cd9429d53fad96fa338b1da48c7072e

You can test it. Just send some ether and You will NOT receive tokens.

        // SPDX-License-Identifier: MIT
    pragma solidity ^0.5.5;
    
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/docs-v2.x/contracts/token/ERC20/ERC20.sol";
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/docs-v2.x/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 Token is Context, ERC20, ERC20Detailed {
    /**
     * @dev Constructor that gives _msgSender() all of existing tokens.
     */
    constructor(
        string memory name,
        string memory symbol,
        uint256 initialSupply
    ) public ERC20Detailed(name, symbol, 8) {
        _mint(_msgSender(), initialSupply);
    }
    }
  1. Second token has 12 decimals - not working with SimpleCrowdsale.sol
    Token: https://ropsten.etherscan.io/token/0xd75f93a9edddce751f0e028b69fc242b87322a89
    Contract: https://ropsten.etherscan.io/address/0xe0f3a78268d438cb0aae16c851581914991f39a4

You can test it. Just send some ether and You will NOT receive tokens.

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.5.5;
    
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/docs-v2.x/contracts/token/ERC20/ERC20.sol";
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/docs-v2.x/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 Token is Context, ERC20, ERC20Detailed {
    /**
     * @dev Constructor that gives _msgSender() all of existing tokens.
     */
    constructor(
        string memory name,
        string memory symbol,
        uint256 initialSupply
    ) public ERC20Detailed(name, symbol, 12) {
        _mint(_msgSender(), initialSupply);
    }
    }
  1. Third token has 18 decimals - working with SimpleCrowdsale.sol
    Token: https://ropsten.etherscan.io/token/0xdfd2a35bcd73a2aa1652f90c0e8844f89c3946c3
    Contract: https://ropsten.etherscan.io/address/0xea8deb636ffae28a819f2896ba6f93cc93fdb613

You can test it. Just send some ether and You will receive tokens.

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.5.5;
    
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/docs-v2.x/contracts/token/ERC20/ERC20.sol";
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/docs-v2.x/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 Token is Context, ERC20, ERC20Detailed {
    /**
     * @dev Constructor that gives _msgSender() all of existing tokens.
     */
    constructor(
        string memory name,
        string memory symbol,
        uint256 initialSupply
    ) public ERC20Detailed(name, symbol, 18) {
        _mint(_msgSender(), initialSupply);
    }
    }

SimpleCrowdsale.sol

    // contracts/SimpleCrowdsale.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.5.5;
    
    import  "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/crowdsale/Crowdsale.sol";
    
    /**
     * @title SimpleCrowdsale
     * @dev This is an example of a fully fledged crowdsale.
     */
    contract SimpleCrowdsale is Crowdsale {
        constructor(
            uint256 rate,
            address payable wallet,
            IERC20 token
        ) public Crowdsale(rate, wallet, token) {}
    }

Earlier solutions on the forum suggested that the problem was not enough tokens on the contract.
I have tested it and it is not a problem.
I have a lot of test tokens on each contract, but only one works - with 18 decimals, why?

For my tests i used SimpleToken.sol and SimpleCrowdsale.sol from this link: Simple ERC20 Crowdsale

For my test I used remix.ethereum.org

Please help!

1 Like

Yeah, you are right, this is due to decimals. I think this crowdsale contract is only for tokens that decimals is 18.
It seems like your rate is 2000, and when you try to but tokens, it will calculate by

// calculate token amount to be created
uint256 tokens = _getTokenAmount(weiAmount) =>  weiAmount.mul(_rate)

so when you use 1 eth to buy token, the final token amount is: 10**18 * 2000(rate),

  • for token that decimals is 18, it means 1 eth can buy 2000 token,
  • for token that decimals is 12, it means 1 eth can buy 2000*10**6 token,
  • for token that decimals is 6, it means 1 eth can buy 2000*10**12 token,

So, for SimpleCrowdsale to sell token has 12 decimals, when you want to buy with 1 eth, the crowdsale contract should have 2000*10**6 token rather than current 10**6 token.

1 Like

Yes, You have right
it’s strange, really but I understand that it could work that way
I sent 0.00000001 Ether to contract with 8 decimals and I finally received 200,000 tokens!

1 Like
  1. What about 8 decimals?
    It will be: 2000*10**8 ??
  2. How to change this simple contract and where put this value?
1 Like

It’s strange. Why I can’t deploy contract with value for example: 0.0002 ??

No, such as above, when you use 0.00000001 eth to buy token, it should be

0.00000001 * 10**18(eth) * 2000(rate) / 10**8(decimals) = 200,000

Which value do you mean? 0.00000001 Ether? You can send eth to this contract directly or call buyTokens with eth value.

Actually, the solidity does not support such number 0.002, if you want to set some value as 0.002, you can do like this:

NUMBER * 0.002 => NUMBER * 2 / 1000

That is you should do the multiplication first, then the division.

1 Like

Hi @Tomy_R,

Please see the documentation on Crowdsale Rate: https://docs.openzeppelin.com/contracts/2.x/crowdsales#crowdsale-rate

I am trying edit this simple crowdsale contract for 8 decimals token.
Therefore how to edit code of this contract to make possible buy 2000 tokens for just one ETH?
How can I do this if I cant put lower rate in deploy window?

Currently, the crowdsale uses the following way to calculate how many token can be bought:

    /**
     * @dev Override to extend the way in which ether is converted to tokens.
     * @param weiAmount Value in wei to be converted into tokens
     * @return Number of tokens that can be purchased with the specified _weiAmount
     */
    function _getTokenAmount(uint256 weiAmount) internal view returns (uint256) {
        return weiAmount.mul(_rate);
    }

so, in order to make compatible with different decimals, maybe the extra action should be actualTokenAmount = (_getTokenAmount()).div(18-_token.decimals()), but this is only for token's decimals is less than 18.

lower rate? Just like I have mentioned above, you should do the multiplication first, then the division.

1 Like