ERC-20 Token Standard
Final · Tokens · created 2015-11-19
A standard that gives tokens built as smart contracts a common set of functions and events. Wallets and exchanges can handle balance queries, transfers, and delegated withdrawals without writing different code for each token.
Why it is needed
On Ethereum, anyone can create a token with a smart contract (a program that runs automatically on the blockchain). But if every token names its balance-reading function differently, transfers differently, and announces transfers differently, then apps such as wallets and decentralized exchanges must analyze each contract separately and add dedicated code every time they support a new token. Without common rules, moving tokens on a user's behalf through another contract would also have to be implemented differently for each token. This standard fixes the names, arguments, and behavior of the functions and events a token must provide, so that any token on Ethereum, from wallets to decentralized exchanges, can be reused as is by other apps.
What to implement
function name() public view returns (string): Returns the token name. This function is optional.function symbol() public view returns (string): Returns the token symbol. This function is optional.function decimals() public view returns (uint8): Returns the number of decimals the token uses. This function is optional.function totalSupply() public view returns (uint256): Returns the total supply of the token.function balanceOf(address _owner) public view returns (uint256 balance): Returns the token balance of the _owner address.function transfer(address _to, uint256 _value) public returns (bool success): Sends _value of the caller's tokens to _to and emits a Transfer event.function transferFrom(address _from, address _to, uint256 _value) public returns (bool success): Moves _from's tokens to _to within the amount _from has allowed, and emits a Transfer event.function approve(address _spender, uint256 _value) public returns (bool success): Allows _spender to withdraw up to _value from the caller's account. Calling it again overwrites the limit.function allowance(address _owner, address _spender) public view returns (uint256 remaining): Returns the remaining amount that _spender can still withdraw from the _owner account.event Transfer(address indexed _from, address indexed _to, uint256 _value): Emitted when tokens are moved. This includes transfers of zero value.event Approval(address indexed _owner, address indexed _spender, uint256 _value): Emitted every time an approve call succeeds.
In depth
Optional functions name, symbol, decimals
name() returns the token name (for example, MyToken), symbol() returns the symbol (for example, HIX), and decimals() returns the number of decimal places. If decimals is 8, the amount stored by the contract divided by 100000000 is the amount to show to the user. All three functions are OPTIONAL. They are used only to improve usability, and other interfaces and contracts MUST NOT expect these values to be present. Wallets and apps must therefore be built to handle tokens that lack these functions.
totalSupply and balanceOf
totalSupply() returns the total supply of the token as a uint256. balanceOf(address _owner) returns the balance held by the _owner address as a uint256. Both are view functions, so they only read state and do not change it. Wallets use these two functions to show a user's holdings, and apps use them to check the balance before a transfer. The function declarations in the specification are written in Solidity 0.4.17 or later syntax.
transfer: Sending my tokens
transfer(address _to, uint256 _value) moves _value of tokens from the caller's account to the _to address and MUST emit a Transfer event. If the caller's balance is insufficient, it SHOULD throw. A transfer of zero value MUST be treated the same as a normal transfer and emit a Transfer event. The function returns a bool success. Callers MUST handle the possibility that false is returned, and MUST NOT assume that false will never be returned.
transferFrom: Moving tokens on someone's behalf
transferFrom(address _from, address _to, uint256 _value) moves _value from the _from address to the _to address and MUST emit a Transfer event. The original text describes this as a withdraw workflow. A contract can use it to move tokens on a user's behalf or to collect fees in tokens. It SHOULD throw unless the _from account has deliberately authorized the caller in some way. A transfer of zero value MUST be treated as a normal transfer and emit a Transfer event.
approve and allowance: Withdrawal limits
approve(address _spender, uint256 _value) allows _spender to withdraw from the caller's account multiple times, up to _value. Calling it again overwrites the existing limit with the new _value. allowance(address _owner, address _spender) returns the remaining amount that _spender can still withdraw from the _owner account. To prevent attacks that arise from the overwrite behavior, the original text recommends that clients build their UI to first set the limit to 0 and then set the new value when changing the limit for the same _spender (SHOULD). However, for compatibility with already deployed contracts, it states that the contract itself must not enforce this order.
Transfer and Approval events
Transfer(address indexed _from, address indexed _to, uint256 _value) MUST be emitted whenever tokens are moved, including transfers of zero value. A contract that creates new tokens SHOULD emit a Transfer event with _from set to 0x0 at creation. Approval(address indexed _owner, address indexed _spender, uint256 _value) MUST be emitted every time an approve call succeeds. _from, _to, _owner, and _spender are declared indexed, so events for a specific address can be selected and queried. Wallets and apps read these events to track token movements.
Implementation and status
The original text notes that many ERC20-compatible tokens are already deployed on the Ethereum network, and that several teams have built implementations with different tradeoffs, from gas savings to stronger security. It links the OpenZeppelin implementation and the ConsenSys implementation as example implementations. This standard was created on November 19, 2015, and its status is Final, so its content will not change further. The history section includes Vitalik Buterin's original proposal, the Reddit discussion, and a link to the original Issue #20.