ERC20Wrapper.test.js 6.8 KB

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