From ec8e265ff293325e1dde6a00f0d01e7c7d4f1782 Mon Sep 17 00:00:00 2001 From: Pandapip1 <45835846+Pandapip1@users.noreply.github.com> Date: Wed, 23 Nov 2022 12:54:24 -0500 Subject: [PATCH 01/11] Update EIP-20: Renovate to fit current EIP-1 recommendations (Incomplete) --- EIPS/eip-20.md | 262 ++++++++++++++++++------------------------------- 1 file changed, 97 insertions(+), 165 deletions(-) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 98600bad83617..874753cf25c63 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -1,193 +1,125 @@ --- eip: 20 title: Token Standard +description: A standard interface for tokens author: Fabian Vogelsteller , Vitalik Buterin +discussions-to: https://github.com/ethereum/EIPs/issues/20 type: Standards Track category: ERC status: Final created: 2015-11-19 --- -## Simple Summary - -A standard interface for tokens. - - ## Abstract -The following standard allows for the implementation of a standard API for tokens within smart contracts. -This standard provides basic functionality to transfer tokens, as well as allow tokens to be approved so they can be spent by another on-chain third party. - +This EIP standardizes an interface for fungible tokens within smart contracts. +The interface has basic transfer functionality, and allows tokens to be approved so they can be spent by another on-chain third party. ## Motivation A standard interface allows any tokens on Ethereum to be re-used by other applications: from wallets to decentralized exchanges. - ## Specification -## Token -### Methods - -**NOTES**: - - The following specifications use syntax from Solidity `0.4.17` (or above) - - Callers MUST handle `false` from `returns (bool success)`. Callers MUST NOT assume that `false` is never returned! - - -#### name - -Returns the name of the token - e.g. `"MyToken"`. - -OPTIONAL - This method can be used to improve usability, -but interfaces and other contracts MUST NOT expect these values to be present. - - -``` js -function name() public view returns (string) +All compliant tokens MUST implement the following interface: + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.17; + +interface ERC20 { + /// @notice MUST trigger when tokens are transferred, including zero value transfers. + /// A token contract which creates new tokens SHOULD trigger a Transfer event with the `_from` address set to `0x0` when tokens are created. + /// @param _from The address from which the tokens were transferred + /// @param _to The address to which the tokens were deposited + /// @param _value The number of tokens that were transferred + event Transfer(address indexed _from, address indexed _to, uint256 _value); + + /// @notice MUST trigger on any successful call to `approve(address _spender, uint256 _value)`. + /// @param _owner The address from which the tokens can be transferred + /// @param _spender The address that can spend the tokens + /// @param _value The number of tokens that can be transferred + event Approval(address indexed _owner, address indexed _spender, uint256 _value); + + /// @notice Returns the total token supply. + /// @return supply The supply of the token + function totalSupply() external view returns (uint256 supply); + + /// @notice Returns the balance of the account with address `_owner`. + /// @param _owner The account to query the balance of + /// @return balance The balance of the account + function balanceOf(address _owner) external view returns (uint256); + + /// @notice Returns the amount which `_spender` is still allowed to withdraw from `_owner`. + /// @param _owner The account which holds the tokens + /// @param _spender The account that can spend the tokens + /// @return remaining + function allowance(address _owner, address _spender) external view returns (uint256 remaining); + + /// @notice Transfers `_value` amount of tokens to address `_to`, and MUST fire the `Transfer` event. + /// The function SHOULD `throw` if the message caller's account balance does not have enough tokens to spend. + /// @dev Transfers of 0 values MUST be treated as normal transfers and fire the `Transfer` event. + /// Callers MUST handle `false` from `returns (bool success)`. Callers MUST NOT assume that `false` is never returned! + /// @param _to The address to which the tokens are deposited + /// @param _value The number of tokens that are transferred + /// @return success Whether the operation was successful or not + function transfer(address _to, uint256 _value) external returns (bool success); + + /// @notice Transfers `_value` amount of tokens from address `_from` to address `_to`, and MUST fire the `Transfer` event. + /// The `transferFrom` method is used for a withdraw workflow, allowing contracts to transfer tokens on your behalf. + /// This can be used for example to allow a contract to transfer tokens on your behalf and/or to charge fees in sub-currencies. + /// The function SHOULD `throw` unless the `_from` account has deliberately authorized the sender of the message via some mechanism. + /// @dev Transfers of 0 values MUST be treated as normal transfers and fire the `Transfer` event. + /// @param _from The address from which the tokens are transferred + /// @param _to The address to which the tokens are deposited + /// @param _value The number of tokens that are transferred + /// @return success Whether the operation was successful or not + function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); + + Allows `_spender` to withdraw from your account multiple times, up to the `_value` amount. If this function is called again it overwrites the current allowance with `_value`. + + **NOTE**: To prevent attack vectors like the one [described here](https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/) and discussed [here](https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729), + clients SHOULD make sure to create user interfaces in such a way that they set the allowance first to `0` before setting it to another value for the same spender. + THOUGH The contract itself shouldn't enforce it, to allow backwards compatibility with contracts deployed before + + function approve(address _spender, uint256 _value) public returns (bool success) +} ``` - -#### symbol - -Returns the symbol of the token. E.g. "HIX". - -OPTIONAL - This method can be used to improve usability, -but interfaces and other contracts MUST NOT expect these values to be present. - -``` js -function symbol() public view returns (string) +In addition, the following RECOMMENDED interfaces MAY be implemented: + +```solidity +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.17; + +interface ERC20Name is ERC20 { + /// @notice Returns the name of the token - e.g. `"MyToken"`. + /// @dev OPTIONAL EXTENSION - This method can be used to improve usability, but interfaces and other contracts MUST NOT expect these values to be present. + /// @return The name of the token + function name() external view returns (string); +} + +interface ERC20Symbol is ERC20 { + /// @notice Returns the symbol of the token - e.g. `"HIX"`. + /// @dev OPTIONAL EXTENSION - This method can be used to improve usability, but interfaces and other contracts MUST NOT expect these values to be present. + /// @return The symbol of the token + function symbol() external view returns (string); +} + +interface ERC20Decimals is ERC20 { + /// @notice Returns the number of decimals the token uses - e.g. `8`, means to divide the token amount by `100000000` to get its user representation. + /// @dev OPTIONAL EXTENSION - This method can be used to improve usability, but interfaces and other contracts MUST NOT expect these values to be present. + /// @return The decimals of the token + function decimals() external view returns (uint8); +} ``` +## Rationale +## Backwards Compatibility -#### decimals - -Returns the number of decimals the token uses - e.g. `8`, means to divide the token amount by `100000000` to get its user representation. - -OPTIONAL - This method can be used to improve usability, -but interfaces and other contracts MUST NOT expect these values to be present. - -``` js -function decimals() public view returns (uint8) -``` - - -#### totalSupply - -Returns the total token supply. - -``` js -function totalSupply() public view returns (uint256) -``` - - - -#### balanceOf - -Returns the account balance of another account with address `_owner`. - -``` js -function balanceOf(address _owner) public view returns (uint256 balance) -``` - - - -#### transfer - -Transfers `_value` amount of tokens to address `_to`, and MUST fire the `Transfer` event. -The function SHOULD `throw` if the message caller's account balance does not have enough tokens to spend. - -*Note* Transfers of 0 values MUST be treated as normal transfers and fire the `Transfer` event. - -``` js -function transfer(address _to, uint256 _value) public returns (bool success) -``` - - - -#### transferFrom - -Transfers `_value` amount of tokens from address `_from` to address `_to`, and MUST fire the `Transfer` event. - -The `transferFrom` method is used for a withdraw workflow, allowing contracts to transfer tokens on your behalf. -This can be used for example to allow a contract to transfer tokens on your behalf and/or to charge fees in sub-currencies. -The function SHOULD `throw` unless the `_from` account has deliberately authorized the sender of the message via some mechanism. - -*Note* Transfers of 0 values MUST be treated as normal transfers and fire the `Transfer` event. - -``` js -function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) -``` - - - -#### approve - -Allows `_spender` to withdraw from your account multiple times, up to the `_value` amount. If this function is called again it overwrites the current allowance with `_value`. - -**NOTE**: To prevent attack vectors like the one [described here](https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/) and discussed [here](https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729), -clients SHOULD make sure to create user interfaces in such a way that they set the allowance first to `0` before setting it to another value for the same spender. -THOUGH The contract itself shouldn't enforce it, to allow backwards compatibility with contracts deployed before - -``` js -function approve(address _spender, uint256 _value) public returns (bool success) -``` - - -#### allowance - -Returns the amount which `_spender` is still allowed to withdraw from `_owner`. - -``` js -function allowance(address _owner, address _spender) public view returns (uint256 remaining) -``` - - - -### Events - - -#### Transfer - -MUST trigger when tokens are transferred, including zero value transfers. - -A token contract which creates new tokens SHOULD trigger a Transfer event with the `_from` address set to `0x0` when tokens are created. - -``` js -event Transfer(address indexed _from, address indexed _to, uint256 _value) -``` - - - -#### Approval - -MUST trigger on any successful call to `approve(address _spender, uint256 _value)`. - -``` js -event Approval(address indexed _owner, address indexed _spender, uint256 _value) -``` - - - -## Implementation - -There are already plenty of ERC20-compliant tokens deployed on the Ethereum network. -Different implementations have been written by various teams that have different trade-offs: from gas saving to improved security. - -#### Example implementations are available at -- [OpenZeppelin implementation](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/9b3710465583284b8c4c5d2245749246bb2e0094/contracts/token/ERC20/ERC20.sol) -- [ConsenSys implementation](https://github.com/ConsenSys/Tokens/blob/fdf687c69d998266a95f15216b1955a4965a0a6d/contracts/eip20/EIP20.sol) - - -## History - -Historical links related to this standard: - -- Original proposal from Vitalik Buterin: https://github.com/ethereum/wiki/wiki/Standardized_Contract_APIs/499c882f3ec123537fc2fccd57eaa29e6032fe4a -- Reddit discussion: https://www.reddit.com/r/ethereum/comments/3n8fkn/lets_talk_about_the_coin_standard/ -- Original Issue #20: https://github.com/ethereum/EIPs/issues/20 - - +Many existing tokens deployed on the Ethereum network already support this EIP. ## Copyright + Copyright and related rights waived via [CC0](../LICENSE.md). From c27ca075cfbb512d2ef25f427d6d481f2bfce63d Mon Sep 17 00:00:00 2001 From: Pandapip1 <45835846+Pandapip1@users.noreply.github.com> Date: Wed, 23 Nov 2022 15:16:27 -0500 Subject: [PATCH 02/11] Update eip-20.md --- EIPS/eip-20.md | 56 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 874753cf25c63..4ab360bab24d6 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -4,9 +4,9 @@ title: Token Standard description: A standard interface for tokens author: Fabian Vogelsteller , Vitalik Buterin discussions-to: https://github.com/ethereum/EIPs/issues/20 +status: Final type: Standards Track category: ERC -status: Final created: 2015-11-19 --- @@ -15,10 +15,6 @@ created: 2015-11-19 This EIP standardizes an interface for fungible tokens within smart contracts. The interface has basic transfer functionality, and allows tokens to be approved so they can be spent by another on-chain third party. -## Motivation - -A standard interface allows any tokens on Ethereum to be re-used by other applications: from wallets to decentralized exchanges. - ## Specification All compliant tokens MUST implement the following interface: @@ -74,15 +70,17 @@ interface ERC20 { /// @param _to The address to which the tokens are deposited /// @param _value The number of tokens that are transferred /// @return success Whether the operation was successful or not - function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); - - Allows `_spender` to withdraw from your account multiple times, up to the `_value` amount. If this function is called again it overwrites the current allowance with `_value`. - - **NOTE**: To prevent attack vectors like the one [described here](https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/) and discussed [here](https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729), - clients SHOULD make sure to create user interfaces in such a way that they set the allowance first to `0` before setting it to another value for the same spender. - THOUGH The contract itself shouldn't enforce it, to allow backwards compatibility with contracts deployed before - - function approve(address _spender, uint256 _value) public returns (bool success) + function transferFrom(address _from, address _to, uint256 _value) external returns (bool success); + + /// @notice Allows `_spender` to withdraw from your account multiple times, up to the `_value` amount. + /// If this function is called again it overwrites the current allowance with `_value`. + /// @dev To prevent the re-approval attack vector described in the Security Considerations section, clients SHOULD make sure + /// to create user interfaces in such a way that they set the allowance `0` before setting it to another value for the + /// same spender. However, contracts SHOULD NOT enforce this, for backward compatibility with previously-deployed contracts. + /// @param _spender The address to which the tokens are deposited + /// @param _value The number of tokens that are transferred + /// @return success Whether the operation was successful or not + function approve(address _spender, uint256 _value) external returns (bool success); } ``` @@ -116,10 +114,40 @@ interface ERC20Decimals is ERC20 { ## Rationale +### The approve and transferFrom flow + +`approve` and `transferFrom` can be used in conjunction with one another to allow smart contracts to take an action if and only if a transfer succeeds. This enables use cases such as decentralized exchanges, which can trustlessly swap one token for another. + +### Decimals is optional + +Some tokens might wish to use a base unit other than $10^{-18}$, and sometimes it doesn't make sense to have a fraction of a token. However, not every token might reasonably need to specify `decimals`. Thus, `decimals` is optional. + ## Backwards Compatibility Many existing tokens deployed on the Ethereum network already support this EIP. +## Security Considerations + +### Re-approval + +#### Description of re-approval attack + +1. Alice approves Bob to transfer $N$ of Alice's tokens (where $N>0$) by calling the `approve(Bob, N)` +2. Later, Alice decides to set the approval from $N$ to $M$ ($M>0$), so she calls the `approve(Bob, M)` +3. Bob notices Alice's second transaction when it is submitted to the mempool +4. Before Alice's `approve(Bob, M)` transaction is included in a block, Bob sends a transaction calling `transferFrom(Alice, Bob, N)` with a higer priority fee than Alice's transaction, and a transaction calling `transferFrom(Alice, Bob, M)` with a lower priority fee than Alice's transaction +5. Bob's `transferFrom(Alice, Bob, N)` will be executed first, transfering $N$ tokens from Alice to Bob +6. Next, Alice's `approve(Bob, M)` will execute, allowing Bob to transfer an additonal $M$ tokens +7. Finally, Bob's `transferFrom(Alice, Bob, M)` will be executed first, transfering another $M$ tokens from Alice to Bob + +Bob was able to transfer a total of $N+M$ tokens instead of a total of $M$. + +(Written by Mikhail Vladimirov and Dmitry Khovratovich , edited by Pandapip1 (@Pandapip1)) + +#### Mitigation of re-appproval attack + +Frontends should be written such that if a non-zero approval is to be raised or lowered, the approval is first set to zero and the transaction included in a block. + ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md). From 2a18cfead927482b492dd6b0e0f8c4f7fad11ef3 Mon Sep 17 00:00:00 2001 From: Pandapip1 <45835846+Pandapip1@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:23:31 -0500 Subject: [PATCH 03/11] Add motivation section back --- EIPS/eip-20.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 4ab360bab24d6..af4d4e8e651a2 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -15,6 +15,10 @@ created: 2015-11-19 This EIP standardizes an interface for fungible tokens within smart contracts. The interface has basic transfer functionality, and allows tokens to be approved so they can be spent by another on-chain third party. +## Motivation + +A standard interface allows any tokens on Ethereum to be re-used by other applications: from wallets to decentralized exchanges. + ## Specification All compliant tokens MUST implement the following interface: From 79da9c68ab64d6927148e80e88385476a8367ce3 Mon Sep 17 00:00:00 2001 From: Pandapip1 <45835846+Pandapip1@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:29:30 -0500 Subject: [PATCH 04/11] Revert (most) changes to Specification section --- EIPS/eip-20.md | 207 +++++++++++++++++++++++++++---------------------- 1 file changed, 116 insertions(+), 91 deletions(-) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index af4d4e8e651a2..25a80d821d134 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -21,99 +21,124 @@ A standard interface allows any tokens on Ethereum to be re-used by other applic ## Specification -All compliant tokens MUST implement the following interface: - -```solidity -// SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.17; - -interface ERC20 { - /// @notice MUST trigger when tokens are transferred, including zero value transfers. - /// A token contract which creates new tokens SHOULD trigger a Transfer event with the `_from` address set to `0x0` when tokens are created. - /// @param _from The address from which the tokens were transferred - /// @param _to The address to which the tokens were deposited - /// @param _value The number of tokens that were transferred - event Transfer(address indexed _from, address indexed _to, uint256 _value); - - /// @notice MUST trigger on any successful call to `approve(address _spender, uint256 _value)`. - /// @param _owner The address from which the tokens can be transferred - /// @param _spender The address that can spend the tokens - /// @param _value The number of tokens that can be transferred - event Approval(address indexed _owner, address indexed _spender, uint256 _value); - - /// @notice Returns the total token supply. - /// @return supply The supply of the token - function totalSupply() external view returns (uint256 supply); - - /// @notice Returns the balance of the account with address `_owner`. - /// @param _owner The account to query the balance of - /// @return balance The balance of the account - function balanceOf(address _owner) external view returns (uint256); - - /// @notice Returns the amount which `_spender` is still allowed to withdraw from `_owner`. - /// @param _owner The account which holds the tokens - /// @param _spender The account that can spend the tokens - /// @return remaining - function allowance(address _owner, address _spender) external view returns (uint256 remaining); - - /// @notice Transfers `_value` amount of tokens to address `_to`, and MUST fire the `Transfer` event. - /// The function SHOULD `throw` if the message caller's account balance does not have enough tokens to spend. - /// @dev Transfers of 0 values MUST be treated as normal transfers and fire the `Transfer` event. - /// Callers MUST handle `false` from `returns (bool success)`. Callers MUST NOT assume that `false` is never returned! - /// @param _to The address to which the tokens are deposited - /// @param _value The number of tokens that are transferred - /// @return success Whether the operation was successful or not - function transfer(address _to, uint256 _value) external returns (bool success); - - /// @notice Transfers `_value` amount of tokens from address `_from` to address `_to`, and MUST fire the `Transfer` event. - /// The `transferFrom` method is used for a withdraw workflow, allowing contracts to transfer tokens on your behalf. - /// This can be used for example to allow a contract to transfer tokens on your behalf and/or to charge fees in sub-currencies. - /// The function SHOULD `throw` unless the `_from` account has deliberately authorized the sender of the message via some mechanism. - /// @dev Transfers of 0 values MUST be treated as normal transfers and fire the `Transfer` event. - /// @param _from The address from which the tokens are transferred - /// @param _to The address to which the tokens are deposited - /// @param _value The number of tokens that are transferred - /// @return success Whether the operation was successful or not - function transferFrom(address _from, address _to, uint256 _value) external returns (bool success); - - /// @notice Allows `_spender` to withdraw from your account multiple times, up to the `_value` amount. - /// If this function is called again it overwrites the current allowance with `_value`. - /// @dev To prevent the re-approval attack vector described in the Security Considerations section, clients SHOULD make sure - /// to create user interfaces in such a way that they set the allowance `0` before setting it to another value for the - /// same spender. However, contracts SHOULD NOT enforce this, for backward compatibility with previously-deployed contracts. - /// @param _spender The address to which the tokens are deposited - /// @param _value The number of tokens that are transferred - /// @return success Whether the operation was successful or not - function approve(address _spender, uint256 _value) external returns (bool success); -} +## Token + +### Methods + +**NOTES**: + - The following specifications use syntax from Solidity `0.4.17` (or above) + - Callers MUST handle `false` from `returns (bool success)`. Callers MUST NOT assume that `false` is never returned! + +#### name + +Returns the name of the token - e.g. `"MyToken"`. + +OPTIONAL - This method can be used to improve usability, +but interfaces and other contracts MUST NOT expect these values to be present. + +``` js +function name() public view returns (string) +``` + +#### symbol + +Returns the symbol of the token. E.g. "HIX". + +OPTIONAL - This method can be used to improve usability, +but interfaces and other contracts MUST NOT expect these values to be present. + +``` js +function symbol() public view returns (string) +``` + +#### decimals + +Returns the number of decimals the token uses - e.g. `8`, means to divide the token amount by `100000000` to get its user representation. + +OPTIONAL - This method can be used to improve usability, +but interfaces and other contracts MUST NOT expect these values to be present. + +``` js +function decimals() public view returns (uint8) +``` + +#### totalSupply + +Returns the total token supply. + +``` js +function totalSupply() public view returns (uint256) +``` + +#### balanceOf + +Returns the account balance of another account with address `_owner`. + +``` js +function balanceOf(address _owner) public view returns (uint256 balance) +``` + +#### transfer + +Transfers `_value` amount of tokens to address `_to`, and MUST fire the `Transfer` event. +The function SHOULD `throw` if the message caller's account balance does not have enough tokens to spend. + +*Note* Transfers of 0 values MUST be treated as normal transfers and fire the `Transfer` event. + +``` js +function transfer(address _to, uint256 _value) public returns (bool success) +``` + +#### transferFrom + +Transfers `_value` amount of tokens from address `_from` to address `_to`, and MUST fire the `Transfer` event. + +The `transferFrom` method is used for a withdraw workflow, allowing contracts to transfer tokens on your behalf. +This can be used for example to allow a contract to transfer tokens on your behalf and/or to charge fees in sub-currencies. +The function SHOULD `throw` unless the `_from` account has deliberately authorized the sender of the message via some mechanism. + +*Note* Transfers of 0 values MUST be treated as normal transfers and fire the `Transfer` event. + +``` js +function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) +``` + +#### approve + +Allows `_spender` to withdraw from your account multiple times, up to the `_value` amount. If this function is called again it overwrites the current allowance with `_value`. + +**NOTE**: Please read the [Security Considerations](#security-considerations) section for potential attack vectors. + +``` js +function approve(address _spender, uint256 _value) public returns (bool success) ``` -In addition, the following RECOMMENDED interfaces MAY be implemented: - -```solidity -// SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.17; - -interface ERC20Name is ERC20 { - /// @notice Returns the name of the token - e.g. `"MyToken"`. - /// @dev OPTIONAL EXTENSION - This method can be used to improve usability, but interfaces and other contracts MUST NOT expect these values to be present. - /// @return The name of the token - function name() external view returns (string); -} - -interface ERC20Symbol is ERC20 { - /// @notice Returns the symbol of the token - e.g. `"HIX"`. - /// @dev OPTIONAL EXTENSION - This method can be used to improve usability, but interfaces and other contracts MUST NOT expect these values to be present. - /// @return The symbol of the token - function symbol() external view returns (string); -} - -interface ERC20Decimals is ERC20 { - /// @notice Returns the number of decimals the token uses - e.g. `8`, means to divide the token amount by `100000000` to get its user representation. - /// @dev OPTIONAL EXTENSION - This method can be used to improve usability, but interfaces and other contracts MUST NOT expect these values to be present. - /// @return The decimals of the token - function decimals() external view returns (uint8); -} +#### allowance + +Returns the amount which `_spender` is still allowed to withdraw from `_owner`. + +``` js +function allowance(address _owner, address _spender) public view returns (uint256 remaining) +``` + +### Events + +#### Transfer + +MUST trigger when tokens are transferred, including zero value transfers. + +A token contract which creates new tokens SHOULD trigger a Transfer event with the `_from` address set to `0x0` when tokens are created. + +``` js +event Transfer(address indexed _from, address indexed _to, uint256 _value) +``` + +#### Approval + +MUST trigger on any successful call to `approve(address _spender, uint256 _value)`. + +``` js +event Approval(address indexed _owner, address indexed _spender, uint256 _value) ``` ## Rationale From c58a054cafc42c7e3b4abe07b80059cb97db0609 Mon Sep 17 00:00:00 2001 From: Pandapip1 <45835846+Pandapip1@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:30:45 -0500 Subject: [PATCH 05/11] Fix small typo --- EIPS/eip-20.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 25a80d821d134..60269cd416641 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -162,7 +162,7 @@ Many existing tokens deployed on the Ethereum network already support this EIP. #### Description of re-approval attack 1. Alice approves Bob to transfer $N$ of Alice's tokens (where $N>0$) by calling the `approve(Bob, N)` -2. Later, Alice decides to set the approval from $N$ to $M$ ($M>0$), so she calls the `approve(Bob, M)` +2. Later, Alice decides to set the approval from $N$ to $M$ ( $M>0$ ), so she calls the `approve(Bob, M)` 3. Bob notices Alice's second transaction when it is submitted to the mempool 4. Before Alice's `approve(Bob, M)` transaction is included in a block, Bob sends a transaction calling `transferFrom(Alice, Bob, N)` with a higer priority fee than Alice's transaction, and a transaction calling `transferFrom(Alice, Bob, M)` with a lower priority fee than Alice's transaction 5. Bob's `transferFrom(Alice, Bob, N)` will be executed first, transfering $N$ tokens from Alice to Bob From 5bbebad7b529c6d2846b5fa10dc736cdeafd8473 Mon Sep 17 00:00:00 2001 From: Pandapip1 <45835846+Pandapip1@users.noreply.github.com> Date: Tue, 17 Jan 2023 23:43:33 -0500 Subject: [PATCH 06/11] Fix minor typos --- EIPS/eip-20.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 60269cd416641..084dd7323f111 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -161,8 +161,8 @@ Many existing tokens deployed on the Ethereum network already support this EIP. #### Description of re-approval attack -1. Alice approves Bob to transfer $N$ of Alice's tokens (where $N>0$) by calling the `approve(Bob, N)` -2. Later, Alice decides to set the approval from $N$ to $M$ ( $M>0$ ), so she calls the `approve(Bob, M)` +1. Alice approves Bob to transfer $N$ of Alice's tokens (where $N>0$) by calling `approve(Bob, N)` +2. Later, Alice decides to set the approval from $N$ to $M$ ( $M>0$ ), so she calls `approve(Bob, M)` 3. Bob notices Alice's second transaction when it is submitted to the mempool 4. Before Alice's `approve(Bob, M)` transaction is included in a block, Bob sends a transaction calling `transferFrom(Alice, Bob, N)` with a higer priority fee than Alice's transaction, and a transaction calling `transferFrom(Alice, Bob, M)` with a lower priority fee than Alice's transaction 5. Bob's `transferFrom(Alice, Bob, N)` will be executed first, transfering $N$ tokens from Alice to Bob From c8828470daa6f169b1ec16a1450e3aa19cb261e6 Mon Sep 17 00:00:00 2001 From: Gavin John Date: Fri, 24 Feb 2023 10:24:24 -0500 Subject: [PATCH 07/11] Fix markdownlint error --- EIPS/eip-20.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 084dd7323f111..2f447b184c8a7 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -26,6 +26,7 @@ A standard interface allows any tokens on Ethereum to be re-used by other applic ### Methods **NOTES**: + - The following specifications use syntax from Solidity `0.4.17` (or above) - Callers MUST handle `false` from `returns (bool success)`. Callers MUST NOT assume that `false` is never returned! From 9981493699a7828e423a47f4c732b744bfeae501 Mon Sep 17 00:00:00 2001 From: Gavin John Date: Fri, 3 Mar 2023 13:49:17 -0500 Subject: [PATCH 08/11] Update EIPS/eip-20.md Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-20.md | 1 - 1 file changed, 1 deletion(-) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 2f447b184c8a7..76b6a8317c247 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -172,7 +172,6 @@ Many existing tokens deployed on the Ethereum network already support this EIP. Bob was able to transfer a total of $N+M$ tokens instead of a total of $M$. -(Written by Mikhail Vladimirov and Dmitry Khovratovich , edited by Pandapip1 (@Pandapip1)) #### Mitigation of re-appproval attack From b5b06f3f9478b3dd1eb07eac321664fc73ee7106 Mon Sep 17 00:00:00 2001 From: Gavin John Date: Fri, 3 Mar 2023 13:49:29 -0500 Subject: [PATCH 09/11] Update EIPS/eip-20.md Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-20.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 76b6a8317c247..184831ebdc3c9 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -12,8 +12,8 @@ created: 2015-11-19 ## Abstract -This EIP standardizes an interface for fungible tokens within smart contracts. -The interface has basic transfer functionality, and allows tokens to be approved so they can be spent by another on-chain third party. +The following standard allows for the implementation of a standard API for tokens within smart contracts. +This standard provides basic functionality to transfer tokens, as well as allow tokens to be approved so they can be spent by another on-chain third party. ## Motivation From 23e1006f7cdf7aee16face6054b727507d791425 Mon Sep 17 00:00:00 2001 From: Gavin John Date: Fri, 3 Mar 2023 13:50:27 -0500 Subject: [PATCH 10/11] Update EIPS/eip-20.md Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-20.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 184831ebdc3c9..49ee13ef84f95 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -108,6 +108,9 @@ function transferFrom(address _from, address _to, uint256 _value) public returns Allows `_spender` to withdraw from your account multiple times, up to the `_value` amount. If this function is called again it overwrites the current allowance with `_value`. +clients SHOULD make sure to create user interfaces in such a way that they set the allowance first to `0` before setting it to another value for the same spender. +THOUGH The contract itself shouldn't enforce it, to allow backwards compatibility with contracts deployed before + **NOTE**: Please read the [Security Considerations](#security-considerations) section for potential attack vectors. ``` js From 9bfa57f43601dd451a3330845b4237a46097f1bf Mon Sep 17 00:00:00 2001 From: Gavin John Date: Wed, 12 Apr 2023 16:31:01 -0400 Subject: [PATCH 11/11] Remove rationale section and fix walidator error --- EIPS/eip-20.md | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 49ee13ef84f95..c60a7fc96a7d5 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -21,16 +21,16 @@ A standard interface allows any tokens on Ethereum to be re-used by other applic ## Specification -## Token +### Token -### Methods +#### Methods **NOTES**: - The following specifications use syntax from Solidity `0.4.17` (or above) - Callers MUST handle `false` from `returns (bool success)`. Callers MUST NOT assume that `false` is never returned! -#### name +##### name Returns the name of the token - e.g. `"MyToken"`. @@ -41,7 +41,7 @@ but interfaces and other contracts MUST NOT expect these values to be present. function name() public view returns (string) ``` -#### symbol +##### symbol Returns the symbol of the token. E.g. "HIX". @@ -52,7 +52,7 @@ but interfaces and other contracts MUST NOT expect these values to be present. function symbol() public view returns (string) ``` -#### decimals +##### decimals Returns the number of decimals the token uses - e.g. `8`, means to divide the token amount by `100000000` to get its user representation. @@ -63,7 +63,7 @@ but interfaces and other contracts MUST NOT expect these values to be present. function decimals() public view returns (uint8) ``` -#### totalSupply +##### totalSupply Returns the total token supply. @@ -71,7 +71,7 @@ Returns the total token supply. function totalSupply() public view returns (uint256) ``` -#### balanceOf +##### balanceOf Returns the account balance of another account with address `_owner`. @@ -79,7 +79,7 @@ Returns the account balance of another account with address `_owner`. function balanceOf(address _owner) public view returns (uint256 balance) ``` -#### transfer +##### transfer Transfers `_value` amount of tokens to address `_to`, and MUST fire the `Transfer` event. The function SHOULD `throw` if the message caller's account balance does not have enough tokens to spend. @@ -90,7 +90,7 @@ The function SHOULD `throw` if the message caller's account balance does not hav function transfer(address _to, uint256 _value) public returns (bool success) ``` -#### transferFrom +##### transferFrom Transfers `_value` amount of tokens from address `_from` to address `_to`, and MUST fire the `Transfer` event. @@ -104,7 +104,7 @@ The function SHOULD `throw` unless the `_from` account has deliberately authoriz function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) ``` -#### approve +##### approve Allows `_spender` to withdraw from your account multiple times, up to the `_value` amount. If this function is called again it overwrites the current allowance with `_value`. @@ -117,7 +117,7 @@ THOUGH The contract itself shouldn't enforce it, to allow backwards compatibilit function approve(address _spender, uint256 _value) public returns (bool success) ``` -#### allowance +##### allowance Returns the amount which `_spender` is still allowed to withdraw from `_owner`. @@ -125,9 +125,9 @@ Returns the amount which `_spender` is still allowed to withdraw from `_owner`. function allowance(address _owner, address _spender) public view returns (uint256 remaining) ``` -### Events +#### Events -#### Transfer +##### Transfer MUST trigger when tokens are transferred, including zero value transfers. @@ -137,7 +137,7 @@ A token contract which creates new tokens SHOULD trigger a Transfer event with t event Transfer(address indexed _from, address indexed _to, uint256 _value) ``` -#### Approval +##### Approval MUST trigger on any successful call to `approve(address _spender, uint256 _value)`. @@ -145,16 +145,6 @@ MUST trigger on any successful call to `approve(address _spender, uint256 _value event Approval(address indexed _owner, address indexed _spender, uint256 _value) ``` -## Rationale - -### The approve and transferFrom flow - -`approve` and `transferFrom` can be used in conjunction with one another to allow smart contracts to take an action if and only if a transfer succeeds. This enables use cases such as decentralized exchanges, which can trustlessly swap one token for another. - -### Decimals is optional - -Some tokens might wish to use a base unit other than $10^{-18}$, and sometimes it doesn't make sense to have a fraction of a token. However, not every token might reasonably need to specify `decimals`. Thus, `decimals` is optional. - ## Backwards Compatibility Many existing tokens deployed on the Ethereum network already support this EIP.