Title: Disclosure_of_a_security_flaw_in_ERC_20_transferri
Category: ERCs

Author: Dexaran
Date: 2023-10-24T21:05:15.235Z

ERC-20 Losses Calculator
This script calculates the amount of tokens that were lost because of the described problem:
ERC-20 Losses Calculator
As of 11/2/2023 there are $228,722,284 lost.
Abstract
The following describes a security flaw in the transferring workflow of ERC-20 token standard. It must be taken into account that all token standards that declare full backwards compatibility with ERC-20 also inherit this security flaw, for example ERC-1363.
Motivation
Security flaw disclosures are an important part of software development. Increasing awareness of the problem helps the development community to implement solutions and minimize the damage that a particular flaw can deal to the users.
Specification
ERC-20 design overview
ERC-20 standard declares two methods of transferring tokens: (1) transfer function and (2) approve & transferFrom pattern. approve & transferFrom is supposed to be used to deposit tokens to contracts. The transfer function is supposed to be used for transfers between externally owned addresses however this is not directly written in the specification. If the tokens are sent to a contract address via the transfer function then the recipient contract will not recognize the depoist.
Security flaw
The transfer function does not notify the recipient of an incoming transaction which makes error handling impossible. Error handling is an essential part of secure software development. If tokens are sent to any contract via the transfer function and the recipient contract does not support extraction of tokens (i.e. it doesn’t implement any functions which would allow to send tokens out) then it is a clear case of user error that must be reverted. For example if a user would send plain ether to a contract that does not explicitly declare that it is intended to accept ether deposits then such transaction would be reverted automatically. In case of ERC-20 tokens a user can push the token contract into incorrect state where a user no longer controls the tokens by picking a wrong function when performing a transaction.
A burden of determining the method of transferring tokens is placed on the user in a situation where one option is obviously wrong and will result in a loss of funds. Prompting a user to make a decision on the internal logic of the contract combined with the lack of an implementation of error handling for users actions is another security failure that can result in incorrect token contract behavior and a loss of funds for the end user.
Token losses
As of 11/2/2023 there are $228,722,284 worth of lost ERC-20 tokens.
Copyright
Copyright and related rights waived via CC0.

Author: sullof
Date: 2023-10-24T22:02:08.501Z

I’m uncertain about the practicality of formalizing this as a standard, considering the use of such a function appears largely pertinent to the contract’s owner. In other words, the necessity to publicly expose this interface is debatable.
However, entertaining the idea of interface exposure for a moment, I believe the EIP could be enhanced by steering away from prescribing a specific function, such as the one you’ve provided:
function rescueERC20(address _token) onlyOwner external {
  amount = IERC20(_token).balanceOf(address(this));
  IERC20(_token).transfer(msg.sender, amount);
}

Instead, I advocate for the adoption of a more generic interface:
interface IRescueERC20 {
  function rescueERC20(address _token) external;
}

This approach would grant implementers the flexibility to define the rescue mechanics that best suit their needs, whether it be through Ownable, AccessControl, or an alternative method. This not only promotes adaptability but also encourages a broader range of use cases and implementations, ensuring the EIP’s relevance and utility across diverse applications.

Author: Dexaran
Date: 2023-10-25T22:33:12.354Z

I’m uncertain about the practicality of formalizing this as a standard, considering the use of such a function appears largely pertinent to the contract’s owner. In other words, the necessity to publicly expose this interface is debatable.

I would like to note that the main goal of this EIP is not to standardize the token extraction method but to highlight a security flaw of ERC-20 and the need to switch to a safer standard.

Instead, I advocate for the adoption of a more generic interface:
…
This approach would grant implementers the flexibility to define the rescue mechanics that best suit their needs, whether it be through Ownable, AccessControl, or an alternative method.

I agree with this point, the more general definition looks reasonable.

Author: sullof
Date: 2023-10-31T02:22:21.450Z

Dexaran:

I would like to note that the main goal of this EIP is not to standardize the token extraction method but to highlight a security flaw of ERC-20 and the need to switch to a safer standard.


That problem has been raised a long ago with many proposals to solve the issue. The most prominent and the only used (even if not too much) is EIP-777.

Author: Dexaran
Date: 2023-11-02T20:29:37.969Z

