ERC2771: What are Meta Transactions?

The Meta transaction (ERC2771) solution was designed to attend to the growing interest in making calls from externally owned accounts(EOAs) successful and gas-free.

When users send a transaction on the Ethereum network, they are expected to pay gas for each transaction. For a newbie, this will involve purchasing the native token and adapting the wallet signing process, which can be a drop-off point for many new users.

With meta-transactions, users can interact with the blockchain network without paying transaction fees, as they are covered by third parties.

What Exactly Happens In Meta Transactions?

In meta transactions, a user signs a message(preferably EIP-712 compliant) with details of the transaction to be executed. The signed message is then passed on to a relayer who covers the gas fee on the user’s behalf, turning the request into a valid transaction and passing it through a ”trusted forwarder.” Before the relayer, no onchain validation has been done. The trusted forwarder validates the nonces and signatures before passing them on to the recipient contract. For context, the recipient contract is the contract the user intends to call.

ERC-2771 is, therefore, the meta-transaction framework that defines a secure contract-level protocol enabling smart contracts to seamlessly process meta transactions.

Transaction Signer → Relayer → Trusted Forwarder → Recipient Contract

The ERC-2771 Standard

The ERC-2771 defines how the caller address, calldata, msg.sender should be resolved for calls relayed by a trusted forwarder.

In typical contract interactions, the address of the direct caller is defined by `msg.sender`, but it proves inadequate for securing meta transactions. With ERC-277, when the Trusted Forwarder (whose address is defined by msg.sender) relays the transaction, the recipient contract appends the transaction signer’s address to the end(last 20 bytes) of the call data.

The ERC-2771, therefore, details how this calldata is forwarded to the contract being called by the signer. Below we have the_msgSender() function of a recipientContract, which separates the 20bytes at the end to determine the real sender.

Security Concerns & Mitigation

ERC2771 and Multicall Integration Vulnerability

When a contract simultaneously implements the ERC-2771 and Multicall, such a contract might be vulnerable to address spoofing attacks. An attacker can wrap malicious calldata within a forwarded request and use Multicall's delegatecall feature to manipulate the _msgSender() interpretation.

Nonetheless, the latest versions of Multicall and ERC2771Context contracts from OpenZeppelin has been proven to be safe and backwards compatible.

Note from OZ on the latest multicall implementation:

* NOTE: Since 5.0.1 and 4.9.4, this contract identifies non-canonical contexts (i.e. `msg.sender` is not {_msgSender}).

* If a non-canonical context is identified, the following self `delegatecall` appends the last bytes of ``

* to the subcall. This makes it safe to use with {ERC2771Context}. Contexts that don't affect the resolution of

* {_msgSender} are not propagated to subcalls.