Skip to content
Lattice

GovernedDiamondCut

Git Source

Inherits: IGovernedDiamondCut, IUpgradeRegistry, IFrozenSelectors, IEmergencyCut

Title: GovernedDiamondCut

Author: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80)

Stateless Diamond facet exposing the EIP-2535 diamondCut function at the canonical selector 0x1f931c1c, gated behind EmergencyStop + UPGRADE_EXECUTOR_ROLE. Drop-in replacement for diamond-lib's owner-gated DiamondCutFacet in a governed deployment. Also serves the append-only on-chain IUpgradeRegistry of every executed cut.

All logic lives in GovernedDiamondCutLib. This contract is stateless and forwards its calls to the library; inherit it in your Diamond to add governed upgrades. The registry getters plus the frozen-selector / preview / verify surface are plain facet functions and are NOT advertised as a distinct ERC-165 interface, so the facet's advertised id stays the canonical cut selector 0x1f931c1c.

Notes:

  • lattice-version: 0.1.0
  • lattice-source: Lattice original

Functions

diamondCut

Add/replace/remove any number of functions and optionally execute a function with delegatecall — but only when not emergency-stopped and the caller holds UPGRADE_EXECUTOR_ROLE. That role is granted solely to address(this) at init AND is pinned to administer itself, so DEFAULT_ADMIN_ROLE cannot grant it out-of-band. In the governed recipes the only way to reach this function is a timelock-relayed passed proposal; a co-cut facet that makes the diamond call itself for an outside caller (e.g. AccessManager execute) reaches it without one.

function diamondCut(FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata)
        external
        payable
        virtual;

Parameters

NameTypeDescription
_diamondCutFacetCut[]The facet addresses, cut actions, and function selectors.
_initaddressThe address of the contract or facet to delegatecall after the cut (0 to skip).
_calldatabytesThe calldata passed to _init.

emergencyRemoveCut

Zero-delay, removal-only emergency cut: instantly unbinds the supplied selectors from the diamond. Callable ONLY by an EMERGENCY_GUARDIAN_ROLE holder, and — unlike the governed diamondCut — it INTENTIONALLY works while EmergencyStop is engaged (it is the panic button). Every FacetCut must use action Remove (revert EmergencyCutMustBeRemoveOnly otherwise); none may target the cut entrypoint (revert EmergencyCutEntrypointProtected), a stop-recovery selector (same revert) or a frozen selector (revert IFrozenSelectors.FrozenSelectorProtected); no init delegatecall is permitted (nothing to initialize on a pure removal). The removal is recorded in the IUpgradeRegistry and emits EmergencyCutExecuted.

function emergencyRemoveCut(FacetCut[] calldata _cuts) external virtual;

Parameters

NameTypeDescription
_cutsFacetCut[]The facet cuts to apply; every entry MUST be a Remove (facetAddress == address(0)).

cutCount

Returns the number of governed cuts recorded so far, which is also the latest version.

function cutCount() external view virtual returns (uint256);

Returns

NameTypeDescription
<none>uint256

getCutRecord

Returns the immutable audit record for a given registry version.

Versions are 1-indexed; an unwritten version (0, or any value > cutCount) returns a zero-valued CutRecord.

function getCutRecord(uint256 _version) external view virtual returns (IUpgradeRegistry.CutRecord memory);

Parameters

NameTypeDescription
_versionuint256The registry version to look up.

Returns

NameTypeDescription
<none>IUpgradeRegistry.CutRecord

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 virtual;

Parameters

NameTypeDescription
_selectorsbytes4[]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 virtual returns (bool);

Parameters

NameTypeDescription
_selectorbytes4The function selector to query.

Returns

NameTypeDescription
<none>booltrue if the selector is frozen (protected from Replace/Remove).

frozenSelectors

Returns the full set of frozen selectors.

function frozenSelectors() external view virtual returns (bytes4[] memory);

Returns

NameTypeDescription
<none>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 virtual returns (bool ok, bytes4 offendingSelector);

Parameters

NameTypeDescription
_cutsFacetCut[]The candidate facet cuts to simulate.

Returns

NameTypeDescription
okbooltrue if no Replace/Remove in cuts targets a frozen selector.
offendingSelectorbytes4The 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 virtual returns (bool);

Parameters

NameTypeDescription
_interfaceIdbytes4The ERC-165 interface identifier to check.

Returns

NameTypeDescription
<none>booltrue if the interface is advertised.

exportSelectors

ERC-8153 selector export: this facet's cuttable selectors, tightly packed (4 bytes each).

Excludes exportSelectors() itself (0x0ef22643) - it is never cut into a diamond. Order matches forge inspect GovernedDiamondCut methodIdentifiers (alphabetical by signature); kept in exact parity by ExportSelectorsParityTest. Chunks: cutCount() 0xaa982c45 diamondCut((address,uint8,bytes4[])[],address,bytes) 0x1f931c1c emergencyRemoveCut((address,uint8,bytes4[])[]) 0xc83542a6 freezeSelectors(bytes4[]) 0x4487678f frozenSelectors() 0x22cabf70 getCutRecord(uint256) 0x3adda78e isSelectorFrozen(bytes4) 0xc8d8e114 previewCut((address,uint8,bytes4[])[]) 0x35342750 verifyInterfaceRegistered(bytes4) 0x0746a956

function exportSelectors() external pure virtual returns (bytes memory selectors);

Returns

NameTypeDescription
selectorsbytes