From 7781c2cedb6e90de56de56342d7b19861730fdbc Mon Sep 17 00:00:00 2001 From: Mr-Lucky <642706757@qq.com> Date: Tue, 4 Oct 2022 23:25:41 +0800 Subject: [PATCH 01/35] commit draft erc20 approval exxpiration --- EIPS/eip-draft_erc20_approval_expiration.md | 187 ++++++ .../erc20-approval-expiration.sol | 550 ++++++++++++++++++ 2 files changed, 737 insertions(+) create mode 100644 EIPS/eip-draft_erc20_approval_expiration.md create mode 100644 assets/eip-draft_erc20_approval_expiration/erc20-approval-expiration.sol diff --git a/EIPS/eip-draft_erc20_approval_expiration.md b/EIPS/eip-draft_erc20_approval_expiration.md new file mode 100644 index 0000000000000..cda5eb2632e17 --- /dev/null +++ b/EIPS/eip-draft_erc20_approval_expiration.md @@ -0,0 +1,187 @@ +--- +eip: +title: Approval Expirations for ERC20 Tokens +description: This EIP introduces a standardized way for users to set expiration limits on ERC-20 token approvals. +author: Go+ Security <@GoPlusSecurity>, Jeff Hall <@JeffHal25193696>, Xavi <@XaaaaavitheFool>, Turan Vural <@turanzv> +discussions-to: +status: Draft +type: Standards Track +category (*only required for Standards Track): Interface +created: 2022-10-02) format +requires (*optional): +--- + +This EIP introduces a standard way for users to set expiration limits on ERC-20 token approvals to prevent the loss of assets due to contractrual vulnerabilities or authorization attacks. + +## Abstract +The standard adds a customizable expiration date as a limit to the _approve() function of token contracts, such as that of the ERC-20 interface, so that all allownces that exceed the expiration date will expire. In this way, the user's approvals for assets will be automatically recalled within a certain period. When an attacker exploits a spender contract vulnerability or spender identity to steal assets, it will fail due to the expiration of approvals. + +## Motivation +The approval attack is the most common attack method in the industry as of the writing of this EIP, with nearly all phishing attacks and asset theft related to it. Although developing good usage habits and having basic knowledge of on-chain security basics can help users avoid phishing, scams, DNS hijacking, JS injection, and other common approval attack methods, this still can't stop the attacks caused by the spender's own security problems. + +In the Transit Swap attack of October 1st, 2022, hackers used a vulnerability in the Transit Swap contract to steal $200 million in assets. Due in part to professional security audits and the strong brand recognition of Transit Swap, many users were given a false sense of security and trusted the platform's service. Transit Swaps's contract had been running smoothly for over a year and had accumulated a large amount of user allownces, making the contract a high-reward target for malicious actors. + +There have been many similar incidents to the Transit Swap attack. Security audits cannot gurantee that a contract is 100% devoid of vulnerability. Some vulnerabilities are intentionally left by malicious developers themselves. In line with good trust practices and general security hygeine, unconditional trust is risky, and modifying approvals into limited trusts in spender with automatic recovery will be a key tool to natively prevent attacks. + +## Specification + +A time period `_expiration` is mapped on top of the original `allowance` to specify an approval time limit. + +The internal `_approve()` method adds a uint256 `period` to the entry and stored in `_expiration`. + +A `DEFAULT_PERIOD` constant is added for legacy implementations that do not specify the `period` parameter. + +In order not to interfere with the existing event statistics and to allow other developers to count the validity of allowance, we add a new event `AllowanceExpireTimeUpdated()`, which will be triggered in the `_approve()` method. + +A separate approval method with the header `approve(address spender, uint256 amount, uint256 period)` modifies the `_expiration` value for existing approvals. + +```solidity +contract ERC20 is Context, IERC20, IERC20Metadata { + + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + + uint256 private constant DEFAULT_PERIOD = 86400 * 30; + mapping(address => mapping(address => uint256)) private _expiration; + + event AllowanceExpireTimeUpdated(address indexed owner, address indexed spender, uint256 value, uint256 expiration); + + + function approve(address spender, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, amount, DEFAULT_PERIOD); + return true; + } + + + function approve(address spender, uint256 amount, uint256 period) public returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, amount, period); + return true; + } + + + function _approve( + address owner, + address spender, + uint256 amount, + uint256 period + ) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + _expiration[owner][spender] = block.timestamp + period; + emit Approval(owner, spender, amount); + emit AllowanceExpireTimeUpdated(owner, spender, amount, _expiration[owner][spender]); + } +``` + +Transactions using the `transferFrom()` method will be checked against `_expiration` through `_spendAllowance()`. Transactions that take place after the alloted time period will fail. + +```solidity + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual override returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, amount); + _transfer(from, to, amount); + return true; + } + + + function _spendAllowance( + address owner, + address spender, + uint256 amount + ) internal virtual { + uint256 currentAllowance = _allowances[owner][spender]; + uint256 currentExpiration = _expiration[owner][spender]; + require(block.timestamp <= currentExpiration, "Approval expired!"); + if (currentAllowance != type(uint256).max) { + require(currentAllowance >= amount, "ERC20: insufficient allowance"); + unchecked { + _approve(owner, spender, currentAllowance - amount, currentExpiration - block.timestamp); + } + } + } +``` + +The `allowance()`, `increaseAllowance()`, and `decreaseAllowance()` method has been modified to accommodate the new features. `allowanceExpiration()` has been added to query the expiry date. + +```solidity + function allowanceExpiration(address owner, address spender) public view returns (uint256) { + return _expiration[owner][spender]; + } + + + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, allowance(owner, spender) + addedValue, DEFAULT_PERIOD); + return true; + } + + function increaseAllowance(address spender, uint256 addedValue, uint256 period) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, allowance(owner, spender) + addedValue, period); + return true; + } + + + function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { + address owner = _msgSender(); + uint256 currentAllowance = allowance(owner, spender); + require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); + unchecked { + _approve(owner, spender, currentAllowance - subtractedValue, DEFAULT_PERIOD); + } + + return true; + } + + function decreaseAllowance(address spender, uint256 subtractedValue, uint256 period) public virtual returns (bool) { + address owner = _msgSender(); + uint256 currentAllowance = allowance(owner, spender); + require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); + unchecked { + _approve(owner, spender, currentAllowance - subtractedValue, period); + } + + return true; + } +``` + +The above modifications adds a validity period to ERC20 token approvals. Users can freely update their allowance validity at any time by calling `approve(address spender, uint256 amount, uint256 period)`. + +## Rationale +`_expiration` is implemented as a mapping to improve the compatibility of the code. + +So that existing event statistics are not perturbed by the implementation of this EIP, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. + +This standard is absolutely compatible with the traditional ERC20 standard. `DEFAULT_PERIOD` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_PERIOD` can be set to a constant or variable according to the developer's needs. + +A separate approval method with the header `approve(address spender, uint256 amount, uint256 period)` has been introduced to allow users to customize the `_expiration` value of the approval. + +The internal method `_spendAllowance()` is introduced for code cleanliness with the function of checking the allowance amount and expiration. + +The `allowance()` method has been modified to accommodate the functionality described in this EIP. `allowanceExpiration()` has been added query the allowance expiration date. + +## Backwards Compatibility +This standard is compatible with the ERC-20, ERC-721 and ERC-1155 standards. Tokens deployed in the form of proxy contracts can be updated to comply with this EIP. + +## Reference Implementation +Implementation can be referenced in `../assets/eip-####/`. + +## Security Considerations +When upgrading a standard ERC20-based proxy contract to this standard, attention should be paid to the storage slots location. + +## Copyright +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/assets/eip-draft_erc20_approval_expiration/erc20-approval-expiration.sol b/assets/eip-draft_erc20_approval_expiration/erc20-approval-expiration.sol new file mode 100644 index 0000000000000..88ae7d5a91f05 --- /dev/null +++ b/assets/eip-draft_erc20_approval_expiration/erc20-approval-expiration.sol @@ -0,0 +1,550 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * ////IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 amount + ) external returns (bool); +} + + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + + +////import "../IERC20.sol"; + +/** + * @dev Interface for the optional metadata functions from the ERC20 standard. + * + * _Available since v4.1._ + */ +interface IERC20Metadata is IERC20 { + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the decimals places of the token. + */ + function decimals() external view returns (uint8); +} + + +////import "./IERC20.sol"; +////import "./extensions/IERC20Metadata.sol"; +////import "../../utils/Context.sol"; + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin Contracts guidelines: functions revert + * instead returning `false` on failure. This behavior is nonetheless + * conventional and does not conflict with the expectations of ERC20 + * applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ERC20 is Context, IERC20, IERC20Metadata { + + + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + + uint256 private constant DEFAULT_PERIOD = 86400 * 30; + mapping(address => mapping(address => uint256)) private _expiration; + + event AllowanceExpirationUpdated(address indexed owner, address indexed spender, uint256 value, uint256 expiration); + + /** + * @dev Sets the values for {name} and {symbol}. + * + * The default value of {decimals} is 18. To select a different value for + * {decimals} you should overload it. + * + * All two of these values are immutable: they can only be set once during + * construction. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the value {ERC20} uses, unless this function is + * overridden; + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view virtual override returns (uint8) { + return 18; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual override returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address to, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _transfer(owner, to, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual override returns (uint256) { + return _allowances[owner][spender]; + } + + function allowanceExpiration(address owner, address spender) public view returns (uint256) { + return _expiration[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, amount, DEFAULT_PERIOD); + return true; + } + + + function approve(address spender, uint256 amount, uint256 period) public returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, amount, period); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + * - the caller must have allowance for ``from``'s tokens of at least + * `amount`. + */ + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual override returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, amount); + _transfer(from, to, amount); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, allowance(owner, spender) + addedValue, DEFAULT_PERIOD); + return true; + } + + function increaseAllowance(address spender, uint256 addedValue, uint256 period) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, allowance(owner, spender) + addedValue, period); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { + address owner = _msgSender(); + uint256 currentAllowance = allowance(owner, spender); + require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); + unchecked { + _approve(owner, spender, currentAllowance - subtractedValue, DEFAULT_PERIOD); + } + + return true; + } + + + function decreaseAllowance(address spender, uint256 subtractedValue, uint256 period) public virtual returns (bool) { + address owner = _msgSender(); + uint256 currentAllowance = allowance(owner, spender); + require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); + unchecked { + _approve(owner, spender, currentAllowance - subtractedValue, period); + } + + return true; + } + + /** + * @dev Moves `amount` of tokens from `sender` to `recipient`. + * + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + */ + function _transfer( + address from, + address to, + uint256 amount + ) internal virtual { + require(from != address(0), "ERC20: transfer from the zero address"); + require(to != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(from, to, amount); + + uint256 fromBalance = _balances[from]; + require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); + unchecked { + _balances[from] = fromBalance - amount; + } + _balances[to] += amount; + + emit Transfer(from, to, amount); + + _afterTokenTransfer(from, to, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply += amount; + _balances[account] += amount; + emit Transfer(address(0), account, amount); + + _afterTokenTransfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + uint256 accountBalance = _balances[account]; + require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); + unchecked { + _balances[account] = accountBalance - amount; + } + _totalSupply -= amount; + + emit Transfer(account, address(0), amount); + + _afterTokenTransfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve( + address owner, + address spender, + uint256 amount, + uint256 period + ) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + _expiration[owner][spender] = block.timestamp + period; + emit Approval(owner, spender, amount); + emit AllowanceExpirationUpdated(owner, spender, amount, _expiration[owner][spender]); + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `amount`. + * + * 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 = _allowances[owner][spender]; + uint256 currentExpiration = _expiration[owner][spender]; + require(block.timestamp <= currentExpiration, "Approval expired!"); + if (currentAllowance != type(uint256).max) { + require(currentAllowance >= amount, "ERC20: insufficient allowance"); + unchecked { + _approve(owner, spender, currentAllowance - amount, currentExpiration - block.timestamp); + } + } + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual {} + + /** + * @dev Hook that is called after any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * has been transferred to `to`. + * - when `from` is zero, `amount` tokens have been minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens have been burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual {} +} + From 83890f92e93b62e1c0cfe30edc05a9289af9367f Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Wed, 5 Oct 2022 00:30:26 -0700 Subject: [PATCH 02/35] general edits --- EIPS/eip-draft_erc20_approval_expiration.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/EIPS/eip-draft_erc20_approval_expiration.md b/EIPS/eip-draft_erc20_approval_expiration.md index cda5eb2632e17..d919d3110aa70 100644 --- a/EIPS/eip-draft_erc20_approval_expiration.md +++ b/EIPS/eip-draft_erc20_approval_expiration.md @@ -14,14 +14,14 @@ requires (*optional): This EIP introduces a standard way for users to set expiration limits on ERC-20 token approvals to prevent the loss of assets due to contractrual vulnerabilities or authorization attacks. ## Abstract -The standard adds a customizable expiration date as a limit to the _approve() function of token contracts, such as that of the ERC-20 interface, so that all allownces that exceed the expiration date will expire. In this way, the user's approvals for assets will be automatically recalled within a certain period. When an attacker exploits a spender contract vulnerability or spender identity to steal assets, it will fail due to the expiration of approvals. +This EIP adds an expiration time to the `_approve()` function of token contracts to automatically recall approvals within a certain time period. This functionality as a standard will prevent vulnerabilty exploits due to outstanding token approvals. ## Motivation -The approval attack is the most common attack method in the industry as of the writing of this EIP, with nearly all phishing attacks and asset theft related to it. Although developing good usage habits and having basic knowledge of on-chain security basics can help users avoid phishing, scams, DNS hijacking, JS injection, and other common approval attack methods, this still can't stop the attacks caused by the spender's own security problems. +As of the writing of this EIP, the approval attack is the most common attack method in the industry with nearly all phishing attacks and asset theft related to it. Although good usage habits and basic knowledge of on-chain security can help users avoid a multitiude of exploits such as phishing, scams, DNS hijacking, JS injection, and other common approval attack methods, the spender's own security (or lack thereof) still needs to be fortified by strong code. In the Transit Swap attack of October 1st, 2022, hackers used a vulnerability in the Transit Swap contract to steal $200 million in assets. Due in part to professional security audits and the strong brand recognition of Transit Swap, many users were given a false sense of security and trusted the platform's service. Transit Swaps's contract had been running smoothly for over a year and had accumulated a large amount of user allownces, making the contract a high-reward target for malicious actors. -There have been many similar incidents to the Transit Swap attack. Security audits cannot gurantee that a contract is 100% devoid of vulnerability. Some vulnerabilities are intentionally left by malicious developers themselves. In line with good trust practices and general security hygeine, unconditional trust is risky, and modifying approvals into limited trusts in spender with automatic recovery will be a key tool to natively prevent attacks. +There have been many similar incidents to the Transit Swap attack. Security audits cannot gurantee that a contract is 100% free from vulnerabilities. Some vulnerabilities are intentionally left by malicious developers themselves. In line with good trust practices and general security hygeine, unconditional trust is risky, and modifying approvals into limited trusts with automatic recovery will be a key tool to natively prevent attacks. ## Specification @@ -115,7 +115,7 @@ Transactions using the `transferFrom()` method will be checked against `_expirat } ``` -The `allowance()`, `increaseAllowance()`, and `decreaseAllowance()` method has been modified to accommodate the new features. `allowanceExpiration()` has been added to query the expiry date. +The `allowance()`, `increaseAllowance()`, and `decreaseAllowance()` methods have been modified to accommodate the new features. `allowanceExpiration()` has been added to query the live period of the contract. ```solidity function allowanceExpiration(address owner, address spender) public view returns (uint256) { @@ -175,13 +175,13 @@ The internal method `_spendAllowance()` is introduced for code cleanliness with The `allowance()` method has been modified to accommodate the functionality described in this EIP. `allowanceExpiration()` has been added query the allowance expiration date. ## Backwards Compatibility -This standard is compatible with the ERC-20, ERC-721 and ERC-1155 standards. Tokens deployed in the form of proxy contracts can be updated to comply with this EIP. +This standard is compatible with the ERC-20, ERC-721 and ERC-1155 standards. Tokens issued in the form of proxy contracts can be updated to comply with this EIP. ## Reference Implementation Implementation can be referenced in `../assets/eip-####/`. ## Security Considerations -When upgrading a standard ERC20-based proxy contract to this standard, attention should be paid to the storage slots location. +When upgrading a standard ERC20-based proxy contract to this standard, attention should be paid to the location of assets. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md). From fd971da262af09e58fe851564fd9a6e7bd2f0c4c Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Wed, 5 Oct 2022 00:33:12 -0700 Subject: [PATCH 03/35] replace EIP with standard --- EIPS/eip-draft_erc20_approval_expiration.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/EIPS/eip-draft_erc20_approval_expiration.md b/EIPS/eip-draft_erc20_approval_expiration.md index d919d3110aa70..5c725341cca5b 100644 --- a/EIPS/eip-draft_erc20_approval_expiration.md +++ b/EIPS/eip-draft_erc20_approval_expiration.md @@ -1,7 +1,7 @@ --- eip: title: Approval Expirations for ERC20 Tokens -description: This EIP introduces a standardized way for users to set expiration limits on ERC-20 token approvals. +description: This standard introduces a standardized way for users to set expiration limits on ERC-20 token approvals. author: Go+ Security <@GoPlusSecurity>, Jeff Hall <@JeffHal25193696>, Xavi <@XaaaaavitheFool>, Turan Vural <@turanzv> discussions-to: status: Draft @@ -11,13 +11,13 @@ created: 2022-10-02) format requires (*optional): --- -This EIP introduces a standard way for users to set expiration limits on ERC-20 token approvals to prevent the loss of assets due to contractrual vulnerabilities or authorization attacks. +This standard introduces a standard way for users to set expiration limits on ERC-20 token approvals to prevent the loss of assets due to contractrual vulnerabilities or authorization attacks. ## Abstract -This EIP adds an expiration time to the `_approve()` function of token contracts to automatically recall approvals within a certain time period. This functionality as a standard will prevent vulnerabilty exploits due to outstanding token approvals. +This standard adds an expiration time to the `_approve()` function of token contracts to automatically recall approvals within a certain time period. This functionality as a standard will prevent vulnerabilty exploits due to outstanding token approvals. ## Motivation -As of the writing of this EIP, the approval attack is the most common attack method in the industry with nearly all phishing attacks and asset theft related to it. Although good usage habits and basic knowledge of on-chain security can help users avoid a multitiude of exploits such as phishing, scams, DNS hijacking, JS injection, and other common approval attack methods, the spender's own security (or lack thereof) still needs to be fortified by strong code. +As of the writing of this standard, the approval attack is the most common attack method in the industry with nearly all phishing attacks and asset theft related to it. Although good usage habits and basic knowledge of on-chain security can help users avoid a multitiude of exploits such as phishing, scams, DNS hijacking, JS injection, and other common approval attack methods, the spender's own security (or lack thereof) still needs to be fortified by strong code. In the Transit Swap attack of October 1st, 2022, hackers used a vulnerability in the Transit Swap contract to steal $200 million in assets. Due in part to professional security audits and the strong brand recognition of Transit Swap, many users were given a false sense of security and trusted the platform's service. Transit Swaps's contract had been running smoothly for over a year and had accumulated a large amount of user allownces, making the contract a high-reward target for malicious actors. @@ -164,7 +164,7 @@ The above modifications adds a validity period to ERC20 token approvals. Users c ## Rationale `_expiration` is implemented as a mapping to improve the compatibility of the code. -So that existing event statistics are not perturbed by the implementation of this EIP, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. +So that existing event statistics are not perturbed by the implementation of this standard, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. This standard is absolutely compatible with the traditional ERC20 standard. `DEFAULT_PERIOD` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_PERIOD` can be set to a constant or variable according to the developer's needs. @@ -172,10 +172,10 @@ A separate approval method with the header `approve(address spender, uint256 amo The internal method `_spendAllowance()` is introduced for code cleanliness with the function of checking the allowance amount and expiration. -The `allowance()` method has been modified to accommodate the functionality described in this EIP. `allowanceExpiration()` has been added query the allowance expiration date. +The `allowance()` method has been modified to accommodate the functionality described in this standard. `allowanceExpiration()` has been added query the allowance expiration date. ## Backwards Compatibility -This standard is compatible with the ERC-20, ERC-721 and ERC-1155 standards. Tokens issued in the form of proxy contracts can be updated to comply with this EIP. +This standard is compatible with the ERC-20, ERC-721 and ERC-1155 standards. Tokens issued in the form of proxy contracts can be updated to comply with this standard. ## Reference Implementation Implementation can be referenced in `../assets/eip-####/`. From 3ef9e71216a2c49ae609dd27b30a1c6dbe1ec8d5 Mon Sep 17 00:00:00 2001 From: Mr-Lucky <642706757@qq.com> Date: Wed, 5 Oct 2022 20:11:57 +0800 Subject: [PATCH 04/35] fix amount of lost currency --- EIPS/eip-draft_erc20_approval_expiration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-draft_erc20_approval_expiration.md b/EIPS/eip-draft_erc20_approval_expiration.md index 5c725341cca5b..2b728868884fe 100644 --- a/EIPS/eip-draft_erc20_approval_expiration.md +++ b/EIPS/eip-draft_erc20_approval_expiration.md @@ -19,7 +19,7 @@ This standard adds an expiration time to the `_approve()` function of token cont ## Motivation As of the writing of this standard, the approval attack is the most common attack method in the industry with nearly all phishing attacks and asset theft related to it. Although good usage habits and basic knowledge of on-chain security can help users avoid a multitiude of exploits such as phishing, scams, DNS hijacking, JS injection, and other common approval attack methods, the spender's own security (or lack thereof) still needs to be fortified by strong code. -In the Transit Swap attack of October 1st, 2022, hackers used a vulnerability in the Transit Swap contract to steal $200 million in assets. Due in part to professional security audits and the strong brand recognition of Transit Swap, many users were given a false sense of security and trusted the platform's service. Transit Swaps's contract had been running smoothly for over a year and had accumulated a large amount of user allownces, making the contract a high-reward target for malicious actors. +In the Transit Swap attack of October 1st, 2022, hackers used a vulnerability in the Transit Swap contract to steal $20 million in assets. Due in part to professional security audits and the strong brand recognition of Transit Swap, many users were given a false sense of security and trusted the platform's service. Transit Swaps's contract had been running smoothly for over a year and had accumulated a large amount of user allownces, making the contract a high-reward target for malicious actors. There have been many similar incidents to the Transit Swap attack. Security audits cannot gurantee that a contract is 100% free from vulnerabilities. Some vulnerabilities are intentionally left by malicious developers themselves. In line with good trust practices and general security hygeine, unconditional trust is risky, and modifying approvals into limited trusts with automatic recovery will be a key tool to natively prevent attacks. From 0556b6270cde84c11f4961004921c8f8c1508970 Mon Sep 17 00:00:00 2001 From: Turan Vural <18318682+turanzv@users.noreply.github.com> Date: Thu, 6 Oct 2022 18:19:29 -0700 Subject: [PATCH 05/35] Update EIPS/eip-draft_erc20_approval_expiration.md Approval Expirations for ERC20 Tokens -> Approval Expiration for ERC-20 Tokens Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --- EIPS/eip-draft_erc20_approval_expiration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-draft_erc20_approval_expiration.md b/EIPS/eip-draft_erc20_approval_expiration.md index 2b728868884fe..84cc400976cde 100644 --- a/EIPS/eip-draft_erc20_approval_expiration.md +++ b/EIPS/eip-draft_erc20_approval_expiration.md @@ -1,6 +1,6 @@ --- eip: -title: Approval Expirations for ERC20 Tokens +title: Approval Expiration for ERC-20 Tokens description: This standard introduces a standardized way for users to set expiration limits on ERC-20 token approvals. author: Go+ Security <@GoPlusSecurity>, Jeff Hall <@JeffHal25193696>, Xavi <@XaaaaavitheFool>, Turan Vural <@turanzv> discussions-to: From 6b9c8f50608a573eaf1597a2ce4ddfd8c28b352c Mon Sep 17 00:00:00 2001 From: Turan Vural <18318682+turanzv@users.noreply.github.com> Date: Thu, 6 Oct 2022 18:20:08 -0700 Subject: [PATCH 06/35] adding eip number Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --- EIPS/eip-draft_erc20_approval_expiration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-draft_erc20_approval_expiration.md b/EIPS/eip-draft_erc20_approval_expiration.md index 84cc400976cde..6a8dc5e135f38 100644 --- a/EIPS/eip-draft_erc20_approval_expiration.md +++ b/EIPS/eip-draft_erc20_approval_expiration.md @@ -1,5 +1,5 @@ --- -eip: +eip: 5748 title: Approval Expiration for ERC-20 Tokens description: This standard introduces a standardized way for users to set expiration limits on ERC-20 token approvals. author: Go+ Security <@GoPlusSecurity>, Jeff Hall <@JeffHal25193696>, Xavi <@XaaaaavitheFool>, Turan Vural <@turanzv> From 314bccc9c95d5e6a092c223d4274fae383fda92a Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Thu, 6 Oct 2022 18:23:40 -0700 Subject: [PATCH 07/35] rename files to eip number --- EIPS/{eip-draft_erc20_approval_expiration.md => eip-5748.md} | 2 +- .../erc20-approval-expiration.sol => eip-5748/eip-5748.sol} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename EIPS/{eip-draft_erc20_approval_expiration.md => eip-5748.md} (99%) rename assets/{eip-draft_erc20_approval_expiration/erc20-approval-expiration.sol => eip-5748/eip-5748.sol} (100%) diff --git a/EIPS/eip-draft_erc20_approval_expiration.md b/EIPS/eip-5748.md similarity index 99% rename from EIPS/eip-draft_erc20_approval_expiration.md rename to EIPS/eip-5748.md index 5c725341cca5b..1b07a25101a99 100644 --- a/EIPS/eip-draft_erc20_approval_expiration.md +++ b/EIPS/eip-5748.md @@ -178,7 +178,7 @@ The `allowance()` method has been modified to accommodate the functionality desc This standard is compatible with the ERC-20, ERC-721 and ERC-1155 standards. Tokens issued in the form of proxy contracts can be updated to comply with this standard. ## Reference Implementation -Implementation can be referenced in `../assets/eip-####/`. +Implementation can be referenced in `../assets/eip-5748/`. ## Security Considerations When upgrading a standard ERC20-based proxy contract to this standard, attention should be paid to the location of assets. diff --git a/assets/eip-draft_erc20_approval_expiration/erc20-approval-expiration.sol b/assets/eip-5748/eip-5748.sol similarity index 100% rename from assets/eip-draft_erc20_approval_expiration/erc20-approval-expiration.sol rename to assets/eip-5748/eip-5748.sol From aed99f066a3424329f21490de7b20b15c7062449 Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Thu, 6 Oct 2022 18:30:09 -0700 Subject: [PATCH 08/35] fix contact info --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 78eebad0f0eb1..1dfb69669913a 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -2,7 +2,7 @@ eip: 5748 title: Approval Expiration for ERC-20 Tokens description: This standard introduces a standardized way for users to set expiration limits on ERC-20 token approvals. -author: Go+ Security <@GoPlusSecurity>, Jeff Hall <@JeffHal25193696>, Xavi <@XaaaaavitheFool>, Turan Vural <@turanzv> +author: Go+ Security (@GoPlusSecurity), Jeff Hall <642706757@qq.com>, Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) discussions-to: status: Draft type: Standards Track From c5817f16373180171072cd882c0313f2b1f771bf Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Thu, 6 Oct 2022 18:32:20 -0700 Subject: [PATCH 09/35] fix ERC references to comply w/ ERC-### format --- EIPS/eip-5748.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 1dfb69669913a..7292bc160ac71 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -159,14 +159,14 @@ The `allowance()`, `increaseAllowance()`, and `decreaseAllowance()` methods have } ``` -The above modifications adds a validity period to ERC20 token approvals. Users can freely update their allowance validity at any time by calling `approve(address spender, uint256 amount, uint256 period)`. +The above modifications adds a validity period to ERC-20 token approvals. Users can freely update their allowance validity at any time by calling `approve(address spender, uint256 amount, uint256 period)`. ## Rationale `_expiration` is implemented as a mapping to improve the compatibility of the code. So that existing event statistics are not perturbed by the implementation of this standard, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. -This standard is absolutely compatible with the traditional ERC20 standard. `DEFAULT_PERIOD` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_PERIOD` can be set to a constant or variable according to the developer's needs. +This standard is absolutely compatible with the traditional ERC-20 standard. `DEFAULT_PERIOD` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_PERIOD` can be set to a constant or variable according to the developer's needs. A separate approval method with the header `approve(address spender, uint256 amount, uint256 period)` has been introduced to allow users to customize the `_expiration` value of the approval. From 51d77b199be38224a1eb9cd8ab1cac584b811d40 Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Thu, 6 Oct 2022 18:33:05 -0700 Subject: [PATCH 10/35] fix ERC references to comply w/ ERC-### format --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 7292bc160ac71..8149cb72e171a 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -181,7 +181,7 @@ This standard is compatible with the ERC-20, ERC-721 and ERC-1155 standards. Tok Implementation can be referenced in `../assets/eip-5748/`. ## Security Considerations -When upgrading a standard ERC20-based proxy contract to this standard, attention should be paid to the location of assets. +When upgrading a standard ERC-20-based proxy contract to this standard, attention should be paid to the location of assets. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md). From a7d068ae74180b18e33350f57ea8cf2658aef226 Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Thu, 6 Oct 2022 18:35:36 -0700 Subject: [PATCH 11/35] add discussions-to --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 8149cb72e171a..052e64b1fafcc 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -3,7 +3,7 @@ eip: 5748 title: Approval Expiration for ERC-20 Tokens description: This standard introduces a standardized way for users to set expiration limits on ERC-20 token approvals. author: Go+ Security (@GoPlusSecurity), Jeff Hall <642706757@qq.com>, Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) -discussions-to: +discussions-to: status: Draft type: Standards Track category (*only required for Standards Track): Interface From f756e394778f4c6097b6eb75ddae7c5ac5db5cc8 Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Thu, 6 Oct 2022 19:04:18 -0700 Subject: [PATCH 12/35] edit contact info --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 052e64b1fafcc..d112ab313a1a2 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -2,7 +2,7 @@ eip: 5748 title: Approval Expiration for ERC-20 Tokens description: This standard introduces a standardized way for users to set expiration limits on ERC-20 token approvals. -author: Go+ Security (@GoPlusSecurity), Jeff Hall <642706757@qq.com>, Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) +author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) discussions-to: status: Draft type: Standards Track From b74515a6302fcf898f1ffb5b0f82b9969ff00a4b Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Fri, 7 Oct 2022 08:59:32 -0700 Subject: [PATCH 13/35] updte discussion forum --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index d112ab313a1a2..b4f41d0de3813 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -3,7 +3,7 @@ eip: 5748 title: Approval Expiration for ERC-20 Tokens description: This standard introduces a standardized way for users to set expiration limits on ERC-20 token approvals. author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) -discussions-to: +discussions-to: status: Draft type: Standards Track category (*only required for Standards Track): Interface From 506bdff042ae17920992f219ed1ec07e882e47f3 Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Fri, 7 Oct 2022 09:26:37 -0700 Subject: [PATCH 14/35] update discussion forum --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index b4f41d0de3813..a3d6a3c812f8f 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -3,7 +3,7 @@ eip: 5748 title: Approval Expiration for ERC-20 Tokens description: This standard introduces a standardized way for users to set expiration limits on ERC-20 token approvals. author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) -discussions-to: +discussions-to: status: Draft type: Standards Track category (*only required for Standards Track): Interface From 93fa23006e4e16f2f3895e435b0ebcb280776b34 Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Fri, 7 Oct 2022 09:32:24 -0700 Subject: [PATCH 15/35] editing header --- EIPS/eip-5748.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index a3d6a3c812f8f..8c186788b9732 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -6,9 +6,9 @@ author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@Xaaaaavith discussions-to: status: Draft type: Standards Track -category (*only required for Standards Track): Interface +category: Interface created: 2022-10-02) format -requires (*optional): +requires: --- This standard introduces a standard way for users to set expiration limits on ERC-20 token approvals to prevent the loss of assets due to contractrual vulnerabilities or authorization attacks. From 65d3750adf1e9da837896c34b7210d44aa73c677 Mon Sep 17 00:00:00 2001 From: Turan Vural <18318682+turanzv@users.noreply.github.com> Date: Mon, 10 Oct 2022 21:16:35 -0700 Subject: [PATCH 16/35] Update EIPS/eip-5748.md Co-authored-by: Pandapip1 <45835846+Pandapip1@users.noreply.github.com> --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 8c186788b9732..e12918bce678b 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -1,6 +1,6 @@ --- eip: 5748 -title: Approval Expiration for ERC-20 Tokens +title: Approval Expiration for EIP-20 Tokens description: This standard introduces a standardized way for users to set expiration limits on ERC-20 token approvals. author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) discussions-to: From e6dd69c52352276d951bd7933e3eb84f2db714d1 Mon Sep 17 00:00:00 2001 From: Mr-Lucky <642706757@qq.com> Date: Tue, 11 Oct 2022 14:13:29 +0800 Subject: [PATCH 17/35] add defaultExpiration method --- assets/eip-5748/eip-5748.sol | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/assets/eip-5748/eip-5748.sol b/assets/eip-5748/eip-5748.sol index 88ae7d5a91f05..3fe1d235c53cf 100644 --- a/assets/eip-5748/eip-5748.sol +++ b/assets/eip-5748/eip-5748.sol @@ -169,7 +169,7 @@ contract ERC20 is Context, IERC20, IERC20Metadata { string private _name; string private _symbol; - uint256 private constant DEFAULT_PERIOD = 86400 * 30; + uint256 private constant DEFAULT_EXPIRATION = 86400 * 30; mapping(address => mapping(address => uint256)) private _expiration; event AllowanceExpirationUpdated(address indexed owner, address indexed spender, uint256 value, uint256 expiration); @@ -188,6 +188,13 @@ contract ERC20 is Context, IERC20, IERC20Metadata { _symbol = symbol_; } + /** + * @dev Returns the defaultPeriod of the token. + */ + function defaultExpiration() public pure returns (uint256) { + return DEFAULT_EXPIRATION; + } + /** * @dev Returns the name of the token. */ @@ -271,7 +278,7 @@ contract ERC20 is Context, IERC20, IERC20Metadata { */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); - _approve(owner, spender, amount, DEFAULT_PERIOD); + _approve(owner, spender, amount, DEFAULT_EXPIRATION); return true; } @@ -323,7 +330,7 @@ contract ERC20 is Context, IERC20, IERC20Metadata { */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); - _approve(owner, spender, allowance(owner, spender) + addedValue, DEFAULT_PERIOD); + _approve(owner, spender, allowance(owner, spender) + addedValue, DEFAULT_EXPIRATION); return true; } @@ -352,7 +359,7 @@ contract ERC20 is Context, IERC20, IERC20Metadata { uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { - _approve(owner, spender, currentAllowance - subtractedValue, DEFAULT_PERIOD); + _approve(owner, spender, currentAllowance - subtractedValue, DEFAULT_EXPIRATION); } return true; From b615e30db78c1790711466f74b369592a433a206 Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Tue, 11 Oct 2022 02:07:38 -0700 Subject: [PATCH 18/35] add getter and rename DEFAULT_EXPIRATION --- EIPS/eip-5748.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index e12918bce678b..9dff336921a16 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -29,7 +29,7 @@ A time period `_expiration` is mapped on top of the original `allowance` to spec The internal `_approve()` method adds a uint256 `period` to the entry and stored in `_expiration`. -A `DEFAULT_PERIOD` constant is added for legacy implementations that do not specify the `period` parameter. +A `DEFAULT_EXPIRATION` constant is added for implementations that do not specify the `period` parameter. A getter method `defaultExpiration()` is included in the implementation for transparency to the user in the approval process. In order not to interfere with the existing event statistics and to allow other developers to count the validity of allowance, we add a new event `AllowanceExpireTimeUpdated()`, which will be triggered in the `_approve()` method. @@ -47,15 +47,19 @@ contract ERC20 is Context, IERC20, IERC20Metadata { string private _name; string private _symbol; - uint256 private constant DEFAULT_PERIOD = 86400 * 30; + uint256 private constant DEFAULT_EXPIRATION = 86400 * 30; mapping(address => mapping(address => uint256)) private _expiration; event AllowanceExpireTimeUpdated(address indexed owner, address indexed spender, uint256 value, uint256 expiration); + function defaultExpiration() public pure returns (uint256) { + return DEFAULT_EXPIRATION; + } + function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); - _approve(owner, spender, amount, DEFAULT_PERIOD); + _approve(owner, spender, amount, DEFAULT_EXPIRATION); return true; } @@ -125,7 +129,7 @@ The `allowance()`, `increaseAllowance()`, and `decreaseAllowance()` methods have function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); - _approve(owner, spender, allowance(owner, spender) + addedValue, DEFAULT_PERIOD); + _approve(owner, spender, allowance(owner, spender) + addedValue, DEFAULT_EXPIRATION); return true; } @@ -141,7 +145,7 @@ The `allowance()`, `increaseAllowance()`, and `decreaseAllowance()` methods have uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { - _approve(owner, spender, currentAllowance - subtractedValue, DEFAULT_PERIOD); + _approve(owner, spender, currentAllowance - subtractedValue, DEFAULT_EXPIRATION); } return true; @@ -166,7 +170,7 @@ The above modifications adds a validity period to ERC-20 token approvals. Users So that existing event statistics are not perturbed by the implementation of this standard, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. -This standard is absolutely compatible with the traditional ERC-20 standard. `DEFAULT_PERIOD` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_PERIOD` can be set to a constant or variable according to the developer's needs. +This standard is absolutely compatible with the traditional ERC-20 standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. A separate approval method with the header `approve(address spender, uint256 amount, uint256 period)` has been introduced to allow users to customize the `_expiration` value of the approval. From 470912b18c057e315459c59a8b484445df38f8d2 Mon Sep 17 00:00:00 2001 From: Turan Vural <18318682+turanzv@users.noreply.github.com> Date: Sun, 23 Oct 2022 21:22:09 -0700 Subject: [PATCH 19/35] Update EIPS/eip-5748.md Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 9dff336921a16..da5c70f3d68a4 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -1,7 +1,7 @@ --- eip: 5748 title: Approval Expiration for EIP-20 Tokens -description: This standard introduces a standardized way for users to set expiration limits on ERC-20 token approvals. +description: Extending EIP-20 approvals to automatically expire after a duration author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) discussions-to: status: Draft From b0183f0b55b884d16c5900e74069393aeaa0d30f Mon Sep 17 00:00:00 2001 From: Turan Vural <18318682+turanzv@users.noreply.github.com> Date: Sun, 23 Oct 2022 21:22:26 -0700 Subject: [PATCH 20/35] Update EIPS/eip-5748.md Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index da5c70f3d68a4..9bc1dcd53a83d 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -8,7 +8,7 @@ status: Draft type: Standards Track category: Interface created: 2022-10-02) format -requires: +requires: 20 --- This standard introduces a standard way for users to set expiration limits on ERC-20 token approvals to prevent the loss of assets due to contractrual vulnerabilities or authorization attacks. From d9ffc785092fc6e8aa81927f478467082ed60e6c Mon Sep 17 00:00:00 2001 From: Turan Vural <18318682+turanzv@users.noreply.github.com> Date: Sun, 23 Oct 2022 21:23:34 -0700 Subject: [PATCH 21/35] Update EIPS/eip-5748.md Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 9bc1dcd53a83d..993f72f133579 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -3,7 +3,7 @@ eip: 5748 title: Approval Expiration for EIP-20 Tokens description: Extending EIP-20 approvals to automatically expire after a duration author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) -discussions-to: +discussions-to: https://ethereum-magicians.org/t/eip-5748-automatic-expiration-of-token-approvals/ status: Draft type: Standards Track category: Interface From 96dc0838802f8a71dc5aaf0f946cd8c60d225792 Mon Sep 17 00:00:00 2001 From: Turan Vural <18318682+turanzv@users.noreply.github.com> Date: Sun, 23 Oct 2022 21:23:41 -0700 Subject: [PATCH 22/35] Update EIPS/eip-5748.md Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 993f72f133579..e31ecdf745ff1 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -7,7 +7,7 @@ discussions-to: https://ethereum-magicians.org/t/eip-5748-automatic-expiration-o status: Draft type: Standards Track category: Interface -created: 2022-10-02) format +created: 2022-10-02 requires: 20 --- From 8db83190371c98daebd467925e5f4fc28cbcdaf8 Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Sun, 23 Oct 2022 21:44:31 -0700 Subject: [PATCH 23/35] corrected discussions-to link --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index e31ecdf745ff1..fcfbe07d887a1 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -3,7 +3,7 @@ eip: 5748 title: Approval Expiration for EIP-20 Tokens description: Extending EIP-20 approvals to automatically expire after a duration author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) -discussions-to: https://ethereum-magicians.org/t/eip-5748-automatic-expiration-of-token-approvals/ +discussions-to: https://ethereum-magicians.org/t/eip-5748-automatic-token-approval-expiration/11185 status: Draft type: Standards Track category: Interface From df609c68028b3f3947220ec8491988fd00981110 Mon Sep 17 00:00:00 2001 From: Turan Vural <18318682+turanzv@users.noreply.github.com> Date: Sun, 23 Oct 2022 21:47:23 -0700 Subject: [PATCH 24/35] Remove pre-abstract text Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-5748.md | 1 - 1 file changed, 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index fcfbe07d887a1..d39541e3f3a6c 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -11,7 +11,6 @@ created: 2022-10-02 requires: 20 --- -This standard introduces a standard way for users to set expiration limits on ERC-20 token approvals to prevent the loss of assets due to contractrual vulnerabilities or authorization attacks. ## Abstract This standard adds an expiration time to the `_approve()` function of token contracts to automatically recall approvals within a certain time period. This functionality as a standard will prevent vulnerabilty exploits due to outstanding token approvals. From 9a368a28a9d2b32cf607474ab2c0b9eb7ea6a7e7 Mon Sep 17 00:00:00 2001 From: Turan Vural <18318682+turanzv@users.noreply.github.com> Date: Sun, 23 Oct 2022 21:47:55 -0700 Subject: [PATCH 25/35] Correct tone in Specification section Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-5748.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index d39541e3f3a6c..27b26a0d0306b 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -28,7 +28,9 @@ A time period `_expiration` is mapped on top of the original `allowance` to spec The internal `_approve()` method adds a uint256 `period` to the entry and stored in `_expiration`. -A `DEFAULT_EXPIRATION` constant is added for implementations that do not specify the `period` parameter. A getter method `defaultExpiration()` is included in the implementation for transparency to the user in the approval process. +Contracts implementing this standard MUST expose a `DEFAULT_EXPIRATION` constant of type `uint256`. This constant stores the expiration period to use for `approve` calls that do not include a `period` argument. + +`approve` functions without a `period` argument MUST use the expiry period exposed in the `DEFAULT_EXPIRATION` constant. In order not to interfere with the existing event statistics and to allow other developers to count the validity of allowance, we add a new event `AllowanceExpireTimeUpdated()`, which will be triggered in the `_approve()` method. From 77bc9b3653be2da0f4e7708281ec5baf6d9a7e2d Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Mon, 31 Oct 2022 00:53:07 -0700 Subject: [PATCH 26/35] adding @xyfidea to authors --- EIPS/eip-5748.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 27b26a0d0306b..5142abd3c403f 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -2,7 +2,7 @@ eip: 5748 title: Approval Expiration for EIP-20 Tokens description: Extending EIP-20 approvals to automatically expire after a duration -author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) +author: Go+ Security (@GoPlusSecurity), Eskil (@xyfidea), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) discussions-to: https://ethereum-magicians.org/t/eip-5748-automatic-token-approval-expiration/11185 status: Draft type: Standards Track @@ -26,7 +26,7 @@ There have been many similar incidents to the Transit Swap attack. Security audi A time period `_expiration` is mapped on top of the original `allowance` to specify an approval time limit. -The internal `_approve()` method adds a uint256 `period` to the entry and stored in `_expiration`. +The `_approve()` method adds uint256 `period` to the entry, which is stored in `_expiration`. Contracts implementing this standard MUST expose a `DEFAULT_EXPIRATION` constant of type `uint256`. This constant stores the expiration period to use for `approve` calls that do not include a `period` argument. From a11982f39a7512a4a0361fa88687f37ade68836c Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Wed, 2 Nov 2022 18:20:20 -0700 Subject: [PATCH 27/35] moving snippet from rationale to Backwards Compatibility --- EIPS/eip-5748.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 5142abd3c403f..396d94ecafa03 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -169,10 +169,6 @@ The above modifications adds a validity period to ERC-20 token approvals. Users ## Rationale `_expiration` is implemented as a mapping to improve the compatibility of the code. -So that existing event statistics are not perturbed by the implementation of this standard, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. - -This standard is absolutely compatible with the traditional ERC-20 standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. - A separate approval method with the header `approve(address spender, uint256 amount, uint256 period)` has been introduced to allow users to customize the `_expiration` value of the approval. The internal method `_spendAllowance()` is introduced for code cleanliness with the function of checking the allowance amount and expiration. @@ -182,6 +178,9 @@ The `allowance()` method has been modified to accommodate the functionality desc ## Backwards Compatibility This standard is compatible with the ERC-20, ERC-721 and ERC-1155 standards. Tokens issued in the form of proxy contracts can be updated to comply with this standard. +So that existing event statistics are not perturbed by the implementation of this standard, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. + +This standard is absolutely compatible with the traditional ERC-20 standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. ## Reference Implementation Implementation can be referenced in `../assets/eip-5748/`. From 86cc023ba98a56f249e3ecc9620d6c7489df535b Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Wed, 2 Nov 2022 18:35:27 -0700 Subject: [PATCH 28/35] fixing ERC-20 references re @ballestar --- EIPS/eip-5748.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 396d94ecafa03..0e0834b436bef 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -13,9 +13,11 @@ requires: 20 ## Abstract + This standard adds an expiration time to the `_approve()` function of token contracts to automatically recall approvals within a certain time period. This functionality as a standard will prevent vulnerabilty exploits due to outstanding token approvals. ## Motivation + As of the writing of this standard, the approval attack is the most common attack method in the industry with nearly all phishing attacks and asset theft related to it. Although good usage habits and basic knowledge of on-chain security can help users avoid a multitiude of exploits such as phishing, scams, DNS hijacking, JS injection, and other common approval attack methods, the spender's own security (or lack thereof) still needs to be fortified by strong code. In the Transit Swap attack of October 1st, 2022, hackers used a vulnerability in the Transit Swap contract to steal $20 million in assets. Due in part to professional security audits and the strong brand recognition of Transit Swap, many users were given a false sense of security and trusted the platform's service. Transit Swaps's contract had been running smoothly for over a year and had accumulated a large amount of user allownces, making the contract a high-reward target for malicious actors. @@ -90,7 +92,7 @@ contract ERC20 is Context, IERC20, IERC20Metadata { Transactions using the `transferFrom()` method will be checked against `_expiration` through `_spendAllowance()`. Transactions that take place after the alloted time period will fail. -```solidity +```solidity function transferFrom( address from, address to, @@ -164,9 +166,10 @@ The `allowance()`, `increaseAllowance()`, and `decreaseAllowance()` methods have } ``` -The above modifications adds a validity period to ERC-20 token approvals. Users can freely update their allowance validity at any time by calling `approve(address spender, uint256 amount, uint256 period)`. +The above modifications adds a validity period to [ERC-20] token approvals. Users can freely update their allowance validity at any time by calling `approve(address spender, uint256 amount, uint256 period)`. ## Rationale + `_expiration` is implemented as a mapping to improve the compatibility of the code. A separate approval method with the header `approve(address spender, uint256 amount, uint256 period)` has been introduced to allow users to customize the `_expiration` value of the approval. @@ -176,16 +179,20 @@ The internal method `_spendAllowance()` is introduced for code cleanliness with The `allowance()` method has been modified to accommodate the functionality described in this standard. `allowanceExpiration()` has been added query the allowance expiration date. ## Backwards Compatibility -This standard is compatible with the ERC-20, ERC-721 and ERC-1155 standards. Tokens issued in the form of proxy contracts can be updated to comply with this standard. + +This standard is compatible with the [ERC-20], ERC-721 and ERC-1155 standards. Tokens issued in the form of proxy contracts can be updated to comply with this standard. So that existing event statistics are not perturbed by the implementation of this standard, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. -This standard is absolutely compatible with the traditional ERC-20 standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. +This standard is absolutely compatible with the traditional [ERC-20] standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. ## Reference Implementation + Implementation can be referenced in `../assets/eip-5748/`. ## Security Considerations -When upgrading a standard ERC-20-based proxy contract to this standard, attention should be paid to the location of assets. + +When upgrading a standard [ERC-20]-based proxy contract to this standard, attention should be paid to the location of assets. ## Copyright + Copyright and related rights waived via [CC0](../LICENSE.md). From 836dc7ec442d3f7f529f06e1590886364661917b Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Wed, 2 Nov 2022 18:44:11 -0700 Subject: [PATCH 29/35] fixing markdown linting --- EIPS/eip-5748.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 0e0834b436bef..b218e4e115aaa 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -185,6 +185,7 @@ This standard is compatible with the [ERC-20], ERC-721 and ERC-1155 standards. T So that existing event statistics are not perturbed by the implementation of this standard, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. This standard is absolutely compatible with the traditional [ERC-20] standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. + ## Reference Implementation Implementation can be referenced in `../assets/eip-5748/`. From 6fde6e8c93978e86ece641c03ba65c8e88b9b87f Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Wed, 2 Nov 2022 18:49:27 -0700 Subject: [PATCH 30/35] adding links to ERCs in repo --- EIPS/eip-5748.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index b218e4e115aaa..59e565f1f2ca5 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -166,7 +166,7 @@ The `allowance()`, `increaseAllowance()`, and `decreaseAllowance()` methods have } ``` -The above modifications adds a validity period to [ERC-20] token approvals. Users can freely update their allowance validity at any time by calling `approve(address spender, uint256 amount, uint256 period)`. +The above modifications adds a validity period to [ERC-20](./eip-20.md) token approvals. Users can freely update their allowance validity at any time by calling `approve(address spender, uint256 amount, uint256 period)`. ## Rationale @@ -180,11 +180,11 @@ The `allowance()` method has been modified to accommodate the functionality desc ## Backwards Compatibility -This standard is compatible with the [ERC-20], ERC-721 and ERC-1155 standards. Tokens issued in the form of proxy contracts can be updated to comply with this standard. +This standard is compatible with the [ERC-20](./eip-20.md), [ERC-721](./eip-721.md) and [ERC-1155](./eip-1155.md) standards. Tokens issued in the form of proxy contracts can be updated to comply with this standard. So that existing event statistics are not perturbed by the implementation of this standard, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. -This standard is absolutely compatible with the traditional [ERC-20] standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. +This standard is absolutely compatible with the traditional [ERC-20](./eip-20.md) standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. ## Reference Implementation @@ -192,7 +192,7 @@ Implementation can be referenced in `../assets/eip-5748/`. ## Security Considerations -When upgrading a standard [ERC-20]-based proxy contract to this standard, attention should be paid to the location of assets. +When upgrading a standard [ERC-20](./eip-20.md)-based proxy contract to this standard, attention should be paid to the location of assets. ## Copyright From 1846db3c3d17c3c2f319f2c38b1dd6ae74b5413d Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Wed, 2 Nov 2022 18:53:28 -0700 Subject: [PATCH 31/35] changing ERC references to ERC b/c 'EIP Walidator' --- EIPS/eip-5748.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 59e565f1f2ca5..c2ab1c472fb5b 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -166,7 +166,7 @@ The `allowance()`, `increaseAllowance()`, and `decreaseAllowance()` methods have } ``` -The above modifications adds a validity period to [ERC-20](./eip-20.md) token approvals. Users can freely update their allowance validity at any time by calling `approve(address spender, uint256 amount, uint256 period)`. +The above modifications adds a validity period to [EIP-20](./eip-20.md) token approvals. Users can freely update their allowance validity at any time by calling `approve(address spender, uint256 amount, uint256 period)`. ## Rationale @@ -180,11 +180,11 @@ The `allowance()` method has been modified to accommodate the functionality desc ## Backwards Compatibility -This standard is compatible with the [ERC-20](./eip-20.md), [ERC-721](./eip-721.md) and [ERC-1155](./eip-1155.md) standards. Tokens issued in the form of proxy contracts can be updated to comply with this standard. +This standard is compatible with the [EIP-20](./eip-20.md), [EIP-721](./eip-721.md) and [EIP-1155](./eip-1155.md) standards. Tokens issued in the form of proxy contracts can be updated to comply with this standard. So that existing event statistics are not perturbed by the implementation of this standard, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. -This standard is absolutely compatible with the traditional [ERC-20](./eip-20.md) standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. +This standard is absolutely compatible with the traditional [EIP-20](./eip-20.md) standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. ## Reference Implementation @@ -192,7 +192,7 @@ Implementation can be referenced in `../assets/eip-5748/`. ## Security Considerations -When upgrading a standard [ERC-20](./eip-20.md)-based proxy contract to this standard, attention should be paid to the location of assets. +When upgrading a standard [EIP-20](./eip-20.md)-based proxy contract to this standard, attention should be paid to the location of assets. ## Copyright From abfe6314c5cac283a7345bcdacaf8b189159d3fe Mon Sep 17 00:00:00 2001 From: ballestar Date: Fri, 11 Nov 2022 21:44:40 -0600 Subject: [PATCH 32/35] refactor and adding interface --- EIPS/eip-5748.md | 183 +++++++++++++++-------------------------------- 1 file changed, 56 insertions(+), 127 deletions(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index c2ab1c472fb5b..0218bd6f0c108 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -11,7 +11,6 @@ created: 2022-10-02 requires: 20 --- - ## Abstract This standard adds an expiration time to the `_approve()` function of token contracts to automatically recall approvals within a certain time period. This functionality as a standard will prevent vulnerabilty exploits due to outstanding token approvals. @@ -26,6 +25,60 @@ There have been many similar incidents to the Transit Swap attack. Security audi ## Specification +```solidity +pragma solidity ^0.8.0; + +/// @title Approval Expiration for EIP-20 Tokens + +interface IERC20ApprovalExpire { + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve} or {transferFrom}. + */ + event AllowanceExpirationUpdated(address indexed _owner, address indexed _spender, uint256 _value, uint256 _expireAt); + + + /** + * @dev returns the default expiration time for approval + */ + function defaultExpiration() external pure returns (uint256); + + /** + * @dev Return the expire timestamp of the Approval which the address owner approve to the spender. _expiration[_owner][_spender] + */ + function allowanceExpiration(address _owner, address _spender) external view returns(uint256); + + /** + * @dev + * + * Returns a boolean value indicating whether the operation succeeded. + * + * the origin ERC20 approve, increaseAllowance, decreaseAllowance functions need to use DEFAULT_EXPIRATION + * as the params ‘period’ when call this internal _approve function. + * In this function, set _expiration[owner][spender] = block.timestamp + period, + * and emit AllowanceExpirationUpdated event. + * + * Emits an {AllowanceExpirationUpdated} event. + * Emits an {Approval} event. + * + * In the success case + */ + function approve(address _spender, uint256 _value, uint256 _period) external returns (bool); + + /** + * @dev Add the param 'period' for ERC20.increaseAllowance + * Default increaseAllowance is overridden if the period is specified + */ + function increaseAllowance(address _spender, uint256 _addedValue, uint256 _period) external returns (bool); + + /** + * @dev Add the param 'period' for ERC20.decreaseAllowance + * Default decreaseAllowance is overridden if the period is specified + */ + function decreaseAllowance(address spender, uint256 subtractedValue, uint256 period) external returns (bool); +} + +``` + A time period `_expiration` is mapped on top of the original `allowance` to specify an approval time limit. The `_approve()` method adds uint256 `period` to the entry, which is stored in `_expiration`. @@ -38,134 +91,10 @@ In order not to interfere with the existing event statistics and to allow other A separate approval method with the header `approve(address spender, uint256 amount, uint256 period)` modifies the `_expiration` value for existing approvals. -```solidity -contract ERC20 is Context, IERC20, IERC20Metadata { - - mapping(address => uint256) private _balances; - - mapping(address => mapping(address => uint256)) private _allowances; - - uint256 private _totalSupply; - - string private _name; - string private _symbol; - - uint256 private constant DEFAULT_EXPIRATION = 86400 * 30; - mapping(address => mapping(address => uint256)) private _expiration; - - event AllowanceExpireTimeUpdated(address indexed owner, address indexed spender, uint256 value, uint256 expiration); - - - function defaultExpiration() public pure returns (uint256) { - return DEFAULT_EXPIRATION; - } - - function approve(address spender, uint256 amount) public virtual override returns (bool) { - address owner = _msgSender(); - _approve(owner, spender, amount, DEFAULT_EXPIRATION); - return true; - } - - - function approve(address spender, uint256 amount, uint256 period) public returns (bool) { - address owner = _msgSender(); - _approve(owner, spender, amount, period); - return true; - } - - - function _approve( - address owner, - address spender, - uint256 amount, - uint256 period - ) internal virtual { - require(owner != address(0), "ERC20: approve from the zero address"); - require(spender != address(0), "ERC20: approve to the zero address"); - - _allowances[owner][spender] = amount; - _expiration[owner][spender] = block.timestamp + period; - emit Approval(owner, spender, amount); - emit AllowanceExpireTimeUpdated(owner, spender, amount, _expiration[owner][spender]); - } -``` - Transactions using the `transferFrom()` method will be checked against `_expiration` through `_spendAllowance()`. Transactions that take place after the alloted time period will fail. -```solidity - function transferFrom( - address from, - address to, - uint256 amount - ) public virtual override returns (bool) { - address spender = _msgSender(); - _spendAllowance(from, spender, amount); - _transfer(from, to, amount); - return true; - } - - - function _spendAllowance( - address owner, - address spender, - uint256 amount - ) internal virtual { - uint256 currentAllowance = _allowances[owner][spender]; - uint256 currentExpiration = _expiration[owner][spender]; - require(block.timestamp <= currentExpiration, "Approval expired!"); - if (currentAllowance != type(uint256).max) { - require(currentAllowance >= amount, "ERC20: insufficient allowance"); - unchecked { - _approve(owner, spender, currentAllowance - amount, currentExpiration - block.timestamp); - } - } - } -``` - The `allowance()`, `increaseAllowance()`, and `decreaseAllowance()` methods have been modified to accommodate the new features. `allowanceExpiration()` has been added to query the live period of the contract. -```solidity - function allowanceExpiration(address owner, address spender) public view returns (uint256) { - return _expiration[owner][spender]; - } - - - function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { - address owner = _msgSender(); - _approve(owner, spender, allowance(owner, spender) + addedValue, DEFAULT_EXPIRATION); - return true; - } - - function increaseAllowance(address spender, uint256 addedValue, uint256 period) public virtual returns (bool) { - address owner = _msgSender(); - _approve(owner, spender, allowance(owner, spender) + addedValue, period); - return true; - } - - - function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { - address owner = _msgSender(); - uint256 currentAllowance = allowance(owner, spender); - require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); - unchecked { - _approve(owner, spender, currentAllowance - subtractedValue, DEFAULT_EXPIRATION); - } - - return true; - } - - function decreaseAllowance(address spender, uint256 subtractedValue, uint256 period) public virtual returns (bool) { - address owner = _msgSender(); - uint256 currentAllowance = allowance(owner, spender); - require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); - unchecked { - _approve(owner, spender, currentAllowance - subtractedValue, period); - } - - return true; - } -``` - The above modifications adds a validity period to [EIP-20](./eip-20.md) token approvals. Users can freely update their allowance validity at any time by calling `approve(address spender, uint256 amount, uint256 period)`. ## Rationale @@ -176,7 +105,7 @@ A separate approval method with the header `approve(address spender, uint256 amo The internal method `_spendAllowance()` is introduced for code cleanliness with the function of checking the allowance amount and expiration. -The `allowance()` method has been modified to accommodate the functionality described in this standard. `allowanceExpiration()` has been added query the allowance expiration date. +The `allowance()` method has been modified to accommodate the functionality described in this standard. `allowanceExpiration()` has been added query the allowance expiration date. ## Backwards Compatibility @@ -184,7 +113,7 @@ This standard is compatible with the [EIP-20](./eip-20.md), [EIP-721](./eip-721. So that existing event statistics are not perturbed by the implementation of this standard, `_approve()` is triggered by the new event `AllowanceExpireTimeUpdated()`. -This standard is absolutely compatible with the traditional [EIP-20](./eip-20.md) standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. +This standard is absolutely compatible with the traditional [EIP-20](./eip-20.md) standard. `DEFAULT_EXPIRATION` is added so that the original `approve(address spender, uint256 amount)` method header can remain for backwards compatibility and ease of programming. `DEFAULT_EXPIRATION` can be set to a constant or variable according to the developer's needs. ## Reference Implementation From 5459e2fccde9d9bfeee4824e97c929f9bf21838a Mon Sep 17 00:00:00 2001 From: Turan Vural Date: Thu, 15 Dec 2022 23:51:41 -0600 Subject: [PATCH 33/35] adding @ballestar to contributors --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index 0218bd6f0c108..c2cf857439bf1 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -2,7 +2,7 @@ eip: 5748 title: Approval Expiration for EIP-20 Tokens description: Extending EIP-20 approvals to automatically expire after a duration -author: Go+ Security (@GoPlusSecurity), Eskil (@xyfidea), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv) +author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv), Johans Ballestar (ballestar), Eskil (@xyfidea) discussions-to: https://ethereum-magicians.org/t/eip-5748-automatic-token-approval-expiration/11185 status: Draft type: Standards Track From d098211c659bc33574246446e57e12c195455b75 Mon Sep 17 00:00:00 2001 From: Turan Vural <18318682+turanzv@users.noreply.github.com> Date: Tue, 27 Dec 2022 02:34:31 +0000 Subject: [PATCH 34/35] fixing license on .sol asset --- assets/eip-5748/eip-5748.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/eip-5748/eip-5748.sol b/assets/eip-5748/eip-5748.sol index 3fe1d235c53cf..c8eca29d12134 100644 --- a/assets/eip-5748/eip-5748.sol +++ b/assets/eip-5748/eip-5748.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: CC0-1.0 // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; From a1e8bb8e77a5d1b83c30f1a1bfded8be4ba1f80b Mon Sep 17 00:00:00 2001 From: Turan Vural <18318682+turanzv@users.noreply.github.com> Date: Tue, 27 Dec 2022 02:35:27 +0000 Subject: [PATCH 35/35] fixing @ballestar annotation --- EIPS/eip-5748.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5748.md b/EIPS/eip-5748.md index c2cf857439bf1..0100a6bfd6dac 100644 --- a/EIPS/eip-5748.md +++ b/EIPS/eip-5748.md @@ -2,7 +2,7 @@ eip: 5748 title: Approval Expiration for EIP-20 Tokens description: Extending EIP-20 approvals to automatically expire after a duration -author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv), Johans Ballestar (ballestar), Eskil (@xyfidea) +author: Go+ Security (@GoPlusSecurity), Jeff Hall (@Mr-Lucky), Xavi (@XaaaaavitheFool), Turan Vural (@turanzv), Johans Ballestar (@ballestar), Eskil (@xyfidea) discussions-to: https://ethereum-magicians.org/t/eip-5748-automatic-token-approval-expiration/11185 status: Draft type: Standards Track