Extending Deployed Contracts with LSP17
Adding new capability to a contract after deployment usually means an upgrade key someone has to hold forever, or a diamond-storage layout everyone has to get right. LSP17 Contract Extension takes a third path: the base contract's fallback resolves an incoming function selector against an ERC725Y-keyed registry of extension addresses and forwards the call. New capability ships as a new extension contract plus a permission-gated setData call β no admin upgrade key, no shared storage, no diamond-cut ceremony.
The stackβ
| Standard | Role |
|---|---|
| LSP17 | The fallback router on the base contract |
| Extension contracts | One per new function selector you want to add |
| LSP14 | Safer ownership rotation for whoever can register extensions |
| LSP6 | Governs the permission to write the registration key, when the registrant is a Universal Profile controller |
When this vertical fitsβ
You're shipping a contract that will need to grow over time β new asset receivers, new signature verifiers, new app-specific entry points β without ever surrendering a permanent upgrade key over the base bytecode. Or you're extending a Universal Profile with custom behavior that should be registered per-profile rather than coded directly into the account contract.
A Universal Profile is the canonical use case, but LSP17 is a general primitive β any contract can adopt the same fallback-and-registry pattern.
Known functions always execute as immutable base bytecode. Only unknown selectors ever hit the fallback and route to a registered extension β so there's no path back to silently rewriting behavior the base contract already has, unlike a diamond's permanent diamondCut authority.
Related reading: ERC2535 Diamonds vs LSP17 Β· The contract-extension problem