It's an ERC20 token, so it's secure, right?

I came across a great article about web3 the other day that inspired me to do an experiment. Moxie wrote about an NFT he created that changes itself depending on what wallet you use to look at it. His work made me think about other popular cryptocurrency standards that may not work the way we think.

The most popular token standard is probably ERC20, which is implemented by most of the cryptocurrencies running on the Ethereum blockchain. BEP20 is its Binance Smart Chain counterpart, which implements ERC20 and extends it to make cross-chain transfers possible. It means that if your coin complies with BEP20, it automatically complies with ERC20 as well.

Many people think that compliance with these standards automatically means that the token in question can be traded, bought, sold, and it will behave like any other ERC20 token. They (hopefully) know that the chosen token can still be a rug pull but also think that at least what they buy is theirs. Some examples are here and here.

ERC20 and BEP20

The ERC20 (and BEP20) token standard is actually an interface that your smart contract must implement in order to comply with it. When you go to a blockchain explorer like Etherscan and look up a token’s address, it will show you the token’s name, symbol, total supply, number of holder addresses, etc. It is able to do so because each of these tokens implements the ERC20 token standard, and the explorer can query the information with the corresponding function calls. The same goes with Metamask when you import a token, and it auto-fills the Token Symbol and Token Decimal field.

However, these standards say nothing about the implementation of the functions. They write down what the functions should do, but that’s it. The owner could quickly implement that the symbol of a token is swapped with its name. To show this in practice, I created a token that changes its name and symbol depending on when you look at it. It is truly a unique token. Right?

A token with many names

Based on the latest block number, my token shows a different name when you look at it. It chooses a name from a list of ten. When you try to import it in Metamask, it auto-fills the symbol field with a different string almost every time. Metamask probably uses some caching because sometimes the whole floating window must be reopened before importing the token again to see it change itself.

Interestingly, however, the token symbol won’t change itself anymore after you import it. It is also the case when you open the token address in a blockchain explorer. You will always see Transformer with the symbol TFORMR. Trying a different explorer will also show a static name and symbol, but a different one. In my case, it shows MANY. Probably on the first search, it queries the contract, then saves the result.

Of course, my token is not a traditional one, and in the case of a regular token, you can assume that its name and symbol are static, and you can cache the result. However, this is not the expected functionality, if you ask me. I would think that each request is sent directly to the blockchain, and I can be sure that I see the chain’s current state, even if it costs more in computational power.

This is just the start

My token does not do anything malicious. It just changes its name and symbol depending on time. However, there are more dangerous functions in the standards that can cause more trouble if implemented that way. My example shows that the standard does not restrict the implementation. You are free to do anything in your functions. As long as the function names are correct, supporting sites will handle it as a valid token.

For example, the transfer(address _to, uint256 _value) function is used to send tokens from one address to another. I could quickly implement it so that every time Alice sends Bob some TFORMR, she also sends some to me. Let’s say 0.01% of the amount of each transaction goes to the deployer address that I control. Or 10%. Or 100%.

I think you get the idea.

There is an option to upload the source code of a contract to Etherscan and Bscscan, but it is not an obligation. There are many contracts without their source code provided. You may try to reverse engineer what they do under the hood, but you would have a hard time detecting anything malicious without the source.

Also, I could have created a token with the names of the most popular coins instead of arbitrary ones. This way, a single contract could contain the scam versions of multiple coins.

Lessons learned

What does this example show us? What should you take home from all of this?

First of all, compliance to a well-known token standard guarantees you nothing, except that the token in question will have some functions with specific names like name(), symbol(), totalSupply(), etc. Their implementation is up to the developer of the contract.

It goes without saying that interacting with a contract whose source code is not uploaded and readable by anyone is generally a bad idea. The problem I try to show here can easily be fixed when the source code is uploaded with the contract. But even in this case, I suggest many people would blindly buy a token or call a contract’s function just because there is hype around it.

Fortunately, large exchanges won’t list a token without available source code. Also, they will check the implementation and tricks like mine won’t pass their audits. At least, Coinbase claims they do that before listing a token. Also, decentralized exchanges like PancakeSwap will show you a warning saying anyone can create a BEP20 (or ERC20) token when you import an unknown contract address. At least in exchanges, you are mostly protected or warned in some way.

Although we use blockchains because we would like to be sure about their state without believing someone, the tools we use to look at it are sometimes the same third parties we wanted to eliminate in the first place. The fact that my token’s symbol and name does not change on every refresh means that explorers and wallets do not query the chain at each request. Maybe they do in the case of other functions. The point is, we cannot be sure. Perhaps, this is not so much of a problem. But it is not what I expected.


Maybe, there is nothing to do with this. After all, these standards are popular, and some companies do audits on smart contracts that many people use. Also, there is the option to provide and verify the source code, so you are free to check the implementation yourself before interacting with it. Large exchanges warn you before you try to do something dangerous, and you are free to ignore any token that is not open source.

The bottom line is you shouldn’t fall for a new project claiming to comply 100% with ERC20, without verifying what it does under the hood.

The contract address is 0x1Ce921A23eDEb4f4Cd4bA829E74292CE558Ca138. The source code is available on GitHub.

comments powered by Disqus