ERC20Wrapper.test.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
  2. const { expect } = require('chai');
  3. const { ZERO_ADDRESS, MAX_UINT256 } = constants;
  4. const { shouldBehaveLikeERC20 } = require('../ERC20.behavior');
  5. const NotAnERC20 = artifacts.require('CallReceiverMock');
  6. const ERC20Decimals = artifacts.require('$ERC20DecimalsMock');
  7. const ERC20Wrapper = artifacts.require('$ERC20Wrapper');
  8. contract('ERC20', function (accounts) {
  9. const [initialHolder, recipient, anotherAccount] = accounts;
  10. const name = 'My Token';
  11. const symbol = 'MTKN';
  12. const initialSupply = new BN(100);
  13. beforeEach(async function () {
  14. this.underlying = await ERC20Decimals.new(name, symbol, 9);
  15. await this.underlying.$_mint(initialHolder, initialSupply);
  16. this.token = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, this.underlying.address);
  17. });
  18. afterEach(async function () {
  19. expect(await this.underlying.balanceOf(this.token.address)).to.be.bignumber.equal(await this.token.totalSupply());
  20. });
  21. it('has a name', async function () {
  22. expect(await this.token.name()).to.equal(`Wrapped ${name}`);
  23. });
  24. it('has a symbol', async function () {
  25. expect(await this.token.symbol()).to.equal(`W${symbol}`);
  26. });
  27. it('has the same decimals as the underlying token', async function () {
  28. expect(await this.token.decimals()).to.be.bignumber.equal('9');
  29. });
  30. it('decimals default back to 18 if token has no metadata', async function () {
  31. const noDecimals = await NotAnERC20.new();
  32. const otherToken = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, noDecimals.address);
  33. expect(await otherToken.decimals()).to.be.bignumber.equal('18');
  34. });
  35. it('has underlying', async function () {
  36. expect(await this.token.underlying()).to.be.bignumber.equal(this.underlying.address);
  37. });
  38. describe('deposit', function () {
  39. it('valid', async function () {
  40. await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
  41. const { tx } = await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
  42. await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
  43. from: initialHolder,
  44. to: this.token.address,
  45. value: initialSupply,
  46. });
  47. await expectEvent.inTransaction(tx, this.token, 'Transfer', {
  48. from: ZERO_ADDRESS,
  49. to: initialHolder,
  50. value: initialSupply,
  51. });
  52. });
  53. it('missing approval', async function () {
  54. await expectRevert(
  55. this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }),
  56. 'ERC20: insufficient allowance',
  57. );
  58. });
  59. it('missing balance', async function () {
  60. await this.underlying.approve(this.token.address, MAX_UINT256, { from: initialHolder });
  61. await expectRevert(
  62. this.token.depositFor(initialHolder, MAX_UINT256, { from: initialHolder }),
  63. 'ERC20: transfer amount exceeds balance',
  64. );
  65. });
  66. it('to other account', async function () {
  67. await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
  68. const { tx } = await this.token.depositFor(anotherAccount, initialSupply, { from: initialHolder });
  69. await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
  70. from: initialHolder,
  71. to: this.token.address,
  72. value: initialSupply,
  73. });
  74. await expectEvent.inTransaction(tx, this.token, 'Transfer', {
  75. from: ZERO_ADDRESS,
  76. to: anotherAccount,
  77. value: initialSupply,
  78. });
  79. });
  80. });
  81. describe('withdraw', function () {
  82. beforeEach(async function () {
  83. await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
  84. await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
  85. });
  86. it('missing balance', async function () {
  87. await expectRevert(
  88. this.token.withdrawTo(initialHolder, MAX_UINT256, { from: initialHolder }),
  89. 'ERC20: burn amount exceeds balance',
  90. );
  91. });
  92. it('valid', async function () {
  93. const value = new BN(42);
  94. const { tx } = await this.token.withdrawTo(initialHolder, value, { from: initialHolder });
  95. await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
  96. from: this.token.address,
  97. to: initialHolder,
  98. value: value,
  99. });
  100. await expectEvent.inTransaction(tx, this.token, 'Transfer', {
  101. from: initialHolder,
  102. to: ZERO_ADDRESS,
  103. value: value,
  104. });
  105. });
  106. it('entire balance', async function () {
  107. const { tx } = await this.token.withdrawTo(initialHolder, initialSupply, { from: initialHolder });
  108. await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
  109. from: this.token.address,
  110. to: initialHolder,
  111. value: initialSupply,
  112. });
  113. await expectEvent.inTransaction(tx, this.token, 'Transfer', {
  114. from: initialHolder,
  115. to: ZERO_ADDRESS,
  116. value: initialSupply,
  117. });
  118. });
  119. it('to other account', async function () {
  120. const { tx } = await this.token.withdrawTo(anotherAccount, initialSupply, { from: initialHolder });
  121. await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
  122. from: this.token.address,
  123. to: anotherAccount,
  124. value: initialSupply,
  125. });
  126. await expectEvent.inTransaction(tx, this.token, 'Transfer', {
  127. from: initialHolder,
  128. to: ZERO_ADDRESS,
  129. value: initialSupply,
  130. });
  131. });
  132. });
  133. describe('recover', function () {
  134. it('nothing to recover', async function () {
  135. await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
  136. await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
  137. const { tx } = await this.token.$_recover(anotherAccount);
  138. await expectEvent.inTransaction(tx, this.token, 'Transfer', {
  139. from: ZERO_ADDRESS,
  140. to: anotherAccount,
  141. value: '0',
  142. });
  143. });
  144. it('something to recover', async function () {
  145. await this.underlying.transfer(this.token.address, initialSupply, { from: initialHolder });
  146. const { tx } = await this.token.$_recover(anotherAccount);
  147. await expectEvent.inTransaction(tx, this.token, 'Transfer', {
  148. from: ZERO_ADDRESS,
  149. to: anotherAccount,
  150. value: initialSupply,
  151. });
  152. });
  153. });
  154. describe('erc20 behaviour', function () {
  155. beforeEach(async function () {
  156. await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
  157. await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
  158. });
  159. shouldBehaveLikeERC20('ERC20', initialSupply, initialHolder, recipient, anotherAccount);
  160. });
  161. });