ERC20Snapshot.test.js 8.4 KB

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