Properly implementing fee structure into ERC20

Hey!

This is more of a question regarding a proper implementation of a transfer fee with the current (5.X) version of the ERC20 Contract. Is the intended way to override _update? The comments mention doing that in _transfer which is not virtual anymore and wouldn't even work with _update afterwards (for example checking the balance of the sender).

I can just write that myself of course, just wondering what the proper implementation with inheriting would be, not touching the flattened code afterwards.

Cheers

Well, that's NOT what the comment says.

As you can see here, the comment explicitly says:

    /**
     * ...
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        ...
    }

And as you can see here, function _update is indeed virtual, which means that you can override it:

    function _update(address from, address to, uint256 value) internal virtual {
        ...
    }

If you don't want to implement all of the original contents of this function within your overridden function, then you can just implement your desired extension, and then call super._update before or after your extension (or even split your extension into two parts, and then call the super function in between them).

Besides _transfer literally mentioning slashing / fees does overriding _update not fully answer my question since calling super._update will not work in a case of fees since its checks for the balance and updates the balances.

If I want to deduct a simple fee this would either check for the balance with fees deducted or updates the full amount depending on if I call it before or after the fee deduction. I need to implement all contents, the fee structure and ignore mints for the initial creation of the total supply. Which just doesn't seem to be like the proper way but I guess it is.

I find this long statement very hard to follow; consider simplifying it.

Please share exactly what part in the code makes this claim true.

The entire _update function is literally less than 30 lines of code.

Just meant that the _transfer function mentions to implements fees in there in the comments even tho its not overridable.

Second one is like I mentioned if you take a look at _update. It checks the balance from from, subtracts the value and adds it to to. If I send someone 100 for example and have 2 deducted as fee, I either call _update with 98 or 100. If I call it with 98, the user could send more than he owns and if I use 100 the recipient gets more than he should. Ergo I can't just call it and have to fully write it myself.

Yes I know, it just feels a bit hacky and weird to implement it that way after I need to also ignore mints for example. Just wanted to know if there's a proper way. Thanks tho!

Can you not just "do your stuff", then call super._update with value = 98 instead of value = 100?

And regarding this:

It's probably "leftovers" from the previous version, which OZ dev team has forgot to remove.

Then I would only revert if the user only has 98 and could at least ignore the fees.
Yes I can check for that before but that would be just redundant to do it twice. So i guess overriding update is the only call

Yes

This was the case in 4.X, before we introduced _update. Any overrides of _transfer, _beforeTokenTransfer or _afterTokenTransfer in 4.x, should be replaced with overrides _update in 5.x