ERC2771 Explained in Detail
ERC2771 lets a trusted forwarder relay a signed request to a recipient contract. The forwarder verifies the request and appends the original signer address to the end of calldata.
The recipient must use the ERC2771 context, usually _msgSender(), instead of raw msg.sender for user authorization.
Smart contract example
address sender = _msgSender();
When the caller is the trusted forwarder, _msgSender() extracts the original signer.
ERC2771 in Auditing
ERC2771 changes caller identity. A contract that mixes msg.sender and _msgSender() can accidentally grant or deny access.
Auditors treat the trusted forwarder as part of the contract's trust boundary.
Red flags in code
-
Privileged functions still use raw
msg.sender. -
The trusted forwarder can be changed without controls.
-
Untrusted callers can spoof the appended address.
-
Forwarded requests lack nonce, deadline, or EIP-712 domain checks.
-
Calldata length is not checked before reading the final 20 bytes.
How to test or review it
-
Call functions directly and through the forwarder.
-
Try spoofing calldata from an untrusted caller.
-
Replay a forwarded request and expect failure.
-
Test expired requests and wrong target contracts.
-
Review every access-control check for
msg.senderversus_msgSender().
Keep learning this topic
Trusted Forwarder
A trusted forwarder is the ERC2771 contract a recipient trusts to verify signed requests and relay calls with the original signer appended.
msg.sender
msg.sender is the address that directly called the current Solidity function in the current EVM call context.
EIP-712
EIP-712 is a standard for signing typed structured data so a signature is bound to a specific message type and domain.
Practice this in real audit scenarios
Definitions help, but auditors need reps. SCH turns concepts like ERC2771 into exploit labs, code review habits, and report-writing practice.
Start the free trial or see the full smart contract auditing course.