ERC20Migrator.test.js 7.6 KB

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