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?
Hey!
Check this:
var LeonardianCrowdsale = artifacts.require("./LeonardianCrowdsale.sol");
var LeonardianToken = artifacts.require("./LeonardianToken.sol");
module.exports = function(deployer) {
deployer.deploy(LeonardianToken);
LeonardianToken.deployed().then(function (instance) {
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.
instance.address
);
});
};
You need to deploy token contract first and then deploy crowd sale.
Thanks for the help but the result is same
Transaction: 0x409ca94905779864e2802108e04c0ecc4629e77113393a66e42aa9241e8b263d
[23:29:26] Gas usage: 45072
[23:29:26] Block Number: 16
[23:29:26] Block Time: Mon Mar 05 2018 23:29:26 GMT+0200 (EET)
[23:29:26] Runtime Error: revert
@microdesign your crowdsale does not own any tokens to transfer. The deploy account is the owner of the token, so you must mint your crowdsale some tokens using
Token.mint(MyCrowdsale.address, amount)
will reopen if that wasn't the issue
I dont think this was the issue. I have tried to reproduce this. I've created simple example here: https://github.com/pplonski/test-token-open-zeppelin-crowdsale
the contracts:
pragma solidity ^0.4.18;
import "zeppelin-solidity/contracts/token/ERC20/MintableToken.sol";
contract TestToken is MintableToken {
string public constant name = "Test Token";
string public constant symbol = "TTT";
uint8 public constant decimals = 18;
}
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 Crowdsale {
function TestTokenCrowdsale(uint256 _rate, address _wallet, MintableToken _token) public
Crowdsale(_rate, _wallet, _token) {
}
}
md5-889da5c1b72c9431c0ae4ebf2789565d
var Token = artifacts.require("./TestToken.sol");
var Crowdsale = artifacts.require("./TestTokenCrowdsale.sol");
module.exports = function(deployer, network, accounts) {
deployer.deploy(Token);
Token.deployed().then(function(instance) {
deployer.deploy(Crowdsale, 3*10**14, accounts[0], 210000000, instance);
});
};
md5-25130c56f875b0734c703f2439606289
require("babel-core/register");
require("babel-polyfill");
var Token = artifacts.require('./TestToken.sol')
var Crowdsale = artifacts.require("./TestTokenCrowdsale.sol");
contract('Crowdsale', function() {
it("should buy token", async () => {
const owner = web3.eth.accounts[0];
const account1 = web3.eth.accounts[1];
const amount = web3.toWei('0.01', 'ether');
let crowdsale = await Crowdsale.deployed();
let tx = await crowdsale.buyTokens(account1,
{value: amount,
from: account1});
});
});
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) {
}
}
Thank you @pplonski I`ll try it now.
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.
```
@pjworrall
TimedCrowdsale(_openingTime, _closingTime)
Will case the problem ,try to remove it . It work.
But I don't know how 2 fix it.
@pjworrall the crowdsale is not the owner of the mintable token; it must be the owner in order to mint tokens
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);
});
I have not tried but that looks right @microdesign . Thanks. I had reverted to creating the token contract in the Crowdsale contract to avoid that problem. If there is a reason to have abstracted out the token contract creation from the Crowdsale contract then I will revert back and use the migration you've shown.
Let me know.
The OpenZeppeling team told me the other way caused some problems in contracts and that is why they move Token creation and that is why there is the need for the transfer Ownership.
In your way, everything is working just when you try to purchase tokens - the onlyOwner modifier throw error.
@microdesign thanks. Maybe @Shrugs can let us know what the problems were with Token contracts created inside/by Crowdsale contracts because that might be why I still ran into problems elsewhere. If it is related to Gas limit issues that would make sense as that is a problem I have now :-) .
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.
My Transfer function seems not works normal, can somebody know?
i used mintable token, and here's my function in transfer.js:
transferToken() {
let web3 = store.getState().web3.web3Instance;
const receiver = this.state.receipt_add; // address from input form
const token_value = this.state.token_amount; // amount from input form
var account;
var tokenInstance;
const token = contract(MyToken)
token.setProvider(web3.currentProvider)
web3.eth.getAccounts((error, accounts) => {
if (error) {
console.log(error);
}
account = accounts[0];
token.deployed().then( inst => {
tokenInstance = inst
console.log(tokenInstance)
return tokenInstance.transfer(receiver, token_value, {from: account, gas: 3000000})
}).then(result => {
console.log(result);
alert('Transfer Successfull!');
return this.getBalances();
}).catch( err => {
console.log(err);
});
});
}
and here's my token crowdsale contract:
```
pragma solidity ^0.4.23;
import "./MyToken.sol";
import "zeppelin-solidity/contracts/crowdsale/emission/MintedCrowdsale.sol";
import "zeppelin-solidity/contracts/crowdsale/validation/TimedCrowdsale.sol";
contract MyTokenCrowdsale is TimedCrowdsale, MintedCrowdsale {
function MyTokenCrowdsale
(
uint256 _openingTime,
uint256 _closingTime,
uint256 _rate,
address _wallet,
MintableToken _token
)
public
Crowdsale(_rate, _wallet, _token)
TimedCrowdsale(_openingTime, _closingTime) {
}
}
pragma solidity ^0.4.23;
import "zeppelin-solidity/contracts/token/ERC20/MintableToken.sol";
contract MyToken is MintableToken {
string public name = "My Token";
string public symbol = "MYT";
uint8 public decimals = 18;
}
```
while i run the program:
then the metamask confirmation show, and after i submit the request, my token from
1000MYT -> new balance is 999MYT
did i miss something? thanks
@yosuasabatino let's move that question to https://ethereum.stackexchange.com/ since it's more appropriate there. Then feel free to post the link to the question in the OpenZeppelin slack community. thanks!
Most helpful comment
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.