ERC20Snapshot.test.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. const { accounts, contract } = require('@openzeppelin/test-environment');
  2. const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
  3. const ERC20SnapshotMock = contract.fromArtifact('ERC20SnapshotMock');
  4. const { expect } = require('chai');
  5. describe('ERC20Snapshot', function () {
  6. const [ initialHolder, recipient, other ] = accounts;
  7. const initialSupply = new BN(100);
  8. beforeEach(async function () {
  9. this.token = await ERC20SnapshotMock.new(initialHolder, initialSupply);
  10. });
  11. describe('snapshot', function () {
  12. it('emits a snapshot event', async function () {
  13. const { logs } = await this.token.snapshot();
  14. expectEvent.inLogs(logs, 'Snapshot');
  15. });
  16. it('creates increasing snapshots ids, starting from 1', async function () {
  17. for (const id of ['1', '2', '3', '4', '5']) {
  18. const { logs } = await this.token.snapshot();
  19. expectEvent.inLogs(logs, 'Snapshot', { id });
  20. }
  21. });
  22. });
  23. describe('totalSupplyAt', function () {
  24. it('reverts with a snapshot id of 0', async function () {
  25. await expectRevert(this.token.totalSupplyAt(0), 'ERC20Snapshot: id is 0');
  26. });
  27. it('reverts with a not-yet-created snapshot id', async function () {
  28. await expectRevert(this.token.totalSupplyAt(1), 'ERC20Snapshot: nonexistent id');
  29. });
  30. context('with initial snapshot', function () {
  31. beforeEach(async function () {
  32. this.initialSnapshotId = new BN('1');
  33. const { logs } = await this.token.snapshot();
  34. expectEvent.inLogs(logs, 'Snapshot', { id: this.initialSnapshotId });
  35. });
  36. context('with no supply changes after the snapshot', function () {
  37. it('returns the current total supply', async function () {
  38. expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply);
  39. });
  40. });
  41. context('with supply changes after the snapshot', function () {
  42. beforeEach(async function () {
  43. await this.token.mint(other, new BN('50'));
  44. await this.token.burn(initialHolder, new BN('20'));
  45. });
  46. it('returns the total supply before the changes', async function () {
  47. expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply);
  48. });
  49. context('with a second snapshot after supply changes', function () {
  50. beforeEach(async function () {
  51. this.secondSnapshotId = new BN('2');
  52. const { logs } = await this.token.snapshot();
  53. expectEvent.inLogs(logs, 'Snapshot', { id: this.secondSnapshotId });
  54. });
  55. it('snapshots return the supply before and after the changes', async function () {
  56. expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply);
  57. expect(await this.token.totalSupplyAt(this.secondSnapshotId)).to.be.bignumber.equal(
  58. await this.token.totalSupply()
  59. );
  60. });
  61. });
  62. context('with multiple snapshots after supply changes', function () {
  63. beforeEach(async function () {
  64. this.secondSnapshotIds = ['2', '3', '4'];
  65. for (const id of this.secondSnapshotIds) {
  66. const { logs } = await this.token.snapshot();
  67. expectEvent.inLogs(logs, 'Snapshot', { id });
  68. }
  69. });
  70. it('all posterior snapshots return the supply after the changes', async function () {
  71. expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply);
  72. const currentSupply = await this.token.totalSupply();
  73. for (const id of this.secondSnapshotIds) {
  74. expect(await this.token.totalSupplyAt(id)).to.be.bignumber.equal(currentSupply);
  75. }
  76. });
  77. });
  78. });
  79. });
  80. });
  81. describe('balanceOfAt', function () {
  82. it('reverts with a snapshot id of 0', async function () {
  83. await expectRevert(this.token.balanceOfAt(other, 0), 'ERC20Snapshot: id is 0');
  84. });
  85. it('reverts with a not-yet-created snapshot id', async function () {
  86. await expectRevert(this.token.balanceOfAt(other, 1), 'ERC20Snapshot: nonexistent id');
  87. });
  88. context('with initial snapshot', function () {
  89. beforeEach(async function () {
  90. this.initialSnapshotId = new BN('1');
  91. const { logs } = await this.token.snapshot();
  92. expectEvent.inLogs(logs, 'Snapshot', { id: this.initialSnapshotId });
  93. });
  94. context('with no balance changes after the snapshot', function () {
  95. it('returns the current balance for all accounts', async function () {
  96. expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))
  97. .to.be.bignumber.equal(initialSupply);
  98. expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0');
  99. expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0');
  100. });
  101. });
  102. context('with balance changes after the snapshot', function () {
  103. beforeEach(async function () {
  104. await this.token.transfer(recipient, new BN('10'), { from: initialHolder });
  105. await this.token.mint(recipient, new BN('50'));
  106. await this.token.burn(initialHolder, new BN('20'));
  107. });
  108. it('returns the balances before the changes', async function () {
  109. expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))
  110. .to.be.bignumber.equal(initialSupply);
  111. expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0');
  112. expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0');
  113. });
  114. context('with a second snapshot after supply changes', function () {
  115. beforeEach(async function () {
  116. this.secondSnapshotId = new BN('2');
  117. const { logs } = await this.token.snapshot();
  118. expectEvent.inLogs(logs, 'Snapshot', { id: this.secondSnapshotId });
  119. });
  120. it('snapshots return the balances before and after the changes', async function () {
  121. expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))
  122. .to.be.bignumber.equal(initialSupply);
  123. expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0');
  124. expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0');
  125. expect(await this.token.balanceOfAt(initialHolder, this.secondSnapshotId)).to.be.bignumber.equal(
  126. await this.token.balanceOf(initialHolder)
  127. );
  128. expect(await this.token.balanceOfAt(recipient, this.secondSnapshotId)).to.be.bignumber.equal(
  129. await this.token.balanceOf(recipient)
  130. );
  131. expect(await this.token.balanceOfAt(other, this.secondSnapshotId)).to.be.bignumber.equal(
  132. await this.token.balanceOf(other)
  133. );
  134. });
  135. });
  136. context('with multiple snapshots after supply changes', function () {
  137. beforeEach(async function () {
  138. this.secondSnapshotIds = ['2', '3', '4'];
  139. for (const id of this.secondSnapshotIds) {
  140. const { logs } = await this.token.snapshot();
  141. expectEvent.inLogs(logs, 'Snapshot', { id });
  142. }
  143. });
  144. it('all posterior snapshots return the supply after the changes', async function () {
  145. expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId))
  146. .to.be.bignumber.equal(initialSupply);
  147. expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0');
  148. expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0');
  149. for (const id of this.secondSnapshotIds) {
  150. expect(await this.token.balanceOfAt(initialHolder, id)).to.be.bignumber.equal(
  151. await this.token.balanceOf(initialHolder)
  152. );
  153. expect(await this.token.balanceOfAt(recipient, id)).to.be.bignumber.equal(
  154. await this.token.balanceOf(recipient)
  155. );
  156. expect(await this.token.balanceOfAt(other, id)).to.be.bignumber.equal(
  157. await this.token.balanceOf(other)
  158. );
  159. }
  160. });
  161. });
  162. });
  163. });
  164. });
  165. });