| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 | const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');const ERC20SnapshotMock = artifacts.require('ERC20SnapshotMock');const { expect } = require('chai');contract('ERC20Snapshot', function (accounts) {  const [ initialHolder, recipient, other ] = accounts;  const initialSupply = new BN(100);  const name = 'My Token';  const symbol = 'MTKN';  beforeEach(async function () {    this.token = await ERC20SnapshotMock.new(name, symbol, initialHolder, initialSupply);  });  describe('snapshot', function () {    it('emits a snapshot event', async function () {      const receipt = await this.token.snapshot();      expectEvent(receipt, 'Snapshot');    });    it('creates increasing snapshots ids, starting from 1', async function () {      for (const id of ['1', '2', '3', '4', '5']) {        const receipt = await this.token.snapshot();        expectEvent(receipt, 'Snapshot', { id });      }    });  });  describe('totalSupplyAt', function () {    it('reverts with a snapshot id of 0', async function () {      await expectRevert(this.token.totalSupplyAt(0), 'ERC20Snapshot: id is 0');    });    it('reverts with a not-yet-created snapshot id', async function () {      await expectRevert(this.token.totalSupplyAt(1), 'ERC20Snapshot: nonexistent id');    });    context('with initial snapshot', function () {      beforeEach(async function () {        this.initialSnapshotId = new BN('1');        const receipt = await this.token.snapshot();        expectEvent(receipt, 'Snapshot', { id: this.initialSnapshotId });      });      context('with no supply changes after the snapshot', function () {        it('returns the current total supply', async function () {          expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply);        });      });      context('with supply changes after the snapshot', function () {        beforeEach(async function () {          await this.token.mint(other, new BN('50'));          await this.token.burn(initialHolder, new BN('20'));        });        it('returns the total supply before the changes', async function () {          expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply);        });        context('with a second snapshot after supply changes', function () {          beforeEach(async function () {            this.secondSnapshotId = new BN('2');            const receipt = await this.token.snapshot();            expectEvent(receipt, 'Snapshot', { id: this.secondSnapshotId });          });          it('snapshots return the supply before and after the changes', async function () {            expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply);            expect(await this.token.totalSupplyAt(this.secondSnapshotId)).to.be.bignumber.equal(              await this.token.totalSupply(),            );          });        });        context('with multiple snapshots after supply changes', function () {          beforeEach(async function () {            this.secondSnapshotIds = ['2', '3', '4'];            for (const id of this.secondSnapshotIds) {              const receipt = await this.token.snapshot();              expectEvent(receipt, 'Snapshot', { id });            }          });          it('all posterior snapshots return the supply after the changes', async function () {            expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply);            const currentSupply = await this.token.totalSupply();            for (const id of this.secondSnapshotIds) {              expect(await this.token.totalSupplyAt(id)).to.be.bignumber.equal(currentSupply);            }          });        });      });    });  });  describe('balanceOfAt', function () {    it('reverts with a snapshot id of 0', async function () {      await expectRevert(this.token.balanceOfAt(other, 0), 'ERC20Snapshot: id is 0');    });    it('reverts with a not-yet-created snapshot id', async function () {      await expectRevert(this.token.balanceOfAt(other, 1), 'ERC20Snapshot: nonexistent id');    });    context('with initial snapshot', function () {      beforeEach(async function () {        this.initialSnapshotId = new BN('1');        const receipt = await this.token.snapshot();        expectEvent(receipt, 'Snapshot', { id: this.initialSnapshotId });      });      context('with no balance changes after the snapshot', function () {        it('returns the current balance for all accounts', async function () {          expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))            .to.be.bignumber.equal(initialSupply);          expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0');          expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0');        });      });      context('with balance changes after the snapshot', function () {        beforeEach(async function () {          await this.token.transfer(recipient, new BN('10'), { from: initialHolder });          await this.token.mint(other, new BN('50'));          await this.token.burn(initialHolder, new BN('20'));        });        it('returns the balances before the changes', async function () {          expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))            .to.be.bignumber.equal(initialSupply);          expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0');          expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0');        });        context('with a second snapshot after supply changes', function () {          beforeEach(async function () {            this.secondSnapshotId = new BN('2');            const receipt = await this.token.snapshot();            expectEvent(receipt, 'Snapshot', { id: this.secondSnapshotId });          });          it('snapshots return the balances before and after the changes', async function () {            expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))              .to.be.bignumber.equal(initialSupply);            expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0');            expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0');            expect(await this.token.balanceOfAt(initialHolder, this.secondSnapshotId)).to.be.bignumber.equal(              await this.token.balanceOf(initialHolder),            );            expect(await this.token.balanceOfAt(recipient, this.secondSnapshotId)).to.be.bignumber.equal(              await this.token.balanceOf(recipient),            );            expect(await this.token.balanceOfAt(other, this.secondSnapshotId)).to.be.bignumber.equal(              await this.token.balanceOf(other),            );          });        });        context('with multiple snapshots after supply changes', function () {          beforeEach(async function () {            this.secondSnapshotIds = ['2', '3', '4'];            for (const id of this.secondSnapshotIds) {              const receipt = await this.token.snapshot();              expectEvent(receipt, 'Snapshot', { id });            }          });          it('all posterior snapshots return the supply after the changes', async function () {            expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))              .to.be.bignumber.equal(initialSupply);            expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0');            expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0');            for (const id of this.secondSnapshotIds) {              expect(await this.token.balanceOfAt(initialHolder, id)).to.be.bignumber.equal(                await this.token.balanceOf(initialHolder),              );              expect(await this.token.balanceOfAt(recipient, id)).to.be.bignumber.equal(                await this.token.balanceOf(recipient),              );              expect(await this.token.balanceOfAt(other, id)).to.be.bignumber.equal(                await this.token.balanceOf(other),              );            }          });        });      });    });  });});
 |