Add a SafeERC20:safePermit function (#3280)

This commit is contained in:
Hadrien Croubois
2022-06-07 17:17:02 +02:00
committed by GitHub
parent 08d109d877
commit 7c75b8aa89
6 changed files with 199 additions and 10 deletions

View File

@ -4,6 +4,7 @@ pragma solidity ^0.8.0;
import "../utils/Context.sol";
import "../token/ERC20/IERC20.sol";
import "../token/ERC20/extensions/draft-ERC20Permit.sol";
import "../token/ERC20/utils/SafeERC20.sol";
contract ERC20ReturnFalseMock is Context {
@ -105,6 +106,43 @@ contract ERC20NoReturnMock is Context {
}
}
contract ERC20PermitNoRevertMock is
ERC20("ERC20PermitNoRevertMock", "ERC20PermitNoRevertMock"),
ERC20Permit("ERC20PermitNoRevertMock")
{
function getChainId() external view returns (uint256) {
return block.chainid;
}
function permitThatMayRevert(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
super.permit(owner, spender, value, deadline, v, r, s);
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
try this.permitThatMayRevert(owner, spender, value, deadline, v, r, s) {
// do nothing
} catch {
// do nothing
}
}
}
contract SafeERC20Wrapper is Context {
using SafeERC20 for IERC20;
@ -134,6 +172,18 @@ contract SafeERC20Wrapper is Context {
_token.safeDecreaseAllowance(address(0), amount);
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public {
SafeERC20.safePermit(IERC20Permit(address(_token)), owner, spender, value, deadline, v, r, s);
}
function setAllowance(uint256 allowance_) public {
ERC20ReturnTrueMock(address(_token)).setAllowance(allowance_);
}

View File

@ -4,6 +4,7 @@
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
@ -79,6 +80,22 @@ library SafeERC20 {
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).