Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to Fallback Admin Functionality and Tests #10

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions solidity/src/AccessRegistry/AccessRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
pragma solidity ^0.8.20;

import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {SuperAdmin2Step} from "./helpers/superAdmin2Step.sol";
import {FallbackAdmin2Step} from "./helpers/fallbackAdmin2Step.sol";
import {SuperAdmin} from "./helpers/superAdmin.sol";
import {FallbackAdmin} from "./helpers/fallbackAdmin.sol";

abstract contract AccessRegistry is Context, SuperAdmin2Step, FallbackAdmin2Step {
abstract contract AccessRegistry is Context, SuperAdmin, FallbackAdmin {
event SignerAdded(address indexed newSigner);
event SignerRemoved(address indexed removedSigner);
event SignerRenounced(address indexed from, address indexed to);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pragma solidity ^0.8.4;
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step fallbackAdminship handover may be unique to this codebase.
abstract contract FallbackAdmin2Step {
abstract contract FallbackAdmin {
/* CUSTOM ERRORS */
/// @dev The caller is not authorized to call the function.

Expand Down Expand Up @@ -40,16 +40,16 @@ abstract contract FallbackAdmin2Step {
event FallbackAdminshipHandoverCanceled(address indexed pendingFallbackAdmin);

/// @dev `keccak256(bytes("FallbackAdminshipTransferred(address,address)"))`.
uint256 private constant _FALLBACKADMINSHIP_TRANSFERRED_EVENT_SIGNATURE =
0xb3b235ec28c0c439d776d6b08d1186ca9e254ab0a45799e7c012c767fd388ab4;
// uint256 private constant _FALLBACKADMINSHIP_TRANSFERRED_EVENT_SIGNATURE =
// 0xb3b235ec28c0c439d776d6b08d1186ca9e254ab0a45799e7c012c767fd388ab4;

/// @dev `keccak256(bytes("FallbackAdminshipHandoverRequested(address)"))`.
uint256 private constant _FALLBACKADMINSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0x28dbfd0a9abc89d42b4958ac24ccb5370d4381d6d9780ec9495d9f865294ec73;
// uint256 private constant _FALLBACKADMINSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
// 0x28dbfd0a9abc89d42b4958ac24ccb5370d4381d6d9780ec9495d9f865294ec73;

/// @dev `keccak256(bytes("FallbackAdminshipHandoverCanceled(address)"))`.
uint256 private constant _FALLBACKADMINSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0xfff645f1f5f25235a50da3b568627809458a7da704bb0700eb960289b102bb52;
// uint256 private constant _FALLBACKADMINSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
// 0xfff645f1f5f25235a50da3b568627809458a7da704bb0700eb960289b102bb52;

/* STORAGE */

Expand All @@ -60,14 +60,10 @@ abstract contract FallbackAdmin2Step {
/// The choice of manual storage layout is to enable compatibility
/// with both regular and upgradeable contracts.
bytes32 internal constant _FALLBACKADMIN_SLOT = 0x0c5cbdbffd46dcbe9fc21989b921bb5428cb1a1f406b6975b85f43539eb5bba3;

/// The fallbackAdminship handover slot of `newFallbackAdmin` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
/// let handoverSlot := keccak256(0x00, 0x20)
/// ```
/// It stores the expiry timestamp of the two-step fallbackAdminship handover.
uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
bytes32 internal constant _PENDINGFALLBACKADMIN_SLOT =
0xd7695d11a3816d58521df826e1b82703428b9d6f01a588416b40a4e02023deae;
bytes32 internal constant _HANDOVERTIME_FALLBACK_SLOT_SEED =
0xe73258ffc050df54d85cbff7148c2a66fde0cd543a82a20fd5b44d963b48ed6e;

/* INTERNAL FUNCTIONS */

Expand All @@ -94,7 +90,7 @@ abstract contract FallbackAdmin2Step {
/// Clean the upper 96 bits.
newFallbackAdmin := shr(96, shl(96, newFallbackAdmin)) // Store the new value.
sstore(fallbackAdminSlot, or(newFallbackAdmin, shl(255, iszero(newFallbackAdmin)))) // Emit the {FallbackAdminshipTransferred} event.
log3(0, 0, _FALLBACKADMINSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newFallbackAdmin)
log3(0, 0, 0xb3b235ec28c0c439d776d6b08d1186ca9e254ab0a45799e7c012c767fd388ab4, 0, newFallbackAdmin)
}
} else {
/// @solidity memory-safe-assembly
Expand All @@ -104,12 +100,13 @@ abstract contract FallbackAdmin2Step {
// Store the new value.
sstore(_FALLBACKADMIN_SLOT, newFallbackAdmin)
// Emit the {FallbackAdminshipTransferred} event.
log3(0, 0, _FALLBACKADMINSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newFallbackAdmin)
log3(0, 0, 0xb3b235ec28c0c439d776d6b08d1186ca9e254ab0a45799e7c012c767fd388ab4, 0, newFallbackAdmin)
}
}
}

/// @dev Sets the fallbackAdmin directly without authorization guard.

function _setFallbackAdmin(address newFallbackAdmin) internal virtual {
if (_guardInitializeFallbackAdmin()) {
/// @solidity memory-safe-assembly
Expand All @@ -118,7 +115,13 @@ abstract contract FallbackAdmin2Step {
// Clean the upper 96 bits.
newFallbackAdmin := shr(96, shl(96, newFallbackAdmin))
// Emit the {FallbackAdminshipTransferred} event.
log3(0, 0, _FALLBACKADMINSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(fallbackAdminSlot), newFallbackAdmin)
log3(
0,
0,
0xb3b235ec28c0c439d776d6b08d1186ca9e254ab0a45799e7c012c767fd388ab4,
sload(fallbackAdminSlot),
newFallbackAdmin
)
// Store the new value.
sstore(fallbackAdminSlot, or(newFallbackAdmin, shl(255, iszero(newFallbackAdmin))))
}
Expand All @@ -129,7 +132,13 @@ abstract contract FallbackAdmin2Step {
// Clean the upper 96 bits.
newFallbackAdmin := shr(96, shl(96, newFallbackAdmin))
// Emit the {FallbackAdminshipTransferred} event.
log3(0, 0, _FALLBACKADMINSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(fallbackAdminSlot), newFallbackAdmin)
log3(
0,
0,
0xb3b235ec28c0c439d776d6b08d1186ca9e254ab0a45799e7c012c767fd388ab4,
sload(fallbackAdminSlot),
newFallbackAdmin
)
// Store the new value.
sstore(fallbackAdminSlot, newFallbackAdmin)
}
Expand All @@ -154,57 +163,69 @@ abstract contract FallbackAdmin2Step {
function _fallbackAdminshipHandoverValidFor() internal view virtual returns (uint64) {
return 24 * 3600;
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/// @dev Request a two-step fallbackAdminship handover to the caller.
/// The request will automatically expire in 48 hours (172800 seconds) by default.
function requestFallbackAdminshipHandover() public virtual {
/// @notice Initiates the ownership handover process by setting an expiration time for the new fallback admin.
/// @dev The function uses low-level assembly to store the expiration timestamp in a specific storage slot
/// calculated based on the `newFallbackAdmin` address and a unique handover slot seed.
/// @param newFallbackAdmin The address designated as the new fallback admin.
function sendFallbackAdminOwnership(address newFallbackAdmin) public virtual onlyFallbackAdmin {
unchecked {
uint256 expires = block.timestamp + _fallbackAdminshipHandoverValidFor();
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to `expires`.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), expires)
// Emit the {FallbackAdminshipHandoverRequested} event.
log2(0, 0, _FALLBACKADMINSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
sstore(_PENDINGFALLBACKADMIN_SLOT, newFallbackAdmin)
sstore(_HANDOVERTIME_FALLBACK_SLOT_SEED, expires)
// Emit the {OwnershipHandoverRequested} event.
log2(0, 0, 0x28dbfd0a9abc89d42b4958ac24ccb5370d4381d6d9780ec9495d9f865294ec73, caller())
}
}
}

/// @dev Cancels the two-step fallbackAdminship handover to the caller, if any.
function cancelFallbackAdminshipHandover() public virtual {
/// @notice Cancels any pending ownership handover request for a specified new fallback admin.
/// @dev This function uses inline assembly to reset the designated handover storage slot to zero,
/// effectively canceling the handover request.
function cancelFallbackAdminshipHandover() public virtual onlyFallbackAdmin {
/// @solidity memory-safe-assembly
assembly {
let newFallbackAdmin := sload(_PENDINGFALLBACKADMIN_SLOT)
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), 0)
// Emit the {FallbackAdminshipHandoverCanceled} event.
log2(0, 0, _FALLBACKADMINSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
sstore(_PENDINGFALLBACKADMIN_SLOT, 0)
sstore(_HANDOVERTIME_FALLBACK_SLOT_SEED, 0)
// Emit the {OwnershipHandoverCanceled} event.
log2(0, 0, 0xfff645f1f5f25235a50da3b568627809458a7da704bb0700eb960289b102bb52, newFallbackAdmin)
}
}

/// @dev Allows the fallbackAdmin to complete the two-step fallbackAdminship handover to `pendingFallbackAdmin`.
/// Reverts if there is no existing fallbackAdminship handover requested by `pendingFallbackAdmin`.
function completeFallbackAdminshipHandover(address pendingFallbackAdmin) public virtual onlyFallbackAdmin {
/// @notice Accepts a pending ownership handover request for the caller, provided it is still valid.
/// @dev This function checks if a handover request exists for the caller and that it has not expired.
/// If valid, it sets the handover slot to zero and assigns the caller as the new fallback admin.
/// Reverts if there is no valid handover request or if the request has expired.
function completeFallbackAdminshipHandover() public {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingFallbackAdmin)
let handoverSlot := keccak256(0x0c, 0x20)
if iszero(eq(caller(), sload(_PENDINGFALLBACKADMIN_SLOT))) {
mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
revert(0x1c, 0x04)
}
// If the handover does not exist, or has expired.
if gt(timestamp(), sload(handoverSlot)) {
mstore(0x00, 0x292ff959) // `FallbackAdmin2Step_NoHandoverRequest()`.
if gt(timestamp(), sload(_HANDOVERTIME_FALLBACK_SLOT_SEED)) {
mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
revert(0x1c, 0x04)
}
// Set the handover slot to 0.
sstore(handoverSlot, 0)
sstore(_PENDINGFALLBACKADMIN_SLOT, 0)
sstore(_HANDOVERTIME_FALLBACK_SLOT_SEED, 0)
let newFallbackAdmin := shr(96, shl(96, caller())) // Store the new value.
log3(0, 0, 0xb3b235ec28c0c439d776d6b08d1186ca9e254ab0a45799e7c012c767fd388ab4, 0, newFallbackAdmin)
}
_setFallbackAdmin(pendingFallbackAdmin);
_setFallbackAdmin(msg.sender);
}

/* PUBLIC READ FUNCTIONS */

/// @dev Returns the fallbackAdmin of the contract.
Expand All @@ -224,11 +245,10 @@ abstract contract FallbackAdmin2Step {
{
/// @solidity memory-safe-assembly
assembly {
// Compute the handover slot.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingFallbackAdmin)
// Load the handover slot.
result := sload(keccak256(0x0c, 0x20))
if eq(pendingFallbackAdmin, sload(_PENDINGFALLBACKADMIN_SLOT)) {
// Load the handover slot.
result := sload(_HANDOVERTIME_FALLBACK_SLOT_SEED)
}
}
}
/* MODIFIERS */
Expand Down
40 changes: 26 additions & 14 deletions solidity/src/AccessRegistry/helpers/superAdmin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ abstract contract SuperAdmin {
event SuperAdminshipHandoverCanceled(address indexed pendingSuperAdmin);

/// @dev `keccak256(bytes("SuperAdminshipTransferred(address,address)"))`.
uint256 private constant _SUPERADMINSHIP_TRANSFERRED_EVENT_SIGNATURE =
0x04d129ae6ee1a7d168abd097a088e4f07a0292c23aefc0e49b5603d029b8543f;
// uint256 private constant _SUPERADMINSHIP_TRANSFERRED_EVENT_SIGNATURE =
// 0x04d129ae6ee1a7d168abd097a088e4f07a0292c23aefc0e49b5603d029b8543f;

/// @dev `keccak256(bytes("SuperAdminshipHandoverRequested(address)"))`.
uint256 private constant _SUPERADMINSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0xa391cf6317e44c1bf84ce787a20d5a7193fa44caff9e68b0597edf3cabd29fb7;
// uint256 private constant _SUPERADMINSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
// 0xa391cf6317e44c1bf84ce787a20d5a7193fa44caff9e68b0597edf3cabd29fb7;

/// @dev `keccak256(bytes("SuperAdminshipHandoverCanceled(address)"))`.
uint256 private constant _SUPERADMINSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0x1570624318df302ecdd05ea20a0f8b0f8931a0cb8f4f1f8e07221e636988aa7b;
// uint256 private constant _SUPERADMINSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
// 0x1570624318df302ecdd05ea20a0f8b0f8931a0cb8f4f1f8e07221e636988aa7b;

/* STORAGE */

Expand Down Expand Up @@ -84,7 +84,7 @@ abstract contract SuperAdmin {
/// Clean the upper 96 bits.
newSuperAdmin := shr(96, shl(96, newSuperAdmin)) // Store the new value.
sstore(superAdminSlot, or(newSuperAdmin, shl(255, iszero(newSuperAdmin)))) // Emit the {SuperAdminshipTransferred} event.
log3(0, 0, _SUPERADMINSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newSuperAdmin)
log3(0, 0, 0x04d129ae6ee1a7d168abd097a088e4f07a0292c23aefc0e49b5603d029b8543f, 0, newSuperAdmin)
}
} else {
/// @solidity memory-safe-assembly
Expand All @@ -94,21 +94,27 @@ abstract contract SuperAdmin {
// Store the new value.
sstore(_SUPERADMIN_SLOT, newSuperAdmin)
// Emit the {SuperAdminshipTransferred} event.
log3(0, 0, _SUPERADMINSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newSuperAdmin)
log3(0, 0, 0x04d129ae6ee1a7d168abd097a088e4f07a0292c23aefc0e49b5603d029b8543f, 0, newSuperAdmin)
}
}
}

/// @dev Sets the superAdmin directly without authorization guard.
function _setSuperAdmin(address newSuperAdmin) internal {
function _setSuperAdmin(address newSuperAdmin) internal virtual {
if (_guardInitializeSuperAdmin()) {
/// @solidity memory-safe-assembly
assembly {
let superAdminSlot := _SUPERADMIN_SLOT
// Clean the upper 96 bits.
newSuperAdmin := shr(96, shl(96, newSuperAdmin))
// Emit the {SuperAdminshipTransferred} event.
log3(0, 0, _SUPERADMINSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(superAdminSlot), newSuperAdmin)
log3(
0,
0,
0x04d129ae6ee1a7d168abd097a088e4f07a0292c23aefc0e49b5603d029b8543f,
sload(superAdminSlot),
newSuperAdmin
)
// Store the new value.
sstore(superAdminSlot, or(newSuperAdmin, shl(255, iszero(newSuperAdmin))))
}
Expand All @@ -119,7 +125,13 @@ abstract contract SuperAdmin {
// Clean the upper 96 bits.
newSuperAdmin := shr(96, shl(96, newSuperAdmin))
// Emit the {SuperAdminshipTransferred} event.
log3(0, 0, _SUPERADMINSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(superAdminSlot), newSuperAdmin)
log3(
0,
0,
0x04d129ae6ee1a7d168abd097a088e4f07a0292c23aefc0e49b5603d029b8543f,
sload(superAdminSlot),
newSuperAdmin
)
// Store the new value.
sstore(superAdminSlot, newSuperAdmin)
}
Expand Down Expand Up @@ -162,7 +174,7 @@ abstract contract SuperAdmin {
sstore(_PENDINGADMIN_SLOT, newSuperAdmin)
sstore(_HANDOVERTIME_SLOT_SEED, expires)
// Emit the {OwnershipHandoverRequested} event.
log2(0, 0, _SUPERADMINSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
log2(0, 0, 0xa391cf6317e44c1bf84ce787a20d5a7193fa44caff9e68b0597edf3cabd29fb7, caller())
}
}
}
Expand All @@ -178,7 +190,7 @@ abstract contract SuperAdmin {
sstore(_PENDINGADMIN_SLOT, 0)
sstore(_HANDOVERTIME_SLOT_SEED, 0)
// Emit the {OwnershipHandoverCanceled} event.
log2(0, 0, _SUPERADMINSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, newSuperAdmin)
log2(0, 0, 0x1570624318df302ecdd05ea20a0f8b0f8931a0cb8f4f1f8e07221e636988aa7b, newSuperAdmin)
}
}

Expand All @@ -202,7 +214,7 @@ abstract contract SuperAdmin {
sstore(_PENDINGADMIN_SLOT, 0)
sstore(_HANDOVERTIME_SLOT_SEED, 0)
let newSuperAdmin := shr(96, shl(96, caller())) // Store the new value.
log3(0, 0, _SUPERADMINSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newSuperAdmin)
log3(0, 0, 0x04d129ae6ee1a7d168abd097a088e4f07a0292c23aefc0e49b5603d029b8543f, 0, newSuperAdmin)
}
_setSuperAdmin(msg.sender);
}
Expand Down
Loading