IMO it is better for the standard to allow the user to pay if desired instead of having yet another system for it. After all, this is not so much to add and having it, does not preclude using yet another system later if it turns ou to be inadequate.
I would also like to add than having token support allow for more than just paying for the gas. My solution actually also include token transfer in that it can approve the recipient, allowing recipient to receive token without prior approval, a current pain in web3 user experience.
In your system if the user wanted to be the repayer, which in my opinion is an obvious case, (as even if there were a third party repayer, it might want to charge the users tokens, maybe to implement some sort of rate-limit), it would have to make 2 meta-transaction, one inside the other.
By the way, your code that specify the gas amount for the inner call is not enough. The gas amount specified is just a maximum value and does not error out if there is not enough gas to fulfil it. This also means this does not ensure the gas provided is that amount. So unless you do extra check like my implementation do, you run the risk of the relayer making the inner tx fails even if it was signed with the correct gas amount. If a repayer is involved, this means it can lose money while not fulfilling the signer message.
Another important aspect of gas consumption that will affect the repayer is that you also need to account for the extra gas require to process the meta-tx itlesf in order to be accurate. You do with a hardcoded value FLAT_GAS_USAGE
For that EIP-1776 propose the baseGas
parameter that allow the system to remains independent of opcode pricing. Relayer can simply reject meta-tx that do not provide enough baseGas
to ensure they can compute the price of the meta-tx accurately.
By the way EIP-1776 focus on the message format, so that multiple implementation are possible. This means that if the refunding mechansim (gas price) is specified as part of the format, your solution could simply ignore it.
That’s why I believe at this stage we should focus on the message format so that we can experiment with multiple implementation in parallel and not block ourselves in one.
We still need to agree on some other thing though, the thing that will affect the receivers, like how the signer is identified (whether through data appended to the call or through reusing the first parameter of functions)…