123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- const { BN, constants, expectEvent, expectRevert } = require('openzeppelin-test-helpers');
- const { ZERO_ADDRESS } = constants;
- function shouldBehaveLikeERC20 (errorPrefix, initialSupply, initialHolder, recipient, anotherAccount) {
- describe('total supply', function () {
- it('returns the total amount of tokens', async function () {
- (await this.token.totalSupply()).should.be.bignumber.equal(initialSupply);
- });
- });
- describe('balanceOf', function () {
- describe('when the requested account has no tokens', function () {
- it('returns zero', async function () {
- (await this.token.balanceOf(anotherAccount)).should.be.bignumber.equal('0');
- });
- });
- describe('when the requested account has some tokens', function () {
- it('returns the total amount of tokens', async function () {
- (await this.token.balanceOf(initialHolder)).should.be.bignumber.equal(initialSupply);
- });
- });
- });
- describe('transfer', function () {
- shouldBehaveLikeERC20Transfer(errorPrefix, initialHolder, recipient, initialSupply,
- function (from, to, value) {
- return this.token.transfer(to, value, { from });
- }
- );
- });
- describe('transfer from', function () {
- const spender = recipient;
- describe('when the token owner is not the zero address', function () {
- const tokenOwner = initialHolder;
- describe('when the recipient is not the zero address', function () {
- const to = anotherAccount;
- describe('when the spender has enough approved balance', function () {
- beforeEach(async function () {
- await this.token.approve(spender, initialSupply, { from: initialHolder });
- });
- describe('when the token owner has enough balance', function () {
- const amount = initialSupply;
- it('transfers the requested amount', async function () {
- await this.token.transferFrom(tokenOwner, to, amount, { from: spender });
- (await this.token.balanceOf(tokenOwner)).should.be.bignumber.equal('0');
- (await this.token.balanceOf(to)).should.be.bignumber.equal(amount);
- });
- it('decreases the spender allowance', async function () {
- await this.token.transferFrom(tokenOwner, to, amount, { from: spender });
- (await this.token.allowance(tokenOwner, spender)).should.be.bignumber.equal('0');
- });
- it('emits a transfer event', async function () {
- const { logs } = await this.token.transferFrom(tokenOwner, to, amount, { from: spender });
- expectEvent.inLogs(logs, 'Transfer', {
- from: tokenOwner,
- to: to,
- value: amount,
- });
- });
- it('emits an approval event', async function () {
- const { logs } = await this.token.transferFrom(tokenOwner, to, amount, { from: spender });
- expectEvent.inLogs(logs, 'Approval', {
- owner: tokenOwner,
- spender: spender,
- value: await this.token.allowance(tokenOwner, spender),
- });
- });
- });
- describe('when the token owner does not have enough balance', function () {
- const amount = initialSupply.addn(1);
- it('reverts', async function () {
- await expectRevert(this.token.transferFrom(
- tokenOwner, to, amount, { from: spender }), 'SafeMath: subtraction overflow'
- );
- });
- });
- });
- describe('when the spender does not have enough approved balance', function () {
- beforeEach(async function () {
- await this.token.approve(spender, initialSupply.subn(1), { from: tokenOwner });
- });
- describe('when the token owner has enough balance', function () {
- const amount = initialSupply;
- it('reverts', async function () {
- await expectRevert(this.token.transferFrom(
- tokenOwner, to, amount, { from: spender }), 'SafeMath: subtraction overflow'
- );
- });
- });
- describe('when the token owner does not have enough balance', function () {
- const amount = initialSupply.addn(1);
- it('reverts', async function () {
- await expectRevert(this.token.transferFrom(
- tokenOwner, to, amount, { from: spender }), 'SafeMath: subtraction overflow'
- );
- });
- });
- });
- });
- describe('when the recipient is the zero address', function () {
- const amount = initialSupply;
- const to = ZERO_ADDRESS;
- beforeEach(async function () {
- await this.token.approve(spender, amount, { from: tokenOwner });
- });
- it('reverts', async function () {
- await expectRevert(this.token.transferFrom(
- tokenOwner, to, amount, { from: spender }), `${errorPrefix}: transfer to the zero address`
- );
- });
- });
- });
- describe('when the token owner is the zero address', function () {
- const amount = 0;
- const tokenOwner = ZERO_ADDRESS;
- const to = recipient;
- it('reverts', async function () {
- await expectRevert(this.token.transferFrom(
- tokenOwner, to, amount, { from: spender }), `${errorPrefix}: transfer from the zero address`
- );
- });
- });
- });
- describe('approve', function () {
- shouldBehaveLikeERC20Approve(errorPrefix, initialHolder, recipient, initialSupply,
- function (owner, spender, amount) {
- return this.token.approve(spender, amount, { from: owner });
- }
- );
- });
- }
- function shouldBehaveLikeERC20Transfer (errorPrefix, from, to, balance, transfer) {
- describe('when the recipient is not the zero address', function () {
- describe('when the sender does not have enough balance', function () {
- const amount = balance.addn(1);
- it('reverts', async function () {
- await expectRevert(transfer.call(this, from, to, amount),
- 'SafeMath: subtraction overflow'
- );
- });
- });
- describe('when the sender transfers all balance', function () {
- const amount = balance;
- it('transfers the requested amount', async function () {
- await transfer.call(this, from, to, amount);
- (await this.token.balanceOf(from)).should.be.bignumber.equal('0');
- (await this.token.balanceOf(to)).should.be.bignumber.equal(amount);
- });
- it('emits a transfer event', async function () {
- const { logs } = await transfer.call(this, from, to, amount);
- expectEvent.inLogs(logs, 'Transfer', {
- from,
- to,
- value: amount,
- });
- });
- });
- describe('when the sender transfers zero tokens', function () {
- const amount = new BN('0');
- it('transfers the requested amount', async function () {
- await transfer.call(this, from, to, amount);
- (await this.token.balanceOf(from)).should.be.bignumber.equal(balance);
- (await this.token.balanceOf(to)).should.be.bignumber.equal('0');
- });
- it('emits a transfer event', async function () {
- const { logs } = await transfer.call(this, from, to, amount);
- expectEvent.inLogs(logs, 'Transfer', {
- from,
- to,
- value: amount,
- });
- });
- });
- });
- describe('when the recipient is the zero address', function () {
- it('reverts', async function () {
- await expectRevert(transfer.call(this, from, ZERO_ADDRESS, balance),
- `${errorPrefix}: transfer to the zero address`
- );
- });
- });
- }
- function shouldBehaveLikeERC20Approve (errorPrefix, owner, spender, supply, approve) {
- describe('when the spender is not the zero address', function () {
- describe('when the sender has enough balance', function () {
- const amount = supply;
- it('emits an approval event', async function () {
- const { logs } = await approve.call(this, owner, spender, amount);
- expectEvent.inLogs(logs, 'Approval', {
- owner: owner,
- spender: spender,
- value: amount,
- });
- });
- describe('when there was no approved amount before', function () {
- it('approves the requested amount', async function () {
- await approve.call(this, owner, spender, amount);
- (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
- });
- });
- describe('when the spender had an approved amount', function () {
- beforeEach(async function () {
- await approve.call(this, owner, spender, new BN(1));
- });
- it('approves the requested amount and replaces the previous one', async function () {
- await approve.call(this, owner, spender, amount);
- (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
- });
- });
- });
- describe('when the sender does not have enough balance', function () {
- const amount = supply.addn(1);
- it('emits an approval event', async function () {
- const { logs } = await approve.call(this, owner, spender, amount);
- expectEvent.inLogs(logs, 'Approval', {
- owner: owner,
- spender: spender,
- value: amount,
- });
- });
- describe('when there was no approved amount before', function () {
- it('approves the requested amount', async function () {
- await approve.call(this, owner, spender, amount);
- (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
- });
- });
- describe('when the spender had an approved amount', function () {
- beforeEach(async function () {
- await approve.call(this, owner, spender, new BN(1));
- });
- it('approves the requested amount and replaces the previous one', async function () {
- await approve.call(this, owner, spender, amount);
- (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
- });
- });
- });
- });
- describe('when the spender is the zero address', function () {
- it('reverts', async function () {
- await expectRevert(approve.call(this, owner, ZERO_ADDRESS, supply),
- `${errorPrefix}: approve to the zero address`
- );
- });
- });
- }
- module.exports = {
- shouldBehaveLikeERC20,
- shouldBehaveLikeERC20Transfer,
- shouldBehaveLikeERC20Approve,
- };
|