Skip to content
Lattice

IGovernedSafeDiamondCut

Git Source

Title: IGovernedSafeDiamondCut

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

External interface for the Safe-multisig-gated diamond-cut facet WITH a built-in timelock. Cuts cannot be applied synchronously; they must first be scheduleCut-ed by the pinned Safe, mature past a minDelay, and only then be executeCut-ed. A pending operation can be cancelCut-ed by the Safe. This module deliberately does NOT expose diamondCut at the canonical selector 0x1f931c1c — every cut is delayed — so its scheduling surface forms a genuinely new interface with its own ERC-165 id.

The authority is a pinned Gnosis Safe address (an M-of-N smart-contract multisig). The Safe collects owner signatures off-chain and verifies the threshold on-chain inside execTransaction, then dispatches the schedule/execute/cancel call to this facet. The facet does NOT re-verify signatures; it trusts solely that msg.sender == the pinned Safe. The Safe MUST invoke this facet with operation = Call (NEVER DelegateCall) — a DelegateCall would run this facet's code in the Safe's own context, where msg.sender is whoever called the Safe, defeating the gate. An operation id is keccak256(abi.encode(cuts, init, calldata, salt)); the salt lets the same cut payload be scheduled more than once over the diamond's lifetime.

Functions

scheduleCut

Schedules a cut for later execution. Gated to the pinned Safe and rejected while emergency-stopped. Reverts CutAlreadyScheduled if the id is already scheduled or was executed.

function scheduleCut(FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata, bytes32 _salt)
        external
        returns (bytes32 id);

Parameters

NameTypeDescription
_diamondCutFacetCut[]The facet addresses, cut actions, and function selectors.
_initaddressThe address delegatecalled after the cut (address(0) to skip).
_calldatabytesThe calldata passed to _init.
_saltbytes32A caller-chosen salt disambiguating otherwise-identical payloads.

Returns

NameTypeDescription
idbytes32The operation id keccak256(abi.encode(_diamondCut, _init, _calldata, _salt)).

executeCut

Executes a previously-scheduled, matured cut. Gated to the pinned Safe and rejected while emergency-stopped. Reverts CutNotScheduled if unknown, cancelled or already executed, CutNotReady if before eta, and the shared frozen-selector guard if a Replace/Remove touches a frozen selector. The arguments must match those passed to scheduleCut exactly (they re-derive the id).

function executeCut(FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata, bytes32 _salt)
        external
        payable;

Parameters

NameTypeDescription
_diamondCutFacetCut[]The facet addresses, cut actions, and function selectors.
_initaddressThe address delegatecalled after the cut (address(0) to skip).
_calldatabytesThe calldata passed to _init.
_saltbytes32The salt used at schedule time.

cancelCut

Cancels a scheduled, not-yet-executed operation. Gated to the pinned Safe. Reverts CutNotScheduled if the id is not currently scheduled (including an executed id).

function cancelCut(bytes32 _id) external;

Parameters

NameTypeDescription
_idbytes32The operation id to cancel.

getTimestamp

Returns the ready timestamp (eta) of an operation.

function getTimestamp(bytes32 _id) external view returns (uint256);

Parameters

NameTypeDescription
_idbytes32The operation id to query.

Returns

NameTypeDescription
<none>uint256The eta; 0 if never scheduled or cancelled; 1 once executed.

isOperationPending

Returns whether _id is scheduled but not yet matured (eta in the future).

function isOperationPending(bytes32 _id) external view returns (bool);

Parameters

NameTypeDescription
_idbytes32The operation id to query.

Returns

NameTypeDescription
<none>bool

isOperationReady

Returns whether _id is scheduled and matured (eta reached, not yet executed).

function isOperationReady(bytes32 _id) external view returns (bool);

Parameters

NameTypeDescription
_idbytes32The operation id to query.

Returns

NameTypeDescription
<none>bool

isOperationDone

Returns whether _id has been executed. False for never-scheduled and cancelled ids.

function isOperationDone(bytes32 _id) external view returns (bool);

Parameters

NameTypeDescription
_idbytes32The operation id to query.

Returns

NameTypeDescription
<none>bool

minDelay

Returns the minimum timelock delay (seconds) enforced between schedule and execute for operations scheduled now. A requested change shows here only once it takes effect.

function minDelay() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256

Events

CutScheduled

Emitted when the pinned Safe schedules a cut. The operation becomes executable at eta.

event CutScheduled(bytes32 indexed id, uint256 facetCutCount, address indexed init, bytes32 salt, uint256 eta);

Parameters

NameTypeDescription
idbytes32The operation id keccak256(abi.encode(cuts, init, calldata, salt)).
facetCutCountuint256The number of FacetCut entries scheduled.
initaddressThe init address that will be delegatecalled after the cut (address(0) if none).
saltbytes32The caller-chosen salt disambiguating otherwise-identical payloads.
etauint256The earliest block.timestamp at which the operation may be executed.

CutExecuted

Emitted after a scheduled, matured cut is executed and applied.

event CutExecuted(bytes32 indexed id);

Parameters

NameTypeDescription
idbytes32The operation id that was executed.

CutCancelled

Emitted when the pinned Safe cancels a still-pending operation.

event CutCancelled(bytes32 indexed id);

Parameters

NameTypeDescription
idbytes32The operation id that was cancelled.

MinDelayChangeScheduled

Emitted when the pinned Safe requests a minimum-delay change. The new delay does not apply until effectAt, which is max(oldDelay, newDelay) seconds after the request, so lowering the delay always waits out the delay it replaces.

event MinDelayChangeScheduled(uint256 oldDelay, uint256 newDelay, uint256 effectAt);

Parameters

NameTypeDescription
oldDelayuint256The minimum delay (seconds) in force when the change was requested.
newDelayuint256The requested minimum delay (seconds).
effectAtuint256The timestamp from which newDelay applies to newly scheduled cuts.

Errors

CutAlreadyScheduled

Thrown when scheduling an operation id that is already scheduled (pending or matured) or was already executed. Re-running an executed cut takes a new salt.

error CutAlreadyScheduled(bytes32 id);

Parameters

NameTypeDescription
idbytes32The duplicate operation id.

CutNotScheduled

Thrown when executing or cancelling an operation id that is not currently scheduled: never scheduled, cancelled, or already executed.

error CutNotScheduled(bytes32 id);

Parameters

NameTypeDescription
idbytes32The unknown operation id.

CutNotReady

Thrown when executing an operation before its eta (timelock not yet elapsed).

error CutNotReady(bytes32 id, uint256 eta);

Parameters

NameTypeDescription
idbytes32The operation id.
etauint256The earliest timestamp at which execution is permitted.