Simple Burnable Token Incompatible with (Uni|Pancake)Swap

I am experiencing a recurring bug when extending Openzepplin ERC20 contracts. This issue is that my ERC20 tokens are not “tradeable”. AMM DEX platform such as UniSwap or PancakeSwap allow privileged users only to trade.

I have been researching for fixes all over the Internet but can’t find anything compelling.

:computer: Environment

Truffle v5.3.6 (core: 5.3.6)
Solidity - 0.8.4 (solc-js)
Node v16.1.0
Web3.js v1.3.5

:memo:Details

This bug is occurs whenever I implement some sort of taxes on my contracts, may it be liquidity, burn or whatever. Unprivileged users aka users with _isExcludedFromPayingFees[account] = false are only able to buy the tokens but canno sell them afterward on UniSwap/PancakeSwap.

:1234: Code to reproduce

The relevant parts of the code are the following:

    function _burn(address account, uint256 amount) internal virtual override {
        require(account != address(0), "ERC20: burn from the zero address");
        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");

        _balances[account] = accountBalance - amount;
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);
    }

    function _beforeTokenTransfer(address sender, uint256 amount)
        internal
        returns (uint256)
    {
        uint256 updatedAmount = amount;

        if (_burnTax != 0) {
            uint256 burnFee = (amount * _burnTax) / 100;

            _balances[sender] -= burnFee;
            _balances[address(this)] += burnFee;

            emit Transfer(sender, address(this), burnFee);

            _approve(address(this), sender, burnFee);
            burnFrom(address(this), burnFee);

            _totalBurnt += burnFee;
            updatedAmount -= burnFee;
        }

        return updatedAmount;
    }

        function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal virtual override notNull(amount) {
        require(
            _balances[sender] >= amount,
            "ERC20: transfer amount exceeds balance"
        );
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");
        require(
            sender != recipient,
            "_transfer: 'sender' cannot also be 'recipient'"
        );

        if (!_isExcludedFromPayingFees[sender]) {
            uint256 updatedAmount = _beforeTokenTransfer(sender, amount);
            amount = updatedAmount;
        }

        _balances[sender] -= amount;
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);
    }

    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        _approve(sender, _msgSender(), currentAllowance - amount);

        return true;
    }

Other functions/parts of the code are identical to Openzepplin default ERC20 token. Please if anyone know how to fix that, reply to this thread.

EDIT: Unprivileged users can buy the token and it actually gets burnt as expected but when selling this is what UniSwap is saying…

EDIT 1: After more troubleshooting, it seems that the following lines of codes in the _transfer function are causing the bug since when commented out UniSwap behaves properly.

            _approve(address(this), sender, burnFee);
            burnFrom(address(this), burnFee);

Does anyone know what is wrong with the above approve? What should I change in the code?

Came across this post, makes me wonder if it is possible to allow the message sender to burn tokens on behalf of the contracts, this seems to work for the case where the user is not the DEX.

The most obvious reason for the transfers to fail on pancake swap is due to the nature of how swaps happen in erc20 tokens , whenever a swap transaction happens we send token amount as a value to swap such as 100 and when our token contract burns 1 token on transfer pancake swap checks whether the amount is same as user requested to swap but instead of 100 Pancake receives 99 tokens so the transactiion is reverted.