ERC20Snapshot.test.js 8.4 KB

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