IFrozenSelectors
Title: IFrozenSelectors
Author: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80)
Protection layer for the GovernedDiamondCut facet: a governance-curated, append-only set
of "frozen" function selectors that can never be Replaced or Removed by a subsequent
governed cut, plus a pre-flight simulator and an ERC-165 verification helper for upgrade
workflows. Freezing prevents the executor from accidentally replacing or removing a frozen
selector, and bounds emergencyRemoveCut. It does not constrain _init or added facets:
the defence against a hostile proposal is the delay and cancel.
This interface is intentionally SEPARATE from IGovernedDiamondCut: that interface exposes
only diamondCut, so type(IGovernedDiamondCut).interfaceId == 0x1f931c1c (identical to
IDiamondCut), which is load-bearing — the governed facet must occupy the canonical cut
selector. The freeze/preview/verify surface therefore lives here so it cannot perturb that
pinned id. None of these functions are advertised as a distinct ERC-165 interface: they are
plain facet admin/view functions, so no new ERC-165 map slot is registered for them.
Functions
freezeSelectors
Permanently marks selectors as frozen: once frozen, a selector can never be the
target of a Replace or Remove in any future governed cut. Append-only — there is
deliberately no unfreeze. Gated like the facet's cut: on GovernedDiamondCut, behind
UPGRADE_EXECUTOR_ROLE (the single-holder role that gates diamondCut), so in its recipes
only a timelock-relayed governance proposal can freeze (a co-cut self-call relay such as
AccessManager execute would also reach it); on SafeDiamondCut and
GovernedSafeDiamondCut, by the pinned Safe.
function freezeSelectors(bytes4[] calldata selectors) external;Parameters
| Name | Type | Description |
|---|---|---|
| selectors | bytes4[] | The function selectors to freeze. Already-frozen selectors are idempotent. |
isSelectorFrozen
Returns whether selector is in the frozen set.
function isSelectorFrozen(bytes4 selector) external view returns (bool frozen);Parameters
| Name | Type | Description |
|---|---|---|
| selector | bytes4 | The function selector to query. |
Returns
| Name | Type | Description |
|---|---|---|
| frozen | bool | true if the selector is frozen (protected from Replace/Remove). |
frozenSelectors
Returns the full set of frozen selectors.
function frozenSelectors() external view returns (bytes4[] memory selectors);Returns
| Name | Type | Description |
|---|---|---|
| selectors | bytes4[] | The frozen selectors, in insertion order (subject to swap-and-pop reordering on internal set mechanics, though the set is append-only so order is stable here). |
previewCut
Pre-flight simulation of the frozen-selector guard against the CURRENT frozen set, with
no state change and no broadcast. Lets an upgrade workflow fail fast — before proposing
— if a cut would touch a frozen selector. Mirrors exactly the check the guarded
diamondCut performs before applying: only Replace/Remove actions are inspected.
This is a pure read of the frozen set; it does NOT re-implement diamond-lib's collision / immutable-function / bytecode-existence checks, which fire at execution time.
function previewCut(FacetCut[] calldata cuts) external view returns (bool ok, bytes4 offendingSelector);Parameters
| Name | Type | Description |
|---|---|---|
| cuts | FacetCut[] | The candidate facet cuts to simulate. |
Returns
| Name | Type | Description |
|---|---|---|
| ok | bool | true if no Replace/Remove in cuts targets a frozen selector. |
| offendingSelector | bytes4 | The first frozen selector a Replace/Remove would touch (zero if ok). |
verifyInterfaceRegistered
Verifies whether interfaceId is currently advertised in the diamond's ERC-165 map.
A thin wrapper over the shared ERC-165 support read, so an upgrade workflow can confirm an
expected interface is still (or now) advertised after a cut. Equivalent to calling
supportsInterface(interfaceId) on the diamond.
function verifyInterfaceRegistered(bytes4 interfaceId) external view returns (bool registered);Parameters
| Name | Type | Description |
|---|---|---|
| interfaceId | bytes4 | The ERC-165 interface identifier to check. |
Returns
| Name | Type | Description |
|---|---|---|
| registered | bool | true if the interface is advertised. |
Events
SelectorsFrozen
Emitted once per freezeSelectors call that adds at least one new selector. Carries the
full argument array as passed (including any selectors that were already frozen, which are
idempotent no-ops in the set).
event SelectorsFrozen(address indexed caller, bytes4[] selectors);Parameters
| Name | Type | Description |
|---|---|---|
| caller | address | The UPGRADE_EXECUTOR_ROLE holder that froze the selectors (the timelock relay). |
| selectors | bytes4[] | The selectors supplied to freezeSelectors. |
Errors
FrozenSelectorProtected
Thrown by the guarded diamondCut (and surfaced via previewCut) when a Replace or
Remove cut targets a frozen selector. Add actions are never affected.
error FrozenSelectorProtected(bytes4 selector);Parameters
| Name | Type | Description |
|---|---|---|
| selector | bytes4 | The frozen selector a cut attempted to replace or remove. |