{"id":"ERC-2535","name":"Diamonds, Multi-Facet Proxy","status":"Final","chain":"both","category":{"id":"infrastructure","name":"Infrastructure","description":"Foundational patterns enabling other standards"},"journeyStages":[{"id":"infra","name":"Infrastructure","description":"Foundational patterns"}],"uxImpact":"ERC-2535 lets a diamond route function calls to multiple facet contracts at one address. Facet composition and any upgrade authority must be inspected for that deployment. The pattern does not remove transaction gas limits or make a diamond safe or necessarily upgradeable.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-2535","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-2535","sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-2535","type":"official-spec"}],"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","summary":"ERC-2535 lets a diamond route function calls to multiple facet contracts at one address. Facet composition and any upgrade authority must be inspected for that deployment. The pattern does not remove transaction gas limits or make a diamond safe or necessarily upgradeable.","designerTakeaways":["Keep the contract address and requested action clear; offer facet details when they inform the decision.","Read facet routing and upgrade authority from the deployed diamond.","Show observed facet changes and explain any effect on the action the user is reviewing."],"applicability":{"whenToUse":["Contract explorer or developer tools display proxy diamonds.","Users interact with known diamond deployments.","Upgrade transparency is product value."],"whenToAvoid":["End-user retail flows with no inspect need.","Plain non-diamond contracts.","Cannot resolve facet selector mapping."]},"prototypeFirst":[{"screen":"Diamond address overview","why":"Default view for regular users stays simple.","covers":["Simple mode","Power expand"],"include":["Single address chip","Diamond badge","Expand facets link"]},{"screen":"Facet breakdown panel","why":"Power users audit which code runs.","covers":["Multiple facets","Single facet"],"include":["Facet name rows","Function count","Facet address copy"]},{"screen":"Upgrade history timeline","why":"Track facet adds and replacements.","covers":["Recent upgrade","Empty history"],"include":["Timeline","Facet affected","Tx link"]},{"screen":"Send to diamond confirm","why":"Confirm stays human — no facet dump.","covers":["Standard send"],"include":["Human action summary","Contract address","Facets in advanced only"]}],"mentalModel":[{"label":"Diamond address","description":"The same contract address can route calls to different facets after an authorized upgrade."},{"label":"Facet","description":"Module holding subset of functions."},{"label":"Selector routing","description":"Function call hits correct facet — invisible to user."},{"label":"Upgrade","description":"Upgradeable diamonds can add, replace, or remove selectors through diamondCut; immutable diamonds have no available upgrade path."},{"label":"Simple vs power view","description":"Retail default simple; auditors expand facets."}],"statesToDesign":[{"state":"Simple contract view","trigger":"Default user path.","userNeed":"Send/interact normally.","designResponse":"Show the decoded action and contract; offer implementation and upgrade context when relevant."},{"state":"Facets expanded","trigger":"User taps View facets.","userNeed":"Audit architecture.","designResponse":"Facet list with function groups."},{"state":"Recent upgrade","trigger":"Facet changed.","userNeed":"Know behavior may differ.","designResponse":"Recently upgraded banner on explorer."},{"state":"Unknown selector","trigger":"Function not in known facet map.","userNeed":"Not broken UI.","designResponse":"Unknown function — check latest facet map."},{"state":"Developer upgrade sim","trigger":"Simulating facet add.","userNeed":"Clear diff.","designResponse":"Before/after facet table."}],"designDecisions":[{"question":"When should a confirmation show facet details?","recommendation":"Lead with the decoded action, affected assets, and permissions. Offer facet and upgrade details when they change the trust decision.","rationale":"A familiar diamond address can route to changed code; detail visibility should follow the action and risk."},{"question":"Diamond badge everywhere?","recommendation":"Explorer and contract pages only.","rationale":"Badge on send form adds noise."},{"question":"Facet naming?","recommendation":"Human labels from manifest; addresses in advanced.","rationale":"0x facet addresses meaningless."}],"problemsSolved":[{"problem":"Contract size limit blocks features","oldWay":"Deploy new address each upgrade","newWay":"Diamond adds facets same address","impact":"high"},{"problem":"Users confused by changing bytecode same address","oldWay":"Looks like same contract different behavior","newWay":"Upgrade history explains facet changes","impact":"medium"},{"problem":"Auditors cannot map functions to code","oldWay":"Opaque proxy","newWay":"Facet breakdown panel","impact":"medium"}],"uxPatterns":[{"name":"Diamond Facet Explorer","description":"Expandable facet list on contract page.","components":["DiamondBadge","FacetList","UpgradeTimeline"],"userFlow":["Open contract","See diamond badge","Expand facets","Inspect functions"]},{"name":"Simple Send to Diamond","description":"Standard confirm without facet noise.","components":["AddressChip","ActionSummary","AdvancedToggle"],"userFlow":["Send to diamond","Human summary","Confirm","Success"]}],"antiPatterns":[{"pattern":"Facet list on every wallet confirm","why":"Overwhelms non-technical users","instead":"Keep a readable action summary and make facet or upgrade details available where they affect consent.","severity":"high"},{"pattern":"No upgrade history on diamond","why":"Same address different behavior surprises","instead":"Upgrade timeline on contract page","severity":"medium"},{"pattern":"Raw selector hex in default view","why":"Meaningless to users","instead":"Function names grouped by facet","severity":"medium"}],"vocabulary":[{"use":"Multi-part contract","avoid":"Diamond proxy facets","why":"Simpler architecture hint."},{"use":"View components","avoid":"List facets","why":"Explorer action language."},{"use":"Recently updated","avoid":"Facet replaced via diamondCut","why":"Plain upgrade notice."}],"specConstraints":[{"id":"erc-2535-diamond-interface","constraint":"Every diamond implements the IDiamond interface.","appliesTo":"infrastructure","normativity":"normative","specQuote":"All diamonds must implement the `IDiamond` interface.","specSection":"Specification — Adding/Replacing/Removing Functions — IDiamond Interface","specUrl":"https://ercs.ethereum.org/ERCS/erc-2535#idiamond-interface","designImplication":"Identify a deployment as a diamond only when its interface and routing data are verifiable; keep the regular contract action visible while exposing architecture in the inspection view."},{"id":"erc-2535-upgrade-interface","constraint":"Diamonds that allow post-deployment selector-map changes SHOULD implement IDiamondCut.","appliesTo":"account-implementation","normativity":"normative","specQuote":"Diamonds should implement the `IDiamondCut` interface if after their deployment they allow modifications to their function selector mapping.","specSection":"Specification — Adding/Replacing/Removing Functions — IDiamondCut Interface","specUrl":"https://ercs.ethereum.org/ERCS/erc-2535#idiamondcut-interface","designImplication":"Expose whether the selected diamond supports the standard upgrade interface before showing upgrade history or claiming that selector changes are inspectable."},{"id":"erc-2535-diamondcut-tooling","constraint":"Diamond tools and user interfaces SHOULD expect and use the standard diamondCut function for interoperability.","appliesTo":"application","normativity":"normative","specQuote":"`diamondCut` is specified for the purpose of interoperability. Diamond tools, software and user-interfaces should expect and use the standard `diamondCut` function.","specSection":"Specification — Adding/Replacing/Removing Functions — IDiamondCut Interface","specUrl":"https://ercs.ethereum.org/ERCS/erc-2535#idiamondcut-interface","designImplication":"Use the standard diamondCut shape in upgrade tooling and make unsupported or custom change paths explicit rather than silently treating them as standard history."},{"id":"erc-2535-interface-discovery-option","constraint":"A diamond MAY implement EIP-165 supportsInterface for optional interface discovery.","appliesTo":"account-implementation","normativity":"normative","specQuote":"A diamond may implement the following:\n\n1. [EIP-165](./eip-165.md)'s `supportsInterface`.","specSection":"Specification — Implementation Points","specUrl":"https://ercs.ethereum.org/ERCS/erc-2535#implementation-points","designImplication":"Treat supportsInterface as an optional capability signal, probe it before relying on interface discovery, and keep a fallback inspection path when it is absent."},{"id":"erc-2535-diamond-cut-history","constraint":"DiamondCut records external functions added at deployment and every later add, replace, or remove change.","appliesTo":"infrastructure","normativity":"normative","specQuote":"During the deployment of a diamond any immutable functions and any external functions added to the diamond must be emitted in the `DiamondCut` event.\n\n**A `DiamondCut` event must be emitted any time external functions are added, replaced, or removed.** This applies to all upgrades, all functions changes, at any time, whether through `diamondCut` or not.","specSection":"Specification — Adding/Replacing/Removing Functions — IDiamond Interface","specUrl":"https://ercs.ethereum.org/ERCS/erc-2535#idiamond-interface","designImplication":"Use observed DiamondCut events to build upgrade history and explain that a stable address can route to changed code."},{"id":"erc-2535-immutable-function-safety","constraint":"Immutable functions cannot be replaced or removed.","appliesTo":"account-implementation","normativity":"normative","specQuote":"Any attempt to replace or remove an immutable function must revert.","specSection":"Specification — Adding/Replacing/Removing Functions — IDiamondCut Interface","specUrl":"https://ercs.ethereum.org/ERCS/erc-2535#idiamondcut-interface","designImplication":"Label immutable routes separately from upgradeable facets and do not promise that every function on a diamond can change."},{"id":"erc-2535-loupe-inspection","constraint":"Diamonds support facet and function inspection through IDiamondLoupe.","appliesTo":"infrastructure","normativity":"normative","specQuote":"Diamonds must support inspecting facets and functions by implementing the `IDiamondLoupe` interface.","specSection":"Specification — Inspecting Facets & Functions","specUrl":"https://ercs.ethereum.org/ERCS/erc-2535#inspecting-facets--functions","designImplication":"Offer facet and selector inspection in an explorer or advanced trust view; do not make users infer implementation changes from the diamond address alone."},{"id":"erc-2535-upgrade-authority","constraint":"Because diamondCut can execute arbitrary delegatecall with diamond storage access, its access must be carefully restricted.","appliesTo":"wallet","normativity":"security-considerations","specQuote":"The `diamondCut` function allows arbitrary execution with access to the diamond's storage (through `delegatecall`). Access to this function must be restricted carefully.","specSection":"Security Considerations — Arbitrary Execution with diamondCut","specUrl":"https://ercs.ethereum.org/ERCS/erc-2535#arbitrary-execution-with-diamondcut","designImplication":"Show upgrade authority and its scope before treating a diamond as trusted; a facet history without the controlling authority is incomplete risk context."},{"id":"erc-2535-selfdestruct-risk","constraint":"Using selfdestruct in a facet is heavily discouraged because misuse can delete a diamond or facet.","appliesTo":"wallet","normativity":"security-considerations","specQuote":"Use of `selfdestruct` in a facet is heavily discouraged. Misuse of it can delete a diamond or a facet.","specSection":"Security Considerations — Do Not Self Destruct","specUrl":"https://ercs.ethereum.org/ERCS/erc-2535#do-not-self-destruct","designImplication":"Flag detected selfdestruct capability in advanced contract risk context rather than presenting a diamond as a routine upgradeable address."},{"id":"erc-2535-selector-clash","constraint":"A selector clash can replace an existing route, so a properly implemented diamondCut prevents adding selectors that already exist.","appliesTo":"account-implementation","normativity":"security-considerations","specQuote":"A function selector clash occurs when two different function signatures hash to the same four-byte hash. This has the unintended consequence of replacing an existing function in a diamond when the intention was to add a new function. This scenario is not possible with a properly implemented `diamondCut` function because it prevents adding function selectors that already exist.","specSection":"Security Considerations — Function Selector Clash","specUrl":"https://ercs.ethereum.org/ERCS/erc-2535#function-selector-clash","designImplication":"Surface selector conflicts or unverifiable upgrade tooling in developer-facing review; do not treat a name-level function diff as sufficient evidence of route safety."},{"id":"erc-2535-upgrade-transparency","constraint":"Diamond change events and verifiable source enable monitoring and review of added, replaced, or removed functions.","appliesTo":"application","normativity":"security-considerations","specQuote":"Diamonds emit an event every time one or more functions are added, replaced or removed. All source code can be verified. This enables people and software to monitor changes to a contract. If any bad acting function is added to a diamond then it can be seen.\n\nSecurity and domain experts can review the history of change of a diamond to detect any history of foul play.","specSection":"Security Considerations — Transparency","specUrl":"https://ercs.ethereum.org/ERCS/erc-2535#transparency","designImplication":"Give users an upgrade timeline and source-verification status; keep recent facet changes visible when they alter the action being reviewed."}],"technicalNotes":"ERC-2535 defines diamond function routing, loupe inspection interfaces, and DiamondCut change events. Upgradeability and authorization depend on the deployment; a diamond can be immutable. Inspect current selectors and authority rather than assuming that every diamond supports upgrades or that unchanged addresses mean unchanged behavior.","relatedStandards":[{"id":"ERC-1967","relationship":"Proxy storage slot standard"},{"id":"ERC-1167","relationship":"Minimal proxy alternative"}]},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-2535","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-2535","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-2535","markdown":"https://www.eipsfordesigners.com/standards/ERC-2535/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-2535/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-2535","official":"https://ercs.ethereum.org/ERCS/erc-2535","discussion":"https://ethereum-magicians.org/search?q=ERC-2535"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}