Migrate Contracts to Solidity v0.6 (#2080)
* Initial migration to Solidity 0.6.x - v3.0 first steps (#2063) * Initial migration, missing GSN, 721, 777 and Crowdsales. * Add _beforeTokenOperation and _afterTokenOperation. * Add documentation for hooks. * Add hooks doc * Add missing drafts * Add back ERC721 with hooks * Bring back ERC777 * Notes on hooks * Bring back GSN * Make functions virtual * Make GSN overrides explicit * Fix ERC20Pausable tests * Remove virtual from some view functions * Update linter * Delete examples * Remove unnecessary virtual * Remove roles from Pausable * Remove roles * Remove users of roles * Adapt ERC20 tests * Fix ERC721 tests * Add all ERC721 hooks * Add ERC777 hooks * Fix remaining tests * Bump compiler version * Move 721BurnableMock into mocks directory * Remove _before hooks * Fix tests * Upgrade linter * Put modifiers last * Remove _beforeTokenApproval and _beforeOperatorApproval hooks
This commit is contained in:
@ -1,15 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior');
|
||||
const CapperRoleMock = contract.fromArtifact('CapperRoleMock');
|
||||
|
||||
describe('CapperRole', function () {
|
||||
const [ capper, otherCapper, ...otherAccounts ] = accounts;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.contract = await CapperRoleMock.new({ from: capper });
|
||||
await this.contract.addCapper(otherCapper, { from: capper });
|
||||
});
|
||||
|
||||
shouldBehaveLikePublicRole(capper, otherCapper, otherAccounts, 'capper');
|
||||
});
|
||||
@ -1,15 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior');
|
||||
const MinterRoleMock = contract.fromArtifact('MinterRoleMock');
|
||||
|
||||
describe('MinterRole', function () {
|
||||
const [ minter, otherMinter, ...otherAccounts ] = accounts;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.contract = await MinterRoleMock.new({ from: minter });
|
||||
await this.contract.addMinter(otherMinter, { from: minter });
|
||||
});
|
||||
|
||||
shouldBehaveLikePublicRole(minter, otherMinter, otherAccounts, 'minter');
|
||||
});
|
||||
@ -1,15 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior');
|
||||
const PauserRoleMock = contract.fromArtifact('PauserRoleMock');
|
||||
|
||||
describe('PauserRole', function () {
|
||||
const [ pauser, otherPauser, ...otherAccounts ] = accounts;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.contract = await PauserRoleMock.new({ from: pauser });
|
||||
await this.contract.addPauser(otherPauser, { from: pauser });
|
||||
});
|
||||
|
||||
shouldBehaveLikePublicRole(pauser, otherPauser, otherAccounts, 'pauser');
|
||||
});
|
||||
@ -1,15 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior');
|
||||
const SignerRoleMock = contract.fromArtifact('SignerRoleMock');
|
||||
|
||||
describe('SignerRole', function () {
|
||||
const [ signer, otherSigner, ...otherAccounts ] = accounts;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.contract = await SignerRoleMock.new({ from: signer });
|
||||
await this.contract.addSigner(otherSigner, { from: signer });
|
||||
});
|
||||
|
||||
shouldBehaveLikePublicRole(signer, otherSigner, otherAccounts, 'signer');
|
||||
});
|
||||
@ -1,15 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior');
|
||||
const WhitelistAdminRoleMock = contract.fromArtifact('WhitelistAdminRoleMock');
|
||||
|
||||
describe('WhitelistAdminRole', function () {
|
||||
const [ whitelistAdmin, otherWhitelistAdmin, ...otherAccounts ] = accounts;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.contract = await WhitelistAdminRoleMock.new({ from: whitelistAdmin });
|
||||
await this.contract.addWhitelistAdmin(otherWhitelistAdmin, { from: whitelistAdmin });
|
||||
});
|
||||
|
||||
shouldBehaveLikePublicRole(whitelistAdmin, otherWhitelistAdmin, otherAccounts, 'whitelistAdmin');
|
||||
});
|
||||
@ -1,16 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior');
|
||||
const WhitelistedRoleMock = contract.fromArtifact('WhitelistedRoleMock');
|
||||
|
||||
describe('WhitelistedRole', function () {
|
||||
const [ whitelisted, otherWhitelisted, whitelistAdmin, ...otherAccounts ] = accounts;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.contract = await WhitelistedRoleMock.new({ from: whitelistAdmin });
|
||||
await this.contract.addWhitelisted(whitelisted, { from: whitelistAdmin });
|
||||
await this.contract.addWhitelisted(otherWhitelisted, { from: whitelistAdmin });
|
||||
});
|
||||
|
||||
shouldBehaveLikePublicRole(whitelisted, otherWhitelisted, otherAccounts, 'whitelisted', whitelistAdmin);
|
||||
});
|
||||
@ -1,89 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { balance, BN, constants, ether, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { ZERO_ADDRESS } = constants;
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const AllowanceCrowdsaleImpl = contract.fromArtifact('AllowanceCrowdsaleImpl');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
|
||||
describe('AllowanceCrowdsale', function () {
|
||||
const [ investor, wallet, purchaser, tokenWallet ] = accounts;
|
||||
|
||||
const rate = new BN('1');
|
||||
const value = ether('0.42');
|
||||
const expectedTokenAmount = rate.mul(value);
|
||||
const tokenAllowance = new BN('10').pow(new BN('22'));
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await SimpleToken.new({ from: tokenWallet });
|
||||
this.crowdsale = await AllowanceCrowdsaleImpl.new(rate, wallet, this.token.address, tokenWallet);
|
||||
await this.token.approve(this.crowdsale.address, tokenAllowance, { from: tokenWallet });
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
it('should have token wallet', async function () {
|
||||
expect(await this.crowdsale.tokenWallet()).to.equal(tokenWallet);
|
||||
});
|
||||
|
||||
it('should accept sends', async function () {
|
||||
await this.crowdsale.send(value);
|
||||
});
|
||||
|
||||
it('should accept payments', async function () {
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
});
|
||||
});
|
||||
|
||||
describe('high-level purchase', function () {
|
||||
it('should log purchase', async function () {
|
||||
const { logs } = await this.crowdsale.sendTransaction({ value: value, from: investor });
|
||||
expectEvent.inLogs(logs, 'TokensPurchased', {
|
||||
purchaser: investor,
|
||||
beneficiary: investor,
|
||||
value: value,
|
||||
amount: expectedTokenAmount,
|
||||
});
|
||||
});
|
||||
|
||||
it('should assign tokens to sender', async function () {
|
||||
await this.crowdsale.sendTransaction({ value: value, from: investor });
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount);
|
||||
});
|
||||
|
||||
it('should forward funds to wallet', async function () {
|
||||
const balanceTracker = await balance.tracker(wallet);
|
||||
await this.crowdsale.sendTransaction({ value, from: investor });
|
||||
expect(await balanceTracker.delta()).to.be.bignumber.equal(value);
|
||||
});
|
||||
});
|
||||
|
||||
describe('check remaining allowance', function () {
|
||||
it('should report correct allowance left', async function () {
|
||||
const remainingAllowance = tokenAllowance.sub(expectedTokenAmount);
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
expect(await this.crowdsale.remainingTokens()).to.be.bignumber.equal(remainingAllowance);
|
||||
});
|
||||
|
||||
context('when the allowance is larger than the token amount', function () {
|
||||
beforeEach(async function () {
|
||||
const amount = await this.token.balanceOf(tokenWallet);
|
||||
await this.token.approve(this.crowdsale.address, amount.addn(1), { from: tokenWallet });
|
||||
});
|
||||
|
||||
it('should report the amount instead of the allowance', async function () {
|
||||
expect(await this.crowdsale.remainingTokens()).to.be.bignumber.equal(await this.token.balanceOf(tokenWallet));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when token wallet is the zero address', function () {
|
||||
it('creation reverts', async function () {
|
||||
this.token = await SimpleToken.new({ from: tokenWallet });
|
||||
await expectRevert(AllowanceCrowdsaleImpl.new(rate, wallet, this.token.address, ZERO_ADDRESS),
|
||||
'AllowanceCrowdsale: token wallet is the zero address'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,67 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const CappedCrowdsaleImpl = contract.fromArtifact('CappedCrowdsaleImpl');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
|
||||
describe('CappedCrowdsale', function () {
|
||||
const [ wallet ] = accounts;
|
||||
|
||||
const rate = new BN('1');
|
||||
const cap = ether('100');
|
||||
const lessThanCap = ether('60');
|
||||
const tokenSupply = new BN('10').pow(new BN('22'));
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await SimpleToken.new();
|
||||
});
|
||||
|
||||
it('rejects a cap of zero', async function () {
|
||||
await expectRevert(CappedCrowdsaleImpl.new(rate, wallet, this.token.address, 0),
|
||||
'CappedCrowdsale: cap is 0'
|
||||
);
|
||||
});
|
||||
|
||||
context('with crowdsale', function () {
|
||||
beforeEach(async function () {
|
||||
this.crowdsale = await CappedCrowdsaleImpl.new(rate, wallet, this.token.address, cap);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
it('should accept payments within cap', async function () {
|
||||
await this.crowdsale.send(cap.sub(lessThanCap));
|
||||
await this.crowdsale.send(lessThanCap);
|
||||
});
|
||||
|
||||
it('should reject payments outside cap', async function () {
|
||||
await this.crowdsale.send(cap);
|
||||
await expectRevert(this.crowdsale.send(1), 'CappedCrowdsale: cap exceeded');
|
||||
});
|
||||
|
||||
it('should reject payments that exceed cap', async function () {
|
||||
await expectRevert(this.crowdsale.send(cap.addn(1)), 'CappedCrowdsale: cap exceeded');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ending', function () {
|
||||
it('should not reach cap if sent under cap', async function () {
|
||||
await this.crowdsale.send(lessThanCap);
|
||||
expect(await this.crowdsale.capReached()).to.equal(false);
|
||||
});
|
||||
|
||||
it('should not reach cap if sent just under cap', async function () {
|
||||
await this.crowdsale.send(cap.subn(1));
|
||||
expect(await this.crowdsale.capReached()).to.equal(false);
|
||||
});
|
||||
|
||||
it('should reach cap if cap sent', async function () {
|
||||
await this.crowdsale.send(cap);
|
||||
expect(await this.crowdsale.capReached()).to.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,129 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { balance, BN, constants, ether, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { ZERO_ADDRESS } = constants;
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const Crowdsale = contract.fromArtifact('CrowdsaleMock');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
|
||||
describe('Crowdsale', function () {
|
||||
const [ investor, wallet, purchaser ] = accounts;
|
||||
|
||||
const rate = new BN(1);
|
||||
const value = ether('42');
|
||||
const tokenSupply = new BN('10').pow(new BN('22'));
|
||||
const expectedTokenAmount = rate.mul(value);
|
||||
|
||||
it('requires a non-null token', async function () {
|
||||
await expectRevert(
|
||||
Crowdsale.new(rate, wallet, ZERO_ADDRESS),
|
||||
'Crowdsale: token is the zero address'
|
||||
);
|
||||
});
|
||||
|
||||
context('with token', async function () {
|
||||
beforeEach(async function () {
|
||||
this.token = await SimpleToken.new();
|
||||
});
|
||||
|
||||
it('requires a non-zero rate', async function () {
|
||||
await expectRevert(
|
||||
Crowdsale.new(0, wallet, this.token.address), 'Crowdsale: rate is 0'
|
||||
);
|
||||
});
|
||||
|
||||
it('requires a non-null wallet', async function () {
|
||||
await expectRevert(
|
||||
Crowdsale.new(rate, ZERO_ADDRESS, this.token.address), 'Crowdsale: wallet is the zero address'
|
||||
);
|
||||
});
|
||||
|
||||
context('once deployed', async function () {
|
||||
beforeEach(async function () {
|
||||
this.crowdsale = await Crowdsale.new(rate, wallet, this.token.address);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
describe('bare payments', function () {
|
||||
it('should accept payments', async function () {
|
||||
await this.crowdsale.send(value, { from: purchaser });
|
||||
});
|
||||
|
||||
it('reverts on zero-valued payments', async function () {
|
||||
await expectRevert(
|
||||
this.crowdsale.send(0, { from: purchaser }), 'Crowdsale: weiAmount is 0'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('buyTokens', function () {
|
||||
it('should accept payments', async function () {
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
});
|
||||
|
||||
it('reverts on zero-valued payments', async function () {
|
||||
await expectRevert(
|
||||
this.crowdsale.buyTokens(investor, { value: 0, from: purchaser }), 'Crowdsale: weiAmount is 0'
|
||||
);
|
||||
});
|
||||
|
||||
it('requires a non-null beneficiary', async function () {
|
||||
await expectRevert(
|
||||
this.crowdsale.buyTokens(ZERO_ADDRESS, { value: value, from: purchaser }),
|
||||
'Crowdsale: beneficiary is the zero address'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('high-level purchase', function () {
|
||||
it('should log purchase', async function () {
|
||||
const { logs } = await this.crowdsale.sendTransaction({ value: value, from: investor });
|
||||
expectEvent.inLogs(logs, 'TokensPurchased', {
|
||||
purchaser: investor,
|
||||
beneficiary: investor,
|
||||
value: value,
|
||||
amount: expectedTokenAmount,
|
||||
});
|
||||
});
|
||||
|
||||
it('should assign tokens to sender', async function () {
|
||||
await this.crowdsale.sendTransaction({ value: value, from: investor });
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount);
|
||||
});
|
||||
|
||||
it('should forward funds to wallet', async function () {
|
||||
const balanceTracker = await balance.tracker(wallet);
|
||||
await this.crowdsale.sendTransaction({ value, from: investor });
|
||||
expect(await balanceTracker.delta()).to.be.bignumber.equal(value);
|
||||
});
|
||||
});
|
||||
|
||||
describe('low-level purchase', function () {
|
||||
it('should log purchase', async function () {
|
||||
const { logs } = await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
expectEvent.inLogs(logs, 'TokensPurchased', {
|
||||
purchaser: purchaser,
|
||||
beneficiary: investor,
|
||||
value: value,
|
||||
amount: expectedTokenAmount,
|
||||
});
|
||||
});
|
||||
|
||||
it('should assign tokens to beneficiary', async function () {
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount);
|
||||
});
|
||||
|
||||
it('should forward funds to wallet', async function () {
|
||||
const balanceTracker = await balance.tracker(wallet);
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
expect(await balanceTracker.delta()).to.be.bignumber.equal(value);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,53 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const FinalizableCrowdsaleImpl = contract.fromArtifact('FinalizableCrowdsaleImpl');
|
||||
const ERC20 = contract.fromArtifact('ERC20');
|
||||
|
||||
describe('FinalizableCrowdsale', function () {
|
||||
const [ wallet, other ] = accounts;
|
||||
|
||||
const rate = new BN('1000');
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache
|
||||
await time.advanceBlock();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.openingTime = (await time.latest()).add(time.duration.weeks(1));
|
||||
this.closingTime = this.openingTime.add(time.duration.weeks(1));
|
||||
this.afterClosingTime = this.closingTime.add(time.duration.seconds(1));
|
||||
|
||||
this.token = await ERC20.new();
|
||||
this.crowdsale = await FinalizableCrowdsaleImpl.new(
|
||||
this.openingTime, this.closingTime, rate, wallet, this.token.address
|
||||
);
|
||||
});
|
||||
|
||||
it('cannot be finalized before ending', async function () {
|
||||
await expectRevert(this.crowdsale.finalize({ from: other }),
|
||||
'FinalizableCrowdsale: not closed'
|
||||
);
|
||||
});
|
||||
|
||||
it('can be finalized by anyone after ending', async function () {
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
await this.crowdsale.finalize({ from: other });
|
||||
});
|
||||
|
||||
it('cannot be finalized twice', async function () {
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
await this.crowdsale.finalize({ from: other });
|
||||
await expectRevert(this.crowdsale.finalize({ from: other }),
|
||||
'FinalizableCrowdsale: already finalized'
|
||||
);
|
||||
});
|
||||
|
||||
it('logs finalized', async function () {
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
const { logs } = await this.crowdsale.finalize({ from: other });
|
||||
expectEvent.inLogs(logs, 'CrowdsaleFinalized');
|
||||
});
|
||||
});
|
||||
@ -1,123 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, ether, expectRevert, time } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const IncreasingPriceCrowdsaleImpl = contract.fromArtifact('IncreasingPriceCrowdsaleImpl');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
|
||||
describe('IncreasingPriceCrowdsale', function () {
|
||||
const [ investor, wallet, purchaser ] = accounts;
|
||||
|
||||
const value = ether('1');
|
||||
const tokenSupply = new BN('10').pow(new BN('22'));
|
||||
|
||||
describe('rate during crowdsale should change at a fixed step every block', async function () {
|
||||
const initialRate = new BN('9166');
|
||||
const finalRate = new BN('5500');
|
||||
const rateAtTime150 = new BN('9166');
|
||||
const rateAtTime300 = new BN('9165');
|
||||
const rateAtTime1500 = new BN('9157');
|
||||
const rateAtTime30 = new BN('9166');
|
||||
const rateAtTime150000 = new BN('8257');
|
||||
const rateAtTime450000 = new BN('6439');
|
||||
|
||||
beforeEach(async function () {
|
||||
await time.advanceBlock();
|
||||
this.startTime = (await time.latest()).add(time.duration.weeks(1));
|
||||
this.closingTime = this.startTime.add(time.duration.weeks(1));
|
||||
this.afterClosingTime = this.closingTime.add(time.duration.seconds(1));
|
||||
this.token = await SimpleToken.new();
|
||||
});
|
||||
|
||||
it('reverts with a final rate larger than the initial rate', async function () {
|
||||
await expectRevert(IncreasingPriceCrowdsaleImpl.new(
|
||||
this.startTime, this.closingTime, wallet, this.token.address, initialRate, initialRate.addn(1)
|
||||
), 'IncreasingPriceCrowdsale: initial rate is not greater than final rate');
|
||||
});
|
||||
|
||||
it('reverts with a final rate equal to the initial rate', async function () {
|
||||
await expectRevert(IncreasingPriceCrowdsaleImpl.new(
|
||||
this.startTime, this.closingTime, wallet, this.token.address, initialRate, initialRate
|
||||
), 'IncreasingPriceCrowdsale: initial rate is not greater than final rate');
|
||||
});
|
||||
|
||||
it('reverts with a final rate of zero', async function () {
|
||||
await expectRevert(IncreasingPriceCrowdsaleImpl.new(
|
||||
this.startTime, this.closingTime, wallet, this.token.address, initialRate, 0
|
||||
), 'IncreasingPriceCrowdsale: final rate is 0');
|
||||
});
|
||||
|
||||
context('with crowdsale', function () {
|
||||
beforeEach(async function () {
|
||||
this.crowdsale = await IncreasingPriceCrowdsaleImpl.new(
|
||||
this.startTime, this.closingTime, wallet, this.token.address, initialRate, finalRate
|
||||
);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
it('should have initial and final rate', async function () {
|
||||
expect(await this.crowdsale.initialRate()).to.be.bignumber.equal(initialRate);
|
||||
expect(await this.crowdsale.finalRate()).to.be.bignumber.equal(finalRate);
|
||||
});
|
||||
|
||||
it('reverts when the base Crowdsale\'s rate function is called', async function () {
|
||||
await expectRevert(this.crowdsale.rate(),
|
||||
'IncreasingPriceCrowdsale: rate() called'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns a rate of 0 before the crowdsale starts', async function () {
|
||||
expect(await this.crowdsale.getCurrentRate()).to.be.bignumber.equal('0');
|
||||
});
|
||||
|
||||
it('returns a rate of 0 after the crowdsale ends', async function () {
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
expect(await this.crowdsale.getCurrentRate()).to.be.bignumber.equal('0');
|
||||
});
|
||||
|
||||
it('at start', async function () {
|
||||
await time.increaseTo(this.startTime);
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(initialRate));
|
||||
});
|
||||
|
||||
it('at time 150', async function () {
|
||||
await time.increaseTo(this.startTime.addn(150));
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime150));
|
||||
});
|
||||
|
||||
it('at time 300', async function () {
|
||||
await time.increaseTo(this.startTime.addn(300));
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime300));
|
||||
});
|
||||
|
||||
it('at time 1500', async function () {
|
||||
await time.increaseTo(this.startTime.addn(1500));
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime1500));
|
||||
});
|
||||
|
||||
it('at time 30', async function () {
|
||||
await time.increaseTo(this.startTime.addn(30));
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime30));
|
||||
});
|
||||
|
||||
it('at time 150000', async function () {
|
||||
await time.increaseTo(this.startTime.addn(150000));
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime150000));
|
||||
});
|
||||
|
||||
it('at time 450000', async function () {
|
||||
await time.increaseTo(this.startTime.addn(450000));
|
||||
await this.crowdsale.buyTokens(investor, { value, from: purchaser });
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value.mul(rateAtTime450000));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,102 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const IndividuallyCappedCrowdsaleImpl = contract.fromArtifact('IndividuallyCappedCrowdsaleImpl');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
const { shouldBehaveLikePublicRole } = require('../behaviors/access/roles/PublicRole.behavior');
|
||||
|
||||
describe('IndividuallyCappedCrowdsale', function () {
|
||||
const [ capper, otherCapper, wallet, alice, bob, charlie, other, ...otherAccounts ] = accounts;
|
||||
|
||||
const rate = new BN(1);
|
||||
const capAlice = ether('10');
|
||||
const capBob = ether('2');
|
||||
const lessThanCapAlice = ether('6');
|
||||
const lessThanCapBoth = ether('1');
|
||||
const tokenSupply = new BN('10').pow(new BN('22'));
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await SimpleToken.new();
|
||||
this.crowdsale = await IndividuallyCappedCrowdsaleImpl.new(rate, wallet, this.token.address, { from: capper });
|
||||
});
|
||||
|
||||
describe('capper role', function () {
|
||||
beforeEach(async function () {
|
||||
this.contract = this.crowdsale;
|
||||
await this.contract.addCapper(otherCapper, { from: capper });
|
||||
});
|
||||
|
||||
shouldBehaveLikePublicRole(capper, otherCapper, otherAccounts, 'capper');
|
||||
});
|
||||
|
||||
describe('individual caps', function () {
|
||||
it('sets a cap when the sender is a capper', async function () {
|
||||
await this.crowdsale.setCap(alice, capAlice, { from: capper });
|
||||
expect(await this.crowdsale.getCap(alice)).to.be.bignumber.equal(capAlice);
|
||||
});
|
||||
|
||||
it('reverts when a non-capper sets a cap', async function () {
|
||||
await expectRevert(this.crowdsale.setCap(alice, capAlice, { from: other }),
|
||||
'CapperRole: caller does not have the Capper role'
|
||||
);
|
||||
});
|
||||
|
||||
context('with individual caps', function () {
|
||||
beforeEach(async function () {
|
||||
await this.crowdsale.setCap(alice, capAlice, { from: capper });
|
||||
await this.crowdsale.setCap(bob, capBob, { from: capper });
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
it('should accept payments within cap', async function () {
|
||||
await this.crowdsale.buyTokens(alice, { value: lessThanCapAlice });
|
||||
await this.crowdsale.buyTokens(bob, { value: lessThanCapBoth });
|
||||
});
|
||||
|
||||
it('should reject payments outside cap', async function () {
|
||||
await this.crowdsale.buyTokens(alice, { value: capAlice });
|
||||
await expectRevert(this.crowdsale.buyTokens(alice, { value: 1 }),
|
||||
'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded'
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject payments that exceed cap', async function () {
|
||||
await expectRevert(this.crowdsale.buyTokens(alice, { value: capAlice.addn(1) }),
|
||||
'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded'
|
||||
);
|
||||
await expectRevert(this.crowdsale.buyTokens(bob, { value: capBob.addn(1) }),
|
||||
'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded'
|
||||
);
|
||||
});
|
||||
|
||||
it('should manage independent caps', async function () {
|
||||
await this.crowdsale.buyTokens(alice, { value: lessThanCapAlice });
|
||||
await expectRevert(this.crowdsale.buyTokens(bob, { value: lessThanCapAlice }),
|
||||
'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded'
|
||||
);
|
||||
});
|
||||
|
||||
it('should default to a cap of zero', async function () {
|
||||
await expectRevert(this.crowdsale.buyTokens(charlie, { value: lessThanCapBoth }),
|
||||
'IndividuallyCappedCrowdsale: beneficiary\'s cap exceeded'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reporting state', function () {
|
||||
it('should report correct cap', async function () {
|
||||
expect(await this.crowdsale.getCap(alice)).to.be.bignumber.equal(capAlice);
|
||||
});
|
||||
|
||||
it('should report actual contribution', async function () {
|
||||
await this.crowdsale.buyTokens(alice, { value: lessThanCapAlice });
|
||||
expect(await this.crowdsale.getContribution(alice)).to.be.bignumber.equal(lessThanCapAlice);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,43 +0,0 @@
|
||||
const { balance, expectEvent } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
function shouldBehaveLikeMintedCrowdsale ([ investor, wallet, purchaser ], rate, value) {
|
||||
const expectedTokenAmount = rate.mul(value);
|
||||
|
||||
describe('as a minted crowdsale', function () {
|
||||
describe('accepting payments', function () {
|
||||
it('should accept payments', async function () {
|
||||
await this.crowdsale.send(value);
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
});
|
||||
});
|
||||
|
||||
describe('high-level purchase', function () {
|
||||
it('should log purchase', async function () {
|
||||
const { logs } = await this.crowdsale.sendTransaction({ value: value, from: investor });
|
||||
expectEvent.inLogs(logs, 'TokensPurchased', {
|
||||
purchaser: investor,
|
||||
beneficiary: investor,
|
||||
value: value,
|
||||
amount: expectedTokenAmount,
|
||||
});
|
||||
});
|
||||
|
||||
it('should assign tokens to sender', async function () {
|
||||
await this.crowdsale.sendTransaction({ value: value, from: investor });
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount);
|
||||
});
|
||||
|
||||
it('should forward funds to wallet', async function () {
|
||||
const balanceTracker = await balance.tracker(wallet);
|
||||
await this.crowdsale.sendTransaction({ value, from: investor });
|
||||
expect(await balanceTracker.delta()).to.be.bignumber.equal(value);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
shouldBehaveLikeMintedCrowdsale,
|
||||
};
|
||||
@ -1,48 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { shouldBehaveLikeMintedCrowdsale } = require('./MintedCrowdsale.behavior');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const MintedCrowdsaleImpl = contract.fromArtifact('MintedCrowdsaleImpl');
|
||||
const ERC20Mintable = contract.fromArtifact('ERC20Mintable');
|
||||
const ERC20 = contract.fromArtifact('ERC20');
|
||||
|
||||
describe('MintedCrowdsale', function () {
|
||||
const [ deployer, investor, wallet, purchaser ] = accounts;
|
||||
|
||||
const rate = new BN('1000');
|
||||
const value = ether('5');
|
||||
|
||||
describe('using ERC20Mintable', function () {
|
||||
beforeEach(async function () {
|
||||
this.token = await ERC20Mintable.new({ from: deployer });
|
||||
this.crowdsale = await MintedCrowdsaleImpl.new(rate, wallet, this.token.address);
|
||||
|
||||
await this.token.addMinter(this.crowdsale.address, { from: deployer });
|
||||
await this.token.renounceMinter({ from: deployer });
|
||||
});
|
||||
|
||||
it('crowdsale should be minter', async function () {
|
||||
expect(await this.token.isMinter(this.crowdsale.address)).to.equal(true);
|
||||
});
|
||||
|
||||
shouldBehaveLikeMintedCrowdsale([investor, wallet, purchaser], rate, value);
|
||||
});
|
||||
|
||||
describe('using non-mintable token', function () {
|
||||
beforeEach(async function () {
|
||||
this.token = await ERC20.new();
|
||||
this.crowdsale = await MintedCrowdsaleImpl.new(rate, wallet, this.token.address);
|
||||
});
|
||||
|
||||
it('rejects bare payments', async function () {
|
||||
await expectRevert.unspecified(this.crowdsale.send(value));
|
||||
});
|
||||
|
||||
it('rejects token purchases', async function () {
|
||||
await expectRevert.unspecified(this.crowdsale.buyTokens(investor, { value: value, from: purchaser }));
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,52 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const PausableCrowdsale = contract.fromArtifact('PausableCrowdsaleImpl');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
|
||||
describe('PausableCrowdsale', function () {
|
||||
const [ pauser, wallet, other ] = accounts;
|
||||
|
||||
const rate = new BN(1);
|
||||
const value = new BN(1);
|
||||
|
||||
beforeEach(async function () {
|
||||
const from = pauser;
|
||||
|
||||
this.token = await SimpleToken.new({ from });
|
||||
this.crowdsale = await PausableCrowdsale.new(rate, wallet, this.token.address, { from });
|
||||
await this.token.transfer(this.crowdsale.address, value.muln(2), { from });
|
||||
});
|
||||
|
||||
it('purchases work', async function () {
|
||||
await this.crowdsale.sendTransaction({ from: other, value });
|
||||
await this.crowdsale.buyTokens(other, { from: other, value });
|
||||
});
|
||||
|
||||
context('after pause', function () {
|
||||
beforeEach(async function () {
|
||||
await this.crowdsale.pause({ from: pauser });
|
||||
});
|
||||
|
||||
it('purchases do not work', async function () {
|
||||
await expectRevert(this.crowdsale.sendTransaction({ from: other, value }),
|
||||
'Pausable: paused'
|
||||
);
|
||||
await expectRevert(this.crowdsale.buyTokens(other, { from: other, value }),
|
||||
'Pausable: paused'
|
||||
);
|
||||
});
|
||||
|
||||
context('after unpause', function () {
|
||||
beforeEach(async function () {
|
||||
await this.crowdsale.unpause({ from: pauser });
|
||||
});
|
||||
|
||||
it('purchases work', async function () {
|
||||
await this.crowdsale.sendTransaction({ from: other, value });
|
||||
await this.crowdsale.buyTokens(other, { from: other, value });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,75 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, ether, expectRevert, time } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const PostDeliveryCrowdsaleImpl = contract.fromArtifact('PostDeliveryCrowdsaleImpl');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
|
||||
describe('PostDeliveryCrowdsale', function () {
|
||||
const [ investor, wallet, purchaser ] = accounts;
|
||||
|
||||
const rate = new BN(1);
|
||||
const tokenSupply = new BN('10').pow(new BN('22'));
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache
|
||||
await time.advanceBlock();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.openingTime = (await time.latest()).add(time.duration.weeks(1));
|
||||
this.closingTime = this.openingTime.add(time.duration.weeks(1));
|
||||
this.afterClosingTime = this.closingTime.add(time.duration.seconds(1));
|
||||
this.token = await SimpleToken.new();
|
||||
this.crowdsale = await PostDeliveryCrowdsaleImpl.new(
|
||||
this.openingTime, this.closingTime, rate, wallet, this.token.address
|
||||
);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
context('after opening time', function () {
|
||||
beforeEach(async function () {
|
||||
await time.increaseTo(this.openingTime);
|
||||
});
|
||||
|
||||
context('with bought tokens', function () {
|
||||
const value = ether('42');
|
||||
|
||||
beforeEach(async function () {
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
});
|
||||
|
||||
it('does not immediately assign tokens to beneficiaries', async function () {
|
||||
expect(await this.crowdsale.balanceOf(investor)).to.be.bignumber.equal(value);
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal('0');
|
||||
});
|
||||
|
||||
it('does not allow beneficiaries to withdraw tokens before crowdsale ends', async function () {
|
||||
await expectRevert(this.crowdsale.withdrawTokens(investor),
|
||||
'PostDeliveryCrowdsale: not closed'
|
||||
);
|
||||
});
|
||||
|
||||
context('after closing time', function () {
|
||||
beforeEach(async function () {
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
});
|
||||
|
||||
it('allows beneficiaries to withdraw tokens', async function () {
|
||||
await this.crowdsale.withdrawTokens(investor);
|
||||
expect(await this.crowdsale.balanceOf(investor)).to.be.bignumber.equal('0');
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value);
|
||||
});
|
||||
|
||||
it('rejects multiple withdrawals', async function () {
|
||||
await this.crowdsale.withdrawTokens(investor);
|
||||
await expectRevert(this.crowdsale.withdrawTokens(investor),
|
||||
'PostDeliveryCrowdsale: beneficiary is not due any tokens'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,111 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { balance, BN, ether, expectRevert, time } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const RefundableCrowdsaleImpl = contract.fromArtifact('RefundableCrowdsaleImpl');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
|
||||
describe('RefundableCrowdsale', function () {
|
||||
const [ wallet, investor, other ] = accounts;
|
||||
|
||||
const rate = new BN(1);
|
||||
const goal = ether('50');
|
||||
const lessThanGoal = ether('45');
|
||||
const tokenSupply = new BN('10').pow(new BN('22'));
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache
|
||||
await time.advanceBlock();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.openingTime = (await time.latest()).add(time.duration.weeks(1));
|
||||
this.closingTime = this.openingTime.add(time.duration.weeks(1));
|
||||
this.afterClosingTime = this.closingTime.add(time.duration.seconds(1));
|
||||
this.preWalletBalance = await balance.current(wallet);
|
||||
|
||||
this.token = await SimpleToken.new();
|
||||
});
|
||||
|
||||
it('rejects a goal of zero', async function () {
|
||||
await expectRevert(
|
||||
RefundableCrowdsaleImpl.new(this.openingTime, this.closingTime, rate, wallet, this.token.address, 0),
|
||||
'RefundableCrowdsale: goal is 0'
|
||||
);
|
||||
});
|
||||
|
||||
context('with crowdsale', function () {
|
||||
beforeEach(async function () {
|
||||
this.crowdsale = await RefundableCrowdsaleImpl.new(
|
||||
this.openingTime, this.closingTime, rate, wallet, this.token.address, goal
|
||||
);
|
||||
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
context('before opening time', function () {
|
||||
it('denies refunds', async function () {
|
||||
await expectRevert(this.crowdsale.claimRefund(investor),
|
||||
'RefundableCrowdsale: not finalized'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('after opening time', function () {
|
||||
beforeEach(async function () {
|
||||
await time.increaseTo(this.openingTime);
|
||||
});
|
||||
|
||||
it('denies refunds', async function () {
|
||||
await expectRevert(this.crowdsale.claimRefund(investor),
|
||||
'RefundableCrowdsale: not finalized'
|
||||
);
|
||||
});
|
||||
|
||||
context('with unreached goal', function () {
|
||||
beforeEach(async function () {
|
||||
await this.crowdsale.sendTransaction({ value: lessThanGoal, from: investor });
|
||||
});
|
||||
|
||||
context('after closing time and finalization', function () {
|
||||
beforeEach(async function () {
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
await this.crowdsale.finalize({ from: other });
|
||||
});
|
||||
|
||||
it('refunds', async function () {
|
||||
const balanceTracker = await balance.tracker(investor);
|
||||
await this.crowdsale.claimRefund(investor, { gasPrice: 0 });
|
||||
expect(await balanceTracker.delta()).to.be.bignumber.equal(lessThanGoal);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('with reached goal', function () {
|
||||
beforeEach(async function () {
|
||||
await this.crowdsale.sendTransaction({ value: goal, from: investor });
|
||||
});
|
||||
|
||||
context('after closing time and finalization', function () {
|
||||
beforeEach(async function () {
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
await this.crowdsale.finalize({ from: other });
|
||||
});
|
||||
|
||||
it('denies refunds', async function () {
|
||||
await expectRevert(this.crowdsale.claimRefund(investor),
|
||||
'RefundableCrowdsale: goal reached'
|
||||
);
|
||||
});
|
||||
|
||||
it('forwards funds to wallet', async function () {
|
||||
const postWalletBalance = await balance.current(wallet);
|
||||
expect(postWalletBalance.sub(this.preWalletBalance)).to.be.bignumber.equal(goal);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,109 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, ether, expectRevert, time } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const RefundablePostDeliveryCrowdsaleImpl = contract.fromArtifact('RefundablePostDeliveryCrowdsaleImpl');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
|
||||
describe('RefundablePostDeliveryCrowdsale', function () {
|
||||
const [ investor, wallet, purchaser ] = accounts;
|
||||
|
||||
const rate = new BN(1);
|
||||
const tokenSupply = new BN('10').pow(new BN('22'));
|
||||
const goal = ether('100');
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache
|
||||
await time.advanceBlock();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.openingTime = (await time.latest()).add(time.duration.weeks(1));
|
||||
this.closingTime = this.openingTime.add(time.duration.weeks(1));
|
||||
this.afterClosingTime = this.closingTime.add(time.duration.seconds(1));
|
||||
this.token = await SimpleToken.new();
|
||||
this.crowdsale = await RefundablePostDeliveryCrowdsaleImpl.new(
|
||||
this.openingTime, this.closingTime, rate, wallet, this.token.address, goal
|
||||
);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
context('after opening time', function () {
|
||||
beforeEach(async function () {
|
||||
await time.increaseTo(this.openingTime);
|
||||
});
|
||||
|
||||
context('with bought tokens below the goal', function () {
|
||||
const value = goal.subn(1);
|
||||
|
||||
beforeEach(async function () {
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
});
|
||||
|
||||
it('does not immediately deliver tokens to beneficiaries', async function () {
|
||||
expect(await this.crowdsale.balanceOf(investor)).to.be.bignumber.equal(value);
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal('0');
|
||||
});
|
||||
|
||||
it('does not allow beneficiaries to withdraw tokens before crowdsale ends', async function () {
|
||||
await expectRevert(this.crowdsale.withdrawTokens(investor),
|
||||
'RefundablePostDeliveryCrowdsale: not finalized'
|
||||
);
|
||||
});
|
||||
|
||||
context('after closing time and finalization', function () {
|
||||
beforeEach(async function () {
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
await this.crowdsale.finalize();
|
||||
});
|
||||
|
||||
it('rejects token withdrawals', async function () {
|
||||
await expectRevert(this.crowdsale.withdrawTokens(investor),
|
||||
'RefundablePostDeliveryCrowdsale: goal not reached'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('with bought tokens matching the goal', function () {
|
||||
const value = goal;
|
||||
|
||||
beforeEach(async function () {
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
});
|
||||
|
||||
it('does not immediately deliver tokens to beneficiaries', async function () {
|
||||
expect(await this.crowdsale.balanceOf(investor)).to.be.bignumber.equal(value);
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal('0');
|
||||
});
|
||||
|
||||
it('does not allow beneficiaries to withdraw tokens before crowdsale ends', async function () {
|
||||
await expectRevert(this.crowdsale.withdrawTokens(investor),
|
||||
'RefundablePostDeliveryCrowdsale: not finalized'
|
||||
);
|
||||
});
|
||||
|
||||
context('after closing time and finalization', function () {
|
||||
beforeEach(async function () {
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
await this.crowdsale.finalize();
|
||||
});
|
||||
|
||||
it('allows beneficiaries to withdraw tokens', async function () {
|
||||
await this.crowdsale.withdrawTokens(investor);
|
||||
expect(await this.crowdsale.balanceOf(investor)).to.be.bignumber.equal('0');
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(value);
|
||||
});
|
||||
|
||||
it('rejects multiple withdrawals', async function () {
|
||||
await this.crowdsale.withdrawTokens(investor);
|
||||
await expectRevert(this.crowdsale.withdrawTokens(investor),
|
||||
'PostDeliveryCrowdsale: beneficiary is not due any tokens'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,150 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, ether, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const TimedCrowdsaleImpl = contract.fromArtifact('TimedCrowdsaleImpl');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
|
||||
describe('TimedCrowdsale', function () {
|
||||
const [ investor, wallet, purchaser ] = accounts;
|
||||
|
||||
const rate = new BN(1);
|
||||
const value = ether('42');
|
||||
const tokenSupply = new BN('10').pow(new BN('22'));
|
||||
|
||||
before(async function () {
|
||||
// Advance to the next block to correctly read time in the solidity "now" function interpreted by ganache
|
||||
await time.advanceBlock();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.openingTime = (await time.latest()).add(time.duration.weeks(1));
|
||||
this.closingTime = this.openingTime.add(time.duration.weeks(1));
|
||||
this.afterClosingTime = this.closingTime.add(time.duration.seconds(1));
|
||||
this.token = await SimpleToken.new();
|
||||
});
|
||||
|
||||
it('reverts if the opening time is in the past', async function () {
|
||||
await expectRevert(TimedCrowdsaleImpl.new(
|
||||
(await time.latest()).sub(time.duration.days(1)), this.closingTime, rate, wallet, this.token.address
|
||||
), 'TimedCrowdsale: opening time is before current time');
|
||||
});
|
||||
|
||||
it('reverts if the closing time is before the opening time', async function () {
|
||||
await expectRevert(TimedCrowdsaleImpl.new(
|
||||
this.openingTime, this.openingTime.sub(time.duration.seconds(1)), rate, wallet, this.token.address
|
||||
), 'TimedCrowdsale: opening time is not before closing time');
|
||||
});
|
||||
|
||||
it('reverts if the closing time equals the opening time', async function () {
|
||||
await expectRevert(TimedCrowdsaleImpl.new(
|
||||
this.openingTime, this.openingTime, rate, wallet, this.token.address
|
||||
), 'TimedCrowdsale: opening time is not before closing time');
|
||||
});
|
||||
|
||||
context('with crowdsale', function () {
|
||||
beforeEach(async function () {
|
||||
this.crowdsale = await TimedCrowdsaleImpl.new(
|
||||
this.openingTime, this.closingTime, rate, wallet, this.token.address
|
||||
);
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply);
|
||||
});
|
||||
|
||||
it('should be ended only after end', async function () {
|
||||
expect(await this.crowdsale.hasClosed()).to.equal(false);
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
expect(await this.crowdsale.isOpen()).to.equal(false);
|
||||
expect(await this.crowdsale.hasClosed()).to.equal(true);
|
||||
});
|
||||
|
||||
describe('accepting payments', function () {
|
||||
it('should reject payments before start', async function () {
|
||||
expect(await this.crowdsale.isOpen()).to.equal(false);
|
||||
await expectRevert(this.crowdsale.send(value), 'TimedCrowdsale: not open');
|
||||
await expectRevert(this.crowdsale.buyTokens(investor, { from: purchaser, value: value }),
|
||||
'TimedCrowdsale: not open'
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept payments after start', async function () {
|
||||
await time.increaseTo(this.openingTime);
|
||||
expect(await this.crowdsale.isOpen()).to.equal(true);
|
||||
await this.crowdsale.send(value);
|
||||
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
|
||||
});
|
||||
|
||||
it('should reject payments after end', async function () {
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
await expectRevert(this.crowdsale.send(value), 'TimedCrowdsale: not open');
|
||||
await expectRevert(this.crowdsale.buyTokens(investor, { value: value, from: purchaser }),
|
||||
'TimedCrowdsale: not open'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('extending closing time', function () {
|
||||
it('should not reduce duration', async function () {
|
||||
// Same date
|
||||
await expectRevert(this.crowdsale.extendTime(this.closingTime),
|
||||
'TimedCrowdsale: new closing time is before current closing time'
|
||||
);
|
||||
|
||||
// Prescending date
|
||||
const newClosingTime = this.closingTime.sub(time.duration.seconds(1));
|
||||
await expectRevert(this.crowdsale.extendTime(newClosingTime),
|
||||
'TimedCrowdsale: new closing time is before current closing time'
|
||||
);
|
||||
});
|
||||
|
||||
context('before crowdsale start', function () {
|
||||
beforeEach(async function () {
|
||||
expect(await this.crowdsale.isOpen()).to.equal(false);
|
||||
await expectRevert(this.crowdsale.send(value), 'TimedCrowdsale: not open');
|
||||
});
|
||||
|
||||
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,
|
||||
});
|
||||
expect(await this.crowdsale.closingTime()).to.be.bignumber.equal(newClosingTime);
|
||||
});
|
||||
});
|
||||
|
||||
context('after crowdsale start', function () {
|
||||
beforeEach(async function () {
|
||||
await time.increaseTo(this.openingTime);
|
||||
expect(await this.crowdsale.isOpen()).to.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,
|
||||
});
|
||||
expect(await this.crowdsale.closingTime()).to.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 expectRevert(this.crowdsale.extendTime(newClosingTime),
|
||||
'TimedCrowdsale: already closed'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,61 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const WhitelistCrowdsale = contract.fromArtifact('WhitelistCrowdsaleImpl');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
|
||||
describe('WhitelistCrowdsale', function () {
|
||||
const [ wallet, whitelister, whitelisted, otherWhitelisted, other ] = accounts;
|
||||
|
||||
const rate = new BN(1);
|
||||
const value = ether('42');
|
||||
const tokenSupply = new BN('10').pow(new BN('22'));
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await SimpleToken.new({ from: whitelister });
|
||||
this.crowdsale = await WhitelistCrowdsale.new(rate, wallet, this.token.address, { from: whitelister });
|
||||
await this.token.transfer(this.crowdsale.address, tokenSupply, { from: whitelister });
|
||||
});
|
||||
|
||||
async function purchaseShouldSucceed (crowdsale, beneficiary, value) {
|
||||
await crowdsale.buyTokens(beneficiary, { from: beneficiary, value });
|
||||
await crowdsale.sendTransaction({ from: beneficiary, value });
|
||||
}
|
||||
|
||||
async function purchaseExpectRevert (crowdsale, beneficiary, value) {
|
||||
await expectRevert(crowdsale.buyTokens(beneficiary, { from: beneficiary, value }),
|
||||
'WhitelistCrowdsale: beneficiary doesn\'t have the Whitelisted role'
|
||||
);
|
||||
await expectRevert(crowdsale.sendTransaction({ from: beneficiary, value }),
|
||||
'WhitelistCrowdsale: beneficiary doesn\'t have the Whitelisted role'
|
||||
);
|
||||
}
|
||||
|
||||
context('with no whitelisted addresses', function () {
|
||||
it('rejects all purchases', async function () {
|
||||
await purchaseExpectRevert(this.crowdsale, other, value);
|
||||
await purchaseExpectRevert(this.crowdsale, whitelisted, value);
|
||||
});
|
||||
});
|
||||
|
||||
context('with whitelisted addresses', function () {
|
||||
beforeEach(async function () {
|
||||
await this.crowdsale.addWhitelisted(whitelisted, { from: whitelister });
|
||||
await this.crowdsale.addWhitelisted(otherWhitelisted, { from: whitelister });
|
||||
});
|
||||
|
||||
it('accepts purchases with whitelisted beneficiaries', async function () {
|
||||
await purchaseShouldSucceed(this.crowdsale, whitelisted, value);
|
||||
await purchaseShouldSucceed(this.crowdsale, otherWhitelisted, value);
|
||||
});
|
||||
|
||||
it('rejects purchases from whitelisted addresses with non-whitelisted beneficiaries', async function () {
|
||||
await expectRevert.unspecified(this.crowdsale.buyTokens(other, { from: whitelisted, value }));
|
||||
});
|
||||
|
||||
it('rejects purchases with non-whitelisted beneficiaries', async function () {
|
||||
await purchaseExpectRevert(this.crowdsale, other, value);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,203 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { ZERO_ADDRESS } = constants;
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const ERC20Mock = contract.fromArtifact('ERC20Mock');
|
||||
const ERC20Mintable = contract.fromArtifact('ERC20Mintable');
|
||||
const ERC20Migrator = contract.fromArtifact('ERC20Migrator');
|
||||
|
||||
describe('ERC20Migrator', function () {
|
||||
const [ owner ] = accounts;
|
||||
|
||||
const totalSupply = new BN('200');
|
||||
|
||||
it('reverts with a null legacy token address', async function () {
|
||||
await expectRevert(ERC20Migrator.new(ZERO_ADDRESS),
|
||||
'ERC20Migrator: legacy token is the zero address'
|
||||
);
|
||||
});
|
||||
|
||||
describe('with tokens and migrator', function () {
|
||||
beforeEach('deploying tokens and migrator', async function () {
|
||||
this.legacyToken = await ERC20Mock.new(owner, totalSupply);
|
||||
this.migrator = await ERC20Migrator.new(this.legacyToken.address);
|
||||
this.newToken = await ERC20Mintable.new();
|
||||
});
|
||||
|
||||
it('returns legacy token', async function () {
|
||||
expect(await this.migrator.legacyToken()).to.equal(this.legacyToken.address);
|
||||
});
|
||||
|
||||
describe('beginMigration', function () {
|
||||
it('reverts with a null new token address', async function () {
|
||||
await expectRevert(this.migrator.beginMigration(ZERO_ADDRESS),
|
||||
'ERC20Migrator: new token is the zero address'
|
||||
);
|
||||
});
|
||||
|
||||
it('reverts if not a minter of the token', async function () {
|
||||
await expectRevert(this.migrator.beginMigration(this.newToken.address),
|
||||
'ERC20Migrator: not a minter for new token'
|
||||
);
|
||||
});
|
||||
|
||||
it('succeeds if it is a minter of the token', async function () {
|
||||
await this.newToken.addMinter(this.migrator.address);
|
||||
await this.migrator.beginMigration(this.newToken.address);
|
||||
});
|
||||
|
||||
it('reverts the second time it is called', async function () {
|
||||
await this.newToken.addMinter(this.migrator.address);
|
||||
await this.migrator.beginMigration(this.newToken.address);
|
||||
await expectRevert(this.migrator.beginMigration(this.newToken.address),
|
||||
'ERC20Migrator: migration already started'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('before starting the migration', function () {
|
||||
it('returns the zero address for the new token', async function () {
|
||||
expect(await this.migrator.newToken()).to.equal(ZERO_ADDRESS);
|
||||
});
|
||||
|
||||
describe('migrateAll', function () {
|
||||
const amount = totalSupply;
|
||||
|
||||
describe('when the approved balance is equal to the owned balance', function () {
|
||||
beforeEach('approving the whole balance to the new contract', async function () {
|
||||
await this.legacyToken.approve(this.migrator.address, amount, { from: owner });
|
||||
});
|
||||
|
||||
it('reverts', async function () {
|
||||
await expectRevert(this.migrator.migrateAll(owner),
|
||||
'ERC20Migrator: migration not started'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('migrate', function () {
|
||||
const amount = new BN(50);
|
||||
|
||||
describe('when the amount is equal to the approved value', function () {
|
||||
beforeEach('approving tokens to the new contract', async function () {
|
||||
await this.legacyToken.approve(this.migrator.address, amount, { from: owner });
|
||||
});
|
||||
|
||||
it('reverts', async function () {
|
||||
await expectRevert(this.migrator.migrate(owner, amount),
|
||||
'ERC20Migrator: migration not started'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('once migration began', function () {
|
||||
beforeEach('beginning migration', async function () {
|
||||
await this.newToken.addMinter(this.migrator.address);
|
||||
await this.migrator.beginMigration(this.newToken.address);
|
||||
});
|
||||
|
||||
it('returns new token', async function () {
|
||||
expect(await this.migrator.newToken()).to.equal(this.newToken.address);
|
||||
});
|
||||
|
||||
describe('migrateAll', function () {
|
||||
const baseAmount = totalSupply;
|
||||
|
||||
describe('when the approved balance is equal to the owned balance', function () {
|
||||
const amount = baseAmount;
|
||||
|
||||
beforeEach('approving the whole balance to the new contract', async function () {
|
||||
await this.legacyToken.approve(this.migrator.address, amount, { from: owner });
|
||||
});
|
||||
|
||||
beforeEach('migrating token', async function () {
|
||||
const tx = await this.migrator.migrateAll(owner);
|
||||
this.logs = tx.receipt.logs;
|
||||
});
|
||||
|
||||
it('mints the same balance of the new token', async function () {
|
||||
const currentBalance = await this.newToken.balanceOf(owner);
|
||||
expect(currentBalance).to.be.bignumber.equal(amount);
|
||||
});
|
||||
|
||||
it('burns a given amount of old tokens', async function () {
|
||||
const currentBurnedBalance = await this.legacyToken.balanceOf(this.migrator.address);
|
||||
expect(currentBurnedBalance).to.be.bignumber.equal(amount);
|
||||
|
||||
const currentLegacyTokenBalance = await this.legacyToken.balanceOf(owner);
|
||||
expect(currentLegacyTokenBalance).to.be.bignumber.equal('0');
|
||||
});
|
||||
|
||||
it('updates the total supply', async function () {
|
||||
const currentSupply = await this.newToken.totalSupply();
|
||||
expect(currentSupply).to.be.bignumber.equal(amount);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the approved balance is lower than the owned balance', function () {
|
||||
const amount = baseAmount.subn(1);
|
||||
|
||||
beforeEach('approving part of the balance to the new contract', async function () {
|
||||
await this.legacyToken.approve(this.migrator.address, amount, { from: owner });
|
||||
await this.migrator.migrateAll(owner);
|
||||
});
|
||||
|
||||
it('migrates only approved amount', async function () {
|
||||
const currentBalance = await this.newToken.balanceOf(owner);
|
||||
expect(currentBalance).to.be.bignumber.equal(amount);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('migrate', function () {
|
||||
const baseAmount = new BN(50);
|
||||
|
||||
beforeEach('approving tokens to the new contract', async function () {
|
||||
await this.legacyToken.approve(this.migrator.address, baseAmount, { from: owner });
|
||||
});
|
||||
|
||||
describe('when the amount is equal to the one approved', function () {
|
||||
const amount = baseAmount;
|
||||
|
||||
beforeEach('migrate token', async function () {
|
||||
({ logs: this.logs } = await this.migrator.migrate(owner, amount));
|
||||
});
|
||||
|
||||
it('mints that amount of the new token', async function () {
|
||||
const currentBalance = await this.newToken.balanceOf(owner);
|
||||
expect(currentBalance).to.be.bignumber.equal(amount);
|
||||
});
|
||||
|
||||
it('burns a given amount of old tokens', async function () {
|
||||
const currentBurnedBalance = await this.legacyToken.balanceOf(this.migrator.address);
|
||||
expect(currentBurnedBalance).to.be.bignumber.equal(amount);
|
||||
|
||||
const currentLegacyTokenBalance = await this.legacyToken.balanceOf(owner);
|
||||
expect(currentLegacyTokenBalance).to.be.bignumber.equal(totalSupply.sub(amount));
|
||||
});
|
||||
|
||||
it('updates the total supply', async function () {
|
||||
const currentSupply = await this.newToken.totalSupply();
|
||||
expect(currentSupply).to.be.bignumber.equal(amount);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the given amount is higher than the one approved', function () {
|
||||
const amount = baseAmount.addn(1);
|
||||
|
||||
it('reverts', async function () {
|
||||
await expectRevert(this.migrator.migrate(owner, amount),
|
||||
'SafeERC20: low-level call failed'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -5,7 +5,7 @@ const { ZERO_ADDRESS } = constants;
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const ERC20Mintable = contract.fromArtifact('ERC20Mintable');
|
||||
const ERC20Mock = contract.fromArtifact('ERC20Mock');
|
||||
const TokenVesting = contract.fromArtifact('TokenVesting');
|
||||
|
||||
describe('TokenVesting', function () {
|
||||
@ -61,8 +61,7 @@ describe('TokenVesting', function () {
|
||||
this.vesting = await TokenVesting.new(
|
||||
beneficiary, this.start, this.cliffDuration, this.duration, true, { from: owner });
|
||||
|
||||
this.token = await ERC20Mintable.new({ from: owner });
|
||||
await this.token.mint(this.vesting.address, amount, { from: owner });
|
||||
this.token = await ERC20Mock.new(this.vesting.address, amount);
|
||||
});
|
||||
|
||||
it('can get state', async function () {
|
||||
|
||||
@ -1,111 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, balance, ether, expectRevert, time } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const SampleCrowdsale = contract.fromArtifact('SampleCrowdsale');
|
||||
const SampleCrowdsaleToken = contract.fromArtifact('SampleCrowdsaleToken');
|
||||
|
||||
describe('SampleCrowdsale', function () {
|
||||
const [ deployer, owner, wallet, investor ] = accounts;
|
||||
|
||||
const RATE = new BN(10);
|
||||
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 ganache
|
||||
await time.advanceBlock();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.openingTime = (await time.latest()).add(time.duration.weeks(1));
|
||||
this.closingTime = this.openingTime.add(time.duration.weeks(1));
|
||||
this.afterClosingTime = this.closingTime.add(time.duration.seconds(1));
|
||||
|
||||
this.token = await SampleCrowdsaleToken.new({ from: deployer });
|
||||
this.crowdsale = await SampleCrowdsale.new(
|
||||
this.openingTime, this.closingTime, RATE, wallet, CAP, this.token.address, GOAL,
|
||||
{ from: owner }
|
||||
);
|
||||
|
||||
await this.token.addMinter(this.crowdsale.address, { from: deployer });
|
||||
await this.token.renounceMinter({ from: deployer });
|
||||
});
|
||||
|
||||
it('should create crowdsale with correct parameters', async function () {
|
||||
expect(await this.crowdsale.openingTime()).to.be.bignumber.equal(this.openingTime);
|
||||
expect(await this.crowdsale.closingTime()).to.be.bignumber.equal(this.closingTime);
|
||||
expect(await this.crowdsale.rate()).to.be.bignumber.equal(RATE);
|
||||
expect(await this.crowdsale.wallet()).to.equal(wallet);
|
||||
expect(await this.crowdsale.goal()).to.be.bignumber.equal(GOAL);
|
||||
expect(await this.crowdsale.cap()).to.be.bignumber.equal(CAP);
|
||||
});
|
||||
|
||||
it('should not accept payments before start', async function () {
|
||||
await expectRevert(this.crowdsale.send(ether('1')), 'TimedCrowdsale: not open');
|
||||
await expectRevert(this.crowdsale.buyTokens(investor, { from: investor, value: ether('1') }),
|
||||
'TimedCrowdsale: not open'
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept payments during the sale', async function () {
|
||||
const investmentAmount = ether('1');
|
||||
const expectedTokenAmount = RATE.mul(investmentAmount);
|
||||
|
||||
await time.increaseTo(this.openingTime);
|
||||
await this.crowdsale.buyTokens(investor, { value: investmentAmount, from: investor });
|
||||
|
||||
expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount);
|
||||
expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedTokenAmount);
|
||||
});
|
||||
|
||||
it('should reject payments after end', async function () {
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
await expectRevert(this.crowdsale.send(ether('1')), 'TimedCrowdsale: not open');
|
||||
await expectRevert(this.crowdsale.buyTokens(investor, { value: ether('1'), from: investor }),
|
||||
'TimedCrowdsale: not open'
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject payments over cap', async function () {
|
||||
await time.increaseTo(this.openingTime);
|
||||
await this.crowdsale.send(CAP);
|
||||
await expectRevert(this.crowdsale.send(1), 'CappedCrowdsale: cap exceeded');
|
||||
});
|
||||
|
||||
it('should allow finalization and transfer funds to wallet if the goal is reached', async function () {
|
||||
await time.increaseTo(this.openingTime);
|
||||
await this.crowdsale.send(GOAL);
|
||||
|
||||
const balanceTracker = await balance.tracker(wallet);
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
await this.crowdsale.finalize({ from: owner });
|
||||
expect(await balanceTracker.delta()).to.be.bignumber.equal(GOAL);
|
||||
});
|
||||
|
||||
it('should allow refunds if the goal is not reached', async function () {
|
||||
const balanceTracker = await balance.tracker(investor);
|
||||
|
||||
await time.increaseTo(this.openingTime);
|
||||
await this.crowdsale.sendTransaction({ value: ether('1'), from: investor, gasPrice: 0 });
|
||||
await time.increaseTo(this.afterClosingTime);
|
||||
|
||||
await this.crowdsale.finalize({ from: owner });
|
||||
await this.crowdsale.claimRefund(investor, { gasPrice: 0 });
|
||||
|
||||
expect(await balanceTracker.delta()).to.be.bignumber.equal('0');
|
||||
});
|
||||
|
||||
describe('when goal > cap', function () {
|
||||
// goal > cap
|
||||
const HIGH_GOAL = ether('30');
|
||||
|
||||
it('creation reverts', async function () {
|
||||
await expectRevert(SampleCrowdsale.new(
|
||||
this.openingTime, this.closingTime, RATE, wallet, CAP, this.token.address, HIGH_GOAL
|
||||
), 'SampleCrowdSale: goal is greater than cap');
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,41 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { constants, expectEvent } = require('@openzeppelin/test-helpers');
|
||||
const { ZERO_ADDRESS } = constants;
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
|
||||
describe('SimpleToken', function () {
|
||||
const [ creator ] = accounts;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await SimpleToken.new({ from: creator });
|
||||
});
|
||||
|
||||
it('has a name', async function () {
|
||||
expect(await this.token.name()).to.equal('SimpleToken');
|
||||
});
|
||||
|
||||
it('has a symbol', async function () {
|
||||
expect(await this.token.symbol()).to.equal('SIM');
|
||||
});
|
||||
|
||||
it('has 18 decimals', async function () {
|
||||
expect(await this.token.decimals()).to.be.bignumber.equal('18');
|
||||
});
|
||||
|
||||
it('assigns the initial total supply to the creator', async function () {
|
||||
const totalSupply = await this.token.totalSupply();
|
||||
const creatorBalance = await this.token.balanceOf(creator);
|
||||
|
||||
expect(creatorBalance).to.be.bignumber.equal(totalSupply);
|
||||
|
||||
await expectEvent.inConstruction(this.token, 'Transfer', {
|
||||
from: ZERO_ADDRESS,
|
||||
to: creator,
|
||||
value: totalSupply,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,26 +1,16 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { shouldBehaveLikePublicRole } = require('../behaviors/access/roles/PublicRole.behavior');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const PausableMock = contract.fromArtifact('PausableMock');
|
||||
|
||||
describe('Pausable', function () {
|
||||
const [ pauser, otherPauser, other, ...otherAccounts ] = accounts;
|
||||
const [ pauser ] = accounts;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.pausable = await PausableMock.new({ from: pauser });
|
||||
});
|
||||
|
||||
describe('pauser role', function () {
|
||||
beforeEach(async function () {
|
||||
this.contract = this.pausable;
|
||||
await this.contract.addPauser(otherPauser, { from: pauser });
|
||||
});
|
||||
|
||||
shouldBehaveLikePublicRole(pauser, otherPauser, otherAccounts, 'pauser');
|
||||
this.pausable = await PausableMock.new();
|
||||
});
|
||||
|
||||
context('when unpaused', function () {
|
||||
@ -31,87 +21,68 @@ describe('Pausable', function () {
|
||||
it('can perform normal process in non-pause', async function () {
|
||||
expect(await this.pausable.count()).to.be.bignumber.equal('0');
|
||||
|
||||
await this.pausable.normalProcess({ from: other });
|
||||
await this.pausable.normalProcess();
|
||||
expect(await this.pausable.count()).to.be.bignumber.equal('1');
|
||||
});
|
||||
|
||||
it('cannot take drastic measure in non-pause', async function () {
|
||||
await expectRevert(this.pausable.drasticMeasure({ from: other }),
|
||||
await expectRevert(this.pausable.drasticMeasure(),
|
||||
'Pausable: not paused'
|
||||
);
|
||||
expect(await this.pausable.drasticMeasureTaken()).to.equal(false);
|
||||
});
|
||||
|
||||
describe('pausing', function () {
|
||||
it('is pausable by the pauser', async function () {
|
||||
await this.pausable.pause({ from: pauser });
|
||||
expect(await this.pausable.paused()).to.equal(true);
|
||||
context('when paused', function () {
|
||||
beforeEach(async function () {
|
||||
({ logs: this.logs } = await this.pausable.pause({ from: pauser }));
|
||||
});
|
||||
|
||||
it('reverts when pausing from non-pauser', async function () {
|
||||
await expectRevert(this.pausable.pause({ from: other }),
|
||||
'PauserRole: caller does not have the Pauser role'
|
||||
);
|
||||
it('emits a Paused event', function () {
|
||||
expectEvent.inLogs(this.logs, 'Paused', { account: pauser });
|
||||
});
|
||||
|
||||
context('when paused', function () {
|
||||
beforeEach(async function () {
|
||||
({ logs: this.logs } = await this.pausable.pause({ from: pauser }));
|
||||
it('cannot perform normal process in pause', async function () {
|
||||
await expectRevert(this.pausable.normalProcess(), 'Pausable: paused');
|
||||
});
|
||||
|
||||
it('can take a drastic measure in a pause', async function () {
|
||||
await this.pausable.drasticMeasure();
|
||||
expect(await this.pausable.drasticMeasureTaken()).to.equal(true);
|
||||
});
|
||||
|
||||
it('reverts when re-pausing', async function () {
|
||||
await expectRevert(this.pausable.pause(), 'Pausable: paused');
|
||||
});
|
||||
|
||||
describe('unpausing', function () {
|
||||
it('is unpausable by the pauser', async function () {
|
||||
await this.pausable.unpause();
|
||||
expect(await this.pausable.paused()).to.equal(false);
|
||||
});
|
||||
|
||||
it('emits a Paused event', function () {
|
||||
expectEvent.inLogs(this.logs, 'Paused', { account: pauser });
|
||||
});
|
||||
|
||||
it('cannot perform normal process in pause', async function () {
|
||||
await expectRevert(this.pausable.normalProcess({ from: other }), 'Pausable: paused');
|
||||
});
|
||||
|
||||
it('can take a drastic measure in a pause', async function () {
|
||||
await this.pausable.drasticMeasure({ from: other });
|
||||
expect(await this.pausable.drasticMeasureTaken()).to.equal(true);
|
||||
});
|
||||
|
||||
it('reverts when re-pausing', async function () {
|
||||
await expectRevert(this.pausable.pause({ from: pauser }), 'Pausable: paused');
|
||||
});
|
||||
|
||||
describe('unpausing', function () {
|
||||
it('is unpausable by the pauser', async function () {
|
||||
await this.pausable.unpause({ from: pauser });
|
||||
expect(await this.pausable.paused()).to.equal(false);
|
||||
context('when unpaused', function () {
|
||||
beforeEach(async function () {
|
||||
({ logs: this.logs } = await this.pausable.unpause({ from: pauser }));
|
||||
});
|
||||
|
||||
it('reverts when unpausing from non-pauser', async function () {
|
||||
await expectRevert(this.pausable.unpause({ from: other }),
|
||||
'PauserRole: caller does not have the Pauser role'
|
||||
it('emits an Unpaused event', function () {
|
||||
expectEvent.inLogs(this.logs, 'Unpaused', { account: pauser });
|
||||
});
|
||||
|
||||
it('should resume allowing normal process', async function () {
|
||||
expect(await this.pausable.count()).to.be.bignumber.equal('0');
|
||||
await this.pausable.normalProcess();
|
||||
expect(await this.pausable.count()).to.be.bignumber.equal('1');
|
||||
});
|
||||
|
||||
it('should prevent drastic measure', async function () {
|
||||
await expectRevert(this.pausable.drasticMeasure(),
|
||||
'Pausable: not paused'
|
||||
);
|
||||
});
|
||||
|
||||
context('when unpaused', function () {
|
||||
beforeEach(async function () {
|
||||
({ logs: this.logs } = await this.pausable.unpause({ from: pauser }));
|
||||
});
|
||||
|
||||
it('emits an Unpaused event', function () {
|
||||
expectEvent.inLogs(this.logs, 'Unpaused', { account: pauser });
|
||||
});
|
||||
|
||||
it('should resume allowing normal process', async function () {
|
||||
expect(await this.pausable.count()).to.be.bignumber.equal('0');
|
||||
await this.pausable.normalProcess({ from: other });
|
||||
expect(await this.pausable.count()).to.be.bignumber.equal('1');
|
||||
});
|
||||
|
||||
it('should prevent drastic measure', async function () {
|
||||
await expectRevert(this.pausable.drasticMeasure({ from: other }),
|
||||
'Pausable: not paused'
|
||||
);
|
||||
});
|
||||
|
||||
it('reverts when re-unpausing', async function () {
|
||||
await expectRevert(this.pausable.unpause({ from: pauser }), 'Pausable: not paused');
|
||||
});
|
||||
it('reverts when re-unpausing', async function () {
|
||||
await expectRevert(this.pausable.unpause(), 'Pausable: not paused');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { shouldBehaveLikeERC20Mintable } = require('./behaviors/ERC20Mintable.behavior');
|
||||
const { shouldBehaveLikeERC20Capped } = require('./behaviors/ERC20Capped.behavior');
|
||||
|
||||
const ERC20Capped = contract.fromArtifact('ERC20Capped');
|
||||
const ERC20Capped = contract.fromArtifact('ERC20CappedMock');
|
||||
|
||||
describe('ERC20Capped', function () {
|
||||
const [ minter, ...otherAccounts ] = accounts;
|
||||
@ -23,6 +22,5 @@ describe('ERC20Capped', function () {
|
||||
});
|
||||
|
||||
shouldBehaveLikeERC20Capped(minter, otherAccounts, cap);
|
||||
shouldBehaveLikeERC20Mintable(minter, otherAccounts);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { shouldBehaveLikeERC20Mintable } = require('./behaviors/ERC20Mintable.behavior');
|
||||
const ERC20MintableMock = contract.fromArtifact('ERC20MintableMock');
|
||||
const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior');
|
||||
|
||||
describe('ERC20Mintable', function () {
|
||||
const [ minter, otherMinter, ...otherAccounts ] = accounts;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await ERC20MintableMock.new({ from: minter });
|
||||
});
|
||||
|
||||
describe('minter role', function () {
|
||||
beforeEach(async function () {
|
||||
this.contract = this.token;
|
||||
await this.contract.addMinter(otherMinter, { from: minter });
|
||||
});
|
||||
|
||||
shouldBehaveLikePublicRole(minter, otherMinter, otherAccounts, 'minter');
|
||||
});
|
||||
|
||||
shouldBehaveLikeERC20Mintable(minter, otherAccounts);
|
||||
});
|
||||
@ -1,178 +1,44 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { BN, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const ERC20PausableMock = contract.fromArtifact('ERC20PausableMock');
|
||||
const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior');
|
||||
|
||||
describe('ERC20Pausable', function () {
|
||||
const [ pauser, otherPauser, recipient, anotherAccount, ...otherAccounts ] = accounts;
|
||||
const [ holder, recipient, anotherAccount ] = accounts;
|
||||
|
||||
const initialSupply = new BN(100);
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await ERC20PausableMock.new(pauser, initialSupply, { from: pauser });
|
||||
});
|
||||
|
||||
describe('pauser role', function () {
|
||||
beforeEach(async function () {
|
||||
this.contract = this.token;
|
||||
await this.contract.addPauser(otherPauser, { from: pauser });
|
||||
});
|
||||
|
||||
shouldBehaveLikePublicRole(pauser, otherPauser, otherAccounts, 'pauser');
|
||||
});
|
||||
|
||||
describe('pause', function () {
|
||||
describe('when the sender is the token pauser', function () {
|
||||
const from = pauser;
|
||||
|
||||
describe('when the token is unpaused', function () {
|
||||
it('pauses the token', async function () {
|
||||
await this.token.pause({ from });
|
||||
expect(await this.token.paused()).to.equal(true);
|
||||
});
|
||||
|
||||
it('emits a Pause event', async function () {
|
||||
const { logs } = await this.token.pause({ from });
|
||||
|
||||
expectEvent.inLogs(logs, 'Paused');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the token is paused', function () {
|
||||
beforeEach(async function () {
|
||||
await this.token.pause({ from });
|
||||
});
|
||||
|
||||
it('reverts', async function () {
|
||||
await expectRevert(this.token.pause({ from }), 'Pausable: paused');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the sender is not the token pauser', function () {
|
||||
const from = anotherAccount;
|
||||
|
||||
it('reverts', async function () {
|
||||
await expectRevert(this.token.pause({ from }),
|
||||
'PauserRole: caller does not have the Pauser role'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('unpause', function () {
|
||||
describe('when the sender is the token pauser', function () {
|
||||
const from = pauser;
|
||||
|
||||
describe('when the token is paused', function () {
|
||||
beforeEach(async function () {
|
||||
await this.token.pause({ from });
|
||||
});
|
||||
|
||||
it('unpauses the token', async function () {
|
||||
await this.token.unpause({ from });
|
||||
expect(await this.token.paused()).to.equal(false);
|
||||
});
|
||||
|
||||
it('emits an Unpause event', async function () {
|
||||
const { logs } = await this.token.unpause({ from });
|
||||
|
||||
expectEvent.inLogs(logs, 'Unpaused');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the token is unpaused', function () {
|
||||
it('reverts', async function () {
|
||||
await expectRevert(this.token.unpause({ from }), 'Pausable: not paused');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the sender is not the token pauser', function () {
|
||||
const from = anotherAccount;
|
||||
|
||||
it('reverts', async function () {
|
||||
await expectRevert(this.token.unpause({ from }),
|
||||
'PauserRole: caller does not have the Pauser role'
|
||||
);
|
||||
});
|
||||
});
|
||||
this.token = await ERC20PausableMock.new(holder, initialSupply);
|
||||
});
|
||||
|
||||
describe('pausable token', function () {
|
||||
const from = pauser;
|
||||
|
||||
describe('paused', function () {
|
||||
it('is not paused by default', async function () {
|
||||
expect(await this.token.paused({ from })).to.equal(false);
|
||||
});
|
||||
|
||||
it('is paused after being paused', async function () {
|
||||
await this.token.pause({ from });
|
||||
expect(await this.token.paused({ from })).to.equal(true);
|
||||
});
|
||||
|
||||
it('is not paused after being paused and then unpaused', async function () {
|
||||
await this.token.pause({ from });
|
||||
await this.token.unpause({ from });
|
||||
expect(await this.token.paused()).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transfer', function () {
|
||||
it('allows to transfer when unpaused', async function () {
|
||||
await this.token.transfer(recipient, initialSupply, { from: pauser });
|
||||
await this.token.transfer(recipient, initialSupply, { from: holder });
|
||||
|
||||
expect(await this.token.balanceOf(pauser)).to.be.bignumber.equal('0');
|
||||
expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0');
|
||||
expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply);
|
||||
});
|
||||
|
||||
it('allows to transfer when paused and then unpaused', async function () {
|
||||
await this.token.pause({ from: pauser });
|
||||
await this.token.unpause({ from: pauser });
|
||||
await this.token.pause();
|
||||
await this.token.unpause();
|
||||
|
||||
await this.token.transfer(recipient, initialSupply, { from: pauser });
|
||||
await this.token.transfer(recipient, initialSupply, { from: holder });
|
||||
|
||||
expect(await this.token.balanceOf(pauser)).to.be.bignumber.equal('0');
|
||||
expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0');
|
||||
expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply);
|
||||
});
|
||||
|
||||
it('reverts when trying to transfer when paused', async function () {
|
||||
await this.token.pause({ from: pauser });
|
||||
await this.token.pause();
|
||||
|
||||
await expectRevert(this.token.transfer(recipient, initialSupply, { from: pauser }),
|
||||
'Pausable: paused'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('approve', function () {
|
||||
const allowance = new BN(40);
|
||||
|
||||
it('allows to approve when unpaused', async function () {
|
||||
await this.token.approve(anotherAccount, allowance, { from: pauser });
|
||||
|
||||
expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance);
|
||||
});
|
||||
|
||||
it('allows to approve when paused and then unpaused', async function () {
|
||||
await this.token.pause({ from: pauser });
|
||||
await this.token.unpause({ from: pauser });
|
||||
|
||||
await this.token.approve(anotherAccount, allowance, { from: pauser });
|
||||
|
||||
expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance);
|
||||
});
|
||||
|
||||
it('reverts when trying to approve when paused', async function () {
|
||||
await this.token.pause({ from: pauser });
|
||||
|
||||
await expectRevert(this.token.approve(anotherAccount, allowance, { from: pauser }),
|
||||
'Pausable: paused'
|
||||
await expectRevert(this.token.transfer(recipient, initialSupply, { from: holder }),
|
||||
'ERC20Pausable: token transfer while paused'
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -181,95 +47,31 @@ describe('ERC20Pausable', function () {
|
||||
const allowance = new BN(40);
|
||||
|
||||
beforeEach(async function () {
|
||||
await this.token.approve(anotherAccount, allowance, { from: pauser });
|
||||
await this.token.approve(anotherAccount, allowance, { from: holder });
|
||||
});
|
||||
|
||||
it('allows to transfer from when unpaused', async function () {
|
||||
await this.token.transferFrom(pauser, recipient, allowance, { from: anotherAccount });
|
||||
await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount });
|
||||
|
||||
expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance);
|
||||
expect(await this.token.balanceOf(pauser)).to.be.bignumber.equal(initialSupply.sub(allowance));
|
||||
expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance));
|
||||
});
|
||||
|
||||
it('allows to transfer when paused and then unpaused', async function () {
|
||||
await this.token.pause({ from: pauser });
|
||||
await this.token.unpause({ from: pauser });
|
||||
await this.token.pause();
|
||||
await this.token.unpause();
|
||||
|
||||
await this.token.transferFrom(pauser, recipient, allowance, { from: anotherAccount });
|
||||
await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount });
|
||||
|
||||
expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance);
|
||||
expect(await this.token.balanceOf(pauser)).to.be.bignumber.equal(initialSupply.sub(allowance));
|
||||
expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance));
|
||||
});
|
||||
|
||||
it('reverts when trying to transfer from when paused', async function () {
|
||||
await this.token.pause({ from: pauser });
|
||||
await this.token.pause();
|
||||
|
||||
await expectRevert(this.token.transferFrom(
|
||||
pauser, recipient, allowance, { from: anotherAccount }), 'Pausable: paused'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('decrease approval', function () {
|
||||
const allowance = new BN(40);
|
||||
const decrement = new BN(10);
|
||||
|
||||
beforeEach(async function () {
|
||||
await this.token.approve(anotherAccount, allowance, { from: pauser });
|
||||
});
|
||||
|
||||
it('allows to decrease approval when unpaused', async function () {
|
||||
await this.token.decreaseAllowance(anotherAccount, decrement, { from: pauser });
|
||||
|
||||
expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance.sub(decrement));
|
||||
});
|
||||
|
||||
it('allows to decrease approval when paused and then unpaused', async function () {
|
||||
await this.token.pause({ from: pauser });
|
||||
await this.token.unpause({ from: pauser });
|
||||
|
||||
await this.token.decreaseAllowance(anotherAccount, decrement, { from: pauser });
|
||||
|
||||
expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance.sub(decrement));
|
||||
});
|
||||
|
||||
it('reverts when trying to transfer when paused', async function () {
|
||||
await this.token.pause({ from: pauser });
|
||||
|
||||
await expectRevert(this.token.decreaseAllowance(
|
||||
anotherAccount, decrement, { from: pauser }), 'Pausable: paused'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('increase approval', function () {
|
||||
const allowance = new BN(40);
|
||||
const increment = new BN(30);
|
||||
|
||||
beforeEach(async function () {
|
||||
await this.token.approve(anotherAccount, allowance, { from: pauser });
|
||||
});
|
||||
|
||||
it('allows to increase approval when unpaused', async function () {
|
||||
await this.token.increaseAllowance(anotherAccount, increment, { from: pauser });
|
||||
|
||||
expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance.add(increment));
|
||||
});
|
||||
|
||||
it('allows to increase approval when paused and then unpaused', async function () {
|
||||
await this.token.pause({ from: pauser });
|
||||
await this.token.unpause({ from: pauser });
|
||||
|
||||
await this.token.increaseAllowance(anotherAccount, increment, { from: pauser });
|
||||
|
||||
expect(await this.token.allowance(pauser, anotherAccount)).to.be.bignumber.equal(allowance.add(increment));
|
||||
});
|
||||
|
||||
it('reverts when trying to increase approval when paused', async function () {
|
||||
await this.token.pause({ from: pauser });
|
||||
|
||||
await expectRevert(this.token.increaseAllowance(
|
||||
anotherAccount, increment, { from: pauser }), 'Pausable: paused'
|
||||
holder, recipient, allowance, { from: anotherAccount }), 'ERC20Pausable: token transfer while paused'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -4,17 +4,17 @@ const { BN, expectRevert, time } = require('@openzeppelin/test-helpers');
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const ERC20Mintable = contract.fromArtifact('ERC20Mintable');
|
||||
const ERC20Mock = contract.fromArtifact('ERC20Mock');
|
||||
const TokenTimelock = contract.fromArtifact('TokenTimelock');
|
||||
|
||||
describe('TokenTimelock', function () {
|
||||
const [ minter, beneficiary ] = accounts;
|
||||
const [ beneficiary ] = accounts;
|
||||
|
||||
const amount = new BN(100);
|
||||
|
||||
context('with token', function () {
|
||||
beforeEach(async function () {
|
||||
this.token = await ERC20Mintable.new({ from: minter });
|
||||
this.token = await ERC20Mock.new(beneficiary, 0); // We're not using the preminted tokens
|
||||
});
|
||||
|
||||
it('rejects a release time in the past', async function () {
|
||||
@ -29,7 +29,7 @@ describe('TokenTimelock', function () {
|
||||
beforeEach(async function () {
|
||||
this.releaseTime = (await time.latest()).add(time.duration.years(1));
|
||||
this.timelock = await TokenTimelock.new(this.token.address, beneficiary, this.releaseTime);
|
||||
await this.token.mint(this.timelock.address, amount, { from: minter });
|
||||
await this.token.mint(this.timelock.address, amount);
|
||||
});
|
||||
|
||||
it('can get state', async function () {
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { ZERO_ADDRESS } = constants;
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
function shouldBehaveLikeERC20Mintable (minter, [other]) {
|
||||
describe('as a mintable token', function () {
|
||||
describe('mint', function () {
|
||||
const amount = new BN(100);
|
||||
|
||||
context('when the sender has minting permission', function () {
|
||||
const from = minter;
|
||||
|
||||
context('for a zero amount', function () {
|
||||
shouldMint(new BN(0));
|
||||
});
|
||||
|
||||
context('for a non-zero amount', function () {
|
||||
shouldMint(amount);
|
||||
});
|
||||
|
||||
function shouldMint (amount) {
|
||||
beforeEach(async function () {
|
||||
({ logs: this.logs } = await this.token.mint(other, amount, { from }));
|
||||
});
|
||||
|
||||
it('mints the requested amount', async function () {
|
||||
expect(await this.token.balanceOf(other)).to.be.bignumber.equal(amount);
|
||||
});
|
||||
|
||||
it('emits a mint and a transfer event', async function () {
|
||||
expectEvent.inLogs(this.logs, 'Transfer', {
|
||||
from: ZERO_ADDRESS,
|
||||
to: other,
|
||||
value: amount,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
context('when the sender doesn\'t have minting permission', function () {
|
||||
const from = other;
|
||||
|
||||
it('reverts', async function () {
|
||||
await expectRevert(this.token.mint(other, amount, { from }),
|
||||
'MinterRole: caller does not have the Minter role'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
shouldBehaveLikeERC20Mintable,
|
||||
};
|
||||
@ -8,8 +8,6 @@ const ERC721Mock = contract.fromArtifact('ERC721Mock');
|
||||
const ERC721ReceiverMock = contract.fromArtifact('ERC721ReceiverMock');
|
||||
|
||||
function shouldBehaveLikeERC721 (
|
||||
creator,
|
||||
minter,
|
||||
[owner, approved, anotherApproved, operator, other]
|
||||
) {
|
||||
const firstTokenId = new BN(1);
|
||||
@ -19,8 +17,8 @@ function shouldBehaveLikeERC721 (
|
||||
|
||||
describe('like an ERC721', function () {
|
||||
beforeEach(async function () {
|
||||
await this.token.mint(owner, firstTokenId, { from: minter });
|
||||
await this.token.mint(owner, secondTokenId, { from: minter });
|
||||
await this.token.mint(owner, firstTokenId);
|
||||
await this.token.mint(owner, secondTokenId);
|
||||
this.toWhom = other; // default to anyone for toWhom in context-dependent tests
|
||||
});
|
||||
|
||||
@ -593,7 +591,7 @@ function shouldBehaveLikeERC721 (
|
||||
context('when token is not minted', async function () {
|
||||
it('reverts', async function () {
|
||||
await expectRevert(
|
||||
this.token.getApproved(unknownTokenId, { from: minter }),
|
||||
this.token.getApproved(unknownTokenId),
|
||||
'ERC721: approved query for nonexistent token'
|
||||
);
|
||||
});
|
||||
|
||||
@ -9,13 +9,13 @@ const { shouldBehaveLikeERC721 } = require('./ERC721.behavior');
|
||||
const ERC721Mock = contract.fromArtifact('ERC721Mock');
|
||||
|
||||
describe('ERC721', function () {
|
||||
const [ creator, owner, other, ...otherAccounts ] = accounts;
|
||||
const [ owner, other ] = accounts;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await ERC721Mock.new({ from: creator });
|
||||
this.token = await ERC721Mock.new();
|
||||
});
|
||||
|
||||
shouldBehaveLikeERC721(creator, creator, otherAccounts);
|
||||
shouldBehaveLikeERC721(accounts);
|
||||
|
||||
describe('internal functions', function () {
|
||||
const tokenId = new BN('5042');
|
||||
|
||||
@ -1,22 +1,79 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
require('@openzeppelin/test-helpers');
|
||||
const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { ZERO_ADDRESS } = constants;
|
||||
|
||||
const { shouldBehaveLikeERC721 } = require('./ERC721.behavior');
|
||||
const {
|
||||
shouldBehaveLikeMintAndBurnERC721,
|
||||
} = require('./ERC721MintBurn.behavior');
|
||||
const { expect } = require('chai');
|
||||
|
||||
const ERC721BurnableImpl = contract.fromArtifact('ERC721MintableBurnableImpl');
|
||||
const ERC721BurnableMock = contract.fromArtifact('ERC721BurnableMock');
|
||||
|
||||
describe('ERC721Burnable', function () {
|
||||
const [ creator, ...otherAccounts ] = accounts;
|
||||
const minter = creator;
|
||||
const [owner, approved] = accounts;
|
||||
|
||||
const firstTokenId = new BN(1);
|
||||
const secondTokenId = new BN(2);
|
||||
const unknownTokenId = new BN(3);
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await ERC721BurnableImpl.new({ from: creator });
|
||||
this.token = await ERC721BurnableMock.new();
|
||||
});
|
||||
|
||||
shouldBehaveLikeERC721(creator, minter, otherAccounts);
|
||||
shouldBehaveLikeMintAndBurnERC721(creator, minter, otherAccounts);
|
||||
describe('like a burnable ERC721', function () {
|
||||
beforeEach(async function () {
|
||||
await this.token.mint(owner, firstTokenId);
|
||||
await this.token.mint(owner, secondTokenId);
|
||||
});
|
||||
|
||||
describe('burn', function () {
|
||||
const tokenId = firstTokenId;
|
||||
let logs = null;
|
||||
|
||||
describe('when successful', function () {
|
||||
beforeEach(async function () {
|
||||
const result = await this.token.burn(tokenId, { from: owner });
|
||||
logs = result.logs;
|
||||
});
|
||||
|
||||
it('burns the given token ID and adjusts the balance of the owner', async function () {
|
||||
await expectRevert(
|
||||
this.token.ownerOf(tokenId),
|
||||
'ERC721: owner query for nonexistent token'
|
||||
);
|
||||
expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1');
|
||||
});
|
||||
|
||||
it('emits a burn event', async function () {
|
||||
expectEvent.inLogs(logs, 'Transfer', {
|
||||
from: owner,
|
||||
to: ZERO_ADDRESS,
|
||||
tokenId: tokenId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there is a previous approval burned', function () {
|
||||
beforeEach(async function () {
|
||||
await this.token.approve(approved, tokenId, { from: owner });
|
||||
const result = await this.token.burn(tokenId, { from: owner });
|
||||
logs = result.logs;
|
||||
});
|
||||
|
||||
context('getApproved', function () {
|
||||
it('reverts', async function () {
|
||||
await expectRevert(
|
||||
this.token.getApproved(tokenId), 'ERC721: approved query for nonexistent token'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the given token ID was not tracked by this contract', function () {
|
||||
it('reverts', async function () {
|
||||
await expectRevert(
|
||||
this.token.burn(unknownTokenId, { from: owner }), 'ERC721: operator query for nonexistent token'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -9,14 +9,7 @@ const { shouldSupportInterfaces } = require('../../introspection/SupportsInterfa
|
||||
const ERC721FullMock = contract.fromArtifact('ERC721FullMock');
|
||||
|
||||
describe('ERC721Full', function () {
|
||||
const [ creator, ...otherAccounts ] = accounts;
|
||||
const minter = creator;
|
||||
|
||||
const [
|
||||
owner,
|
||||
newOwner,
|
||||
other,
|
||||
] = otherAccounts;
|
||||
const [owner, newOwner, other ] = accounts;
|
||||
|
||||
const name = 'Non Fungible Token';
|
||||
const symbol = 'NFT';
|
||||
@ -26,18 +19,18 @@ describe('ERC721Full', function () {
|
||||
const nonExistentTokenId = new BN(999);
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await ERC721FullMock.new(name, symbol, { from: creator });
|
||||
this.token = await ERC721FullMock.new(name, symbol);
|
||||
});
|
||||
|
||||
describe('like a full ERC721', function () {
|
||||
beforeEach(async function () {
|
||||
await this.token.mint(owner, firstTokenId, { from: minter });
|
||||
await this.token.mint(owner, secondTokenId, { from: minter });
|
||||
await this.token.mint(owner, firstTokenId);
|
||||
await this.token.mint(owner, secondTokenId);
|
||||
});
|
||||
|
||||
describe('mint', function () {
|
||||
beforeEach(async function () {
|
||||
await this.token.mint(newOwner, thirdTokenId, { from: minter });
|
||||
await this.token.mint(newOwner, thirdTokenId);
|
||||
});
|
||||
|
||||
it('adjusts owner tokens by index', async function () {
|
||||
@ -228,8 +221,8 @@ describe('ERC721Full', function () {
|
||||
const anotherNewTokenId = new BN(400);
|
||||
|
||||
await this.token.burn(tokenId, { from: owner });
|
||||
await this.token.mint(newOwner, newTokenId, { from: minter });
|
||||
await this.token.mint(newOwner, anotherNewTokenId, { from: minter });
|
||||
await this.token.mint(newOwner, newTokenId);
|
||||
await this.token.mint(newOwner, anotherNewTokenId);
|
||||
|
||||
expect(await this.token.totalSupply()).to.be.bignumber.equal('3');
|
||||
|
||||
@ -245,7 +238,7 @@ describe('ERC721Full', function () {
|
||||
});
|
||||
});
|
||||
|
||||
shouldBehaveLikeERC721(creator, minter, otherAccounts);
|
||||
shouldBehaveLikeERC721(accounts);
|
||||
|
||||
shouldSupportInterfaces([
|
||||
'ERC165',
|
||||
|
||||
@ -5,18 +5,18 @@ const { BN } = require('@openzeppelin/test-helpers');
|
||||
const { expect } = require('chai');
|
||||
|
||||
const ERC721Holder = contract.fromArtifact('ERC721Holder');
|
||||
const ERC721Mintable = contract.fromArtifact('ERC721MintableBurnableImpl');
|
||||
const ERC721Mock = contract.fromArtifact('ERC721Mock');
|
||||
|
||||
describe('ERC721Holder', function () {
|
||||
const [ creator ] = accounts;
|
||||
const [ owner ] = accounts;
|
||||
|
||||
it('receives an ERC721 token', async function () {
|
||||
const token = await ERC721Mintable.new({ from: creator });
|
||||
const token = await ERC721Mock.new();
|
||||
const tokenId = new BN(1);
|
||||
await token.mint(creator, tokenId, { from: creator });
|
||||
await token.mint(owner, tokenId);
|
||||
|
||||
const receiver = await ERC721Holder.new();
|
||||
await token.safeTransferFrom(creator, receiver.address, tokenId, { from: creator });
|
||||
await token.safeTransferFrom(owner, receiver.address, tokenId, { from: owner });
|
||||
|
||||
expect(await token.ownerOf(tokenId)).to.be.equal(receiver.address);
|
||||
});
|
||||
|
||||
@ -1,144 +0,0 @@
|
||||
const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { ZERO_ADDRESS } = constants;
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
function shouldBehaveLikeMintAndBurnERC721 (
|
||||
creator,
|
||||
minter,
|
||||
[owner, newOwner, approved]
|
||||
) {
|
||||
const firstTokenId = new BN(1);
|
||||
const secondTokenId = new BN(2);
|
||||
const thirdTokenId = new BN(3);
|
||||
const unknownTokenId = new BN(4);
|
||||
const MOCK_URI = 'https://example.com';
|
||||
const data = '0x42';
|
||||
|
||||
describe('like a mintable and burnable ERC721', function () {
|
||||
beforeEach(async function () {
|
||||
await this.token.mint(owner, firstTokenId, { from: minter });
|
||||
await this.token.mint(owner, secondTokenId, { from: minter });
|
||||
});
|
||||
|
||||
describe('mint', function () {
|
||||
let logs = null;
|
||||
|
||||
describe('when successful', function () {
|
||||
beforeEach(async function () {
|
||||
const result = await this.token.mint(newOwner, thirdTokenId, { from: minter });
|
||||
logs = result.logs;
|
||||
});
|
||||
|
||||
it('assigns the token to the new owner', async function () {
|
||||
expect(await this.token.ownerOf(thirdTokenId)).to.equal(newOwner);
|
||||
});
|
||||
|
||||
it('increases the balance of its owner', async function () {
|
||||
expect(await this.token.balanceOf(newOwner)).to.be.bignumber.equal('1');
|
||||
});
|
||||
|
||||
it('emits a transfer and minted event', async function () {
|
||||
expectEvent.inLogs(logs, 'Transfer', {
|
||||
from: ZERO_ADDRESS,
|
||||
to: newOwner,
|
||||
tokenId: thirdTokenId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the given owner address is the zero address', function () {
|
||||
it('reverts', async function () {
|
||||
await expectRevert(
|
||||
this.token.mint(ZERO_ADDRESS, thirdTokenId, { from: minter }),
|
||||
'ERC721: mint to the zero address'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the given token ID was already tracked by this contract', function () {
|
||||
it('reverts', async function () {
|
||||
await expectRevert(this.token.mint(owner, firstTokenId, { from: minter }),
|
||||
'ERC721: token already minted.'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mintWithTokenURI', function () {
|
||||
it('can mint with a tokenUri', async function () {
|
||||
await this.token.mintWithTokenURI(newOwner, thirdTokenId, MOCK_URI, {
|
||||
from: minter,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('safeMint', function () {
|
||||
it('it can safely mint with data', async function () {
|
||||
await this.token.methods['safeMint(address,uint256,bytes)'](...[newOwner, thirdTokenId, data],
|
||||
{ from: minter });
|
||||
});
|
||||
|
||||
it('it can safely mint without data', async function () {
|
||||
await this.token.methods['safeMint(address,uint256)'](...[newOwner, thirdTokenId],
|
||||
{ from: minter });
|
||||
});
|
||||
});
|
||||
|
||||
describe('burn', function () {
|
||||
const tokenId = firstTokenId;
|
||||
let logs = null;
|
||||
|
||||
describe('when successful', function () {
|
||||
beforeEach(async function () {
|
||||
const result = await this.token.burn(tokenId, { from: owner });
|
||||
logs = result.logs;
|
||||
});
|
||||
|
||||
it('burns the given token ID and adjusts the balance of the owner', async function () {
|
||||
await expectRevert(
|
||||
this.token.ownerOf(tokenId),
|
||||
'ERC721: owner query for nonexistent token'
|
||||
);
|
||||
expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1');
|
||||
});
|
||||
|
||||
it('emits a burn event', async function () {
|
||||
expectEvent.inLogs(logs, 'Transfer', {
|
||||
from: owner,
|
||||
to: ZERO_ADDRESS,
|
||||
tokenId: tokenId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there is a previous approval burned', function () {
|
||||
beforeEach(async function () {
|
||||
await this.token.approve(approved, tokenId, { from: owner });
|
||||
const result = await this.token.burn(tokenId, { from: owner });
|
||||
logs = result.logs;
|
||||
});
|
||||
|
||||
context('getApproved', function () {
|
||||
it('reverts', async function () {
|
||||
await expectRevert(
|
||||
this.token.getApproved(tokenId), 'ERC721: approved query for nonexistent token'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the given token ID was not tracked by this contract', function () {
|
||||
it('reverts', async function () {
|
||||
await expectRevert(
|
||||
this.token.burn(unknownTokenId, { from: creator }), 'ERC721: operator query for nonexistent token'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
shouldBehaveLikeMintAndBurnERC721,
|
||||
};
|
||||
@ -1,21 +0,0 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
require('@openzeppelin/test-helpers');
|
||||
const { shouldBehaveLikeERC721 } = require('./ERC721.behavior');
|
||||
const { shouldBehaveLikeMintAndBurnERC721 } = require('./ERC721MintBurn.behavior');
|
||||
|
||||
const ERC721MintableImpl = contract.fromArtifact('ERC721MintableBurnableImpl');
|
||||
|
||||
describe('ERC721Mintable', function () {
|
||||
const [ creator, ...otherAccounts ] = accounts;
|
||||
const minter = creator;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await ERC721MintableImpl.new({
|
||||
from: creator,
|
||||
});
|
||||
});
|
||||
|
||||
shouldBehaveLikeERC721(creator, minter, otherAccounts);
|
||||
shouldBehaveLikeMintAndBurnERC721(creator, minter, otherAccounts);
|
||||
});
|
||||
@ -1,46 +1,88 @@
|
||||
const { accounts, contract } = require('@openzeppelin/test-environment');
|
||||
|
||||
require('@openzeppelin/test-helpers');
|
||||
const { shouldBehaveLikeERC721PausedToken } = require('./ERC721PausedToken.behavior');
|
||||
const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { ZERO_ADDRESS } = constants;
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
const { shouldBehaveLikeERC721 } = require('./ERC721.behavior');
|
||||
const { shouldBehaveLikePublicRole } = require('../../behaviors/access/roles/PublicRole.behavior');
|
||||
|
||||
const ERC721PausableMock = contract.fromArtifact('ERC721PausableMock');
|
||||
|
||||
describe('ERC721Pausable', function () {
|
||||
const [ creator, otherPauser, ...otherAccounts ] = accounts;
|
||||
const [ owner, receiver, operator ] = accounts;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.token = await ERC721PausableMock.new({ from: creator });
|
||||
});
|
||||
|
||||
describe('pauser role', function () {
|
||||
beforeEach(async function () {
|
||||
this.contract = this.token;
|
||||
await this.contract.addPauser(otherPauser, { from: creator });
|
||||
});
|
||||
|
||||
shouldBehaveLikePublicRole(creator, otherPauser, otherAccounts, 'pauser');
|
||||
});
|
||||
|
||||
context('when token is paused', function () {
|
||||
beforeEach(async function () {
|
||||
await this.token.pause({ from: creator });
|
||||
});
|
||||
|
||||
shouldBehaveLikeERC721PausedToken(creator, otherAccounts);
|
||||
this.token = await ERC721PausableMock.new();
|
||||
});
|
||||
|
||||
context('when token is not paused yet', function () {
|
||||
shouldBehaveLikeERC721(creator, creator, otherAccounts);
|
||||
shouldBehaveLikeERC721(accounts);
|
||||
});
|
||||
|
||||
context('when token is paused and then unpaused', function () {
|
||||
context('when token is paused', function () {
|
||||
const firstTokenId = new BN(1);
|
||||
const mintedTokens = new BN(1);
|
||||
const mockData = '0x42';
|
||||
|
||||
beforeEach(async function () {
|
||||
await this.token.pause({ from: creator });
|
||||
await this.token.unpause({ from: creator });
|
||||
await this.token.mint(owner, firstTokenId, { from: owner });
|
||||
await this.token.pause();
|
||||
});
|
||||
|
||||
shouldBehaveLikeERC721(creator, creator, otherAccounts);
|
||||
it('reverts when trying to transferFrom', async function () {
|
||||
await expectRevert(
|
||||
this.token.transferFrom(owner, receiver, firstTokenId, { from: owner }),
|
||||
'ERC721Pausable: token transfer while paused'
|
||||
);
|
||||
});
|
||||
|
||||
it('reverts when trying to safeTransferFrom', async function () {
|
||||
await expectRevert(
|
||||
this.token.safeTransferFrom(owner, receiver, firstTokenId, { from: owner }),
|
||||
'ERC721Pausable: token transfer while paused'
|
||||
);
|
||||
});
|
||||
|
||||
it('reverts when trying to safeTransferFrom with data', async function () {
|
||||
await expectRevert(
|
||||
this.token.methods['safeTransferFrom(address,address,uint256,bytes)'](
|
||||
owner, receiver, firstTokenId, mockData, { from: owner }
|
||||
), 'ERC721Pausable: token transfer while paused'
|
||||
);
|
||||
});
|
||||
|
||||
describe('getApproved', function () {
|
||||
it('returns approved address', async function () {
|
||||
const approvedAccount = await this.token.getApproved(firstTokenId);
|
||||
expect(approvedAccount).to.equal(ZERO_ADDRESS);
|
||||
});
|
||||
});
|
||||
|
||||
describe('balanceOf', function () {
|
||||
it('returns the amount of tokens owned by the given address', async function () {
|
||||
const balance = await this.token.balanceOf(owner);
|
||||
expect(balance).to.be.bignumber.equal(mintedTokens);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ownerOf', function () {
|
||||
it('returns the amount of tokens owned by the given address', async function () {
|
||||
const ownerOfToken = await this.token.ownerOf(firstTokenId);
|
||||
expect(ownerOfToken).to.equal(owner);
|
||||
});
|
||||
});
|
||||
|
||||
describe('exists', function () {
|
||||
it('should return token existence', async function () {
|
||||
expect(await this.token.exists(firstTokenId)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isApprovedForAll', function () {
|
||||
it('returns the approval of the operator', async function () {
|
||||
expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers');
|
||||
const { ZERO_ADDRESS } = constants;
|
||||
|
||||
const { expect } = require('chai');
|
||||
|
||||
function shouldBehaveLikeERC721PausedToken (owner, [receiver, operator]) {
|
||||
const firstTokenId = new BN(1);
|
||||
const mintedTokens = new BN(1);
|
||||
const mockData = '0x42';
|
||||
|
||||
describe('like a paused ERC721', function () {
|
||||
beforeEach(async function () {
|
||||
await this.token.mint(owner, firstTokenId, { from: owner });
|
||||
});
|
||||
|
||||
it('reverts when trying to approve', async function () {
|
||||
await expectRevert(
|
||||
this.token.approve(receiver, firstTokenId, { from: owner }), 'Pausable: paused'
|
||||
);
|
||||
});
|
||||
|
||||
it('reverts when trying to setApprovalForAll', async function () {
|
||||
await expectRevert(
|
||||
this.token.setApprovalForAll(operator, true, { from: owner }), 'Pausable: paused'
|
||||
);
|
||||
});
|
||||
|
||||
it('reverts when trying to transferFrom', async function () {
|
||||
await expectRevert(
|
||||
this.token.transferFrom(owner, receiver, firstTokenId, { from: owner }), 'Pausable: paused'
|
||||
);
|
||||
});
|
||||
|
||||
it('reverts when trying to safeTransferFrom', async function () {
|
||||
await expectRevert(
|
||||
this.token.safeTransferFrom(owner, receiver, firstTokenId, { from: owner }), 'Pausable: paused'
|
||||
);
|
||||
});
|
||||
|
||||
it('reverts when trying to safeTransferFrom with data', async function () {
|
||||
await expectRevert(
|
||||
this.token.methods['safeTransferFrom(address,address,uint256,bytes)'](
|
||||
owner, receiver, firstTokenId, mockData, { from: owner }
|
||||
), 'Pausable: paused'
|
||||
);
|
||||
});
|
||||
|
||||
describe('getApproved', function () {
|
||||
it('returns approved address', async function () {
|
||||
const approvedAccount = await this.token.getApproved(firstTokenId);
|
||||
expect(approvedAccount).to.equal(ZERO_ADDRESS);
|
||||
});
|
||||
});
|
||||
|
||||
describe('balanceOf', function () {
|
||||
it('returns the amount of tokens owned by the given address', async function () {
|
||||
const balance = await this.token.balanceOf(owner);
|
||||
expect(balance).to.be.bignumber.equal(mintedTokens);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ownerOf', function () {
|
||||
it('returns the amount of tokens owned by the given address', async function () {
|
||||
const ownerOfToken = await this.token.ownerOf(firstTokenId);
|
||||
expect(ownerOfToken).to.equal(owner);
|
||||
});
|
||||
});
|
||||
|
||||
describe('exists', function () {
|
||||
it('should return token existence', async function () {
|
||||
expect(await this.token.exists(firstTokenId)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isApprovedForAll', function () {
|
||||
it('returns the approval of the operator', async function () {
|
||||
expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
shouldBehaveLikeERC721PausedToken,
|
||||
};
|
||||
@ -4,7 +4,6 @@ const { balance, constants, ether, expectRevert, send } = require('@openzeppelin
|
||||
const { expect } = require('chai');
|
||||
|
||||
const AddressImpl = contract.fromArtifact('AddressImpl');
|
||||
const SimpleToken = contract.fromArtifact('SimpleToken');
|
||||
const EtherReceiver = contract.fromArtifact('EtherReceiverMock');
|
||||
|
||||
describe('Address', function () {
|
||||
@ -22,7 +21,7 @@ describe('Address', function () {
|
||||
});
|
||||
|
||||
it('should return true for contract address', async function () {
|
||||
const contract = await SimpleToken.new();
|
||||
const contract = await AddressImpl.new();
|
||||
expect(await this.mock.isContract(contract.address)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user