LivenessModule
Table of Contents
Overview
The LivenessModule enables permissionless removal of inactive Safe owners based on liveness tracking data from the LivenessGuard. When the owner count falls below the minimum threshold, the module transfers sole ownership to a designated Fallback Owner and deactivates itself.
Definitions
Liveness Interval
The time period (in seconds) during which an owner must demonstrate activity to avoid being considered inactive. An owner is eligible for removal if their last recorded activity timestamp plus the Liveness Interval is less than the current block timestamp.
Minimum Owners
The minimum number of owners that must be maintained in the Safe before triggering Shutdown. If owner removals would reduce the count below this threshold, all remaining owners must be removed and ownership transferred to the Fallback Owner.
Threshold Percentage
The percentage (1-100) used to calculate the Safe's signing threshold based on the current number of owners. The
threshold is computed as the smallest integer greater than or equal to (numOwners * ThresholdPercentage) / 100.
Fallback Owner
The address that receives sole ownership of the Safe during Shutdown. This address is expected to be controlled by governance and serves as the recovery mechanism when the owner set becomes too small.
Shutdown
The process triggered when owner removals would reduce the owner count below Minimum Owners. During
shutdown, all remaining owners are removed, the Fallback Owner becomes the sole owner with a
threshold of 1, and the module permanently deactivates itself by setting ownershipTransferredToFallback to true.
Assumptions
a01-001: LivenessGuard provides accurate liveness data
The LivenessGuard contract correctly tracks and reports the last activity timestamp for each Safe owner via its
lastLive mapping. Inaccurate liveness data would cause the module to incorrectly identify owners as inactive or
active.
Mitigations
- The LivenessGuard specification defines invariants ensuring liveness tracking accuracy
- The module verifies the LivenessGuard has not been changed during the removal process
- The LivenessGuard address is immutable in the module, preventing substitution
a02-002: Fallback owner is trusted
The Fallback Owner address is trusted to act in the best interest of the Safe's stakeholders. A malicious fallback owner could gain complete control of the Safe during Shutdown.
Mitigations
- The Fallback Owner is set at deployment and cannot be changed without deploying a new module
- Shutdown only occurs when the owner count falls below Minimum Owners, which requires multiple owner removals
- The Safe's existing owners can remove the module before Shutdown occurs if they maintain sufficient liveness
Invariants
i01-001: Threshold is maintained
The Safe's signing threshold is correctly maintained throughout all owner removal operations, ensuring the Safe remains operational and secure.
Impact
Severity: Critical
If the threshold is incorrectly maintained, the Safe could become unusable (threshold too high for remaining owners) or insecure (threshold too low for the number of owners). This could result in loss of access to Safe assets or unauthorized transaction execution.
i02-002: Live owners are not removed
Owners who have demonstrated liveness within the Liveness Interval cannot be removed through the
removeOwners function, except during Shutdown when the owner count has already fallen below Minimum
Owners. This protects active participants from being incorrectly removed.
Impact
Severity: Critical
If live owners could be removed, active participants could lose access to the Safe despite maintaining their responsibilities. This could lead to unauthorized changes to the Safe's owner set and potential loss of control over Safe assets.
i03-003: Non-live owners are correctly removed
Owners who have not demonstrated liveness within the Liveness Interval can be successfully removed
through the removeOwners function when the owner count is at or above Minimum Owners. This ensures
the liveness enforcement mechanism functions as intended.
Impact
Severity: High
If non-live owners cannot be removed, the liveness enforcement mechanism fails its core purpose. Inactive owners would accumulate over time, potentially leading to a Safe where the threshold cannot be met because too many owners have lost access to their keys.
i04-004: Fallback is properly triggered when owner count is unsafe
When owner removals reduce the count below Minimum Owners, Shutdown is triggered: all remaining owners are removed, the Fallback Owner becomes the sole owner with threshold 1, and the module deactivates itself. This ensures the Safe never remains in an unsafe configuration with too few owners.
Impact
Severity: Critical
If Shutdown fails to trigger properly, the Safe could be left with too few owners to meet the threshold, causing permanent loss of access to Safe assets. Alternatively, if Shutdown triggers incorrectly, legitimate owners could lose control to the Fallback Owner prematurely.
Function Specification
constructor
Initializes the LivenessModule with configuration parameters and validates the initial Safe state.
Parameters:
_safe: The Safe contract instance this module will manage_livenessGuard: The LivenessGuard contract instance providing liveness data_livenessInterval: The Liveness Interval in seconds_minOwners: The Minimum Owners threshold_thresholdPercentage: The Threshold Percentage (1-100)_fallbackOwner: The Fallback Owner address
Behavior:
- MUST set all immutable parameters to the provided values
- MUST revert if
_minOwnersexceeds the current number of Safe owners - MUST revert if
_thresholdPercentageis zero - MUST revert if
_thresholdPercentageexceeds 100
safe
Returns the Safe contract instance managed by this module.
Behavior:
- MUST return the immutable
SAFEreference
livenessGuard
Returns the LivenessGuard contract instance used for liveness data.
Behavior:
- MUST return the immutable
LIVENESS_GUARDreference
livenessInterval
Returns the Liveness Interval in seconds.
Behavior:
- MUST return the immutable
LIVENESS_INTERVALvalue
minOwners
Returns the Minimum Owners threshold.
Behavior:
- MUST return the immutable
MIN_OWNERSvalue
thresholdPercentage
Returns the Threshold Percentage.
Behavior:
- MUST return the immutable
THRESHOLD_PERCENTAGEvalue
fallbackOwner
Returns the Fallback Owner address.
Behavior:
- MUST return the immutable
FALLBACK_OWNERaddress
getRequiredThreshold
Calculates the required Safe threshold for a given number of owners based on the Threshold Percentage.
Parameters:
_numOwners: The number of owners to calculate the threshold for
Behavior:
- MUST return
(_numOwners * THRESHOLD_PERCENTAGE + 99) / 100 - MUST return 1 when
_numOwnersis 1
canRemove
Checks whether a specific owner is eligible for removal based on liveness data.
Parameters:
_owner: The owner address to check
Behavior:
- MUST revert if
_owneris not a current owner of the Safe - MUST return true if
LIVENESS_GUARD.lastLive(_owner) + LIVENESS_INTERVAL < block.timestamp - MUST return false otherwise
removeOwners
Removes a set of inactive owners from the Safe, updating the threshold after each removal. If the owner count falls below Minimum Owners, triggers Shutdown.
Parameters:
_previousOwners: Array of previous owners in the Safe's linked list (one per owner to remove)_ownersToRemove: Array of owner addresses to remove
Behavior:
- MUST revert if the arrays have different lengths
- MUST revert if
ownershipTransferredToFallbackis true - MUST process each owner removal in array order:
- If current owner count is at least Minimum Owners, MUST revert if
canRemove(_ownersToRemove[i])returns false - If current owner count is below Minimum Owners, MUST remove the owner regardless of liveness
- MUST call
OwnerManager.removeOwnerwith the new threshold viaexecTransactionFromModuleReturnData - MUST emit
RemovedOwnerevent for each removed owner
- If current owner count is at least Minimum Owners, MUST revert if
- MUST trigger Shutdown when removing the last non-Fallback Owner:
- MUST call
OwnerManager.swapOwnerto replace the last owner with Fallback Owner - MUST set
ownershipTransferredToFallbackto true - MUST emit
OwnershipTransferredToFallbackevent
- MUST call
- MUST verify the final Safe state after all removals:
- If one owner remains, MUST be the Fallback Owner
- If multiple owners remain, MUST be at least Minimum Owners
- MUST have threshold equal to
getRequiredThreshold(numOwners) - MUST have the same LivenessGuard address in the guard storage slot
- MUST revert with
OwnerRemovalFailedif any Safe call fails