diff --git a/.changeset/wild-windows-trade.md b/.changeset/wild-windows-trade.md new file mode 100644 index 00000000000..f599d0fcbbc --- /dev/null +++ b/.changeset/wild-windows-trade.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': major +--- + +`SafeERC20`: Refactor `safeDecreaseAllowance` and `safeIncreaseAllowance` to support USDT-like tokens. diff --git a/contracts/token/ERC20/utils/SafeERC20.sol b/contracts/token/ERC20/utils/SafeERC20.sol index f24447fb4f3..7248134f217 100644 --- a/contracts/token/ERC20/utils/SafeERC20.sol +++ b/contracts/token/ERC20/utils/SafeERC20.sol @@ -41,7 +41,7 @@ library SafeERC20 { */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); + forceApprove(token, spender, oldAllowance + value); } /** @@ -52,7 +52,7 @@ library SafeERC20 { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); + forceApprove(token, spender, oldAllowance - value); } } diff --git a/test/token/ERC20/utils/SafeERC20.test.js b/test/token/ERC20/utils/SafeERC20.test.js index 04b3b5cb14d..b0daf438412 100644 --- a/test/token/ERC20/utils/SafeERC20.test.js +++ b/test/token/ERC20/utils/SafeERC20.test.js @@ -182,16 +182,19 @@ contract('SafeERC20', function (accounts) { await this.token.$_approve(this.mock.address, spender, 100); }); - it('safeApprove can increase approval', async function () { - await expectRevert(this.mock.$safeIncreaseAllowance(this.token.address, spender, 10), 'USDT approval failure'); + it('safeIncreaseAllowance works', async function () { + await this.mock.$safeIncreaseAllowance(this.token.address, spender, 10); + expect(this.token.allowance(this.mock.address, spender, 90)); }); - it('safeApprove can decrease approval', async function () { - await expectRevert(this.mock.$safeDecreaseAllowance(this.token.address, spender, 10), 'USDT approval failure'); + it('safeDecreaseAllowance works', async function () { + await this.mock.$safeDecreaseAllowance(this.token.address, spender, 10); + expect(this.token.allowance(this.mock.address, spender, 110)); }); it('forceApprove works', async function () { await this.mock.$forceApprove(this.token.address, spender, 200); + expect(this.token.allowance(this.mock.address, spender, 200)); }); }); });