From 77dfcb6e23b452031e478f8f3794a9dbe90b7c64 Mon Sep 17 00:00:00 2001 From: Jakub Wojciechowski Date: Sun, 6 Aug 2017 16:40:19 +0200 Subject: [PATCH 1/6] Change crowdsales to use timestamps instead of block numbers #350 --- contracts/crowdsale/Crowdsale.sol | 23 +++++++++++------------ test/Crowdsale.js | 24 ++++++++++++++++-------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/contracts/crowdsale/Crowdsale.sol b/contracts/crowdsale/Crowdsale.sol index 4c1e526ff7e..e4cc4eb077d 100644 --- a/contracts/crowdsale/Crowdsale.sol +++ b/contracts/crowdsale/Crowdsale.sol @@ -6,7 +6,7 @@ import '../math/SafeMath.sol'; /** * @title Crowdsale * @dev Crowdsale is a base contract for managing a token crowdsale. - * Crowdsales have a start and end block, where investors can make + * Crowdsales have a start and end timestamps, where investors can make * token purchases and the crowdsale will assign them tokens based * on a token per ETH rate. Funds collected are forwarded to a wallet * as they arrive. @@ -17,9 +17,9 @@ contract Crowdsale { // The token being sold MintableToken public token; - // start and end block where investments are allowed (both inclusive) - uint256 public startBlock; - uint256 public endBlock; + // start and end timestamps where investments are allowed (both inclusive) + uint256 public startTime; + uint256 public endTime; // address where funds are collected address public wallet; @@ -40,15 +40,15 @@ contract Crowdsale { event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount); - function Crowdsale(uint256 _startBlock, uint256 _endBlock, uint256 _rate, address _wallet) { - require(_startBlock >= block.number); - require(_endBlock >= _startBlock); + function Crowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, address _wallet) { + require(_startTime >= now); + require(_endTime >= _startTime); require(_rate > 0); require(_wallet != 0x0); token = createTokenContract(); - startBlock = _startBlock; - endBlock = _endBlock; + startTime = _startTime; + endTime = _endTime; rate = _rate; wallet = _wallet; } @@ -92,15 +92,14 @@ contract Crowdsale { // @return true if the transaction can buy tokens function validPurchase() internal constant returns (bool) { - uint256 current = block.number; - bool withinPeriod = current >= startBlock && current <= endBlock; + bool withinPeriod = now >= startTime && now <= endTime; bool nonZeroPurchase = msg.value != 0; return withinPeriod && nonZeroPurchase; } // @return true if crowdsale event has ended function hasEnded() public constant returns (bool) { - return block.number > endBlock; + return now > endTime; } diff --git a/test/Crowdsale.js b/test/Crowdsale.js index 5160fea421b..69859269073 100644 --- a/test/Crowdsale.js +++ b/test/Crowdsale.js @@ -1,5 +1,8 @@ +import moment from 'moment' import ether from './helpers/ether' import advanceToBlock from './helpers/advanceToBlock' +import increaseTime from './helpers/increaseTime' +import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' const BigNumber = web3.BigNumber @@ -19,11 +22,16 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { const expectedTokenAmount = rate.mul(value) + before(async function() { + //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc + await advanceToBlock(web3.eth.getBlock('latest').number + 1) + }) + beforeEach(async function () { - this.startBlock = web3.eth.blockNumber + 10 - this.endBlock = web3.eth.blockNumber + 20 + this.startTime = latestTime().unix() + moment.duration(1, 'week').asSeconds(); + this.endTime = latestTime().unix() + moment.duration(2, 'week').asSeconds(); - this.crowdsale = await Crowdsale.new(this.startBlock, this.endBlock, rate, wallet) + this.crowdsale = await Crowdsale.new(this.startTime, this.endTime, rate, wallet) this.token = MintableToken.at(await this.crowdsale.token()) }) @@ -36,7 +44,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { it('should be ended only after end', async function () { let ended = await this.crowdsale.hasEnded() ended.should.equal(false) - await advanceToBlock(this.endBlock + 1) + await increaseTime(moment.duration(2.1, 'week')) ended = await this.crowdsale.hasEnded() ended.should.equal(true) }) @@ -49,13 +57,13 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { }) it('should accept payments after start', async function () { - await advanceToBlock(this.startBlock - 1) + await increaseTime(moment.duration(1, 'week')) await this.crowdsale.send(value).should.be.fulfilled await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.fulfilled }) it('should reject payments after end', async function () { - await advanceToBlock(this.endBlock) + await increaseTime(moment.duration(2.1, 'week')) await this.crowdsale.send(value).should.be.rejectedWith(EVMThrow) await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.rejectedWith(EVMThrow) }) @@ -65,7 +73,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { describe('high-level purchase', function () { beforeEach(async function() { - await advanceToBlock(this.startBlock) + await increaseTime(moment.duration(1, 'week')) }) it('should log purchase', async function () { @@ -104,7 +112,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { describe('low-level purchase', function () { beforeEach(async function() { - await advanceToBlock(this.startBlock) + await increaseTime(moment.duration(1, 'week')) }) it('should log purchase', async function () { From 2b5192b9ce1f56a21ddde643af0f9661ee7ef3d3 Mon Sep 17 00:00:00 2001 From: Jakub Wojciechowski Date: Sun, 6 Aug 2017 16:41:43 +0200 Subject: [PATCH 2/6] Change crowdsales to use timestamps instead of block numbers #350 update derived crowdsales --- test/CappedCrowdsale.js | 34 ++++++++++++-------- test/FinalizableCrowdsale.js | 24 +++++++++----- test/RefundableCrowdsale.js | 39 +++++++++++++---------- test/helpers/CappedCrowdsaleImpl.sol | 6 ++-- test/helpers/FinalizableCrowdsaleImpl.sol | 6 ++-- test/helpers/RefundableCrowdsaleImpl.sol | 6 ++-- 6 files changed, 69 insertions(+), 46 deletions(-) diff --git a/test/CappedCrowdsale.js b/test/CappedCrowdsale.js index 753da5c1808..96fcd0c8992 100644 --- a/test/CappedCrowdsale.js +++ b/test/CappedCrowdsale.js @@ -1,5 +1,8 @@ +import moment from 'moment' import ether from './helpers/ether' import advanceToBlock from './helpers/advanceToBlock' +import increaseTime from './helpers/increaseTime' +import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' const BigNumber = web3.BigNumber @@ -19,28 +22,33 @@ contract('CappedCrowdsale', function ([_, wallet]) { const cap = ether(300) const lessThanCap = ether(60) - describe('creating a valid crowdsale', function () { - - it('should fail with zero cap', async function () { - await CappedCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, 0).should.be.rejectedWith(EVMThrow); - }) - - }); - + before(async function() { + //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc + await advanceToBlock(web3.eth.getBlock('latest').number + 1) + }) beforeEach(async function () { - this.startBlock = web3.eth.blockNumber + 10 - this.endBlock = web3.eth.blockNumber + 20 + this.startTime = latestTime().unix() + moment.duration(1, 'week').asSeconds(); + this.endTime = latestTime().unix() + moment.duration(2, 'week').asSeconds(); - this.crowdsale = await CappedCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, cap) + + this.crowdsale = await CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, cap) this.token = MintableToken.at(await this.crowdsale.token()) }) + describe('creating a valid crowdsale', function () { + + it('should fail with zero cap', async function () { + await CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0).should.be.rejectedWith(EVMThrow); + }) + + }); + describe('accepting payments', function () { beforeEach(async function () { - await advanceToBlock(this.startBlock - 1) + await increaseTime(moment.duration(1, 'week')) }) it('should accept payments within cap', async function () { @@ -62,7 +70,7 @@ contract('CappedCrowdsale', function ([_, wallet]) { describe('ending', function () { beforeEach(async function () { - await advanceToBlock(this.startBlock - 1) + await increaseTime(moment.duration(1, 'week')) }) it('should not be ended if under cap', async function () { diff --git a/test/FinalizableCrowdsale.js b/test/FinalizableCrowdsale.js index 53224bb7652..5675c755786 100644 --- a/test/FinalizableCrowdsale.js +++ b/test/FinalizableCrowdsale.js @@ -1,4 +1,7 @@ +import moment from 'moment' import advanceToBlock from './helpers/advanceToBlock' +import increaseTime from './helpers/increaseTime' +import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' const BigNumber = web3.BigNumber @@ -15,11 +18,16 @@ contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { const rate = new BigNumber(1000) + before(async function() { + //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc + await advanceToBlock(web3.eth.getBlock('latest').number + 1) + }) + beforeEach(async function () { - this.startBlock = web3.eth.blockNumber + 10 - this.endBlock = web3.eth.blockNumber + 20 + this.startTime = latestTime().unix() + moment.duration(1, 'week').asSeconds(); + this.endTime = latestTime().unix() + moment.duration(2, 'week').asSeconds(); - this.crowdsale = await FinalizableCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, {from: owner}) + this.crowdsale = await FinalizableCrowdsale.new(this.startTime, this.endTime, rate, wallet, {from: owner}) this.token = MintableToken.at(await this.crowdsale.token()) }) @@ -29,30 +37,30 @@ contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { }) it('cannot be finalized by third party after ending', async function () { - await advanceToBlock(this.endBlock) + await increaseTime(moment.duration(2.1, 'week')) await this.crowdsale.finalize({from: thirdparty}).should.be.rejectedWith(EVMThrow) }) it('can be finalized by owner after ending', async function () { - await advanceToBlock(this.endBlock) + await increaseTime(moment.duration(2.1, 'week')) await this.crowdsale.finalize({from: owner}).should.be.fulfilled }) it('cannot be finalized twice', async function () { - await advanceToBlock(this.endBlock + 1) + await increaseTime(moment.duration(2.1, 'week')) await this.crowdsale.finalize({from: owner}) await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMThrow) }) it('logs finalized', async function () { - await advanceToBlock(this.endBlock) + await increaseTime(moment.duration(2.1, 'week')) const {logs} = await this.crowdsale.finalize({from: owner}) const event = logs.find(e => e.event === 'Finalized') should.exist(event) }) it('finishes minting of token', async function () { - await advanceToBlock(this.endBlock) + await increaseTime(moment.duration(2.1, 'week')) await this.crowdsale.finalize({from: owner}) const finished = await this.token.mintingFinished() finished.should.equal(true) diff --git a/test/RefundableCrowdsale.js b/test/RefundableCrowdsale.js index f1d6fda6830..518f9204713 100644 --- a/test/RefundableCrowdsale.js +++ b/test/RefundableCrowdsale.js @@ -1,5 +1,8 @@ +import moment from 'moment' import ether from './helpers/ether' import advanceToBlock from './helpers/advanceToBlock' +import increaseTime from './helpers/increaseTime' +import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' const BigNumber = web3.BigNumber @@ -17,39 +20,43 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) { const goal = ether(800) const lessThanGoal = ether(750) + before(async function() { + //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc + await advanceToBlock(web3.eth.getBlock('latest').number + 1) + }) + + beforeEach(async function () { + this.startTime = latestTime().unix() + moment.duration(1, 'week').asSeconds(); + this.endTime = latestTime().unix() + moment.duration(2, 'week').asSeconds(); + + this.crowdsale = await RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, goal, {from: owner}) + }) + describe('creating a valid crowdsale', function () { it('should fail with zero goal', async function () { - await RefundableCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, 0, {from: owner}).should.be.rejectedWith(EVMThrow); + await RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0, {from: owner}).should.be.rejectedWith(EVMThrow); }) }); - - beforeEach(async function () { - this.startBlock = web3.eth.blockNumber + 10 - this.endBlock = web3.eth.blockNumber + 20 - - this.crowdsale = await RefundableCrowdsale.new(this.startBlock, this.endBlock, rate, wallet, goal, {from: owner}) - }) - it('should deny refunds before end', async function () { await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) - await advanceToBlock(this.endBlock - 1) + await increaseTime(moment.duration(2, 'week')) await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) }) it('should deny refunds after end if goal was reached', async function () { - await advanceToBlock(this.startBlock - 1) + await increaseTime(moment.duration(1, 'week')) await this.crowdsale.sendTransaction({value: goal, from: investor}) - await advanceToBlock(this.endBlock) + await increaseTime(moment.duration(1.1, 'week')) await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) }) it('should allow refunds after end if goal was not reached', async function () { - await advanceToBlock(this.startBlock - 1) + await increaseTime(moment.duration(1, 'week')) await this.crowdsale.sendTransaction({value: lessThanGoal, from: investor}) - await advanceToBlock(this.endBlock) + await increaseTime(moment.duration(1.1, 'week')) await this.crowdsale.finalize({from: owner}) @@ -62,9 +69,9 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) { }) it('should forward funds to wallet after end if goal was reached', async function () { - await advanceToBlock(this.startBlock - 1) + await increaseTime(moment.duration(1, 'week')) await this.crowdsale.sendTransaction({value: goal, from: investor}) - await advanceToBlock(this.endBlock) + await increaseTime(moment.duration(1.1, 'week')) const pre = web3.eth.getBalance(wallet) await this.crowdsale.finalize({from: owner}) diff --git a/test/helpers/CappedCrowdsaleImpl.sol b/test/helpers/CappedCrowdsaleImpl.sol index 6a255dca30d..1a949749829 100644 --- a/test/helpers/CappedCrowdsaleImpl.sol +++ b/test/helpers/CappedCrowdsaleImpl.sol @@ -7,13 +7,13 @@ import '../../contracts/crowdsale/CappedCrowdsale.sol'; contract CappedCrowdsaleImpl is CappedCrowdsale { function CappedCrowdsaleImpl ( - uint256 _startBlock, - uint256 _endBlock, + uint256 _startTime, + uint256 _endTime, uint256 _rate, address _wallet, uint256 _cap ) - Crowdsale(_startBlock, _endBlock, _rate, _wallet) + Crowdsale(_startTime, _endTime, _rate, _wallet) CappedCrowdsale(_cap) { } diff --git a/test/helpers/FinalizableCrowdsaleImpl.sol b/test/helpers/FinalizableCrowdsaleImpl.sol index b35b633a93f..cc6d31c09e1 100644 --- a/test/helpers/FinalizableCrowdsaleImpl.sol +++ b/test/helpers/FinalizableCrowdsaleImpl.sol @@ -7,12 +7,12 @@ import '../../contracts/crowdsale/FinalizableCrowdsale.sol'; contract FinalizableCrowdsaleImpl is FinalizableCrowdsale { function FinalizableCrowdsaleImpl ( - uint256 _startBlock, - uint256 _endBlock, + uint256 _startTime, + uint256 _endTime, uint256 _rate, address _wallet ) - Crowdsale(_startBlock, _endBlock, _rate, _wallet) + Crowdsale(_startTime, _endTime, _rate, _wallet) FinalizableCrowdsale() { } diff --git a/test/helpers/RefundableCrowdsaleImpl.sol b/test/helpers/RefundableCrowdsaleImpl.sol index 5250f56f8c0..2db8257fc35 100644 --- a/test/helpers/RefundableCrowdsaleImpl.sol +++ b/test/helpers/RefundableCrowdsaleImpl.sol @@ -7,13 +7,13 @@ import '../../contracts/crowdsale/RefundableCrowdsale.sol'; contract RefundableCrowdsaleImpl is RefundableCrowdsale { function RefundableCrowdsaleImpl ( - uint256 _startBlock, - uint256 _endBlock, + uint256 _startTime, + uint256 _endTime, uint256 _rate, address _wallet, uint256 _goal ) - Crowdsale(_startBlock, _endBlock, _rate, _wallet) + Crowdsale(_startTime, _endTime, _rate, _wallet) RefundableCrowdsale(_goal) { } From c6e055689b90853460e2ce4eb3cc4dbca07b5eec Mon Sep 17 00:00:00 2001 From: Jakub Wojciechowski Date: Sun, 6 Aug 2017 16:42:16 +0200 Subject: [PATCH 3/6] Change crowdsales to use timestamps instead of block numbers #350 update example --- contracts/examples/SampleCrowdsale.sol | 4 ++-- test/SampleCrowdsale.js | 32 +++++++++++++++++--------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/contracts/examples/SampleCrowdsale.sol b/contracts/examples/SampleCrowdsale.sol index 2fc95c61035..554aa6be8f9 100644 --- a/contracts/examples/SampleCrowdsale.sol +++ b/contracts/examples/SampleCrowdsale.sol @@ -30,11 +30,11 @@ contract SampleCrowdsaleToken is MintableToken { */ contract SampleCrowdsale is CappedCrowdsale, RefundableCrowdsale { - function SampleCrowdsale(uint256 _startBlock, uint256 _endBlock, uint256 _rate, uint256 _goal, uint256 _cap, address _wallet) + function SampleCrowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, uint256 _goal, uint256 _cap, address _wallet) CappedCrowdsale(_cap) FinalizableCrowdsale() RefundableCrowdsale(_goal) - Crowdsale(_startBlock, _endBlock, _rate, _wallet) + Crowdsale(_startTime, _endTime, _rate, _wallet) { //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 diff --git a/test/SampleCrowdsale.js b/test/SampleCrowdsale.js index a589194f7c5..b2669699a29 100644 --- a/test/SampleCrowdsale.js +++ b/test/SampleCrowdsale.js @@ -1,5 +1,8 @@ +import moment from 'moment' import ether from './helpers/ether' import advanceToBlock from './helpers/advanceToBlock' +import increaseTime from './helpers/increaseTime' +import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' const BigNumber = web3.BigNumber; @@ -18,11 +21,17 @@ contract('Crowdsale', function ([owner, wallet, investor]) { const GOAL = ether(10); const CAP = ether(20); + before(async function() { + //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc + await advanceToBlock(web3.eth.getBlock('latest').number + 1) + }) + beforeEach(async function () { - this.startBlock = web3.eth.blockNumber + 10; - this.endBlock = web3.eth.blockNumber + 20; + this.startTime = latestTime().unix() + moment.duration(1, 'week').asSeconds(); + this.endTime = latestTime().unix() + moment.duration(2, 'week').asSeconds(); + - this.crowdsale = await SampleCrowdsale.new(this.startBlock, this.endBlock, RATE, GOAL, CAP, wallet); + this.crowdsale = await SampleCrowdsale.new(this.startTime, this.endTime, RATE, GOAL, CAP, wallet); this.token = SampleCrowdsaleToken.at(await this.crowdsale.token()); }); @@ -31,8 +40,8 @@ contract('Crowdsale', function ([owner, wallet, investor]) { this.crowdsale.should.exist; this.token.should.exist; - (await this.crowdsale.startBlock()).should.be.bignumber.equal(this.startBlock); - (await this.crowdsale.endBlock()).should.be.bignumber.equal(this.endBlock); + (await this.crowdsale.startTime()).should.be.bignumber.equal(this.startTime); + (await this.crowdsale.endTime()).should.be.bignumber.equal(this.endTime); (await this.crowdsale.rate()).should.be.bignumber.equal(RATE); (await this.crowdsale.wallet()).should.be.equal(wallet); (await this.crowdsale.goal()).should.be.bignumber.equal(GOAL); @@ -48,7 +57,7 @@ contract('Crowdsale', function ([owner, wallet, investor]) { const investmentAmount = ether(1); const expectedTokenAmount = RATE.mul(investmentAmount); - await advanceToBlock(this.startBlock - 1); + await increaseTime(moment.duration(1, 'week')); await this.crowdsale.buyTokens(investor, {value: investmentAmount, from: investor}).should.be.fulfilled; (await this.token.balanceOf(investor)).should.be.bignumber.equal(expectedTokenAmount); @@ -56,22 +65,23 @@ contract('Crowdsale', function ([owner, wallet, investor]) { }); it('should reject payments after end', async function () { - await advanceToBlock(this.endBlock); + await increaseTime(moment.duration(2.1, 'week')); await this.crowdsale.send(ether(1)).should.be.rejectedWith(EVMThrow); await this.crowdsale.buyTokens(investor, {value: ether(1), from: investor}).should.be.rejectedWith(EVMThrow); }); it('should reject payments over cap', async function () { - await advanceToBlock(this.startBlock - 1); + await increaseTime(moment.duration(1, 'week')); await this.crowdsale.send(CAP); await this.crowdsale.send(1).should.be.rejectedWith(EVMThrow); }); it('should allow finalization and transfer funds to wallet if the goal is reached', async function () { - await advanceToBlock(this.endBlock - 1); + await increaseTime(moment.duration(1, 'week')); await this.crowdsale.send(GOAL); const beforeFinalization = web3.eth.getBalance(wallet); + await increaseTime(moment.duration(1.1, 'week')); await this.crowdsale.finalize({from: owner}); const afterFinalization = web3.eth.getBalance(wallet); @@ -81,9 +91,9 @@ contract('Crowdsale', function ([owner, wallet, investor]) { it('should allow refunds if the goal is not reached', async function () { const balanceBeforeInvestment = web3.eth.getBalance(investor); - await advanceToBlock(this.startBlock - 1); + await increaseTime(moment.duration(1, 'week')); await this.crowdsale.sendTransaction({value: ether(1), from: investor, gasPrice: 0}); - await advanceToBlock(this.endBlock); + await increaseTime(moment.duration(1.1, 'week')); await this.crowdsale.finalize({from: owner}); await this.crowdsale.claimRefund({from: investor, gasPrice: 0}).should.be.fulfilled; From 2261039d52fe0e433a041c377658bfaab132761b Mon Sep 17 00:00:00 2001 From: Jakub Wojciechowski Date: Mon, 7 Aug 2017 18:29:09 +0200 Subject: [PATCH 4/6] Simplify advanceBlock in tests --- test/CappedCrowdsale.js | 4 ++-- test/Crowdsale.js | 4 ++-- test/FinalizableCrowdsale.js | 4 ++-- test/RefundableCrowdsale.js | 4 ++-- test/SampleCrowdsale.js | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/CappedCrowdsale.js b/test/CappedCrowdsale.js index 96fcd0c8992..65d4ac9bd39 100644 --- a/test/CappedCrowdsale.js +++ b/test/CappedCrowdsale.js @@ -1,6 +1,6 @@ import moment from 'moment' import ether from './helpers/ether' -import advanceToBlock from './helpers/advanceToBlock' +import {advanceBlock} from './helpers/advanceToBlock' import increaseTime from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -24,7 +24,7 @@ contract('CappedCrowdsale', function ([_, wallet]) { before(async function() { //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc - await advanceToBlock(web3.eth.getBlock('latest').number + 1) + await advanceBlock() }) beforeEach(async function () { diff --git a/test/Crowdsale.js b/test/Crowdsale.js index 69859269073..4be91340461 100644 --- a/test/Crowdsale.js +++ b/test/Crowdsale.js @@ -1,6 +1,6 @@ import moment from 'moment' import ether from './helpers/ether' -import advanceToBlock from './helpers/advanceToBlock' +import {advanceBlock} from './helpers/advanceToBlock' import increaseTime from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -24,7 +24,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { before(async function() { //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc - await advanceToBlock(web3.eth.getBlock('latest').number + 1) + await advanceBlock() }) beforeEach(async function () { diff --git a/test/FinalizableCrowdsale.js b/test/FinalizableCrowdsale.js index 5675c755786..d92fe6608e4 100644 --- a/test/FinalizableCrowdsale.js +++ b/test/FinalizableCrowdsale.js @@ -1,5 +1,5 @@ import moment from 'moment' -import advanceToBlock from './helpers/advanceToBlock' +import {advanceBlock} from './helpers/advanceToBlock' import increaseTime from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -20,7 +20,7 @@ contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { before(async function() { //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc - await advanceToBlock(web3.eth.getBlock('latest').number + 1) + await advanceBlock() }) beforeEach(async function () { diff --git a/test/RefundableCrowdsale.js b/test/RefundableCrowdsale.js index 518f9204713..7423fd37fd8 100644 --- a/test/RefundableCrowdsale.js +++ b/test/RefundableCrowdsale.js @@ -1,6 +1,6 @@ import moment from 'moment' import ether from './helpers/ether' -import advanceToBlock from './helpers/advanceToBlock' +import {advanceBlock} from './helpers/advanceToBlock' import increaseTime from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -22,7 +22,7 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) { before(async function() { //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc - await advanceToBlock(web3.eth.getBlock('latest').number + 1) + await advanceBlock() }) beforeEach(async function () { diff --git a/test/SampleCrowdsale.js b/test/SampleCrowdsale.js index b2669699a29..2e64111c9d8 100644 --- a/test/SampleCrowdsale.js +++ b/test/SampleCrowdsale.js @@ -1,6 +1,6 @@ import moment from 'moment' import ether from './helpers/ether' -import advanceToBlock from './helpers/advanceToBlock' +import {advanceBlock} from './helpers/advanceToBlock' import increaseTime from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -23,7 +23,7 @@ contract('Crowdsale', function ([owner, wallet, investor]) { before(async function() { //Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc - await advanceToBlock(web3.eth.getBlock('latest').number + 1) + await advanceBlock() }) beforeEach(async function () { From 7c883b6368419c39f316e78dda5043fe46987605 Mon Sep 17 00:00:00 2001 From: Jakub Wojciechowski Date: Thu, 10 Aug 2017 13:13:49 +0200 Subject: [PATCH 5/6] Duration helper and eliminated hardcoded periods --- test/CappedCrowdsale.js | 13 ++++++++----- test/Crowdsale.js | 32 ++++++++++++++++++-------------- test/FinalizableCrowdsale.js | 20 ++++++++++++-------- test/RefundableCrowdsale.js | 24 ++++++++++++++---------- test/SampleCrowdsale.js | 24 ++++++++++++++---------- test/TokenTimelock.js | 8 ++++---- test/helpers/increaseTime.js | 12 +++++++++++- 7 files changed, 81 insertions(+), 52 deletions(-) diff --git a/test/CappedCrowdsale.js b/test/CappedCrowdsale.js index 65d4ac9bd39..bcc4e4a787a 100644 --- a/test/CappedCrowdsale.js +++ b/test/CappedCrowdsale.js @@ -1,7 +1,7 @@ -import moment from 'moment' import ether from './helpers/ether' import {advanceBlock} from './helpers/advanceToBlock' import increaseTime from './helpers/increaseTime' +import {duration, increaseTimeHandicap} from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -28,8 +28,11 @@ contract('CappedCrowdsale', function ([_, wallet]) { }) beforeEach(async function () { - this.startTime = latestTime().unix() + moment.duration(1, 'week').asSeconds(); - this.endTime = latestTime().unix() + moment.duration(2, 'week').asSeconds(); + this.timeToStart = duration.weeks(1); + this.crowdsalePeriod = duration.weeks(1); + + this.startTime = latestTime().unix() + this.timeToStart; + this.endTime = this.startTime + this.crowdsalePeriod; this.crowdsale = await CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, cap) @@ -48,7 +51,7 @@ contract('CappedCrowdsale', function ([_, wallet]) { describe('accepting payments', function () { beforeEach(async function () { - await increaseTime(moment.duration(1, 'week')) + await increaseTime(this.timeToStart) }) it('should accept payments within cap', async function () { @@ -70,7 +73,7 @@ contract('CappedCrowdsale', function ([_, wallet]) { describe('ending', function () { beforeEach(async function () { - await increaseTime(moment.duration(1, 'week')) + await increaseTime(this.timeToStart) }) it('should not be ended if under cap', async function () { diff --git a/test/Crowdsale.js b/test/Crowdsale.js index 4be91340461..20c1b365d3e 100644 --- a/test/Crowdsale.js +++ b/test/Crowdsale.js @@ -1,7 +1,7 @@ -import moment from 'moment' import ether from './helpers/ether' import {advanceBlock} from './helpers/advanceToBlock' import increaseTime from './helpers/increaseTime' +import {duration, increaseTimeHandicap} from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -28,8 +28,12 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { }) beforeEach(async function () { - this.startTime = latestTime().unix() + moment.duration(1, 'week').asSeconds(); - this.endTime = latestTime().unix() + moment.duration(2, 'week').asSeconds(); + this.timeToStart = duration.weeks(1); + this.crowdsalePeriod = duration.weeks(1); + this.timeToEnd = this.timeToStart + this.crowdsalePeriod + increaseTimeHandicap; + + this.startTime = latestTime().unix() + this.timeToStart; + this.endTime = this.startTime + this.crowdsalePeriod; this.crowdsale = await Crowdsale.new(this.startTime, this.endTime, rate, wallet) @@ -44,7 +48,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { it('should be ended only after end', async function () { let ended = await this.crowdsale.hasEnded() ended.should.equal(false) - await increaseTime(moment.duration(2.1, 'week')) + await increaseTime(this.timeToEnd) ended = await this.crowdsale.hasEnded() ended.should.equal(true) }) @@ -57,13 +61,13 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { }) it('should accept payments after start', async function () { - await increaseTime(moment.duration(1, 'week')) + await increaseTime(this.timeToStart) await this.crowdsale.send(value).should.be.fulfilled await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.fulfilled }) it('should reject payments after end', async function () { - await increaseTime(moment.duration(2.1, 'week')) + await increaseTime(this.timeToEnd) await this.crowdsale.send(value).should.be.rejectedWith(EVMThrow) await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.rejectedWith(EVMThrow) }) @@ -73,7 +77,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { describe('high-level purchase', function () { beforeEach(async function() { - await increaseTime(moment.duration(1, 'week')) + await increaseTime(this.timeToStart) }) it('should log purchase', async function () { @@ -112,33 +116,33 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { describe('low-level purchase', function () { beforeEach(async function() { - await increaseTime(moment.duration(1, 'week')) + await increaseTime(this.timeToStart) }) - + it('should log purchase', async function () { const {logs} = await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}) - + const event = logs.find(e => e.event === 'TokenPurchase') - + should.exist(event) event.args.purchaser.should.equal(purchaser) event.args.beneficiary.should.equal(investor) event.args.value.should.be.bignumber.equal(value) event.args.amount.should.be.bignumber.equal(expectedTokenAmount) }) - + it('should increase totalSupply', async function () { await this.crowdsale.buyTokens(investor, {value, from: purchaser}) const totalSupply = await this.token.totalSupply() totalSupply.should.be.bignumber.equal(expectedTokenAmount) }) - + it('should assign tokens to beneficiary', async function () { await this.crowdsale.buyTokens(investor, {value, from: purchaser}) const balance = await this.token.balanceOf(investor) balance.should.be.bignumber.equal(expectedTokenAmount) }) - + it('should forward funds to wallet', async function () { const pre = web3.eth.getBalance(wallet) await this.crowdsale.buyTokens(investor, {value, from: purchaser}) diff --git a/test/FinalizableCrowdsale.js b/test/FinalizableCrowdsale.js index d92fe6608e4..af14708ea0d 100644 --- a/test/FinalizableCrowdsale.js +++ b/test/FinalizableCrowdsale.js @@ -1,6 +1,6 @@ -import moment from 'moment' import {advanceBlock} from './helpers/advanceToBlock' import increaseTime from './helpers/increaseTime' +import {duration, increaseTimeHandicap} from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -24,8 +24,12 @@ contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { }) beforeEach(async function () { - this.startTime = latestTime().unix() + moment.duration(1, 'week').asSeconds(); - this.endTime = latestTime().unix() + moment.duration(2, 'week').asSeconds(); + this.timeToStart = duration.weeks(1); + this.crowdsalePeriod = duration.weeks(1); + this.timeToEnd = this.timeToStart + this.crowdsalePeriod + increaseTimeHandicap; + + this.startTime = latestTime().unix() + this.timeToStart; + this.endTime = this.startTime + this.crowdsalePeriod; this.crowdsale = await FinalizableCrowdsale.new(this.startTime, this.endTime, rate, wallet, {from: owner}) @@ -37,30 +41,30 @@ contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { }) it('cannot be finalized by third party after ending', async function () { - await increaseTime(moment.duration(2.1, 'week')) + await increaseTime(this.timeToEnd) await this.crowdsale.finalize({from: thirdparty}).should.be.rejectedWith(EVMThrow) }) it('can be finalized by owner after ending', async function () { - await increaseTime(moment.duration(2.1, 'week')) + await increaseTime(this.timeToEnd) await this.crowdsale.finalize({from: owner}).should.be.fulfilled }) it('cannot be finalized twice', async function () { - await increaseTime(moment.duration(2.1, 'week')) + await increaseTime(this.timeToEnd) await this.crowdsale.finalize({from: owner}) await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMThrow) }) it('logs finalized', async function () { - await increaseTime(moment.duration(2.1, 'week')) + await increaseTime(this.timeToEnd) const {logs} = await this.crowdsale.finalize({from: owner}) const event = logs.find(e => e.event === 'Finalized') should.exist(event) }) it('finishes minting of token', async function () { - await increaseTime(moment.duration(2.1, 'week')) + await increaseTime(this.timeToEnd) await this.crowdsale.finalize({from: owner}) const finished = await this.token.mintingFinished() finished.should.equal(true) diff --git a/test/RefundableCrowdsale.js b/test/RefundableCrowdsale.js index 7423fd37fd8..6f0fc39a78f 100644 --- a/test/RefundableCrowdsale.js +++ b/test/RefundableCrowdsale.js @@ -1,7 +1,7 @@ -import moment from 'moment' import ether from './helpers/ether' import {advanceBlock} from './helpers/advanceToBlock' import increaseTime from './helpers/increaseTime' +import {duration, increaseTimeHandicap} from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -26,8 +26,12 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) { }) beforeEach(async function () { - this.startTime = latestTime().unix() + moment.duration(1, 'week').asSeconds(); - this.endTime = latestTime().unix() + moment.duration(2, 'week').asSeconds(); + this.timeToStart = duration.weeks(1); + this.crowdsalePeriod = duration.weeks(1); + this.timeToEnd = this.timeToStart + this.crowdsalePeriod + increaseTimeHandicap; + + this.startTime = latestTime().unix() + this.timeToStart; + this.endTime = this.startTime + this.crowdsalePeriod; this.crowdsale = await RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, goal, {from: owner}) }) @@ -42,21 +46,21 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) { it('should deny refunds before end', async function () { await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) - await increaseTime(moment.duration(2, 'week')) + await increaseTime(this.timeToStart) await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) }) it('should deny refunds after end if goal was reached', async function () { - await increaseTime(moment.duration(1, 'week')) + await increaseTime(this.timeToStart) await this.crowdsale.sendTransaction({value: goal, from: investor}) - await increaseTime(moment.duration(1.1, 'week')) + await increaseTime(this.crowdsalePeriod + increaseTimeHandicap) await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) }) it('should allow refunds after end if goal was not reached', async function () { - await increaseTime(moment.duration(1, 'week')) + await increaseTime(this.timeToStart) await this.crowdsale.sendTransaction({value: lessThanGoal, from: investor}) - await increaseTime(moment.duration(1.1, 'week')) + await increaseTime(this.crowdsalePeriod + increaseTimeHandicap) await this.crowdsale.finalize({from: owner}) @@ -69,9 +73,9 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) { }) it('should forward funds to wallet after end if goal was reached', async function () { - await increaseTime(moment.duration(1, 'week')) + await increaseTime(this.timeToStart) await this.crowdsale.sendTransaction({value: goal, from: investor}) - await increaseTime(moment.duration(1.1, 'week')) + await increaseTime(this.crowdsalePeriod + increaseTimeHandicap) const pre = web3.eth.getBalance(wallet) await this.crowdsale.finalize({from: owner}) diff --git a/test/SampleCrowdsale.js b/test/SampleCrowdsale.js index 2e64111c9d8..dbcf2ba56ff 100644 --- a/test/SampleCrowdsale.js +++ b/test/SampleCrowdsale.js @@ -1,7 +1,7 @@ -import moment from 'moment' import ether from './helpers/ether' import {advanceBlock} from './helpers/advanceToBlock' import increaseTime from './helpers/increaseTime' +import {duration, increaseTimeHandicap} from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -27,8 +27,12 @@ contract('Crowdsale', function ([owner, wallet, investor]) { }) beforeEach(async function () { - this.startTime = latestTime().unix() + moment.duration(1, 'week').asSeconds(); - this.endTime = latestTime().unix() + moment.duration(2, 'week').asSeconds(); + this.timeToStart = duration.weeks(1); + this.crowdsalePeriod = duration.weeks(1); + this.timeToEnd = this.timeToStart + this.crowdsalePeriod + increaseTimeHandicap; + + this.startTime = latestTime().unix() + this.timeToStart; + this.endTime = this.startTime + this.crowdsalePeriod; this.crowdsale = await SampleCrowdsale.new(this.startTime, this.endTime, RATE, GOAL, CAP, wallet); @@ -57,7 +61,7 @@ contract('Crowdsale', function ([owner, wallet, investor]) { const investmentAmount = ether(1); const expectedTokenAmount = RATE.mul(investmentAmount); - await increaseTime(moment.duration(1, 'week')); + await increaseTime(this.timeToStart); await this.crowdsale.buyTokens(investor, {value: investmentAmount, from: investor}).should.be.fulfilled; (await this.token.balanceOf(investor)).should.be.bignumber.equal(expectedTokenAmount); @@ -65,23 +69,23 @@ contract('Crowdsale', function ([owner, wallet, investor]) { }); it('should reject payments after end', async function () { - await increaseTime(moment.duration(2.1, 'week')); + await increaseTime(this.timeToEnd); await this.crowdsale.send(ether(1)).should.be.rejectedWith(EVMThrow); await this.crowdsale.buyTokens(investor, {value: ether(1), from: investor}).should.be.rejectedWith(EVMThrow); }); it('should reject payments over cap', async function () { - await increaseTime(moment.duration(1, 'week')); + await increaseTime(this.timeToStart); await this.crowdsale.send(CAP); await this.crowdsale.send(1).should.be.rejectedWith(EVMThrow); }); it('should allow finalization and transfer funds to wallet if the goal is reached', async function () { - await increaseTime(moment.duration(1, 'week')); + await increaseTime(this.timeToStart); await this.crowdsale.send(GOAL); const beforeFinalization = web3.eth.getBalance(wallet); - await increaseTime(moment.duration(1.1, 'week')); + await increaseTime(this.crowdsalePeriod + increaseTimeHandicap); await this.crowdsale.finalize({from: owner}); const afterFinalization = web3.eth.getBalance(wallet); @@ -91,9 +95,9 @@ contract('Crowdsale', function ([owner, wallet, investor]) { it('should allow refunds if the goal is not reached', async function () { const balanceBeforeInvestment = web3.eth.getBalance(investor); - await increaseTime(moment.duration(1, 'week')); + await increaseTime(this.timeToStart); await this.crowdsale.sendTransaction({value: ether(1), from: investor, gasPrice: 0}); - await increaseTime(moment.duration(1.1, 'week')); + await increaseTime(this.crowdsalePeriod + increaseTimeHandicap); await this.crowdsale.finalize({from: owner}); await this.crowdsale.claimRefund({from: investor, gasPrice: 0}).should.be.fulfilled; diff --git a/test/TokenTimelock.js b/test/TokenTimelock.js index 318cec98b73..25ffd9e2e93 100644 --- a/test/TokenTimelock.js +++ b/test/TokenTimelock.js @@ -29,26 +29,26 @@ contract('TokenTimelock', function ([_, owner, beneficiary]) { }) it('cannot be released just before time limit', async function () { - await increaseTime(moment.duration(0.99, 'year')) + await increaseTime(moment.duration(0.99, 'year').asSeconds()) await this.timelock.release().should.be.rejected }) it('can be released just after limit', async function () { - await increaseTime(moment.duration(1.01, 'year')) + await increaseTime(moment.duration(1.01, 'year').asSeconds()) await this.timelock.release().should.be.fulfilled const balance = await this.token.balanceOf(beneficiary) balance.should.be.bignumber.equal(amount) }) it('can be released after time limit', async function () { - await increaseTime(moment.duration(2, 'year')) + await increaseTime(moment.duration(2, 'year').asSeconds()) await this.timelock.release().should.be.fulfilled const balance = await this.token.balanceOf(beneficiary) balance.should.be.bignumber.equal(amount) }) it('cannot be released twice', async function () { - await increaseTime(moment.duration(2, 'year')) + await increaseTime(moment.duration(2, 'year').asSeconds()) await this.timelock.release().should.be.fulfilled await this.timelock.release().should.be.rejected const balance = await this.token.balanceOf(beneficiary) diff --git a/test/helpers/increaseTime.js b/test/helpers/increaseTime.js index cd1a756fd62..06f7d9c0bc3 100644 --- a/test/helpers/increaseTime.js +++ b/test/helpers/increaseTime.js @@ -6,7 +6,7 @@ export default function increaseTime(duration) { web3.currentProvider.sendAsync({ jsonrpc: '2.0', method: 'evm_increaseTime', - params: [duration.asSeconds()], + params: [duration], id: id, }, err1 => { if (err1) return reject(err1) @@ -21,3 +21,13 @@ export default function increaseTime(duration) { }) }) } + +export const duration = { + seconds: function(val) { return val}, + minutes: function(val) { return val * this.seconds(60) }, + hours: function(val) { return val * this.minutes(60) }, + days: function(val) { return val * this.hours(24) }, + weeks: function(val) { return val * this.days(7) } +}; + +export const increaseTimeHandicap = duration.seconds(10); \ No newline at end of file From 46c5759b88907ee75c7c698be8198cc09369efd0 Mon Sep 17 00:00:00 2001 From: Jakub Wojciechowski Date: Thu, 10 Aug 2017 16:23:52 +0200 Subject: [PATCH 6/6] Introduce increaseTimeTo helper method. --- test/CappedCrowdsale.js | 15 +++++---------- test/Crowdsale.js | 21 +++++++++------------ test/FinalizableCrowdsale.js | 21 +++++++++------------ test/RefundableCrowdsale.js | 26 +++++++++++--------------- test/SampleCrowdsale.js | 27 +++++++++++---------------- test/helpers/increaseTime.js | 22 ++++++++++++++++++---- 6 files changed, 63 insertions(+), 69 deletions(-) diff --git a/test/CappedCrowdsale.js b/test/CappedCrowdsale.js index bcc4e4a787a..9dd027b3581 100644 --- a/test/CappedCrowdsale.js +++ b/test/CappedCrowdsale.js @@ -1,7 +1,6 @@ import ether from './helpers/ether' import {advanceBlock} from './helpers/advanceToBlock' -import increaseTime from './helpers/increaseTime' -import {duration, increaseTimeHandicap} from './helpers/increaseTime' +import {increaseTimeTo, duration} from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -28,12 +27,8 @@ contract('CappedCrowdsale', function ([_, wallet]) { }) beforeEach(async function () { - this.timeToStart = duration.weeks(1); - this.crowdsalePeriod = duration.weeks(1); - - this.startTime = latestTime().unix() + this.timeToStart; - this.endTime = this.startTime + this.crowdsalePeriod; - + this.startTime = latestTime().unix() + duration.weeks(1); + this.endTime = this.startTime + duration.weeks(1); this.crowdsale = await CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, cap) @@ -51,7 +46,7 @@ contract('CappedCrowdsale', function ([_, wallet]) { describe('accepting payments', function () { beforeEach(async function () { - await increaseTime(this.timeToStart) + await increaseTimeTo(this.startTime) }) it('should accept payments within cap', async function () { @@ -73,7 +68,7 @@ contract('CappedCrowdsale', function ([_, wallet]) { describe('ending', function () { beforeEach(async function () { - await increaseTime(this.timeToStart) + await increaseTimeTo(this.startTime) }) it('should not be ended if under cap', async function () { diff --git a/test/Crowdsale.js b/test/Crowdsale.js index 20c1b365d3e..e3abe197523 100644 --- a/test/Crowdsale.js +++ b/test/Crowdsale.js @@ -1,7 +1,6 @@ import ether from './helpers/ether' import {advanceBlock} from './helpers/advanceToBlock' -import increaseTime from './helpers/increaseTime' -import {duration, increaseTimeHandicap} from './helpers/increaseTime' +import {increaseTimeTo, duration} from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -28,12 +27,10 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { }) beforeEach(async function () { - this.timeToStart = duration.weeks(1); - this.crowdsalePeriod = duration.weeks(1); - this.timeToEnd = this.timeToStart + this.crowdsalePeriod + increaseTimeHandicap; + this.startTime = latestTime().unix() + duration.weeks(1); + this.endTime = this.startTime + duration.weeks(1); + this.afterEndTime = this.endTime + duration.seconds(1) - this.startTime = latestTime().unix() + this.timeToStart; - this.endTime = this.startTime + this.crowdsalePeriod; this.crowdsale = await Crowdsale.new(this.startTime, this.endTime, rate, wallet) @@ -48,7 +45,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { it('should be ended only after end', async function () { let ended = await this.crowdsale.hasEnded() ended.should.equal(false) - await increaseTime(this.timeToEnd) + await increaseTimeTo(this.afterEndTime) ended = await this.crowdsale.hasEnded() ended.should.equal(true) }) @@ -61,13 +58,13 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { }) it('should accept payments after start', async function () { - await increaseTime(this.timeToStart) + await increaseTimeTo(this.startTime) await this.crowdsale.send(value).should.be.fulfilled await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.fulfilled }) it('should reject payments after end', async function () { - await increaseTime(this.timeToEnd) + await increaseTimeTo(this.afterEndTime) await this.crowdsale.send(value).should.be.rejectedWith(EVMThrow) await this.crowdsale.buyTokens(investor, {value: value, from: purchaser}).should.be.rejectedWith(EVMThrow) }) @@ -77,7 +74,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { describe('high-level purchase', function () { beforeEach(async function() { - await increaseTime(this.timeToStart) + await increaseTimeTo(this.startTime) }) it('should log purchase', async function () { @@ -116,7 +113,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { describe('low-level purchase', function () { beforeEach(async function() { - await increaseTime(this.timeToStart) + await increaseTimeTo(this.startTime) }) it('should log purchase', async function () { diff --git a/test/FinalizableCrowdsale.js b/test/FinalizableCrowdsale.js index af14708ea0d..a7e76bfbf3f 100644 --- a/test/FinalizableCrowdsale.js +++ b/test/FinalizableCrowdsale.js @@ -1,6 +1,5 @@ import {advanceBlock} from './helpers/advanceToBlock' -import increaseTime from './helpers/increaseTime' -import {duration, increaseTimeHandicap} from './helpers/increaseTime' +import {increaseTimeTo, duration} from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -24,12 +23,10 @@ contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { }) beforeEach(async function () { - this.timeToStart = duration.weeks(1); - this.crowdsalePeriod = duration.weeks(1); - this.timeToEnd = this.timeToStart + this.crowdsalePeriod + increaseTimeHandicap; + this.startTime = latestTime().unix() + duration.weeks(1) + this.endTime = this.startTime + duration.weeks(1) + this.afterEndTime = this.endTime + duration.seconds(1) - this.startTime = latestTime().unix() + this.timeToStart; - this.endTime = this.startTime + this.crowdsalePeriod; this.crowdsale = await FinalizableCrowdsale.new(this.startTime, this.endTime, rate, wallet, {from: owner}) @@ -41,30 +38,30 @@ contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { }) it('cannot be finalized by third party after ending', async function () { - await increaseTime(this.timeToEnd) + await increaseTimeTo(this.afterEndTime) await this.crowdsale.finalize({from: thirdparty}).should.be.rejectedWith(EVMThrow) }) it('can be finalized by owner after ending', async function () { - await increaseTime(this.timeToEnd) + await increaseTimeTo(this.afterEndTime) await this.crowdsale.finalize({from: owner}).should.be.fulfilled }) it('cannot be finalized twice', async function () { - await increaseTime(this.timeToEnd) + await increaseTimeTo(this.afterEndTime) await this.crowdsale.finalize({from: owner}) await this.crowdsale.finalize({from: owner}).should.be.rejectedWith(EVMThrow) }) it('logs finalized', async function () { - await increaseTime(this.timeToEnd) + await increaseTimeTo(this.afterEndTime) const {logs} = await this.crowdsale.finalize({from: owner}) const event = logs.find(e => e.event === 'Finalized') should.exist(event) }) it('finishes minting of token', async function () { - await increaseTime(this.timeToEnd) + await increaseTimeTo(this.afterEndTime) await this.crowdsale.finalize({from: owner}) const finished = await this.token.mintingFinished() finished.should.equal(true) diff --git a/test/RefundableCrowdsale.js b/test/RefundableCrowdsale.js index 6f0fc39a78f..d3150a94fa0 100644 --- a/test/RefundableCrowdsale.js +++ b/test/RefundableCrowdsale.js @@ -1,7 +1,6 @@ import ether from './helpers/ether' import {advanceBlock} from './helpers/advanceToBlock' -import increaseTime from './helpers/increaseTime' -import {duration, increaseTimeHandicap} from './helpers/increaseTime' +import {increaseTimeTo, duration} from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -26,12 +25,9 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) { }) beforeEach(async function () { - this.timeToStart = duration.weeks(1); - this.crowdsalePeriod = duration.weeks(1); - this.timeToEnd = this.timeToStart + this.crowdsalePeriod + increaseTimeHandicap; - - this.startTime = latestTime().unix() + this.timeToStart; - this.endTime = this.startTime + this.crowdsalePeriod; + this.startTime = latestTime().unix() + duration.weeks(1) + this.endTime = this.startTime + duration.weeks(1) + this.afterEndTime = this.endTime + duration.seconds(1) this.crowdsale = await RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, goal, {from: owner}) }) @@ -46,21 +42,21 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) { it('should deny refunds before end', async function () { await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) - await increaseTime(this.timeToStart) + await increaseTimeTo(this.startTime) await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) }) it('should deny refunds after end if goal was reached', async function () { - await increaseTime(this.timeToStart) + await increaseTimeTo(this.startTime) await this.crowdsale.sendTransaction({value: goal, from: investor}) - await increaseTime(this.crowdsalePeriod + increaseTimeHandicap) + await increaseTimeTo(this.afterEndTime) await this.crowdsale.claimRefund({from: investor}).should.be.rejectedWith(EVMThrow) }) it('should allow refunds after end if goal was not reached', async function () { - await increaseTime(this.timeToStart) + await increaseTimeTo(this.startTime) await this.crowdsale.sendTransaction({value: lessThanGoal, from: investor}) - await increaseTime(this.crowdsalePeriod + increaseTimeHandicap) + await increaseTimeTo(this.afterEndTime) await this.crowdsale.finalize({from: owner}) @@ -73,9 +69,9 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor]) { }) it('should forward funds to wallet after end if goal was reached', async function () { - await increaseTime(this.timeToStart) + await increaseTimeTo(this.startTime) await this.crowdsale.sendTransaction({value: goal, from: investor}) - await increaseTime(this.crowdsalePeriod + increaseTimeHandicap) + await increaseTimeTo(this.afterEndTime) const pre = web3.eth.getBalance(wallet) await this.crowdsale.finalize({from: owner}) diff --git a/test/SampleCrowdsale.js b/test/SampleCrowdsale.js index dbcf2ba56ff..b17c15aeb49 100644 --- a/test/SampleCrowdsale.js +++ b/test/SampleCrowdsale.js @@ -1,7 +1,6 @@ import ether from './helpers/ether' import {advanceBlock} from './helpers/advanceToBlock' -import increaseTime from './helpers/increaseTime' -import {duration, increaseTimeHandicap} from './helpers/increaseTime' +import {increaseTimeTo, duration} from './helpers/increaseTime' import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' @@ -27,13 +26,9 @@ contract('Crowdsale', function ([owner, wallet, investor]) { }) beforeEach(async function () { - this.timeToStart = duration.weeks(1); - this.crowdsalePeriod = duration.weeks(1); - this.timeToEnd = this.timeToStart + this.crowdsalePeriod + increaseTimeHandicap; - - this.startTime = latestTime().unix() + this.timeToStart; - this.endTime = this.startTime + this.crowdsalePeriod; - + this.startTime = latestTime().unix() + duration.weeks(1); + this.endTime = this.startTime + duration.weeks(1); + this.afterEndTime = this.endTime + duration.seconds(1); this.crowdsale = await SampleCrowdsale.new(this.startTime, this.endTime, RATE, GOAL, CAP, wallet); this.token = SampleCrowdsaleToken.at(await this.crowdsale.token()); @@ -61,7 +56,7 @@ contract('Crowdsale', function ([owner, wallet, investor]) { const investmentAmount = ether(1); const expectedTokenAmount = RATE.mul(investmentAmount); - await increaseTime(this.timeToStart); + await increaseTimeTo(this.startTime); await this.crowdsale.buyTokens(investor, {value: investmentAmount, from: investor}).should.be.fulfilled; (await this.token.balanceOf(investor)).should.be.bignumber.equal(expectedTokenAmount); @@ -69,23 +64,23 @@ contract('Crowdsale', function ([owner, wallet, investor]) { }); it('should reject payments after end', async function () { - await increaseTime(this.timeToEnd); + await increaseTimeTo(this.afterEnd); await this.crowdsale.send(ether(1)).should.be.rejectedWith(EVMThrow); await this.crowdsale.buyTokens(investor, {value: ether(1), from: investor}).should.be.rejectedWith(EVMThrow); }); it('should reject payments over cap', async function () { - await increaseTime(this.timeToStart); + await increaseTimeTo(this.startTime); await this.crowdsale.send(CAP); await this.crowdsale.send(1).should.be.rejectedWith(EVMThrow); }); it('should allow finalization and transfer funds to wallet if the goal is reached', async function () { - await increaseTime(this.timeToStart); + await increaseTimeTo(this.startTime); await this.crowdsale.send(GOAL); const beforeFinalization = web3.eth.getBalance(wallet); - await increaseTime(this.crowdsalePeriod + increaseTimeHandicap); + await increaseTimeTo(this.afterEndTime); await this.crowdsale.finalize({from: owner}); const afterFinalization = web3.eth.getBalance(wallet); @@ -95,9 +90,9 @@ contract('Crowdsale', function ([owner, wallet, investor]) { it('should allow refunds if the goal is not reached', async function () { const balanceBeforeInvestment = web3.eth.getBalance(investor); - await increaseTime(this.timeToStart); + await increaseTimeTo(this.startTime); await this.crowdsale.sendTransaction({value: ether(1), from: investor, gasPrice: 0}); - await increaseTime(this.crowdsalePeriod + increaseTimeHandicap); + await increaseTimeTo(this.afterEndTime); await this.crowdsale.finalize({from: owner}); await this.crowdsale.claimRefund({from: investor, gasPrice: 0}).should.be.fulfilled; diff --git a/test/helpers/increaseTime.js b/test/helpers/increaseTime.js index 06f7d9c0bc3..5a6a8e2c284 100644 --- a/test/helpers/increaseTime.js +++ b/test/helpers/increaseTime.js @@ -1,4 +1,6 @@ -// Increases testrpc time by the passed duration (a moment.js instance) +import latestTime from './latestTime' + +// Increases testrpc time by the passed duration in seconds export default function increaseTime(duration) { const id = Date.now() @@ -22,12 +24,24 @@ export default function increaseTime(duration) { }) } +/** + * Beware that due to the need of calling two separate testrpc methods and rpc calls overhead + * it's hard to increase time precisely to a target point so design your test to tolerate + * small fluctuations from time to time. + * + * @param target time in seconds + */ +export function increaseTimeTo(target) { + let now = latestTime().unix(); + if (target < now) throw Error(`Cannot increase current time(${now}) to a moment in the past(${target})`); + let diff = target - now; + return increaseTime(diff); +} + export const duration = { seconds: function(val) { return val}, minutes: function(val) { return val * this.seconds(60) }, hours: function(val) { return val * this.minutes(60) }, days: function(val) { return val * this.hours(24) }, weeks: function(val) { return val * this.days(7) } -}; - -export const increaseTimeHandicap = duration.seconds(10); \ No newline at end of file +}; \ No newline at end of file