ERC20Migrator.test.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. const { accounts, contract } = require('@openzeppelin/test-environment');
  2. const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers');
  3. const { ZERO_ADDRESS } = constants;
  4. const { expect } = require('chai');
  5. const ERC20Mock = contract.fromArtifact('ERC20Mock');
  6. const ERC20Mintable = contract.fromArtifact('ERC20Mintable');
  7. const ERC20Migrator = contract.fromArtifact('ERC20Migrator');
  8. describe('ERC20Migrator', function () {
  9. const [ owner ] = accounts;
  10. const totalSupply = new BN('200');
  11. it('reverts with a null legacy token address', async function () {
  12. await expectRevert(ERC20Migrator.new(ZERO_ADDRESS),
  13. 'ERC20Migrator: legacy token is the zero address'
  14. );
  15. });
  16. describe('with tokens and migrator', function () {
  17. beforeEach('deploying tokens and migrator', async function () {
  18. this.legacyToken = await ERC20Mock.new(owner, totalSupply);
  19. this.migrator = await ERC20Migrator.new(this.legacyToken.address);
  20. this.newToken = await ERC20Mintable.new();
  21. });
  22. it('returns legacy token', async function () {
  23. expect(await this.migrator.legacyToken()).to.equal(this.legacyToken.address);
  24. });
  25. describe('beginMigration', function () {
  26. it('reverts with a null new token address', async function () {
  27. await expectRevert(this.migrator.beginMigration(ZERO_ADDRESS),
  28. 'ERC20Migrator: new token is the zero address'
  29. );
  30. });
  31. it('reverts if not a minter of the token', async function () {
  32. await expectRevert(this.migrator.beginMigration(this.newToken.address),
  33. 'ERC20Migrator: not a minter for new token'
  34. );
  35. });
  36. it('succeeds if it is a minter of the token', async function () {
  37. await this.newToken.addMinter(this.migrator.address);
  38. await this.migrator.beginMigration(this.newToken.address);
  39. });
  40. it('reverts the second time it is called', async function () {
  41. await this.newToken.addMinter(this.migrator.address);
  42. await this.migrator.beginMigration(this.newToken.address);
  43. await expectRevert(this.migrator.beginMigration(this.newToken.address),
  44. 'ERC20Migrator: migration already started'
  45. );
  46. });
  47. });
  48. context('before starting the migration', function () {
  49. it('returns the zero address for the new token', async function () {
  50. expect(await this.migrator.newToken()).to.equal(ZERO_ADDRESS);
  51. });
  52. describe('migrateAll', function () {
  53. const amount = totalSupply;
  54. describe('when the approved balance is equal to the owned balance', function () {
  55. beforeEach('approving the whole balance to the new contract', async function () {
  56. await this.legacyToken.approve(this.migrator.address, amount, { from: owner });
  57. });
  58. it('reverts', async function () {
  59. await expectRevert(this.migrator.migrateAll(owner),
  60. 'ERC20Migrator: migration not started'
  61. );
  62. });
  63. });
  64. });
  65. describe('migrate', function () {
  66. const amount = new BN(50);
  67. describe('when the amount is equal to the approved value', function () {
  68. beforeEach('approving tokens to the new contract', async function () {
  69. await this.legacyToken.approve(this.migrator.address, amount, { from: owner });
  70. });
  71. it('reverts', async function () {
  72. await expectRevert(this.migrator.migrate(owner, amount),
  73. 'ERC20Migrator: migration not started'
  74. );
  75. });
  76. });
  77. });
  78. });
  79. describe('once migration began', function () {
  80. beforeEach('beginning migration', async function () {
  81. await this.newToken.addMinter(this.migrator.address);
  82. await this.migrator.beginMigration(this.newToken.address);
  83. });
  84. it('returns new token', async function () {
  85. expect(await this.migrator.newToken()).to.equal(this.newToken.address);
  86. });
  87. describe('migrateAll', function () {
  88. const baseAmount = totalSupply;
  89. describe('when the approved balance is equal to the owned balance', function () {
  90. const amount = baseAmount;
  91. beforeEach('approving the whole balance to the new contract', async function () {
  92. await this.legacyToken.approve(this.migrator.address, amount, { from: owner });
  93. });
  94. beforeEach('migrating token', async function () {
  95. const tx = await this.migrator.migrateAll(owner);
  96. this.logs = tx.receipt.logs;
  97. });
  98. it('mints the same balance of the new token', async function () {
  99. const currentBalance = await this.newToken.balanceOf(owner);
  100. expect(currentBalance).to.be.bignumber.equal(amount);
  101. });
  102. it('burns a given amount of old tokens', async function () {
  103. const currentBurnedBalance = await this.legacyToken.balanceOf(this.migrator.address);
  104. expect(currentBurnedBalance).to.be.bignumber.equal(amount);
  105. const currentLegacyTokenBalance = await this.legacyToken.balanceOf(owner);
  106. expect(currentLegacyTokenBalance).to.be.bignumber.equal('0');
  107. });
  108. it('updates the total supply', async function () {
  109. const currentSupply = await this.newToken.totalSupply();
  110. expect(currentSupply).to.be.bignumber.equal(amount);
  111. });
  112. });
  113. describe('when the approved balance is lower than the owned balance', function () {
  114. const amount = baseAmount.subn(1);
  115. beforeEach('approving part of the balance to the new contract', async function () {
  116. await this.legacyToken.approve(this.migrator.address, amount, { from: owner });
  117. await this.migrator.migrateAll(owner);
  118. });
  119. it('migrates only approved amount', async function () {
  120. const currentBalance = await this.newToken.balanceOf(owner);
  121. expect(currentBalance).to.be.bignumber.equal(amount);
  122. });
  123. });
  124. });
  125. describe('migrate', function () {
  126. const baseAmount = new BN(50);
  127. beforeEach('approving tokens to the new contract', async function () {
  128. await this.legacyToken.approve(this.migrator.address, baseAmount, { from: owner });
  129. });
  130. describe('when the amount is equal to the one approved', function () {
  131. const amount = baseAmount;
  132. beforeEach('migrate token', async function () {
  133. ({ logs: this.logs } = await this.migrator.migrate(owner, amount));
  134. });
  135. it('mints that amount of the new token', async function () {
  136. const currentBalance = await this.newToken.balanceOf(owner);
  137. expect(currentBalance).to.be.bignumber.equal(amount);
  138. });
  139. it('burns a given amount of old tokens', async function () {
  140. const currentBurnedBalance = await this.legacyToken.balanceOf(this.migrator.address);
  141. expect(currentBurnedBalance).to.be.bignumber.equal(amount);
  142. const currentLegacyTokenBalance = await this.legacyToken.balanceOf(owner);
  143. expect(currentLegacyTokenBalance).to.be.bignumber.equal(totalSupply.sub(amount));
  144. });
  145. it('updates the total supply', async function () {
  146. const currentSupply = await this.newToken.totalSupply();
  147. expect(currentSupply).to.be.bignumber.equal(amount);
  148. });
  149. });
  150. describe('when the given amount is higher than the one approved', function () {
  151. const amount = baseAmount.addn(1);
  152. it('reverts', async function () {
  153. await expectRevert(this.migrator.migrate(owner, amount),
  154. 'SafeERC20: low-level call failed'
  155. );
  156. });
  157. });
  158. });
  159. });
  160. });
  161. });