{"id":"ERC-2771","name":"Secure Meta Transactions","status":"Final","chain":"both","category":{"id":"onboarding","name":"Onboarding & Access","description":"Getting users into web3 without friction"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"},{"id":"gas","name":"Gas & Fees","description":"Paying for transactions"}],"uxImpact":"ERC-2771 defines a contract-level protocol for recipients that accept meta-transactions through trusted forwarders. A gas relay may submit a signed request and pay gas, but gasless interaction requires a recipient integration, trusted-forwarder verification, an available relay, and any sponsor policy the product chooses.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-2771","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-2771","summary":"ERC-2771 defines a contract-level protocol for recipients that accept meta-transactions through trusted forwarders. A gas relay may submit a signed request and pay gas, but gasless interaction requires a recipient integration, trusted-forwarder verification, an available relay, and any sponsor policy the product chooses.","applicability":{"whenToUse":["A recipient contract, trusted forwarder, and gas relay are integrated for the selected flow.","The product can explain sponsor scope, relay trust, and what happens when sponsorship is unavailable.","The flow can provide a user-paid or other explicit fallback.","You are designing a sponsored transaction experience with visible request, relay, confirmation, and recovery states."],"whenToAvoid":["No trusted forwarder and receiving-contract integration is configured.","The app cannot show who pays and what happens when sponsorship ends.","Users need direct wallet transactions with no relayer trust dependency."]},"designerTakeaways":["Show a gasless option only when the recipient, forwarder, relay, and sponsor policy are available.","Distinguish the user's signed request from the relayed on-chain transaction.","Name the sponsor, scope, and any limits before the user signs.","Offer an explicit user-paid or retry path when the relay or sponsor declines.","Explain that the recipient must trust the forwarder and that the integration controls the final action."],"problemsSolved":[{"problem":"A user may not hold the native token for a recipient interaction","oldWay":"Acquire the native token before submitting an eligible action","newWay":"When an integrated relay and sponsor accept the request, a gas relay can submit it on the user's behalf","impact":"critical"},{"problem":"The payer and cost of a meta-transaction can be unclear","oldWay":"A user sees a generic gas prompt without knowing whether a sponsor or relay is involved","newWay":"The UI labels the sponsor and fallback while the user still reviews the signed request","impact":"critical"},{"problem":"No standard for gasless transactions","oldWay":"Every relayer had different implementation","newWay":"A recipient can expose isTrustedForwarder and accept the forwarder's appended signer data when implemented correctly","impact":"high"}],"uxPatterns":[{"name":"Sponsored Transaction","description":"A recipient action with sponsor and relay support","userFlow":["User sees the eligible recipient action","App shows sponsor, scope, and any user fallback","User clicks Claim","Signs message (not transaction)","Relay submits if the trusted-forwarder and sponsor checks pass","App reports the recipient and on-chain result"]},{"name":"Gasless Onboarding","description":"An eligible onboarding action with conditional sponsorship","userFlow":["New user connects wallet","App checks recipient and relay support","User signs the request","Relay may pay and submit gas","Fallback appears when sponsorship is unavailable"]}],"uiComponents":[{"name":"SponsoredGasIndicator","description":"Shows that gas is being paid by sponsor","states":["sponsored","partial","user-pays"],"props":["sponsor","savingsAmount"]},{"name":"GaslessButton","description":"Action button that uses meta-transaction","states":["idle","signing","relaying","success","error"],"props":["action","sponsor","onComplete"]},{"name":"RelayerStatus","description":"Shows relayer transaction status","states":["signing","queued","submitted","confirmed"],"props":["txHash","estimatedTime"]}],"antiPatterns":[{"pattern":"Promising universal gasless interaction","why":"Users confused when later asked to pay","instead":"Show sponsor scope, relay status, possible user cost, and a fallback before signing","severity":"high"},{"pattern":"Hiding that it's a signature, not transaction","why":"Users don't understand what they're signing","instead":"Explain what the user signs, who submits the transaction, and whether gas sponsorship is conditional","severity":"medium"},{"pattern":"No fallback when relayer is down","why":"Users stuck if relayer fails","instead":"Offer: \"Pay gas yourself\" as fallback option","severity":"high"}],"keyTakeaways":["ERC-2771 defines recipient and trusted-forwarder support for meta-transactions.","A gas relay may pay and submit a request when the integration accepts it.","Show who sponsors, what the sponsor covers, and when the path falls back.","Keep the user's signed request distinct from the relayed transaction.","Handle recipient rejection, forwarder failure, relay unavailability, and user-paid recovery."],"technicalNotes":"ERC-2771 defines a recipient protocol around a trusted forwarder. The signer authorizes a request; a gas relay submits it to the forwarder; and the forwarder appends the signer address to calldata for the recipient. The recipient must verify that msg.sender is trusted before using the appended address. Relay availability, fee sponsorship, request format, replay protection, and recipient business logic remain integration-specific.","specConstraints":[{"id":"signer-address-suffix","constraint":"A trusted forwarder must append the transaction signer's 20-byte address to the end of the recipient call data.","appliesTo":"account-implementation","normativity":"normative","specQuote":"The **Trusted Forwarder** is responsible for calling the **Recipient** contract and MUST append the address of the **Transaction Signer** (20 bytes of data) to the end of the call data.","specSection":"Specification / Extracting The Transaction Signer address","specUrl":"https://ercs.ethereum.org/ERCS/erc-2771#extracting-the-transaction-signer-address","designImplication":"Keep the signer suffix separate from application calldata, and make relayed sender attribution conditional on the recipient's trusted-forwarder check."},{"id":"recipient-trust-check","constraint":"A recipient must verify that it trusts the forwarder before extracting an appended signer address.","appliesTo":"account-implementation","normativity":"normative","specQuote":"The **Recipient** MUST check that it trusts the Forwarder to prevent it from\nextracting address data appended from an untrusted contract. This could result\nin a forged address.","specSection":"Specification / Extracting The Transaction Signer address","specUrl":"https://ercs.ethereum.org/ERCS/erc-2771#extracting-the-transaction-signer-address","designImplication":"Never show a relayed action as coming from the user until the recipient has validated the forwarder; otherwise an attacker can forge the displayed signer."},{"id":"forwarder-discovery","constraint":"A recipient that supports discovery must expose isTrustedForwarder(address) for wallets and applications.","appliesTo":"application","normativity":"normative","specQuote":"To provide this discovery mechanism a **Recipient** contract MUST implement this function:","specSection":"Specification / Protocol Support Discovery Mechanism","specUrl":"https://ercs.ethereum.org/ERCS/erc-2771#protocol-support-discovery-mechanism","designImplication":"Use the discovery method as the integration boundary for offering meta-transaction controls rather than assuming support from a generic recipient address."},{"id":"discovery-result","constraint":"isTrustedForwarder must return true only for trusted forwarders, false otherwise, and must not revert.","appliesTo":"application","normativity":"normative","specQuote":"`isTrustedForwarder` MUST return `true` if the forwarder is trusted by the Recipient, otherwise it MUST return `false`. `isTrustedForwarder` MUST NOT revert.","specSection":"Specification / Protocol Support Discovery Mechanism","specUrl":"https://ercs.ethereum.org/ERCS/erc-2771#protocol-support-discovery-mechanism","designImplication":"Treat discovery as a safe capability query with an explicit false state, and do not block unrelated UI on a revert-prone support probe."},{"id":"recipient-forwarder-request","constraint":"After discovery and trust validation, the recipient must accept a request from the trusted forwarder.","appliesTo":"account-implementation","normativity":"normative","specQuote":"Internally, the **Recipient** MUST then accept a request from forwarder.","specSection":"Specification / Protocol Support Discovery Mechanism","specUrl":"https://ercs.ethereum.org/ERCS/erc-2771#protocol-support-discovery-mechanism","designImplication":"Keep the recipient's accepted forwarder path aligned with the discovery response so the wallet does not offer a relay that the contract will reject."},{"id":"discovery-gas-limit","constraint":"The on-chain discovery call should remain below 50,000 gas.","appliesTo":"account-implementation","normativity":"normative","specQuote":"`isTrustedForwarder` function MAY be called on-chain, and as such gas restrictions MUST be put in place. It SHOULD NOT consume more than 50,000 gas","specSection":"Specification / Protocol Support Discovery Mechanism","specUrl":"https://ercs.ethereum.org/ERCS/erc-2771#protocol-support-discovery-mechanism","designImplication":"Keep discovery cheap enough for wallet capability checks and avoid making a meta-transaction support query itself a surprising fee-bearing operation."},{"id":"trusted-forwarder-forgery","constraint":"A malicious or upgraded forwarder can forge _msgSender, so recipient trust must be deliberate.","appliesTo":"account-implementation","normativity":"security-considerations","specQuote":"A malicious forwarder may forge the value of `_msgSender()` and effectively send transactions from any address. Therefore, `Recipient` contracts must be very careful in trusting forwarders. If a forwarder is upgradeable, then one must also trust that the contract won't perform a malicious upgrade.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-2771#security-considerations","designImplication":"Show the trusted-forwarder identity and upgradeability boundary in account and relay settings, and never treat a relay's claimed signer as self-authenticating."},{"id":"trusted-forwarder-governance","constraint":"Changes to the trusted-forwarder set must be restricted, preferably immutable or limited to trusted contract owners.","appliesTo":"account-implementation","normativity":"security-considerations","specQuote":"In addition, modifying which forwarders are trusted must be restricted, since an attacker could \"trust\" their own address to forward transactions, and therefore be able to forge transactions. It is recommended to have the list of trusted forwarders be immutable, and if this is not feasible, then only trusted contract owners should be able to modify it.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-2771#security-considerations","designImplication":"Expose forwarder-set changes as a high-risk governance event and revalidate relayed permissions after an owner or upgrade changes trust configuration."}],"lastUpdated":"2026-09-18","sources":[{"label":"ERC-2771 official specification","url":"https://ercs.ethereum.org/ERCS/erc-2771","type":"official-spec"}],"lastReviewed":"2026-09-18"},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-2771","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-2771","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-2771","markdown":"https://www.eipsfordesigners.com/standards/ERC-2771/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-2771/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-2771","official":"https://ercs.ethereum.org/ERCS/erc-2771","discussion":"https://ethereum-magicians.org/search?q=ERC-2771"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}