Hacking Etherscan: ERC20 Cheating

Alain | Web3hackingLabs
4 min readJul 22, 2022


I have an interesting question for you.
Do the information you see in Etherscan is 100% valid ? can you trust at 100% Etherscan for displaying tokenomics/balances?

The answer is unfortunately, NO.

And YOU can modify some of the values for your own advantage.

Hacking Etherscan?

We will talk about tokens, and how balances can be easily faked.

To see how let’s try to deploy this smart contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";contract MyToken is ERC20 { constructor() ERC20("MyToken", "MTK"{ _mint(msg.sender,100*10**18); }

The sender will deploy a token called “TKN” in the blockchain and get the total supply (100 TKN). If we watch on Etherscan:

Token page of the deployed smart contract

There is nothing suspicious. Until now, all are OK.

So let’s modify slightly the code.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";contract MyToken is ERC20 { constructor() ERC20("MyToken", "MTK"{ _mint(msg.sender,100*10**18);
_balances[msg.sender] += 100*10**18;
// don't forget to replace "private" by "internal" in the //defintion of _balances

I’ve added a new line of code, which adds to the sender the same number of tokens but without using _mint().

If we look at Etherscan, the result is NOT the same as expected:

There is still 100MTK in the totalSupply and 100MTK for the msg.sender instead of 200MTK because we added 2 times 100MTK for this address…

Now if I add MTK’s token on metamask, I obtain the expected value (200 instead of 100):

So it’s possible to hide our tokens from the totalsupply and from etherscan by not calling _mint() but instead by changing directly the values in balance storage variable.

But what’s the difference with the _mint() function?

If we inspect the mint function:

We see that there are only two difference between calling the _mint() function and modifying the _balances variable:

  1. totalSupply variable is increased
  2. event Transfer is emitted

When I increase _balances by hand, these 2 instruction are NOT executed, therefore:

  1. totalSupply is not increased, so it’s normal that in Etherscan totalSupply is still 100 TKN.
  2. event Transfer is NOT emitted, so as Etherscan is relying on events to count the balances of each holder, the balance of msg.sender can be FALSE.

If you want to see the true balance of an address in Etherscan, you can click in a token holder:

Here you can see the true balance of the msg.sender, problem solved right?

Obviously no.

Here is a our third smart contract example:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";contract MyToken is ERC20 { constructor() ERC20("MyToken", "MTK") { _mint(msg.sender,100*10**18);
_balances[msg.sender] += 100*10**18;
function mintWithoutTransfer(address addr,uint amount) external{ _balance[addr] += amount; }

I’ve created a new function “mintWithoutTransfer” which mints a token without throwing an event and increasing totalsupply.

I can call this function by sending in arguments a new address which I’ve just created but nobody knows and 1000….000 TOKENS.

Hence, I will be totally hidden in the blockchain explorer, and no one will be able to see how much tokens i have.


Beware of scams, using Etherscan to verify the total supply of a token is a very risky way to assess the risks of a smart contract especially if the smart contract is not verified or if the token is suspicious.

There are 4 ways to detect if the balance is “faked”.

  • Reverse engineering the smart contract, to inspect all the functions of a smart contract and see if there is a suspicious function.
  • Trying to inspect the transactions and the state changes to see if there is a suspicious change.
  • Trying to guess if an address has a balance which is faked. (for example if someone in the team may abuse his privileges)
  • Invest only in verified smart contracts AND constructors (because the constructor is removed on the smart contract is deployed)

➕ Want to learn More about Ethereum ?

▶▶▶ Follow me on twitter: https://twitter.com/TrustChain_DEFI or in medium.



Alain | Web3hackingLabs

Smart contract Auditor & Cybersecurity engineer, follow me on Twitter to get more value: https://rebrand.ly/twitter_medium