problem · contract extension after deployment

contract extension after deployment

Deployed contracts can't grow without a key holder.

EVM LSP17

UUPS makes the upgrade authority permanent. Diamonds make storage your problem.

UUPS upgradeTo(newImplementation) onlyOwner
upgrade key forever trust assumption
LSP17 fallback → extension[selector]
base immutable selector-routed
quotable answer

Adding new function selectors to an already-deployed contract in 2026 has four mainstream paths: upgradeable proxies (transparent, UUPS) that swap the implementation behind a stable address; ERC-2535 Diamonds that route selectors via a facet registry with shared storage; Safe module architecture that installs sandboxed logic; and LSP17 on LUKSO, which uses a fallback router with per-selector extension contracts registered under ERC-725Y keys. Each trades a different property — proxies retain admin authority, diamonds fragment storage, modules scope to one account. LSP17 extensions have isolated storage and no admin key.

LUKSO route

If you're dealing with contract extension after deployment, the LUKSO route is LSP17. LSP17 defines a fallback router: unknown selector → registered extension contract. The base contract stays immutable. New behavior is added by registering extensions in ERC-725Y. No upgrade authority. No diamond storage layout problem.

Why this breaks

A deployed contract cannot grow new external functions. Adding behavior usually means a transparent or UUPS proxy, which makes upgrade authority a permanent trust assumption, or a diamond, which trades trust for storage and tooling complexity.

For account contracts, the per-account module patterns (Safe modules, ERC-4337 validators) help — but they are wallet-specific extension mechanisms, not a general contract extension primitive.

What people try

OpenZeppelin transparent / UUPS proxies

Proven. The upgrade key never goes away. Every user is permanently exposed to whoever holds it.

ERC-2535 Diamonds

Modular. Expensive to author. Storage requires discipline. Tooling is improving but specialized.

Safe modules and guards

Scoped to Safe accounts. Strong for that case. Not a general primitive.

Plugin patterns inside the app contract

Bespoke per-app. No shared tooling.

How LSP solves it

LSP17 defines a fallback router: when a contract receives a call for an unknown function selector, it looks up an extension contract registered for that selector (stored in ERC-725Y data keys) and forwards the call. The base contract stays immutable. New behavior is added by registering extensions.

There is no upgrade authority over base bytecode. There is no diamond-style storage layout problem to manage. Universal Profiles use this to grow without proxy upgrades — and the same primitive is available to any contract that adopts LSP17.

continue at the source