SafeERC20.test.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. const { accounts, contract } = require('@openzeppelin/test-environment');
  2. const { expectRevert } = require('@openzeppelin/test-helpers');
  3. const ERC20ReturnFalseMock = contract.fromArtifact('ERC20ReturnFalseMock');
  4. const ERC20ReturnTrueMock = contract.fromArtifact('ERC20ReturnTrueMock');
  5. const ERC20NoReturnMock = contract.fromArtifact('ERC20NoReturnMock');
  6. const SafeERC20Wrapper = contract.fromArtifact('SafeERC20Wrapper');
  7. describe('SafeERC20', function () {
  8. const [ hasNoCode ] = accounts;
  9. describe('with address that has no contract code', function () {
  10. beforeEach(async function () {
  11. this.wrapper = await SafeERC20Wrapper.new(hasNoCode);
  12. });
  13. shouldRevertOnAllCalls('SafeERC20: call to non-contract');
  14. });
  15. describe('with token that returns false on all calls', function () {
  16. beforeEach(async function () {
  17. this.wrapper = await SafeERC20Wrapper.new((await ERC20ReturnFalseMock.new()).address);
  18. });
  19. shouldRevertOnAllCalls('SafeERC20: ERC20 operation did not succeed');
  20. });
  21. describe('with token that returns true on all calls', function () {
  22. beforeEach(async function () {
  23. this.wrapper = await SafeERC20Wrapper.new((await ERC20ReturnTrueMock.new()).address);
  24. });
  25. shouldOnlyRevertOnErrors();
  26. });
  27. describe('with token that returns no boolean values', function () {
  28. beforeEach(async function () {
  29. this.wrapper = await SafeERC20Wrapper.new((await ERC20NoReturnMock.new()).address);
  30. });
  31. shouldOnlyRevertOnErrors();
  32. });
  33. });
  34. function shouldRevertOnAllCalls (reason) {
  35. it('reverts on transfer', async function () {
  36. await expectRevert(this.wrapper.transfer(), reason);
  37. });
  38. it('reverts on transferFrom', async function () {
  39. await expectRevert(this.wrapper.transferFrom(), reason);
  40. });
  41. it('reverts on approve', async function () {
  42. await expectRevert(this.wrapper.approve(0), reason);
  43. });
  44. it('reverts on increaseAllowance', async function () {
  45. // [TODO] make sure it's reverting for the right reason
  46. await expectRevert.unspecified(this.wrapper.increaseAllowance(0));
  47. });
  48. it('reverts on decreaseAllowance', async function () {
  49. // [TODO] make sure it's reverting for the right reason
  50. await expectRevert.unspecified(this.wrapper.decreaseAllowance(0));
  51. });
  52. }
  53. function shouldOnlyRevertOnErrors () {
  54. it('doesn\'t revert on transfer', async function () {
  55. await this.wrapper.transfer();
  56. });
  57. it('doesn\'t revert on transferFrom', async function () {
  58. await this.wrapper.transferFrom();
  59. });
  60. describe('approvals', function () {
  61. context('with zero allowance', function () {
  62. beforeEach(async function () {
  63. await this.wrapper.setAllowance(0);
  64. });
  65. it('doesn\'t revert when approving a non-zero allowance', async function () {
  66. await this.wrapper.approve(100);
  67. });
  68. it('doesn\'t revert when approving a zero allowance', async function () {
  69. await this.wrapper.approve(0);
  70. });
  71. it('doesn\'t revert when increasing the allowance', async function () {
  72. await this.wrapper.increaseAllowance(10);
  73. });
  74. it('reverts when decreasing the allowance', async function () {
  75. await expectRevert(
  76. this.wrapper.decreaseAllowance(10),
  77. 'SafeERC20: decreased allowance below zero'
  78. );
  79. });
  80. });
  81. context('with non-zero allowance', function () {
  82. beforeEach(async function () {
  83. await this.wrapper.setAllowance(100);
  84. });
  85. it('reverts when approving a non-zero allowance', async function () {
  86. await expectRevert(
  87. this.wrapper.approve(20),
  88. 'SafeERC20: approve from non-zero to non-zero allowance'
  89. );
  90. });
  91. it('doesn\'t revert when approving a zero allowance', async function () {
  92. await this.wrapper.approve(0);
  93. });
  94. it('doesn\'t revert when increasing the allowance', async function () {
  95. await this.wrapper.increaseAllowance(10);
  96. });
  97. it('doesn\'t revert when decreasing the allowance to a positive value', async function () {
  98. await this.wrapper.decreaseAllowance(50);
  99. });
  100. it('reverts when decreasing the allowance to a negative value', async function () {
  101. await expectRevert(
  102. this.wrapper.decreaseAllowance(200),
  103. 'SafeERC20: decreased allowance below zero'
  104. );
  105. });
  106. });
  107. });
  108. }