You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I came across this when I was reading Wasm contract repository and realised there is a clone of ERC-20.
TL; DR The token standard is the most critical element of any blockchain after the consensus and VM. Please do not copy ERC-20 "as is" to any new blockchain, as ERC-20 have many known historical flaws that should be avoided, as they are 1) annoying 2) makes building good UX hard 3) can cause loss of money for the users.
Motivation
ERC-20 was initiated back in 2015, and then formalized starting in 2016. With the passing time we have found many mistakes made with ERC-20 and it would be foolish to copy those mistakes to a new token standard when one can start from a clean slate.
Below I go through ERC-20 shortcomings one by one and also have some links as reference material. Some post-Ethereum networks, like EOS, have already addressed technicalities and have a more user-friendly approach to tokens. Also, Ethereum has addressed issues in the form of later standards, like ERC-1363, and ERC-777, but due to ossification they have not been adopted (more to below).
The list of ERC-20 shortcomings starts here. Some of these can be addressed at a smart contract level. Some like native payable token functions, require VM support but would make future development easier and safer (this has shown to be possible by EOS, Elrond, NEAR and some other novel blockchains.)
Issues that ERC-20 lacks and any new token standard should address:
Smart contracts cannot reject token transfers
Because of the lack of standardized token receive hook, smart contracts cannot reject token transfers on them. If someone accidentally sends ERC-20 to a smart contract address they are likely lost. This error is common and happens especially when copy-pasting addresses around tokens are sent to the token contract itself.
There is a Twitter account tweeting these mistakes:
Root cause: ERC-20 has different transfer() and transferFrom() semantics when dealing with normal accounts and smart contract accounts.
Account cannot express if it can receive tokens
Similar to one above, a common mistake is to send tokens to a centralised exchange address that cannot handle them. For example, Bittrex charged $5000 for "token recovery" in one point to give back the tokens that the user deposited to the exchange if the exchange did not have an active order book for them.
Root cause: Accounts cannot express what tokens they support
Hot wallets cannot interact with smart contracts
Centralised exchanges and other custodial use hot wallets where each receiving address belongs to an user, but withdraw address comes from a pooled wallet. Because most smart contract operations use msg.sender as the author, any reverse payments for msg.sender would go to the hot wallet pooled address directly. Because the transfer is not tripped through the receiving address of the user, the hot wallet accounting cannot mark this reverse payment deposit belonging to the user.
As a hack workaround, centralised exchanges like Kraken and Coinbase set the gas limit for the token transfers very low, hoping that the gas limit prevents any smart contract interaction from hot wallet direct withdrawals.
Root cause: transfer() does not provide alternative address as the return address
Different transfer semantics for account and smart contract interaction
Users expect transfer() to work with a smart contract, as it works with normal accounts. However, this is not the case. Any direct transfer() and not approve() + transferFrom() pair to a smart contract address usually leads to loss of the tokens, because smart contract cannot account tokens to msg.sender correctly.
The ERC-20 approve() mechanism has been found to be unsafe for normal users. This is because of the confusing UX, because of semantics that do not match the underlying transaction, because of laziness of users and developers.
Any token developers and users should be discouraged the use of approve().
Related to above, ERC-20 has unsafe defaults, due to approve() + transferFrom() pattern being inherently complex. This has led to the creation of wrappers like SafeERC20.safeTransferFrom(). However turns out these wrappers themselves are buggy. Doing duct tape solutions on the top of duct tape solutions have proven to be a bad evolutionary path for security.
Any token should have only one way to transfer it and it should be safe under all conditions.
Native asset is treated differently from tokens
In Ethereum Defi world, the native asset ETH must be wrapped to WETH ERC-20 token to interact with many of the smart contracts. This causes extra work for developers, as they need to write double code with ifs to all deposits and withdrawals. This will also confuse users, as they see both the native asset and the wrapped asset in their wallet and wallets do not account them as one item.
As a side note, Solana copied this design mistake. However, for example in the case of EOS, all assets are treated similarly and any token asset can added to any payable transaction.
To transact with ERC-20 tokens, the user needs to have both the token and Ethers on the same account. This is very confusing for the users who are there only for the token, for example in gaming scenarios, and could not less care about cryptocurrency.
ERC-20 lacks native mechanisms for fee markets and relayers who would be willing to pay the gas fee on the behalf of the user and take a fee cut in the token amount. The history has proven that adding this functionality afterwards is especially complicate. Multiple smart contract wallets (Argent, Pillar, etc.) have come up with incompatible, proprietary, solutions.
Root cause: Lack of gas fee market design when ERC-20 was launched
ERC-20 only provides information for name, symbol and token supply. Even the amount of decimals is an add-on. This has created a cottage industry of different "token lists" that supplement this information. A common element to add would be at least homepage, icon and relayer information (for gas market transactions). Metadata often also contains various discussion forums, support email, officially author information (foundation, corporation) and such. Wallets could consume this information directly.
For example, the following applications maintain their incompatible lists just to get a token icon visible in the wallet: MyEtherWallet, TrustWallet, MetaMask, Parity. Then the services maintain their own lists: Uniswap, Loopring, IDEX.
Root cause: Blockchain persistent storage was deemed too expensive for this, community inability to come together for a common standard
Suggestion: Have also "icon", "homepage" and such as the part of the token standard and do not leave this for "third party curated registry."
Lack of notifications
Because how ERC-20 transfer events are implemented, wallets usually need to run extra infrastructure and servers to detect incoming token transfers. Developers lack generic "notify me for all incoming transfers for this address" event. (Furthermore it is even worse for ETH itself as it does not have any notifications and the only way to see balance changes is polling or heavily instrumented custom node.)
This makes it expensive to build wallets as you need to invest to the server-side infrastructure a lot, which is against the point of decentralisation.
Standard UX rules how the user finds out incoming transfer
ERC-20 wallets like MetaMask does not display incoming transfers by default if the ERC-20 token is not whitelisted in the MetaMask source code. This is to avoid airdrop spam attacks where desperate marketers send a small amount of tokens to everyone in the hope the user does a web search for this token and proceeds to buy or sell.
However, it also makes it impossible to send any tokens to new users. Because MetaMask wallet silently ignores all incoming transfers that are not whitelisted either by the MetaMask team or the user itself ("Add custom token") the first question of novice users if their tokens were lost.
Root cause: Community inability to come together for a common standard
Re-entrancy implementation guidelines
Because of re-entrancy issues on badly written smart contracts, people are afraid of moving away from ERC-20 even though these issues would have been already addressed. This has caused the ossification of Ethereum token development, as ERC-20 is barely good enough, but users and developers will be suffering for the years to come.
Whereas this issue was addressed in late code examples and is now even highlighted in Solidity developer manual, the community has still not yet moved over this.
Root cause: Community ossification, psychological change resistance
Any new smart contract VM can avoid this by creating primitives that prevent re-entrant functions by default, then later can be enabled by whitelist or one-by-one if needed.
Functions like increaseAllowance() and decreaseAllowance() are legacy overreaching security research work and do not have any real life usage. They should be dropped.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Summary
I came across this when I was reading Wasm contract repository and realised there is a clone of ERC-20.
TL; DR The token standard is the most critical element of any blockchain after the consensus and VM. Please do not copy ERC-20 "as is" to any new blockchain, as ERC-20 have many known historical flaws that should be avoided, as they are 1) annoying 2) makes building good UX hard 3) can cause loss of money for the users.
Motivation
ERC-20 was initiated back in 2015, and then formalized starting in 2016. With the passing time we have found many mistakes made with ERC-20 and it would be foolish to copy those mistakes to a new token standard when one can start from a clean slate.
Below I go through ERC-20 shortcomings one by one and also have some links as reference material. Some post-Ethereum networks, like EOS, have already addressed technicalities and have a more user-friendly approach to tokens. Also, Ethereum has addressed issues in the form of later standards, like ERC-1363, and ERC-777, but due to ossification they have not been adopted (more to below).
The list of ERC-20 shortcomings starts here. Some of these can be addressed at a smart contract level. Some like native payable token functions, require VM support but would make future development easier and safer (this has shown to be possible by EOS, Elrond, NEAR and some other novel blockchains.)
Currently one of my favourite token standards is Elrond ESDT that strikes a good balance between usability and extensibility.
Issues that ERC-20 lacks and any new token standard should address:
Smart contracts cannot reject token transfers
Because of the lack of standardized token receive hook, smart contracts cannot reject token transfers on them. If someone accidentally sends ERC-20 to a smart contract address they are likely lost. This error is common and happens especially when copy-pasting addresses around tokens are sent to the token contract itself.
There is a Twitter account tweeting these mistakes:
https://twitter.com/TokenOops
Root cause: ERC-20 has different transfer() and transferFrom() semantics when dealing with normal accounts and smart contract accounts.
Account cannot express if it can receive tokens
Similar to one above, a common mistake is to send tokens to a centralised exchange address that cannot handle them. For example, Bittrex charged $5000 for "token recovery" in one point to give back the tokens that the user deposited to the exchange if the exchange did not have an active order book for them.
For example, there is worth of $772M tokens in 0x0 address. Some of them are token burns, but most of them are accidental sends and wallet input field failures: https://etherscan.io/address/0x0000000000000000000000000000000000000000
Root cause: Accounts cannot express what tokens they support
Hot wallets cannot interact with smart contracts
Centralised exchanges and other custodial use hot wallets where each receiving address belongs to an user, but withdraw address comes from a pooled wallet. Because most smart contract operations use msg.sender as the author, any reverse payments for msg.sender would go to the hot wallet pooled address directly. Because the transfer is not tripped through the receiving address of the user, the hot wallet accounting cannot mark this reverse payment deposit belonging to the user.
As a hack workaround, centralised exchanges like Kraken and Coinbase set the gas limit for the token transfers very low, hoping that the gas limit prevents any smart contract interaction from hot wallet direct withdrawals.
Root cause: transfer() does not provide alternative address as the return address
Different transfer semantics for account and smart contract interaction
Users expect
transfer()
to work with a smart contract, as it works with normal accounts. However, this is not the case. Any directtransfer()
and notapprove()
+transferFrom()
pair to a smart contract address usually leads to loss of the tokens, because smart contract cannot account tokens to msg.sender correctly.https://mobile.twitter.com/moo9000/status/1300167829929459713
Approve() inheritently unsafe
The ERC-20 approve() mechanism has been found to be unsafe for normal users. This is because of the confusing UX, because of semantics that do not match the underlying transaction, because of laziness of users and developers.
Any token developers and users should be discouraged the use of approve().
Safe defaults
Related to above, ERC-20 has unsafe defaults, due to
approve()
+transferFrom()
pattern being inherently complex. This has led to the creation of wrappers likeSafeERC20.safeTransferFrom()
. However turns out these wrappers themselves are buggy. Doing duct tape solutions on the top of duct tape solutions have proven to be a bad evolutionary path for security.Any token should have only one way to transfer it and it should be safe under all conditions.
Native asset is treated differently from tokens
In Ethereum Defi world, the native asset ETH must be wrapped to WETH ERC-20 token to interact with many of the smart contracts. This causes extra work for developers, as they need to write double code with ifs to all deposits and withdrawals. This will also confuse users, as they see both the native asset and the wrapped asset in their wallet and wallets do not account them as one item.
As a side note, Solana copied this design mistake. However, for example in the case of EOS, all assets are treated similarly and any token asset can added to any payable transaction.
https://mobile.twitter.com/ProjectSerum/status/1300633211932868610
Lack of native relayers and gas fee markets
To transact with ERC-20 tokens, the user needs to have both the token and Ethers on the same account. This is very confusing for the users who are there only for the token, for example in gaming scenarios, and could not less care about cryptocurrency.
ERC-20 lacks native mechanisms for fee markets and relayers who would be willing to pay the gas fee on the behalf of the user and take a fee cut in the token amount. The history has proven that adding this functionality afterwards is especially complicate. Multiple smart contract wallets (Argent, Pillar, etc.) have come up with incompatible, proprietary, solutions.
Root cause: Lack of gas fee market design when ERC-20 was launched
Cosmos allows any token to be used as a gas token to some limit.
Lack of metadata
ERC-20 only provides information for name, symbol and token supply. Even the amount of decimals is an add-on. This has created a cottage industry of different "token lists" that supplement this information. A common element to add would be at least homepage, icon and relayer information (for gas market transactions). Metadata often also contains various discussion forums, support email, officially author information (foundation, corporation) and such. Wallets could consume this information directly.
For example, the following applications maintain their incompatible lists just to get a token icon visible in the wallet: MyEtherWallet, TrustWallet, MetaMask, Parity. Then the services maintain their own lists: Uniswap, Loopring, IDEX.
Root cause: Blockchain persistent storage was deemed too expensive for this, community inability to come together for a common standard
Suggestion: Have also "icon", "homepage" and such as the part of the token standard and do not leave this for "third party curated registry."
Lack of notifications
Because how ERC-20 transfer events are implemented, wallets usually need to run extra infrastructure and servers to detect incoming token transfers. Developers lack generic "notify me for all incoming transfers for this address" event. (Furthermore it is even worse for ETH itself as it does not have any notifications and the only way to see balance changes is polling or heavily instrumented custom node.)
This makes it expensive to build wallets as you need to invest to the server-side infrastructure a lot, which is against the point of decentralisation.
Standard UX rules how the user finds out incoming transfer
ERC-20 wallets like MetaMask does not display incoming transfers by default if the ERC-20 token is not whitelisted in the MetaMask source code. This is to avoid airdrop spam attacks where desperate marketers send a small amount of tokens to everyone in the hope the user does a web search for this token and proceeds to buy or sell.
However, it also makes it impossible to send any tokens to new users. Because MetaMask wallet silently ignores all incoming transfers that are not whitelisted either by the MetaMask team or the user itself ("Add custom token") the first question of novice users if their tokens were lost.
Root cause: Community inability to come together for a common standard
Re-entrancy implementation guidelines
Because of re-entrancy issues on badly written smart contracts, people are afraid of moving away from ERC-20 even though these issues would have been already addressed. This has caused the ossification of Ethereum token development, as ERC-20 is barely good enough, but users and developers will be suffering for the years to come.
Whereas this issue was addressed in late code examples and is now even highlighted in Solidity developer manual, the community has still not yet moved over this.
Root cause: Community ossification, psychological change resistance
Any new smart contract VM can avoid this by creating primitives that prevent re-entrant functions by default, then later can be enabled by whitelist or one-by-one if needed.
Bad storage layout in blockchain
There is no way for a light client to know which ERc-20 tokens the user has in its wallet currently. This makes writing light wallets or mobile wallets impossible - any wallet must be paired with a custom full chain data indexer.
This is fixed e.g. in the Cosmos SDK bank module where it is easy to query all token balances of an account.
Legacy useless functions
Functions like
increaseAllowance()
anddecreaseAllowance()
are legacy overreaching security research work and do not have any real life usage. They should be dropped.There should be only one token standard
See Cosmos discussion.
Beta Was this translation helpful? Give feedback.
All reactions