Skip to content
crane-access logo

crane-access

This skill should be used when the user asks about "access control", "onlyOwner", "onlyOperator", "ownership transfer", "MultiStepOwnable", "ERC8023", "operable pattern", "function-level permissions", "reentrancy protection", "reentrancy lock", or needs to restrict function access in Crane Diamon...

SKILL.md

Full skill instructions

Crane Access Control Components

Crane provides three access control patterns for Diamond proxies: MultiStepOwnable (ERC-8023), Operable, and ReentrancyLock.

Component Selection

NeedComponentPurpose
Ownership with time-lockMultiStepOwnableTwo-step ownership transfer with buffer period
Delegated permissionsOperableGlobal and function-level operator authorization
Reentrancy protectionReentrancyLockTransient storage lock for cross-function reentrancy

Quick Start: Add Access Control

// Import modifiers
import {MultiStepOwnableModifiers} from "@crane/​contracts/​access/​ERC8023/​MultiStepOwnableModifiers.sol";
import {OperableModifiers} from "@crane/​contracts/​access/​operable/​OperableModifiers.sol";
import {ReentrancyLockModifiers} from "@crane/​contracts/​access/​reentrancy/​ReentrancyLockModifiers.sol";

// Use in your Target contract
contract MyTarget is MultiStepOwnableModifiers, OperableModifiers, ReentrancyLockModifiers {
    function adminOnly() external onlyOwner {
        // Only owner can call
    }

    function operatorOnly() external onlyOperator {
        // Global operators or function-specific operators
    }

    function ownerOrOperator() external onlyOwnerOrOperator {
        // Either owner or operator can call
    }

    function noReentrant() external nonReentrant {
        // Protected from reentrancy
    }
}

MultiStepOwnable (ERC-8023)

Time-locked two-step ownership transfer with buffer period.

Storage

struct Storage {
    address owner;
    address pendingOwner;
    bool pendingOwnerConfirmed;
    uint256 ownershipBufferPeriod;  // e.g., 1 days
    uint256 bufferPeriodEnd;
}

Ownership Transfer Flow

  1. Initiate: Owner calls initiateOwnershipTransfer(newOwner)
  2. Wait: Buffer period must elapse
  3. Confirm: Owner calls confirmOwnershipTransfer(newOwner)
  4. Accept: New owner calls acceptOwnershipTransfer()
// Step 1: Current owner initiates
MultiStepOwnableRepo._initiateOwnershipTransfer(newOwner);

// Step 2: Wait for buffer period (e.g., 1 day)

// Step 3: Current owner confirms
MultiStepOwnableRepo._confirmOwnershipTransfer(newOwner);

// Step 4: New owner accepts
MultiStepOwnableRepo._acceptOwnershipTransfer();

// Owner can cancel anytime before acceptance
MultiStepOwnableRepo._cancelPendingOwnershipTransfer();

Guard Functions

// Revert if msg.sender is not owner
MultiStepOwnableRepo._onlyOwner();

// Revert if msg.sender is not pending owner
MultiStepOwnableRepo._onlyPendingOwner();

Modifiers

modifier onlyOwner() {
    MultiStepOwnableRepo._onlyOwner();
    _;
}

Initialization

// In DFPkg.initAccount()
MultiStepOwnableRepo._initialize(
    initialOwner,    // First owner
    1 days           // Buffer period for transfers
);

Operable Pattern

Delegated authorization for global and function-level permissions.

Storage

struct Storage {
    mapping(address => bool) isOperator;  // Global operators
    mapping(bytes4 func => mapping(address => bool)) isOperatorFor;  // Function-level
}

Authorization Levels

  1. Global Operator: Can call any function protected by onlyOperator
  2. Function Operator: Can only call specific functions

Setting Permissions (Owner Only)

// Grant/​revoke global operator status
OperableRepo._setOperatorStatus(operatorAddress, true);   // Grant
OperableRepo._setOperatorStatus(operatorAddress, false);  // Revoke

// Grant/​revoke function-level operator
OperableRepo._setFunctionOperatorStatus(
    IMyContract.someFunction.selector,  // Function selector
    operatorAddress,                     // Operator
    true                                 // Approval
);

Checking Permissions

// Check global operator
bool isGlobal = OperableRepo._isOperator(account);

// Check function operator
bool isForFunc = OperableRepo._isFunctionOperator(
    IMyContract.someFunction.selector,
    account
);

Guard Functions

// Revert if not global OR function operator for msg.sig
OperableRepo._onlyOperator();

// Revert if not owner AND not operator
OperableRepo._onlyOwnerOrOperator();

Modifiers

// Only global or function-level operators
modifier onlyOperator() {
    OperableRepo._onlyOperator();
    _;
}

// Owner OR any operator
modifier onlyOwnerOrOperator() {
    OperableRepo._onlyOwnerOrOperator();
    _;
}

ReentrancyLock

Transient storage-based reentrancy protection (EIP-1153).

Usage

modifier nonReentrant() {
    ReentrancyLockRepo._onlyUnlocked();
    ReentrancyLockRepo._lock();
    _;
    ReentrancyLockRepo._unlock();
}

Functions

// Lock the reentrancy guard
ReentrancyLockRepo._lock();

// Unlock the reentrancy guard
ReentrancyLockRepo._unlock();

// Check if locked
bool locked = ReentrancyLockRepo._isLocked();

// Revert if locked (guard function)
ReentrancyLockRepo._onlyUnlocked();

Benefits

  • Uses transient storage (cleared after transaction)
  • Gas efficient compared to storage-based guards
  • Protects against cross-function reentrancy

Component Files

ComponentFiles
MultiStepOwnableMultiStepOwnableRepo.sol, MultiStepOwnableModifiers.sol, MultiStepOwnableTarget.sol, MultiStepOwnableFacet.sol
OperableOperableRepo.sol, OperableModifiers.sol, OperableTarget.sol, OperableFacet.sol
ReentrancyLockReentrancyLockRepo.sol, ReentrancyLockModifiers.sol, ReentrancyLockTarget.sol, ReentrancyLockFacet.sol

AccessFacetFactoryService

Deploy access control facets:

import {AccessFacetFactoryService} from "@crane/​contracts/​access/​AccessFacetFactoryService.sol";

// Deploy MultiStepOwnable facet
IFacet ownerFacet = AccessFacetFactoryService.deployMultiStepOwnableFacet(create3Factory);

// Deploy Operable facet
IFacet operableFacet = AccessFacetFactoryService.deployOperableFacet(create3Factory);

// Deploy ReentrancyLock facet
IFacet reentrancyFacet = AccessFacetFactoryService.deployReentrancyLockFacet(create3Factory);

Additional Resources

Reference Files

For detailed patterns and examples:

  • references/​access-patterns.md - Complete access control integration patterns