-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Minimal And Extensible Meta Transaction Forwarder #2585
Comments
I think this is a wonderful synthesis of many of the best ideas that I saw on display during the MetaMask MetaTransaction Hackathon, and I applaud it. Having custom replay-protection is a huge addition to 1776, and pointing to a custom replay protection contract means it's infinitely extensible. A few ideas:
It seems like this can be deployed whenever people find it trustworthy (after an audit?), and then contracts can begin integrating compatibility, so it seems to have a very smooth adoption path. |
I believe |
couldn't
That is more readeable |
Should be hardcoded bytes32, with comment showing the receipe. Unlike what you expect, the current implementation is not computed at compile time and thus optimised. |
Hi @Amxx thanks for the suggestions. Going to update the code. Probably better to put this low details comment there though : https://github.com/ethereum/EIPs/pull/2600/files so we keep that thread on the high level matters Re vanilia solidity call, the issue is that |
Any reason why gas amount value for the forward call is not specified in the message ? |
This is because this is unnecessary as the forwarder does not deal with fee repayment. gas fee repayment can be implemented on top though, in which case the gas to be passed will be passed to the forwarder. See EIP-1776 implementation here : https://github.com/wighawag/eip-2585/blob/ee20b96ba284e45be09c01adec76c21b98dfd4bb/contracts/src/EIP1776ForwarderWrapper.sol#L108 |
Thank you for this initiative 👏 About innerMessageHash About the replay protection |
I'm not sure if Example-implemented, |
Hi @vincentlg and @Nipol thanks for your comments and sorry for the delay @vincentlg I agree that batchId and BatchNonce are misleading But I have actually started to think of a different way to achieve full forwarder flexibility. I show cased it in my latest ETHGlobal hackathon : https://github.com/wighawag/gsn-playground/blob/master/contracts/src/MetaTransaction/ForwarderRegistry.sol This uses a permission-less registry and forwarder can thus use any signature scheme they want, not necessarely EIP-712. Plus if we come up with a minimal metatx standard for forwarder, the registrry use is up to the receiver. @Nipol I think the signature type can be safely guessed off-chain. What would be the benefit of figuring it out on-chain ? This could also be part of the EIP-712 message parameters so the relayer would be forced to pass the intended value |
Is this forwarder on mainnet? |
@yashnaman as far as I know there is no deployment of this standard yet. As for other standards there is a minimal standard (compatible with EIP-2585) here : https://eips.ethereum.org/EIPS/eip-2771 If your receiver contract support it, it will be compatible with EIP-2585 or other standard, like GSN v2: #2770 |
There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review. |
This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment. |
Pull Request Link : #2600
Simple Summary
This standard defines a universal smart contract, the "Forwarder", that accept specially crafted signed message by Externally Owned Accounts (EOA) to be executed as contract calls on their behalf by third parties (relayers). These relayers take the responsibility of signing and broadcasting an ethereum transaction carrying the message (a "Meta Transaction" message). The proposal is made so that extra Meta Transaction functionality can be built on top without the need for receiver contract to be changed.
Abstract
Native Meta Transaction allows users that simply own a private key to interact on the Ethereum network by only signing messages (no need for ether or account contract, just a private key). Third parties (the relayers) broadcast these messages through a contract on their behalf.
That contract is in charge to ensure the signing message is well formed and come from the intended signer. It also ensure replay protection so a message cannot be used twice.
This proposal implements a minimal contract with that responsibility, while remaining flexible for future extension. On particular it allows more complex message format (like EIP-1776) to be implemented on top, while meta transaction receiver can remain unchanged and trust only the singleton Forwarder.
msg.sender verification is achieved by replacing the use of solidity
msg.sender
with a function that extract the signer address from the call data.Motivation
Several EIPs have been proposed to support Meta Transactions (EIP-1776, EIP-1613, EIP-1077). They all have so far failed to get traction. This can be attributed to several factor but one important aspect is that they all tries to implement much more that simply forwarding message to contracts.
By being complex, they increase the friction for contract developer that need to trust that these solution are future proof.
This proposal aims at finding the most basic features while remaining extensible. As such this proposal will not deal with relayer repayment (that EIP-1776 and other tackle) or relayer coordination (that EIP-1613 tackle). Its sole purpose it to ensure the signed message is valid and that receiver contract have only one contract to trust.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Message format
The proposal is using a message format based on EIP-712 so that wallet that support EIP-712 but do not support the proposal described here can still offer an approval display showing all the information albeit in a less than ideal presentation.
Here is the proposed EIP-712 message format :
MetaTransaction(address from,address to,uint256 value,uint256 chainId,address replayProtection,bytes nonce,bytes data,bytes32 innerMessageHash)
The meaning of each field is as follow:
replayProtection.checkAndUpdateNonce(bytes)
. The default is a 2 dimensional nonce represented as a 256 bit integer split in two.to
. thefrom
address will be appended to it so that receiver contract can access the signer of the meta transaction.transaction execution and receiver verification
After the singleton Forwarder contract check for the validity of the signature, it append the address of the signer (or the account contract if using EIP-1271 or EIP-1654) to the call data.
As the result in order for a contract to receive meta transaction it simply has to extend the following contract and replace text occurrence of
msg.sender
with_getTxSigner()
:default replay protection
While the Forwarder allows user to choose any replay protection they chose, this forwarder comes with a default implementation to get started.
The default implementation use a 2 dimensional nonce, so that user can send simultaneous transactions in multiple independent batches.
The nonce is simply an abi encoded uint256 that is split in two 128 bit values. The higher bits represent the batchId while the lower bits represent the nonce in the batch.
Application can request the current nonce by calling the function
getNonce(userAddress, batchId)
The nonce to be sent is equal to the current Nonce. For every use the current Nonce get increased by one for that particular batch.
batching calls
THe forwarder also provide a mechanism to batch meta transaction in one message allowing the calls to either succeed fully or fails.
The message need to perform encode a call to the forwarder with this special function :
batch
that can only be called by the forwarder itself.Calls are a struct containing the destination (
to
), the data (data
) and the ether value to passed in (value
). It is up to the user to ensure it sign a value big enough to cover the sum of all values passed in.wallet / browser
While the forwarder use EIP-712 message format and wallet can use the information to display some information about the meta transaction. Wallets should integrate EIP-2585 more comprehensively.
In particular they should show a UI similar to existing Ethereum transaction.
Furthermore, since that proposal is built to support extensibility via the
innerMessageHash
wallet that supports EIP-2585 should add a specific API for emitting meta transaction :Similar to
eth_signTypedData
(see article)wallet would add a new JSON RPC method :
signer
would be the account asked to sign the messageeip2585Message
would be the message as described in that proposal, except that theinnerMessageHash
is optional, seeinnerMessageData
belowinnerMessageData
is optional. When absent, message need to include theinnerMessageHash
or it default to the zero filled bytes32. If specified, it follows EIP-712 standard and need to specify both the message and types, like specified in EIP-712. But instead of signing such message, it simply hash it. The resulting hash is then used as theinnerMessageHash
field for the eip2585 message.Wallets that support EIP-2585 will thus be able to display new fields name and their values for proposals built on top of EIP-2585. This allow experimentations at a higher level keeping receiver contract compatible.
EIP-1776 or EIP-1613 could thus be built without requiring receiver contracts to change. Their extra fields would be displayed to wallet via the inner EIP-712 message. Obviously, once these standards become mainstream, wallet can decide to support them more natively if necessary.
Rationale
Account Contract Support
While Native Meta Transaction System like this EIP, are designed to allow Externally Owned Accounts (EOA) to emit Meta Transaction, allowing Account contract to use such system is valuable for the following reasons :
Forwarding msg.value
While on its own forwarding
msg.value
might not be used with EIP-2585 alone (as relayer would need to be compensated and EIP-2585 does not attempt to tackle that), EIP built on top, like EIP-1776 would benefit in allowing EOA to pay for service in ETH by rewarding relayers in other tokens.Flexible Replay Protection
While the implementation implements a default 2 dimensional nonce replay protection, it also allows signers to provide their own.
innerMessageHash
The innerMessageHash's purpose is that more complex message format can be used to support more complex meta transaction system. For example relayer repayment mechanism proposed by EIP-1776 can be built on top.
The innerMessageHash is to be used by wallet provider and MUST be the hash of an EIP-712 message, that wallet can then interpret to display the relevant information. See above for a description on how wallet handle such hash. Future message format could be added too.
Signature Format : EIP-712
The message format is based on EIP-712 so that wallet not supporting EIP-2585 can still display some information. Unfortunately, they would not be able to display any information provided by the message hashed into
innerMessageHash
for EIP-2585 extension, like EIP-1776. Special support from Wallet is needed for that.Fork Replay Protection (and transition)
The message format do not use EIP-712 domain for chainId protection as this introduce unnecessary implementation complexity for dealing with EIP-712 domain hash refresh. Instead the chainId is provided as part of the meta transaction message. Since we expect wallet to parse the message for proper display, they can handle chainId verification too.
The chainId is then passed in to the call and checked against the current chain's chainId. This is so a proper error message is given in case the chainId do not match.
Note that such system does not handle fork transition. EIP-1344 is not well suited for it as it would require the maintenance of a chainId cache to handle past chainId and this would add extra complexity. Because contentious chain forks are infrequent and the only downside would be that user would have to resubmit their signed message for the new fork they are interested in, the complexity added is not worth it. Plus even a cache is not full proof as mentioned in EIP-1965
On the other hand if EIP-1965 was implemented we could have used it to offer safe fork transition too.
Batching Capability
The Forwarder allows Meta transaction to be batched in a single transaction, but instead of complexifying the message format to include an array of calls, the implementation instead relies on a special
batch
function that can be the target of the meta transaction itself.Wallet will need to parse this special call to display the list of meta transaction call to be executed.
Backwards Compatibility
This is a new contract and interface, no backward compatibility issues
Test Cases
Tests can be found here
Implementation
Security Considerations
The Security of the proposal relies on the safety of the contract implementation only. One of the reason, native meta transaction has not taken off is that contract creator have to trust a specific mechanism. The proposal aims to be a minimal meta transaction implementation.
References
Copyright
Copyright and related rights waived via CC0.
The text was updated successfully, but these errors were encountered: