Token Burn Total Supply

Hello,

I am trying to add a fixed burn amount of tokens on all transfers using Openzeppelin v5 and the _update function.

When i modify the _update (override) function specificaly "emit Transfer(from, to, value);" (the only change in the entire code of the smart contract) by adding a fixed burning of tokens amount i get this problem, i am not sure if it is a bug.

Initial total supply "_mint(msg.sender, 1000000 * 10 ** decimals ());" 1000000.

The correct amount of tokens are burned from the total supply, before i receive the tokens "999,999.5".

I do not receive the tokens even it is reported a success in the transaction hash.

"
Max Total Supply
Filtered by totalsupply(), method returned a zero value.

Holders
0

Total Transfers
1
"

The holders tab reports no entries.

Deployed using hardhat.

How to correct this problem/bug, thank you.


Hi, welcome to the community! :wave:

Is it possible to share the source code or a verified contract address.

1 Like

Hello and thank you.

Yes here it is:

// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyTokenTest is ERC20 {
    constructor() ERC20("MyTokenTest", "MST") {
        _mint(msg.sender, 1000000 * 10 ** decimals());
    }

   uint256 burnamount = 500000000000000000;

    function _update(address from, address to, uint256 value) internal virtual override {
        emit Transfer(from, to, value - burnamount);
    }
}
1 Like

It seems like you override the function _update(), and in the new logic, it only triggers an event without doing anything, so it would not mint any token, that is why no holders and total supply is 0.

The screeshots provided clearly shows that the tokens have been minted properly, the tokens are then transfered to the token creator and in the transfer 0.5 tokens are burned.

But the token creator doesn't get the tokens it shows no holders and the total supply reports a value of 0.

This looks like the only way in openzeppelin V5 (override _update) since _transfer can't be override anymore. (Trying to override non-virtual function.)

The screeshots provided clearly shows that the tokens have been minted properly, the tokens are then transfered to the token creator and in the transfer 0.5 tokens are burned.

I do not think so, the picture you provided above means the event rather than actual state changed

And if you just wants to make a new event, maybe it can be

function _update(address from, address to, uint256 value) internal virtual override {
    super._update(from, to, value);
    emit Transfer(from, to, value - burnamount);
}

But it does not make sense, cause no token is burned,

1 Like

The constructor mints 1000000 "_mint(msg.sender, 1000000 * 10 ** decimals());".

We can see the "Transfer" in the transaction hash.


The change looks like its working, 0.5 is burned in the "Transfer".

For EtherScan, it parses the event. And the event is not the real state changed. You have overrided the function _update(), and remove the original logic. The original logic is:

    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

It changes the balance of user and total supply of the token.
Use the key word super to inherit from the original logic and then add your own logic if you do not to change the original logic.

1 Like

So do you have any other questions?

Thank you, your explanation and change does corrects my problem.

Emmm, I am not sure what do you want to do, only generates a new event?
Actually it does not burn token, for example, if you transfer 100e18 token to Alice, Alice will receive 100e18 token rather than 99.5e18 token and burn 0.5e18 token.

1 Like

I want to do automatic burning of tokens on all transfers. I did not know about "super." and wasn't understanding the problem but your explanation helped thanks.

Maybe you can do like this:

    function _update(address from, address to, uint256 value) internal virtual override {
        super._update(from, to, value - 500000000000000000);
        super._update(from, address(0), burnamount);
    }

But Do not use it directly for the production environment without any test, and the above code will fail if the amount to transfer is less than burnAmount.
It is recommended that you write the code by yourself and test, then you will have a great improvement

1 Like

It works, thank you for your explanation and solution.