Skip to content
Lattice

SafeDiamondCut

Git Source

Inherits: ISafeDiamondCut, IUpgradeRegistry, IFrozenSelectors, IEmergencyCut

Title: SafeDiamondCut

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 + a pinned Gnosis Safe multisig. Drop-in replacement for diamond-lib's owner-gated DiamondCutFacet in a Safe-governed deployment. Also serves the append-only on-chain IUpgradeRegistry of every executed cut and a self-administered Safe-rotation entry point. This is the INSTANT (no-delay) variant; use GovernedSafeDiamondCut when a mandatory timelock between approval and execution is wanted.

All logic lives in SafeDiamondCutLib. This contract is stateless and forwards its calls to the library; inherit it in your Diamond to add Safe-gated upgrades. The registry getters plus the frozen-selector / preview / verify / setSafe / safe 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.

AUTHORITY: the Safe collects M-of-N owner signatures off-chain and verifies the threshold on-chain in execTransaction, then calls this facet. The facet does NOT re-verify signatures; it trusts solely that msg.sender == the pinned Safe. The Safe MUST dispatch with operation = Call (NEVER DelegateCall): a DelegateCall would run this code in the Safe's own context, where msg.sender is whoever called the Safe, defeating the gate.

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 is the pinned Safe. The Safe MUST call with operation = Call.

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.

setSafe

Rotates the pinned Safe authority to _newSafe. Self-administered: callable ONLY by the current pinned Safe, so only the existing multisig can hand authority to its successor. _newSafe is validated (non-zero, real Safe whose threshold is at least the minimum meaningful threshold of 1). Emits SafeRotated.

function setSafe(address _newSafe) external virtual;

Parameters

NameTypeDescription
_newSafeaddressThe new Safe to pin as the cut authority.

safe

Returns the currently pinned Safe authority.

function safe() external view virtual returns (address);

Returns

NameTypeDescription
<none>addressThe pinned Safe address.

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 SafeDiamondCut 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 safe() 0x186f0354 setSafe(address) 0x5db0cb94 verifyInterfaceRegistered(bytes4) 0x0746a956

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

Returns

NameTypeDescription
selectorsbytes