ERC20Migrator.test.js 7.5 KB

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