Solvedopenzeppelin contracts Revisit gas costs of having Crowdsale deploy the token itself
✔️Accepted Answer
Other Answers:
I've been playing around a bit with removing the token creation from the crowdsale contract, and requiring it as a parameter. The code change would be the following:
- function Crowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, address _wallet) public {
+ function Crowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, address _wallet, MintableToken _token) public {
require(_startTime >= now);
require(_endTime >= _startTime);
require(_rate > 0);
require(_wallet != address(0));
- token = createTokenContract();
+ token = _token;
startTime = _startTime;
endTime = _endTime;
rate = _rate;
wallet = _wallet;
}
- // creates the token to be sold.
- // override this method to have crowdsale of a specific mintable token.
- function createTokenContract() internal returns (MintableToken) {
- return new MintableToken();
- }
The gas costs for the current implementation with the embedded token contract code, vs this new implementation with the token as a parameter, with the solc optimizer on and off, are the following:
Version | Optimized | Not optimized |
---|---|---|
Embedded token | 1872055 | 3629854 |
As a parameter | 757040 + 426098 | 1562529 + 564671 |
Gas savings | 688917 | 1502654 |
The costs of deploying the mintable token and then the sale are shown separately as the two addends in each cell. The cost of the transfer ownership is missing, though it is negligible (~30K in a not optimized version).
The code I used for testing both versions was the following:
// Current version
ts = web3.eth.getBlock('latest').timestamp
Crowdsale.new(ts + 100, ts + 1000, 1000, 0x1).then(c => sale = c)
t = web3.eth.getTransaction(sale.transactionHash)
web3.eth.estimateGas({from: web3.eth.accounts[0], to: 0x0, data: t.input})
// New version
MintableToken.new().then(m => token = m)
web3.eth.estimateGas({from: web3.eth.accounts[0], to: 0x0, data: web3.eth.getTransaction(token.transactionHash).input})
ts = web3.eth.getBlock('latest').timestamp
Crowdsale.new(ts + 100, ts + 1000, 1000, 0x1, token.address).then(c => sale = c)
web3.eth.estimateGas({from: web3.eth.accounts[0], to: 0x0, data: web3.eth.getTransaction(sale.transactionHash).input})
I think we have enough arguments to move the token creation outside of the crowdsale contract, right?
I think the error might be caused by the constructor arguments (not be excessive use of gas) - the first and second Crowdsale constructor arguments are timestamps, not block numbers. Probably the first check throws:
function Crowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, address _wallet) {
require(_startTime >= now);
It works now. This is why it worked on the local TestRPC, and not on Ropsten.
Thanks a lot @spalladino!
The bytecode that results from having
Crowdsale
deploy the token itself is too big and causes the deployment to be too costly.Related to #351. Should be fixed the same way.