openzeppelin-contracts: Token transfer fail

I have your latest version of contracts and almost same example like yours in the Github https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/examples/SampleCrowdsale.sol - I use Ganache for testing on MAC os. And the contract work only when I comment the line

function _deliverTokens(address _beneficiary, uint256 _tokenAmount) internal {
    //token.transfer(_beneficiary, _tokenAmount);
  }

if this is not commented I got a runtime error and revert.

My simple code is as follow:

TOKEN

pragma solidity ^0.4.18;

import 'zeppelin-solidity/contracts/token/ERC20/MintableToken.sol';

/**
 * The LeonardianToken contract does this and that...
 */
contract LeonardianToken is MintableToken {

	uint256 public constant INITIAL_SUPPLY = 10000;

	
	string public constant name = "Leonardian"; // solium-disable-line uppercase
	string public constant symbol = "LEON"; // solium-disable-line uppercase
	uint8 public constant decimals = 18; // solium-disable-line uppercase
}

CONTRACT:

pragma solidity ^0.4.18;

import 'zeppelin-solidity/contracts/crowdsale/validation/TimedCrowdsale.sol';
import "zeppelin-solidity/contracts/crowdsale/Crowdsale.sol";
import './LeonardianToken.sol';

contract LeonardianCrowdsale is Crowdsale {

	function LeonardianCrowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, address _wallet, MintableToken _token) public 
	Crowdsale(_rate, _wallet, _token)
	// TimedCrowdsale(_startTime, _endTime)
	{
		
	}
}

MIGRATION (without any errors):

var LeonardianCrowdsale = artifacts.require("./LeonardianCrowdsale.sol");
var LeonardianToken = artifacts.require("./LeonardianToken.sol");

module.exports = function(deployer) {

  deployer.deploy(LeonardianToken).then(function () {

    const startTime = Math.round((new Date(Date.now() - 86400000).getTime())/1000); // Yesterday
    const endTime = Math.round((new Date().getTime() + (86400000 * 20))/1000); // Today + 20 days
    var exchangeRate = 1; // 1 LEON = 0.0025 ETH or 1 ETH = 400 LEON

    deployer.deploy(LeonardianCrowdsale, 
        startTime, 
        endTime,
        exchangeRate, 
        "0x627306090abaB3A6e1400e9345bC60c78a8BEf57", // Replace this wallet address with the last one (10th account) from Ganache UI. This will be treated as the beneficiary address. 
        LeonardianToken.address
      );
  });

};

Can you help me what, I`m doing wrong?

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 17 (5 by maintainers)

Most upvoted comments

The main issue was that by tying the token creation to the crowdsales:

  1. it’s less extensible
  2. it creates larger gas usage, which was approaching the gas limit

and by separating the concerns we’re now much more composable (the crowdsale only cares about how to issue the token; either by minting, transferring, or some other custom method) and the token can be anything that conforms to the correct interface.

I got help in Open Zeppelin slack! The problem was with crowdsale contract. I updated my github repo.

pragma solidity ^0.4.18;

import "zeppelin-solidity/contracts/crowdsale/validation/CappedCrowdsale.sol";
import "zeppelin-solidity/contracts/crowdsale/emission/MintedCrowdsale.sol";

import "./TestToken.sol";

contract TestTokenCrowdsale is MintedCrowdsale {

  ERC20 _token = new TestToken();
  
  function TestTokenCrowdsale(uint256 _rate, address _wallet) public
    Crowdsale(_rate, _wallet, _token) {
  }

}

@pjworrall the crowdsale is not the owner of the mintable token; it must be the owner in order to mint tokens

Is the explanation here that passing in the token contract from the truffle migration js doesn’t work? Because the contracts/examples/SimpleCrowdsale.js example led me to a pattern where the Token contract was create and deployed by truffle in the migration js and an argument was defined in the SimpleCrowdsale constructor to receive its Address at deployment time with the other arguments like rate, start time and end time etc.

so

contract SampleCrowdsale is CappedCrowdsale, RefundableCrowdsale, MintedCrowdsale {

  function SampleCrowdsale(uint256 _openingTime, uint256 _closingTime, uint256 _rate, address _wallet, uint256 _cap, MintableToken _token, uint256 _goal) public
    Crowdsale(_rate, _wallet, _token)
    CappedCrowdsale(_cap)
    TimedCrowdsale(_openingTime, _closingTime)
    RefundableCrowdsale(_goal)
  {
    //As goal needs to be met for a successful crowdsale
    //the value needs to less or equal than a cap which is limit for accepted funds
    require(_goal <= _cap);
  }
}
```

Proposed a migration like this..

```
module.exports = function (deployer, network, accounts) {
    const startTime = web3.eth.getBlock('latest').timestamp + 60; // 1 min in the future
    const endTime = startTime + 86400 * 20; // 20 days
    const rate = new web3.BigNumber(1);
    const wallet = accounts[9];
    const goal = new web3.BigNumber(1000000000000000000000);
    const cap = new web3.BigNumber(2000000000000000000000);

    return deployer
        .then(() => {
            return deployer.deploy(MyMintableToken);
        })
        .then(() => {
            return deployer.deploy(
                SampleCrowdsale,
                startTime,
                endTime,
                rate,
                wallet,
                goal,
                cap,
                MyMintableToken.address
            );
        });
};
```

and for me when I tried to buy tokens on the Crowdsale fallback()  I always ran into a problem with the overriden function on MintedCrowdsale here:

```
  function _deliverTokens(address _beneficiary, uint256 _tokenAmount) internal {
    require(MintableToken(token).mint(_beneficiary, _tokenAmount));
  }
```
it would throw:

```
transact to TogetherCrowdsale.(fallback) errored: VM error: revert.
revert	The transaction has been reverted to the initial state.
Note: The constructor should be payable if you send value.	Debug the transaction to get more information. 
```

The example migration is something as follow:

return deployer
        .then(() => {
            return deployer.deploy(LeonardianToken);
        })
        .then(() => {
            
            return deployer.deploy(
                LeonardianCrowdsale,
                startTime,
                endTime,
                exchangeRate,
                collect_wallet,
                LeonardianToken.address
            );
        })
        .then(() => {

            var token = LeonardianToken.at(LeonardianToken.address);

            token.transferOwnership(LeonardianCrowdsale.address);
        });