SafeERC20.test.js 4.2 KB

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