Add TimedCrowdsale::_extendTime (#1636)
* Add TimedCrowdsale::_extendTime * Add tests for TimedCrowdsale extending method * Reverse event arguments order * Rename method argument * Refactor TimedCrowdsale test * Simplify TimedCrowdsaleImpl * Fix extendTime method behaviour to deny TimedCrowdsale re-opening after it was ended * Append chengelog * Update CHANGELOG.md Co-Authored-By: k06a <k06aaa@gmail.com> * Update contracts/crowdsale/validation/TimedCrowdsale.sol Co-Authored-By: k06a <k06aaa@gmail.com> * Improve tests
This commit is contained in:
committed by
Nicolás Venturo
parent
3772233cf5
commit
352ec94579
@ -7,6 +7,7 @@
|
|||||||
* `ERC20Metadata`: added internal `_setTokenURI(string memory tokenURI)`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618))
|
* `ERC20Metadata`: added internal `_setTokenURI(string memory tokenURI)`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618))
|
||||||
* `ERC20Snapshot`: create snapshots on demand of the token balances and total supply, to later retrieve and e.g. calculate dividends at a past time. ([#1617](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1617))
|
* `ERC20Snapshot`: create snapshots on demand of the token balances and total supply, to later retrieve and e.g. calculate dividends at a past time. ([#1617](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1617))
|
||||||
* `SafeERC20`: `ERC20` contracts with no return value (i.e. that revert on failure) are now supported. ([#1655](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/))
|
* `SafeERC20`: `ERC20` contracts with no return value (i.e. that revert on failure) are now supported. ([#1655](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/))
|
||||||
|
* `TimedCrowdsale`: added internal `_extendTime(uint256 newClosingTime)` as well as `TimedCrowdsaleExtended(uint256 prevClosingTime, uint256 newClosingTime)` event allowing to extend the crowdsale, as long as it hasn't already closed.
|
||||||
|
|
||||||
### Improvements:
|
### Improvements:
|
||||||
* Upgraded the minimum compiler version to v0.5.2: this removes many Solidity warnings that were false positives. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606))
|
* Upgraded the minimum compiler version to v0.5.2: this removes many Solidity warnings that were false positives. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606))
|
||||||
|
|||||||
@ -13,6 +13,13 @@ contract TimedCrowdsale is Crowdsale {
|
|||||||
uint256 private _openingTime;
|
uint256 private _openingTime;
|
||||||
uint256 private _closingTime;
|
uint256 private _closingTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event for crowdsale extending
|
||||||
|
* @param newClosingTime new closing time
|
||||||
|
* @param prevClosingTime old closing time
|
||||||
|
*/
|
||||||
|
event TimedCrowdsaleExtended(uint256 prevClosingTime, uint256 newClosingTime);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Reverts if not in crowdsale time range.
|
* @dev Reverts if not in crowdsale time range.
|
||||||
*/
|
*/
|
||||||
@ -74,4 +81,16 @@ contract TimedCrowdsale is Crowdsale {
|
|||||||
function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal onlyWhileOpen view {
|
function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal onlyWhileOpen view {
|
||||||
super._preValidatePurchase(beneficiary, weiAmount);
|
super._preValidatePurchase(beneficiary, weiAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Extend crowdsale
|
||||||
|
* @param newClosingTime Crowdsale closing time
|
||||||
|
*/
|
||||||
|
function _extendTime(uint256 newClosingTime) internal {
|
||||||
|
require(!hasClosed());
|
||||||
|
require(newClosingTime > _closingTime);
|
||||||
|
|
||||||
|
emit TimedCrowdsaleExtended(_closingTime, newClosingTime);
|
||||||
|
_closingTime = newClosingTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,4 +11,8 @@ contract TimedCrowdsaleImpl is TimedCrowdsale {
|
|||||||
{
|
{
|
||||||
// solhint-disable-previous-line no-empty-blocks
|
// solhint-disable-previous-line no-empty-blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extendTime(uint256 closingTime) public {
|
||||||
|
_extendTime(closingTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
const { BN, ether, shouldFail, time } = require('openzeppelin-test-helpers');
|
const { BN, ether, expectEvent, shouldFail, time } = require('openzeppelin-test-helpers');
|
||||||
|
|
||||||
const TimedCrowdsaleImpl = artifacts.require('TimedCrowdsaleImpl');
|
const TimedCrowdsaleImpl = artifacts.require('TimedCrowdsaleImpl');
|
||||||
const SimpleToken = artifacts.require('SimpleToken');
|
const SimpleToken = artifacts.require('SimpleToken');
|
||||||
@ -73,5 +73,62 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) {
|
|||||||
await shouldFail.reverting(this.crowdsale.buyTokens(investor, { value: value, from: purchaser }));
|
await shouldFail.reverting(this.crowdsale.buyTokens(investor, { value: value, from: purchaser }));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('extending closing time', function () {
|
||||||
|
it('should not reduce duration', async function () {
|
||||||
|
// Same date
|
||||||
|
await shouldFail.reverting(this.crowdsale.extendTime(this.closingTime));
|
||||||
|
|
||||||
|
// Prescending date
|
||||||
|
const newClosingTime = this.closingTime.sub(time.duration.seconds(1));
|
||||||
|
await shouldFail.reverting(this.crowdsale.extendTime(newClosingTime));
|
||||||
|
});
|
||||||
|
|
||||||
|
context('before crowdsale start', function () {
|
||||||
|
beforeEach(async function () {
|
||||||
|
(await this.crowdsale.isOpen()).should.equal(false);
|
||||||
|
await shouldFail.reverting(this.crowdsale.send(value));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it extends end time', async function () {
|
||||||
|
const newClosingTime = this.closingTime.add(time.duration.days(1));
|
||||||
|
const { logs } = await this.crowdsale.extendTime(newClosingTime);
|
||||||
|
expectEvent.inLogs(logs, 'TimedCrowdsaleExtended', {
|
||||||
|
prevClosingTime: this.closingTime,
|
||||||
|
newClosingTime: newClosingTime,
|
||||||
|
});
|
||||||
|
(await this.crowdsale.closingTime()).should.be.bignumber.equal(newClosingTime);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('after crowdsale start', function () {
|
||||||
|
beforeEach(async function () {
|
||||||
|
await time.increaseTo(this.openingTime);
|
||||||
|
(await this.crowdsale.isOpen()).should.equal(true);
|
||||||
|
await this.crowdsale.send(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it extends end time', async function () {
|
||||||
|
const newClosingTime = this.closingTime.add(time.duration.days(1));
|
||||||
|
const { logs } = await this.crowdsale.extendTime(newClosingTime);
|
||||||
|
expectEvent.inLogs(logs, 'TimedCrowdsaleExtended', {
|
||||||
|
prevClosingTime: this.closingTime,
|
||||||
|
newClosingTime: newClosingTime,
|
||||||
|
});
|
||||||
|
(await this.crowdsale.closingTime()).should.be.bignumber.equal(newClosingTime);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('after crowdsale end', function () {
|
||||||
|
beforeEach(async function () {
|
||||||
|
await time.increaseTo(this.afterClosingTime);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it reverts', async function () {
|
||||||
|
const newClosingTime = await time.latest();
|
||||||
|
await shouldFail.reverting(this.crowdsale.extendTime(newClosingTime));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user