DEMO : https://metatx.eth.link
You can find here an EIP-1776 compliant Meta Transaction processor as a Singleton Contract
It is a full solution for meta-tx including relayer repayment that provides safety guarantees for both relayers and signers
Every recipient contract supporting this standard can receive Meta Transaction
Plus, by approving this smart contract on any ERC20 token, recipient can start receiving payments without themselves being approved first
As such new ERC20 token can have such contract pre-approved to provide a seamless user experience to their user. Alternatively, they can provide a permit
call (a la DAI) to provide a similar experience, except for an extra relayed call.
Here a summary of its distinctive features:
We can categorize meta-transaction support in at least, 6 different dimensions and here we will examine for each, the reasoning behind the choice
There are roughly 4 type of implementation
While EIP-1776 is compatible with any of them, the demo use the singleton proxy pattern. This is for 3 reasons:
Another differentiation is the ability of relayer to get paid.
In our opinion, It is such an important feature for relayers that we should ensure it is at least possible to implement it on top, if not already present.
In that regard one thing that becomes important as soon as a relayer get paid, is that there is a mechanism to ensure the relayer cannot make the meta-tx fails. hence the need for txGas in EIP-1776.
Another important EIP that would help here is EIP-1930 as the EVM call have poor support for passing an exact amount of gas to a call.
It is also worth noting the importance of the baseGas
parameter here too, as this make our implementation independent of opcode pricing while ensuring the relayer can account for the extra gas required to execute the meta transaction processing cost. Other implementation like GSN hardcode values in their contract, which is vulnerable to opcode pricing changes
Note that while it is possible to implement the refund on top of the proposal, as soon as we want the user to pay for the meta-tx (in a token for example), we will have to request yet another signature. We find it would be much convenient to have it implemented here. It is always possible for user to set a tokenGasPrice of zero if they have access to a repayer
While relayer-refund can be on its own, we found that it is trivial to also add the ability for meta-transaction processors to support transfering tokens to recipient.
This is a very powerful feature as it remove the need to pre-approve recipient, if they already support meta-tx.
Finally, another differentation possible for non-account based meta transaction is how the signer is being picked up by the recipient.
In EIP-1776 we assume that recipient can easily add a from field to their functions as this is already a common practice in many standard.
The standard could easily be changed to support a different mechanism, like appending the signer address to the end of the call data.
Earlier meta tx implementation assumed that the relayer was responsible of ensuring that the meta transaction call would not fails. So that when it fails, the whole tx would revert and the relayer would not get its refund if any.
This is in our opinion, not a great idea as this complexify the role of the relayer, since it has to guess whether the meta-tx call will not fails for reason out of its knowledge.
As such, we decided to add the txGas
parameter that dictate how much gas need to be passed into the meta-tx call. If not enough is passed in the relayer's tx revert, causing relayer to lose its gas.
While this seems trivial to implement, this is not the case and almost every meta transaction implementation out there fails to implement it properly
They all seems to believe that the gas parameter passed to the various CALL opcode are a specific gas amount. This is not the case and the gas value only act as a maximum value unfortunately. To my knowledge, we are the first to implement correctly. Unfortunately in order to remain opcode pricing independent we relies on the specific behavior of EIP-150 63/64 rules to do so. The proper way to fix it for all meta transaction implementation would be to get EIP-1930 accepted in the next hard fork.
There are different strategy to ensure tx cannot get replayed. The simplest one, used by ethereum is to simply have an increasing nonce
EIP-1776provide a 2 dimensional nonce system allowing user to group meta-tx in batches independently of each other
This allows user to create and submit simultaneously multiple batch of ordered meta-tx
While the batch/nonce feature allow you to batch tx in order and keep your ability to create transaction that have high gas requirement, they still require user to sign multiple meta-transaction and wait for the relayers to submit all of them. We added a special function in the processor that can be invoked as a meta-transaction itself so users can batch multiple calls in one meta-tx without any change to EIP-1776 format. They simply make a sign message with the call data and destination (and gas) for each call they want to make and submit this as a call to that specific function. See here
In order to avoid the possibilities of relayers submitting 2 meta-tx with the same nonce, at the expense of the relayer getting tis tx included later, the proposal offer a mechanism to avoid it.
Every meta-tx can include a relayer field. This field has 2 purpose, the obvious one is to limit the message to be used by a specific relayer. the second is to ensure the relayer that if the tx get included it get a reward for inclusion
Relayer can thus reject any meta-tx that do not specify their relayer address so that user are incentivized to only submit one tx at a time, or run the risk of paying the cost of the extra relayed tx.
Of course, if the user got rid of its payment token as part of one of this competing tx, the user remains safe and one of the relayer will not get its refund, so this is not full proof.
Also this is not implemented in the demo.