-
Notifications
You must be signed in to change notification settings - Fork 11.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ERC20 standard known issues. #4451
Comments
1 - the isContract method is deprecated 2 - uniswap expects you to transfer to it's contract throught transfer, not transferFrom so this would make any token that uses this non compatible with some defi projects maybe this could be in an ERC20 extension? what do you think? |
This is an issue with ERC20, but changing that behavior breaks more things than it fixes, because the resulting token won't be ERC20 compliant. Many alternatives have been proposed, mostly ERC223 and ERC777, they both have more issues than real benefit. Our code is following the standard, which ensures interoperability with DeFi. If another standard ever reach consensus in the community, we will implement it ... but so far all effort in that dirrection has failled. |
This part has been discussed and documented many times. Developpers that want to add that feature to their token can do it by overloading the |
Well, if you leave it up to token developers without highlighting a necessity of doing this with a big red banner "It is necessary for security of your users" - the problem will not be solved. New tokens still suffer from the issue that was discussed millions of times. May be it is worth to highlight it a bit more. |
This should be handled by wallet providers instead to avoid unnecessary bloat to the transfer function. Should be extremely simple for Metamask for example to add a warning "are you sure you want to transfer to a contract?". |
This is a good way to never solve a problem - delegate it to wallet devs. Back in 2017-2018 we discussed this and also concluded that it can be solved on the side of software that interacts with tokens. In theory it should work. In practice it certainly doesn't because wallet devs are even less aware of an issue than contract devs. And it is certainly not possible to guarantee that all wallet developers in the future will always solve this problem. New wallets and new developers will emerge... so if the underlying technology has some sort of problems/vulnerabilities/security flaws - it will result in lost money. |
Not a problem, people are free to choose a wallet that solves the problem. |
We can solve the problem on the standard level and it will ACTUALLY solve the problem. What I'm proposing here is to mitigate the problem with a better reference implementation and highlighting danger areas in the description and documentation of OpenZeppelin contracts. It WILL help to some degree. Saying "everything is fine, let's do nothing and hope wallet devs will solve the problem" WILL NOT solve the problem as you can see - we did it in 2017 and the amount of lost tokens grew from $4M to $30M. |
How much is 30M as a percentage of all transaction volume? Does it justify making things more expensive for everyone else? |
are we seriously discussing if 30M loss are a problem or not? if it would be stolen by hackers nobody will question if they needed to prevent it or not |
We can improve documentation, but the two technical solutions that were proposed are not viable.
|
Well remembered. Smart contract wallets are pretty much going to become the standard in the future, one more reason why 1. is terrible. |
The main problems of ERC-20 that ERC-223 solves Lost tokens: there are two different ways to transfer ERC20 tokens depending on is the receiver address a contract or a wallet address. You should call transfer to send tokens to a wallet address or call approve on token contract then transferFrom on receiver contract to send tokens to contract. Accidentally call of transfer function to a contract address will cause a loss of tokens inside receiver contract. Impossibility of handling incoming token transactions / lack of event handling in ERC20: ERC20 token transaction is a call of transfer function inside token contract. ERC20 token contract is not notifying receiver that transaction occurs. Also there is no way to handle incoming token transactions on contract and no way to reject any non-supported tokens. Optimization of ERC20 address-to-contract communication: You should call approve on token contract and then call transferFrom on another contract when you want to deposit your tokens into it. In fact address-to-contract transfer is a couple of two different transactions in ERC20. It also costs twice more gas compared to ERC223 transfers. In ERC223 address-to-contract transfer is a single transaction just like address-to-address transfer. Ether transactions and token transactions behave differently: one of the goals of developing ERC223 was to make token transactions similar to Ether transactions to avoid users mistakes when transferring tokens and make interaction with token transactions easier for contract developers. ERC-223 advantages. Provides a possibility to avoid accidentally lost tokens inside contracts that are not designed to work with sent tokens. Allows users to send their tokens anywhere with one function transfer. No difference between is the receiver a contract or not. No need to learn how token contract is working for regular user to send tokens. Allows contract developers to handle incoming token transactions. ERC223 transfer to contract consumes 2 times less gas than ERC20 approve and transferFrom at receiver contract. Allows to deposit tokens into contract with a single transaction. Prevents extra blockchain bloating. Makes token transactions similar to Ether transactions. ERC-223 tokens are backwards compatible with ERC-20 tokens. It means that ERC-223 supports every ERC-20 functional and contracts or services working with ERC-20 tokens will work with ERC-223 tokens correctly. ERC-223 tokens should be sent by calling transfer function on token contract with no difference is receiver a contract or a wallet address. If the receiver is a wallet ERC-223 token transfer will be same to ERC-20 transfer. If the receiver is a contract ERC-223 token contract will try to call tokenReceived function on receiver contract. If there is no tokenReceived function on receiver contract transaction will fail. tokenReceived function is analogue of fallback function for Ether transactions. It can be used to handle incoming transactions. There is a way to attach bytes _data to token transaction similar to _data attached to Ether transactions. It will pass through token contract and will be handled by tokenReceived function on receiver contract. There is also a way to call transfer function on ERC-223 token contract with no data argument or using ERC-20 ABI with no data on transfer function. In this case _data will be empty bytes array. The reason of designing ERC-223 token standard. Here is a description of the ERC-20 token standard problem that is solved by ERC-223: ERC-20 token standard is leading to money losses for end users. The main problem is lack of possibility to handle incoming ERC-20 transactions, that were performed via transfer function of ERC-20 token. If you send 100 ETH to a contract that is not intended to work with Ether, then it will reject a transaction and nothing bad will happen. If you will send 100 ERC-20 tokens to a contract that is not intended to work with ERC-20 tokens, then it will not reject tokens because it cant recognize an incoming transaction. As the result, your tokens will get stuck at the contracts balance. Source: https://github.com/Dexaran/ERC223-token-standard |
The ERC-223 token standard was specifically designed to address the issue you mentioned. It allows for the safe transfer of tokens to both contract wallets and externally owned accounts (EOAs) without the risk of lost tokens. In the ERC-223 standard, the transfer function is modified to include an additional parameter, data, which can be used to pass additional information to the receiving contract. This allows the contract to handle the token transfer in a more controlled manner. The transfer function in ERC-223 looks like this:
With ERC-223, when you transfer tokens to a contract wallet, the contract's code is executed. If the contract implements a token fallback function that can handle the data parameter, it will receive and process the tokens correctly. If the contract does not implement a fallback function, the transaction will revert, preventing the tokens from being lost. ERC-223 provides a more secure and flexible alternative to the traditional ERC-20 token standard, specifically when interacting with contracts. It ensures that tokens are not accidentally lost due to improper transfers to contracts that cannot handle them. |
Ok, if you would improve the documentation you would probably save some people from losing money.
And Relying on what you shouldn't rely on is a security issue that can result in millions of dollars loss - which in fact already happened. If you want to deposit funds to contract - you can just send them via
Implementation must be contract-specific. If your contract calculates how much tokens were deposited then the difference between "how much a contract thinks is deposited" and "how much a token contract thinks is on |
Did you know that in order to calculate how much ERC-20 tokens were lost in the contract we need to perform a number of calls so big that you can't fit it in a single tweet? Here is a list of tokens https://etherscan.io/tokens There are 1200 ERC-20 tokens. We want to take USDT and calculate how much USDT are stuck in USDT contract, then how much USDT are stuck in USDC contract, how much USDT are stuck in BNB contract and so on... Then we want to take USDC and calculate how much USDC are stuck in USDT contract, in USDC contract, in BNB contract and so on... Then we take BNB and calculate stuck BNB for USDT, USDC, BNB and so on... 1200! of calculations. That much:
That's the number of options a user has to lose his tokens due to poorly coded tokens. We can do something about it. |
I have a script that calculates the number of lost tokens: https://dexaran.github.io/erc20_losses/ There are $1,004,000,000 worth of tokens lost. 1 BILLION DOLLARS worth of tokens. |
ERC20 token standard known issues.
All this tokens are affected: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20
Here you can find a full description: https://dexaran820.medium.com/known-problems-of-erc20-token-standard-e98887b9532c
Long story short: there is no transaction handling implementation for
transfer
function in ERC20 standard (it is the flaw of the standard as it must enforce it - it is a critical feature).On 27 Dec, 2017 there were $4 million worth of tokens lost due to this flaw of the standard.
On 9 Mar, 2023 there were about $12 million worth of tokens lost.
As of today there are about $30 millions worth of tokens lost.
Since the tokens are not recoverable the amount can only increase and in fact it WILL increase over time.
💻 Environment
Remix or whatever environment you may use to compile contracts.
📝 Details
Users of ERC-20 tokens can lose their tokens.
I suggest:
transfer(...)
function must not be used to send tokens to ANY contracts (because contracts rely on approve+transferFrom as a depositing pattern).Add a corresponding paragraph to the documentation or code comments to warn the users and token developers about any potential issues. A warning that transferring tokens to contracts via
transfer(...)
func will result in a deposit that will not be recognized by the recipient i.e. the recipient CAN NOT KNOW that the deposit occured and it will not be credited as well as it can not be rejected by the recipient.Suggest implementing the
ERC20Rescure(...)
function in every contract which is supposed to work with tokens in order to extract any unintentionally deposited ERC20 tokens that were not recorded.It is relevant and it often happens. Rescue missions are necessary for ERC20 tokens. For example AAVE handled it already https://twitter.com/AaveAave/status/1633126370166575104
🔢 Code to reproduce bug
It is a flaw of the standard, not any particular implementation so I suggest to add some features that may help to mitigate the consequences to some degree or at least lower the risks for end users.
The text was updated successfully, but these errors were encountered: