I’ve been looking at whether a beacon proxy pattern makes sense on Starknet. My current view is yes, but only as a narrow, Starknet-specific standard for contracts that share a known interface, with some potential extensions, each with trade-offs.
Why this is worth discussing
Starknet already solves single-contract upgrades well with replace_class_syscall.
But there is still an open problem: how do we coordinate upgrades across many deployed contracts that should keep the same interface and switch to the same implementation together?
This shows up in patterns like:
- pools
- vaults
- markets
- per-user accounts
- other fleets of homogeneous contracts
Today the options are:
- upgrade each contract one by one (or redeploy)
- build app-specific orchestration
A standardized orchestration pattern would improve ecosystem-wide discovery and tooling by replacing bespoke app-level coordination with a common surface.
Starknet constraints
The idea should not be framed as “bringing EVM beacon proxies to Starknet” for a few reasons:
library_callgives us the delegatecall-like primitive we need, but- there is no fallback entrypoint
- so a generic catch-all proxy is not possible
That means any realistic beacon proxy pattern on Starknet has to either be interface-oriented
- the proxy explicitly exposes the functions it forwards
- the shared interface is known ahead of time
- the beacon coordinates the implementation class hash used by many proxies
Or implement a custom mechanism for routing custom dynamic entrypoints, like the later proposed beacon_call function, but this hurts composability because on-chain contracts can’t interact with those routers as they would do with regular contracts.
Proposed scope for a first standard
I think a first SNIP should stay narrow and standardize:
IUpgradeableBeacon: returns the current implementationClassHashand exposesupgrade_implementation_hash(new_implementation_hash)IBeaconProxy: exposes the beacon address and current implementation hash- forwarding rules that require
library_callfor the typed proxy path - SRC-5 discoverability for beacons and beacon proxies
Note: The reason to use upgrade_implementation_hash and not just upgrade is to avoid confusion between replacing the beacon’s own class hash via replace_class_syscall and replacing the implementation hash in storage.
Optional beacon_call extension
One optional extension that may be worth standardizing is:
beacon_call(selector, calldata)
The intention is to let the proxy act as a beacon-backed router for arbitrary entrypoints. In other words, instead of only forwarding a fixed set of functions compiled into the proxy, the proxy can also accept a selector plus calldata, resolve the current implementation from the beacon, and route that call through library_call.
This is useful for teams that expect the implementation surface to evolve over time:
- new entrypoints can be reached without redeploying a new proxy class
- one proxy class can remain valid while the implementation ABI grows
- frontend or SDK-driven integrations can manually encode calls when needed
The main limitation is composability. Unlike Solidity proxies, Starknet does not have a fallback entrypoint that automatically catches unknown selectors. That means beacon_call does not make the proxy behave like it directly exposes every function on the implementation.
In practice:
- typed dispatchers will not call those routed functions by default
- regular on-chain contract calls to undeclared entrypoints on the proxy will fail
- other contracts cannot treat the proxy as if it natively implements the full evolving interface
So beacon_call is best understood as an explicit router extension, not as a substitute for a typed proxy surface. It can reduce proxy churn, but it does not provide the same default on-chain composability that fallback-based proxies provide in Solidity.
Why this improves DX
A standard beacon pattern would give:
- one implementation-hash update that switches many proxies
- stable instance addresses
- shared auditable implementation logic
- a common interface for explorers, indexers, SDKs, and auditors
- less bespoke proxy plumbing across projects
Main risks and tradeoffs
The main downsides are:
- one bad implementation-hash update affects the entire fleet
- storage compatibility still has to be maintained across versions
- without fallback, new typed functions still require proxy changes
- if
beacon_callis included, it widens the callable surface without proper (automatic) interface handling
beacon_call should not redefine SRC-5 semantics. If a proxy exposes a generic routing entrypoint, that does not mean it directly implements every routed business interface.
Questions for feedback
I’d especially like feedback on:
- Is there enough ecosystem demand for a shared beacon/proxy standard?
- Is
beacon_calluseful as it is presented? Should it be part of v1, or deferred to a later extension? - Should
IBeaconProxyrequire bothbeacon()andimplementation_hash(), or isbeacon()enough? - Are there any missing safety requirements around beacon validation or implementation-hash updates?
If the direction seems useful, I already have a narrow draft in mind and would refine it around the feedback.