Crowdsale buyTokens fails with error 'SafeERC20: low-level call failed'

Hello
In Remix IDE

  1. I deployed simple token (Simple ERC20 Crowdsale)
  2. I deployed crowdsale token

Everything was working yesterday. I was able to send ether and receive tokens.
Today I created a new test token and contract exactly like a few days ago and I keep getting the same error (starting today).
Can someone explain to me why it doesn’t work today?

1 Like

Ok. I did not find a solution but thanks to the tests I can see that it depends on the version of the solidity language in which we created the token.

EXAMPLE NO 1
I created and deployed token with this code:

Token1.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.2;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/docs-v3.x/contracts/token/ERC20/ERC20.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.
* Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/examples/SimpleToken.sol
  */
 contract SimpleToken is ERC20 {
/**
 * @dev Constructor that gives msg.sender all of existing tokens.
 */
constructor(
    string memory name,
    string memory symbol,
    uint256 initialSupply
) public ERC20(name, symbol) {
    _mint(msg.sender, initialSupply);
}
}

Contract.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) {}
}

Token1.sol and Contract.sol working together.
You can test it. Just send some ether and You will receive tokens.

EXAMPLE NO 2 - token has 8 decimal
I created and deployed token with this code:

Token2.sol

// 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);
}
}

Contract.sol (the same as above)

// 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) {}
}

Token2.sol and Contract.sol NOT WORKING together.
You can test it. Just send some ether and You will NOT receive tokens.

EXAMPLE NO 3 - token has 18 decimal
I created and deployed token with this code:

Token3.sol

// 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);
}
}

Contract.sol (the same as above)

// 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) {}
}

Token3.sol and Contract.sol NOT WORKING together.
You can test it. Just send some ether and You will NOT receive tokens.

Anyone know what is the reason?

With 8 decimal token we have

With 18 decimal token we have

1 Like

Hi @Tomy_R,

Welcome to the community :wave:

I suggest having a look at the following Simple ERC20 Crowdsale.

:warning: Note: You should only use code published in an official release of OpenZeppelin Contracts, the latest release of 2.x is 2.5.1. When importing via GitHub on Remix you can specify the release tag, (otherwise you will get the latest code in the master branch).

Generally a low-level call failed suggests you haven’t transferred enough tokens to the crowdsale. I would recommend checking the balance of tokens that the crowdsale has.

Decimals are just used for display purposes, so I generally wouldn’t expect them to cause issues when changing this value. https://docs.openzeppelin.com/contracts/2.x/erc20#a-note-on-decimals

You can also check your rate calculation: https://docs.openzeppelin.com/contracts/2.x/crowdsales#crowdsale-rate