How to make ERC20 Transfer function payable for taxing via gas fee?

Hey mates,

I seem to have hit a bit of a roadblock, and I was wondering if someone could lend me a hand here.

My goal is as follows:
I want to create a transfer function that charges a tax, but instead of taxing the token amount, the tax should be derived from the gas fee. For instance, when I initiate a transfer call for ERC20 tokens, the transaction would include the gas fee plus a tax (some percentage of the gas fee), and that tax amount would be sent to a designated taxFeeReceiverWallet.

Here’s the implementation I’ve attempted so far:

  function transferPayable (
        address sender, 
        address recipient,
        uint256 amount
    ) external payable returns(bool)
    {
        uint256 fee = msg.value/(taxFeePercentage*100);
        bool success = super._transfer(sender, recipient, amount);
        super._transfer(sender, taxFeeRecieverWallet, fee);  // Send the tax to the designated wallet.
        return success;
    }

   function transfer(
       address recipient,
       uint256 amount
   ) public override returns(bool) {
       address sender = msg.sender;

       if(msg.sender.hasRole(WHITELIST_ROLE)) {  
           bool success = super._transfer(sender, recipient, amount);
           require(success, "Transaction not successful");
           return success;
       }
        else {
            bool success = transferPayable(msg.sender, recipient, amount);  // Call the function here.
            require(success, "Transaction not successful");
            super._transfer( sender, recipient, amount); 
            return success;  
        }   
    }

As you can observe from my code, the point of interaction is the transfer function, which I have overridden from the original function. There are two categories to consider:

  1. Whitelisted addresses (msg.senders with a whitelist role): These addresses are exempt from paying the tax.
  2. All other addresses: These users need to pay the tax.

Initially, I attempted to make the transfer function itself payable, but that caused an issue since it would alter the mutability of the function from nonpayable to payable, resulting in an error.

Hence, I decided to create a new function, transferPayable, which is a payable function intended to handle the tax from the gas fee. However, I’m now facing two major issues with this approach:

  1. Visibility issue: I want transferPayable to be an internal function, as I don’t want it to be accessible publicly. However, payable functions cannot have internal visibility, so I’ve had to make it external. But I need this function to be callable only by the addresses that invoke the transfer function and are not whitelisted.
  2. Undeclared identifier error: When trying to call transferPayable, I receive the error:

"Undeclared identifier. 'transferPayable' is not (or not yet) visible at this point."

I suspect this could be due to a recursive call within the transfer function, but I’m unsure.

In short, I’d greatly appreciate help with the following:

  • How can I make the transferPayable function accessible only to addresses calling the transfer function and who are not whitelisted?
  • How can I resolve the "not visible" error for transferPayable?
  • Or, is there perhaps an alternative approach to achieve my intended functionality?

Thanks in advance for your guidance!

At least for now, Solidity version is 0.8.x, you can not call a payable function(transferPayable) from a non-payable function(transfer).
Maybe you can charge for the token at first, then exchange the token to get eth.