{"id":"ERC-7786","name":"Cross-Chain Messaging Gateway","status":"Final","chain":"both","category":{"id":"cross-chain","name":"Cross-Chain","description":"Moving assets and messages between chains"},"journeyStages":[{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"ERC-7786 defines gateway supportsAttribute() and sendMessage() calls plus the MessageSent source event and recipient receiveMessage(). Route discovery, health, status, destination post-processing, retry, and refunds remain adapter/provider-specific; send and receive IDs may differ.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-7786","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","hasDetailedContent":true,"content":{"id":"ERC-7786","summary":"ERC-7786 standardizes gateway source/recipient message calls and attributes. Applications can send a message through a compliant gateway, while route discovery, bridge health, status, post-processing, retry, and refunds remain adapter/provider-specific.","applicability":{"whenToUse":["Your product addresses: each bridge has different integration requirements.","Your users see inconsistent cross-chain UI across apps.","Your UI should send through a gateway while exposing provider-specific route and status details.","You are designing a bridge-agnostic transfer experience with visible states and recovery paths."],"whenToAvoid":["The product never sends a cross-chain message or changes state across chains.","No gateway source/recipient implementation is available for the flow.","The selected provider exposes no route, status, or recovery data to the application.","The flow only performs same-chain actions."]},"designerTakeaways":["You can design UI around a single gateway interface for providers that implement it.","You can standard message format enables consistent UX patterns.","You can design UI that delivers swap bridge adapters without changing app logic."],"problemsSolved":[{"problem":"Each bridge has different integration requirements","oldWay":"Custom code for LayerZero, different code for Wormhole, etc.","newWay":"Single gateway interface works with any compliant bridge","impact":"critical"},{"problem":"Users see inconsistent cross-chain UI across apps","oldWay":"Every app shows bridges differently, different confirmations","newWay":"Standard message format enables consistent UX patterns","impact":"high"},{"problem":"Switching bridges requires code changes","oldWay":"Hardcoded bridge dependency, risky to change","newWay":"Swap bridge adapters without changing app logic","impact":"high"},{"problem":"No standard way to track cross-chain message status","oldWay":"Each bridge has different tracking APIs","newWay":"MessageSent and send IDs provide a source-side record; status remains provider-specific","impact":"medium"},{"problem":"Bridge failures handled inconsistently","oldWay":"Some bridges auto-retry, some fail silently, some refund","newWay":"Provider-specific error, post-processing, retry, and refund handling","impact":"medium"}],"uxPatterns":[{"name":"Bridge-Agnostic Transfer","description":"User picks destination, not bridge","userFlow":["User enters amount and destination chain","Application/provider supplies available bridge routes","Shows routes sorted by user preference and provider data","User picks route (or accepts default)","Single interface sends regardless of bridge"]},{"name":"Cross-Chain Message Tracker","description":"Unified status view for provider data across selected bridge routes","userFlow":["User sends cross-chain message","Redirected to status page","Polls the provider or adapter for status updates","Progress bar advances through stages","Shows bridge-specific details where helpful"]},{"name":"Bridge Health Dashboard","description":"Show provider-supplied bridge reliability and status","userFlow":["User views bridge dashboard","Provider/adapter aggregates bridge health data","Shows status, speed, and reliability metrics","Alerts highlight any issues","Helps user choose appropriate bridge"]},{"name":"Failed Message Recovery","description":"Handle failed cross-chain messages when provider recovery exists","userFlow":["Message fails to deliver","User sees notification of issue","UI explains what happened clearly","Offers retry or refund options only when the provider supports them","Labels bridge-specific post-processing and recovery"]}],"uiComponents":[{"name":"CrossChainProgress","description":"Visual progress indicator for cross-chain messages","states":["pending","confirming","relaying","executing","complete","failed"],"props":["sourceChain","destChain","currentStage","estimatedTime"]},{"name":"BridgeSelector","description":"Choose between available bridge routes","states":["loading","available","comparing","selected"],"props":["routes[]","sortBy","onSelect"]},{"name":"MessageStatusPoller","description":"Auto-updating status component","states":["polling","updated","complete","error"],"props":["messageId","pollInterval","provider"]},{"name":"BridgeHealthBadge","description":"Quick status indicator for a bridge","states":["healthy","degraded","down","unknown"],"props":["bridgeName","status","lastCheck"]}],"antiPatterns":[{"pattern":"Hiding which bridge is being used","why":"Users need to know for troubleshooting and trust","instead":"Show bridge name with link to their status page","severity":"critical"},{"pattern":"No status updates during bridging","why":"Users anxious when large value transfers show no progress","instead":"Real-time progress with stage indicators and ETA","severity":"critical"},{"pattern":"Abandoning users when messages fail","why":"Stuck funds cause panic and support tickets","instead":"Clear recovery UI with retry and refund options","severity":"critical"},{"pattern":"Auto-selecting bridge without explanation","why":"Users surprised by speed or cost differences","instead":"Show why this bridge was chosen (price/speed/security)","severity":"high"},{"pattern":"Not showing estimated completion time","why":"Users don't know if 5 minutes or 5 hours","instead":"Clear ETA based on bridge historical performance","severity":"medium"}],"keyTakeaways":["ERC-7786 = one interface for all cross-chain messaging","Show which provider/bridge is used and identify the estimate source","Provide status tracking through stages when the provider exposes it","Build recovery UI only for provider-supported retry/refund actions"],"technicalNotes":"ERC-7786 defines IERC7786GatewaySource.supportsAttribute(bytes4) and sendMessage(bytes recipient, bytes payload, bytes[] attributes) payable returns (bytes32 sendId), plus a recipient receiveMessage(bytes32 receiveId, bytes sender, bytes payload). It defines a MessageSent source event; status, destination invocation/post-processing, route discovery, health, retry, and refunds are out of scope. The send ID may be zero or differ from the receive ID.","lastUpdated":"2026-09-18","sources":[{"label":"ERC-7786 official specification","url":"https://ercs.ethereum.org/ERCS/erc-7786","type":"official-spec"}],"lastReviewed":"2026-09-18"},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-7786","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-7786","type":"discussion"},{"label":"ERC-7786 official specification","url":"https://ercs.ethereum.org/ERCS/erc-7786","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-7786","markdown":"https://www.eipsfordesigners.com/standards/ERC-7786/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-7786/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-7786","official":"https://ercs.ethereum.org/ERCS/erc-7786","discussion":"https://ethereum-magicians.org/search?q=ERC-7786"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}