ERC20Snapshot.test.js 8.2 KB

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