Add a _spendAllowance function to ERC20 & ERC777 (#3170)

(cherry picked from commit c5a6cae898)
This commit is contained in:
Hadrien Croubois
2022-02-09 16:26:53 +01:00
committed by Francisco Giordano
parent 234a971410
commit 494b1b9a39
7 changed files with 53 additions and 24 deletions

View File

@ -161,16 +161,8 @@ contract ERC20 is Context, IERC20, IERC20Metadata {
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
uint256 currentAllowance = allowance(from, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
unchecked {
_approve(from, spender, currentAllowance - amount);
}
}
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
@ -327,6 +319,28 @@ contract ERC20 is Context, IERC20, IERC20Metadata {
emit Approval(owner, spender, amount);
}
/**
* @dev Spend `amount` form the allowance of `owner` toward `spender`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.

View File

@ -33,11 +33,7 @@ abstract contract ERC20Burnable is Context, ERC20 {
* `amount`.
*/
function burnFrom(address account, uint256 amount) public virtual {
uint256 currentAllowance = allowance(account, _msgSender());
require(currentAllowance >= amount, "ERC20: burn amount exceeds allowance");
unchecked {
_approve(account, _msgSender(), currentAllowance - amount);
}
_spendAllowance(account, _msgSender(), amount);
_burn(account, amount);
}
}

View File

@ -293,13 +293,7 @@ contract ERC777 is Context, IERC777, IERC20 {
_callTokensToSend(spender, holder, recipient, amount, "", "");
uint256 currentAllowance = _allowances[holder][spender];
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC777: transfer amount exceeds allowance");
unchecked {
_approve(holder, spender, currentAllowance - amount);
}
}
_spendAllowance(holder, spender, amount);
_move(spender, holder, recipient, amount, "", "");
@ -526,6 +520,28 @@ contract ERC777 is Context, IERC777, IERC20 {
}
}
/**
* @dev Spend `amount` form the allowance of `owner` toward `spender`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC777: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any token transfer. This includes
* calls to {send}, {transfer}, {operatorSend}, minting and burning.