sullof:

That problem has been raised a long ago with many proposals to solve the issue. The most prominent and the only used (even if not too much) is EIP-777


Well, this is exactly the reason why I stopped working on ERC-223 promotion in 2017. I thought that there are a lot of smart guys who can solve such an obvious problem without me. In 2017 there were about $1M lost due to ERC-20 flaw.
Now its 2023 and there are about $100M of lost funds in ERC-20 tokens. This is how a disaster looks like. And the “smart guys” haven’t solved it still. That’s why I’m resurrecting ERC-223 standard as it’s the main standard that is designed to solve this problem and replace ERC-20.
Here is a script that calculates the “lost” tokens ERC-20 Losses Calculator

Author: sullof
Date: 2023-11-04T23:43:24.719Z

Dexaran:

Well, this is exactly the reason why I stopped working on ERC-223 promotion in 2017


I totally remember that long discussion. IMO, 223 was a good proposal. Maybe not perfect, but if implemented then, many problems could have been avoided.

Author: SamWilsn
Date: 2023-11-10T02:48:34.695Z

Couple non-editorial comments:

The transfer function is supposed to be used for transfers between externally owned addresses however this is not directly written in the specification

Do you have a source? I’ve always just assumed the two patterns were for push and pull payments, and didn’t have anything to do with who was making the call. I’d love to read more about that!

Author: Dexaran
Date: 2023-11-10T03:26:16.527Z

If you have PUSH transacting methods - you don’t need PULL methods for anything. This is how ether works for example.
ERC-20 standard was proposed in 2015. At this time there was a bug in Ethereum Virtual Machine 1024 call stack depth. The approve & transferFrom method of the ERC-20 standard was introduced so that this bug does not affect tokens. It was not a smart design, it was a weird quirk to address an old bug that doesn’t exist anymore.
In Tangerine Whistle hardfork the call stack depth problem was solved. This happened on block 2463000 in 2016. At this time approve & transferFrom method became obsolete and the ERC-20 standard should have been considered deprecated.

Here is an old comment from Vitalik regarding the call stack depth:
1_ovvWQr2lxjS2tVxzXYl2Yg1878×745 90.8 KB
So, gathering the facts:

At the moment of ERC-20 creation there were two transacting methods: transfer & approve+transferFrom
It was not possible to implement PUSH TX model in a smart-contract at all due to 1024-call-stack depth
The authors most certainly knew about PUSH TXs because ether does implement it
Without notifying a recipient of an incoming transaction it is not possible to make a contract recognize the deposit - so the transfer function couldn’t notify recipients in any way at that moment

If the transfer function couldn’t be used for contract deposits and there was an approve & transferFrom method exactly for contract deposits just because there was no easier way to address 1024-call-stack-depth - what could be the purpose of the transfer other than making EOA to EOA transfers?
I can’t find any source that would directly say transfer is for EOA to EOA, approve is for deposits to contracts. But this is the only way of how it could be used.
Also the first contract on Ethereum that was supposed to interact with tokens was the Alex van de Sande’s “Unicorn Meat Grinder”. It was on the page maintained by Ethereum Foundation and I think it doesn’t exist anymore but I found a recap of the article. The Unicorn Meat Grinder transparently says “you must not deposit funds to contract directly - instead you approve them”.


gist.github.com


https://gist.github.com/alexvandesande/eca0b87da89ab28fa50c
Announcing the Great Unicorn Meat Grinder.md

You all know the [Unicorn Token](http://ethereum.org/donate) a small gratitude token sent by the Foundation to all good samaritans. Althought it has been successful, unicorns have some issues: it's expensive (2014 finney), non divisible (you can't split a unicorn) and it can only be acquired by the pure of heart. Today, all of that will change:

### The Unicorn Meat Grinder

Now all the evil etherians will finally be able hack your own unicorns into tiny little pieces. The Unicorn Meat Grinder is a contract that will take your unicorns, send them to unicorn heaven and will send you back a bunch of meat token. Each Unicorn is worth about a 1000 pieces of meat, but depending on your luck you might get more. Each token is divisible to 3 decimal places, so each single unicorn will be exchanged for more than a million smaller units.

### What is this? You can't kill unicorns!!

No? Watch me. 
   This file has been truncated. show original