ERC20Snapshot.test.js 8.3 KB

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