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/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/CappedCrowdsale.js b/test/CappedCrowdsale.js index 753da5c1808..9dd027b3581 100644 --- a/test/CappedCrowdsale.js +++ b/test/CappedCrowdsale.js @@ -1,5 +1,7 @@ import ether from './helpers/ether' -import advanceToBlock from './helpers/advanceToBlock' +import {advanceBlock} from './helpers/advanceToBlock' +import {increaseTimeTo, duration} from './helpers/increaseTime' +import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' const BigNumber = web3.BigNumber @@ -19,28 +21,32 @@ 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 advanceBlock() + }) beforeEach(async function () { - this.startBlock = web3.eth.blockNumber + 10 - this.endBlock = web3.eth.blockNumber + 20 + this.startTime = latestTime().unix() + duration.weeks(1); + this.endTime = this.startTime + duration.weeks(1); - 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 increaseTimeTo(this.startTime) }) it('should accept payments within cap', async function () { @@ -62,7 +68,7 @@ contract('CappedCrowdsale', function ([_, wallet]) { describe('ending', function () { beforeEach(async function () { - await advanceToBlock(this.startBlock - 1) + 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 5160fea421b..e3abe197523 100644 --- a/test/Crowdsale.js +++ b/test/Crowdsale.js @@ -1,5 +1,7 @@ import ether from './helpers/ether' -import advanceToBlock from './helpers/advanceToBlock' +import {advanceBlock} from './helpers/advanceToBlock' +import {increaseTimeTo, duration} from './helpers/increaseTime' +import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' const BigNumber = web3.BigNumber @@ -19,11 +21,18 @@ 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 advanceBlock() + }) + beforeEach(async function () { - this.startBlock = web3.eth.blockNumber + 10 - this.endBlock = web3.eth.blockNumber + 20 + this.startTime = latestTime().unix() + duration.weeks(1); + this.endTime = this.startTime + duration.weeks(1); + this.afterEndTime = this.endTime + duration.seconds(1) + - 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 +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 advanceToBlock(this.endBlock + 1) + await increaseTimeTo(this.afterEndTime) ended = await this.crowdsale.hasEnded() ended.should.equal(true) }) @@ -49,13 +58,13 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { }) it('should accept payments after start', async function () { - await advanceToBlock(this.startBlock - 1) + 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 advanceToBlock(this.endBlock) + 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) }) @@ -65,7 +74,7 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { describe('high-level purchase', function () { beforeEach(async function() { - await advanceToBlock(this.startBlock) + await increaseTimeTo(this.startTime) }) it('should log purchase', async function () { @@ -104,33 +113,33 @@ contract('Crowdsale', function ([_, investor, wallet, purchaser]) { describe('low-level purchase', function () { beforeEach(async function() { - await advanceToBlock(this.startBlock) + await increaseTimeTo(this.startTime) }) - + 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 53224bb7652..a7e76bfbf3f 100644 --- a/test/FinalizableCrowdsale.js +++ b/test/FinalizableCrowdsale.js @@ -1,4 +1,6 @@ -import advanceToBlock from './helpers/advanceToBlock' +import {advanceBlock} from './helpers/advanceToBlock' +import {increaseTimeTo, duration} from './helpers/increaseTime' +import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' const BigNumber = web3.BigNumber @@ -15,11 +17,18 @@ 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 advanceBlock() + }) + beforeEach(async function () { - this.startBlock = web3.eth.blockNumber + 10 - this.endBlock = web3.eth.blockNumber + 20 + this.startTime = latestTime().unix() + duration.weeks(1) + this.endTime = this.startTime + duration.weeks(1) + this.afterEndTime = this.endTime + duration.seconds(1) + - 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 +38,30 @@ contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { }) it('cannot be finalized by third party after ending', async function () { - await advanceToBlock(this.endBlock) + 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 advanceToBlock(this.endBlock) + await increaseTimeTo(this.afterEndTime) await this.crowdsale.finalize({from: owner}).should.be.fulfilled }) it('cannot be finalized twice', async function () { - await advanceToBlock(this.endBlock + 1) + 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 advanceToBlock(this.endBlock) + 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 advanceToBlock(this.endBlock) + 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 f1d6fda6830..d3150a94fa0 100644 --- a/test/RefundableCrowdsale.js +++ b/test/RefundableCrowdsale.js @@ -1,5 +1,7 @@ import ether from './helpers/ether' -import advanceToBlock from './helpers/advanceToBlock' +import {advanceBlock} from './helpers/advanceToBlock' +import {increaseTimeTo, duration} from './helpers/increaseTime' +import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' const BigNumber = web3.BigNumber @@ -17,39 +19,44 @@ 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 advanceBlock() + }) + + beforeEach(async function () { + 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}) + }) + 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 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 advanceToBlock(this.startBlock - 1) + await increaseTimeTo(this.startTime) await this.crowdsale.sendTransaction({value: goal, from: investor}) - await advanceToBlock(this.endBlock) + 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 advanceToBlock(this.startBlock - 1) + await increaseTimeTo(this.startTime) await this.crowdsale.sendTransaction({value: lessThanGoal, from: investor}) - await advanceToBlock(this.endBlock) + await increaseTimeTo(this.afterEndTime) 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 increaseTimeTo(this.startTime) await this.crowdsale.sendTransaction({value: goal, from: investor}) - await advanceToBlock(this.endBlock) + 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 a589194f7c5..b17c15aeb49 100644 --- a/test/SampleCrowdsale.js +++ b/test/SampleCrowdsale.js @@ -1,5 +1,7 @@ import ether from './helpers/ether' -import advanceToBlock from './helpers/advanceToBlock' +import {advanceBlock} from './helpers/advanceToBlock' +import {increaseTimeTo, duration} from './helpers/increaseTime' +import latestTime from './helpers/latestTime' import EVMThrow from './helpers/EVMThrow' const BigNumber = web3.BigNumber; @@ -18,11 +20,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 advanceBlock() + }) + beforeEach(async function () { - this.startBlock = web3.eth.blockNumber + 10; - this.endBlock = web3.eth.blockNumber + 20; + 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.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 +39,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 +56,7 @@ contract('Crowdsale', function ([owner, wallet, investor]) { const investmentAmount = ether(1); const expectedTokenAmount = RATE.mul(investmentAmount); - await advanceToBlock(this.startBlock - 1); + 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); @@ -56,22 +64,23 @@ contract('Crowdsale', function ([owner, wallet, investor]) { }); it('should reject payments after end', async function () { - await advanceToBlock(this.endBlock); + 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 advanceToBlock(this.startBlock - 1); + 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 advanceToBlock(this.endBlock - 1); + await increaseTimeTo(this.startTime); await this.crowdsale.send(GOAL); const beforeFinalization = web3.eth.getBalance(wallet); + await increaseTimeTo(this.afterEndTime); await this.crowdsale.finalize({from: owner}); const afterFinalization = web3.eth.getBalance(wallet); @@ -81,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 advanceToBlock(this.startBlock - 1); + await increaseTimeTo(this.startTime); await this.crowdsale.sendTransaction({value: ether(1), from: investor, gasPrice: 0}); - await advanceToBlock(this.endBlock); + 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/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/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) { } diff --git a/test/helpers/increaseTime.js b/test/helpers/increaseTime.js index cd1a756fd62..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() @@ -6,7 +8,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 +23,25 @@ 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) } +}; \ No newline at end of file