Skip to content
Draft
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
60 changes: 30 additions & 30 deletions website/docs/library/access/AccessControl/AccessControlFacet.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ Manages role-based access control within a diamond.

<Callout type="info" title="Key Features">
- Role-based access control for granular permission management.
- Support for batch granting and revoking roles.
- Extensible with other access control facets like `AccessControlPausableFacet`.
- Supports hierarchical role administration, allowing roles to be managed by other roles.
- Provides batch operations for granting and revoking roles to multiple accounts efficiently.
</Callout>

## Overview

The AccessControlFacet provides a robust role-based access control (RBAC) system for Compose diamonds. It allows for granular permission management by defining roles and assigning them to accounts. This facet is crucial for securing sensitive functions and orchestrating complex interactions by enforcing role requirements.
The AccessControlFacet provides a robust role-based access control (RBAC) system for Compose diamonds. It enables granular permission management by defining roles, assigning them to accounts, and enforcing these assignments on function calls. This facet is essential for securing sensitive operations and ensuring that only authorized entities can perform specific actions.

---

Expand Down Expand Up @@ -477,49 +477,49 @@ error AccessControlUnauthorizedSender(address _sender, address _account);
<ExpandableCode language="solidity" maxLines={20} title="Example Implementation">
{`pragma solidity ^0.8.30;

import {DiamondInit} from "@compose/diamond/DiamondInit.sol";
import {DiamondCut} from "@compose/diamond/DiamondCut.sol";
import {AccessControlFacet} from "@compose/access/AccessControl/AccessControlFacet.sol";
import {Diamond} from "@compose/diamond/Diamond.sol";
import {DiamondCutFacet} from "@compose/diamond/DiamondCut/DiamondCutFacet";
import {DiamondInitFacet} from "@compose/diamond/DiamondInit/DiamondInitFacet";
import {DiamondLoupeFacet} from "@compose/diamond/DiamondLoupe/DiamondLoupeFacet";
import {AccessControlFacet, AccessControlStorage} from "@compose/access/AccessControl/AccessControlFacet";

contract DeployDiamondWithAccessControl is DiamondInit {
// Define roles
bytes32 constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
contract MyDiamond is DiamondInitFacet, DiamondCutFacet, DiamondLoupeFacet {
// ...

function deploy() external {
// ... diamond deployment logic ...
function upgrade() external {
// ...
AccessControlFacet accessControlFacet = AccessControlFacet(address(this));
bytes32 adminRole = keccak256("DIAMOND_ADMIN_ROLE");
bytes32 userRole = keccak256("USER_ROLE");
address owner = msg.sender;

// Initialize AccessControlFacet
AccessControlFacet accessControlFacet = AccessControlFacet(diamondAddress);
accessControlFacet.grantRole(ADMIN_ROLE, msg.sender); // Grant admin role to deployer
accessControlFacet.grantRole(OPERATOR_ROLE, address(this)); // Grant operator role to diamond itself
// Grant admin role to the owner
accessControlFacet.grantRole(adminRole, owner);

// ... other facet initializations ...
}

// Example of calling a protected function using requireRole
function executeProtectedAction() external {
AccessControlFacet accessControlFacet = AccessControlFacet(diamondAddress);
accessControlFacet.requireRole(OPERATOR_ROLE, msg.sender);
// Grant user role to a specific account
address userAccount = 0x123...;
accessControlFacet.grantRole(userRole, userAccount);

// ... protected action logic ...
// Later, to check permissions or execute sensitive functions:
// accessControlFacet.requireRole(adminRole, msg.sender);
// bool hasPermission = accessControlFacet.hasRole(userRole, msg.sender);
}

// ...
}`}
</ExpandableCode>

## Best Practices

<Callout type="tip" title="Best Practice">
- Initialize roles and grant them to appropriate accounts during diamond deployment.
- Use `grantRoleBatch` and `revokeRoleBatch` for efficient mass role management.
- Define clear hierarchies for roles using `setRoleAdmin` to manage administrative privileges.
- Initialize AccessControlStorage at the correct storage slot (`keccak256("compose.accesscontrol")`) during diamond deployment.
- Define clear and descriptive role names using `bytes32` constants for better readability and maintainability.
- Leverage `grantRoleBatch` and `revokeRoleBatch` for efficient management of multiple accounts for a single role.
</Callout>

## Security Considerations

<Callout type="warning" title="Security">
Ensure that role administration is properly secured. The `setRoleAdmin`, `grantRole`, and `revokeRole` functions require the caller to be the admin of the role. Reentrancy is mitigated as role modifications are atomic. Input validation is handled internally by the facet to prevent invalid role or account assignments.
Ensure that the `setRoleAdmin`, `grantRole`, and `revokeRole` functions are protected by appropriate access control mechanisms, typically by requiring the caller to be the admin of the role being modified. The `renounceRole` function allows accounts to revoke their own roles, which should be carefully considered in the overall access control strategy. Input validation on role names and account addresses is implicitly handled by the underlying Solidity types and Solidity's default behavior, but custom validation can be added if specific constraints are needed.
</Callout>

<div style={{marginTop: "3rem", paddingTop: "2rem", borderTop: "1px solid var(--ifm-color-emphasis-200)"}}>
Expand Down Expand Up @@ -563,4 +563,4 @@ Ensure that role administration is properly secured. The `setRoleAdmin`, `grantR
<WasThisHelpful pageId="AccessControlFacet" />
</div>

<LastUpdated date="2025-12-30T15:54:26.223Z" />
<LastUpdated date="2025-12-30T17:09:24.581Z" />
51 changes: 22 additions & 29 deletions website/docs/library/access/AccessControl/AccessControlMod.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
sidebar_position: 1
title: "AccessControlMod"
description: "Manages roles and permissions within a diamond."
description: "Manages role-based access control for diamond functions."
gitSource: "https://github.com/Perfect-Abstractions/Compose/tree/main/src/access/AccessControl/AccessControlMod.sol"
---

Expand All @@ -21,14 +21,13 @@ import GradientText from '@site/src/components/ui/GradientText';
import GradientButton from '@site/src/components/ui/GradientButton';

<DocSubtitle>
Manages roles and permissions within a diamond.
Manages role-based access control for diamond functions.
</DocSubtitle>

<Callout type="info" title="Key Features">
- Permission management via roles assigned to accounts.
- Ability to grant and revoke roles dynamically.
- Built-in check for role existence with `hasRole`.
- Revert mechanism for unauthorized access attempts via `requireRole`.
- Role-based access control for granular permission management.
- Functions to grant, revoke, and check role assignments.
- Ability to define and manage administrative roles for other roles.
</Callout>

<Callout type="info" title="Module Usage">
Expand All @@ -37,7 +36,7 @@ This module provides internal functions for use in your custom facets. Import it

## Overview

The AccessControl module provides a robust system for managing roles and permissions, ensuring that only authorized accounts can perform specific actions. This is crucial for maintaining security and control within a Compose diamond by enabling granular access delegation and revocation.
The AccessControl module provides a robust system for managing permissions within your diamond. It allows you to define roles and grant them to specific addresses, ensuring that only authorized accounts can execute sensitive functions. This module is crucial for building secure and composable decentralized applications.

---

Expand Down Expand Up @@ -402,48 +401,42 @@ error AccessControlUnauthorizedAccount(address _account, bytes32 _role);
<ExpandableCode language="solidity" maxLines={20} title="Example Implementation">
{`pragma solidity ^0.8.30;

import { AccessControlMod } from "@compose/access/AccessControl/AccessControlMod";
import { AccessControlStorage } from "@compose/access/AccessControl/AccessControlStorage";
import {IAccessControl} from "@compose/access/AccessControl/IAccessControl.sol";
import {AccessControlStorage} from "@compose/access/AccessControl/AccessControlStorage.sol";

contract MyFacet {
AccessControlMod internal accessControl;
IAccessControl accessControl;

// Assuming AccessControlMod is initialized and its storage slot is known
constructor(address _diamondProxy) {
// Fetch storage location from the diamond proxy
address accessControlAddress = _diamondProxy; // Example: If AccessControlMod is a facet itself
accessControl = AccessControlMod(accessControlAddress);
constructor(address _diamondAddress) {
accessControl = IAccessControl(_diamondAddress);
}

function grantAdminRole(address _account) external {
bytes32 adminRole = keccak256("AccessControl.ADMIN_ROLE"); // Example role
bytes32 adminRole = accessControl.getStorage().adminRole; // Assuming adminRole is accessible via storage
accessControl.grantRole(adminRole, _account);
}

function checkAdminRole(address _account) view external returns (bool) {
bytes32 adminRole = keccak256("AccessControl.ADMIN_ROLE"); // Example role
return accessControl.hasRole(adminRole, _account);
}

function enforceAdminRole(address _account) view external {
bytes32 adminRole = keccak256("AccessControl.ADMIN_ROLE"); // Example role
accessControl.requireRole(adminRole, _account);
function checkAccess() public view {
address caller = msg.sender;
bytes32 someRole = keccak256("SOME_ROLE");
accessControl.requireRole(someRole, caller);
// ... proceed with function logic ...
}
}`}
</ExpandableCode>

## Best Practices

<Callout type="tip" title="Best Practice">
- Define roles using `bytes32` and `keccak256` for clarity and gas efficiency.
- Use `requireRole` for immediate enforcement of permissions within functions.
- Carefully manage the administration of roles using `setRoleAdmin` to prevent unintended privilege escalation.
- Minimize the number of roles and grant them with the least privilege necessary.
- Use descriptive `bytes32` role identifiers for clarity.
- Ensure that role administration is properly secured, potentially using a dedicated admin role.
</Callout>

## Integration Notes

<Callout type="success" title="Shared Storage">
The AccessControl module utilizes the diamond storage pattern, storing its state at a well-defined slot identified by `keccak256("compose.accesscontrol")`. Facets can access this state by calling the `getStorage()` function or directly interacting with the module's functions, which implicitly read from this storage slot. Ensure that the AccessControl module is correctly initialized and its storage slot is reserved to avoid conflicts with other modules.
The AccessControl module utilizes a dedicated storage slot identified by `keccak256("compose.accesscontrol")` for its `AccessControlStorage`. Facets interacting with this module should import the `IAccessControl` interface and cast the diamond proxy address to it. The `getStorage()` function can be used to retrieve the storage struct, allowing read-only access to configuration like the admin role.
</Callout>

<div style={{marginTop: "3rem", paddingTop: "2rem", borderTop: "1px solid var(--ifm-color-emphasis-200)"}}>
Expand Down Expand Up @@ -481,4 +474,4 @@ The AccessControl module utilizes the diamond storage pattern, storing its state
<WasThisHelpful pageId="AccessControlMod" />
</div>

<LastUpdated date="2025-12-30T15:54:22.483Z" />
<LastUpdated date="2025-12-30T17:09:21.336Z" />
2 changes: 1 addition & 1 deletion website/docs/library/access/AccessControl/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import Icon from '@site/src/components/ui/Icon';
/>
<DocCard
title="AccessControlMod"
description={"Manages roles and permissions within a diamond."}
description={"Manages role-based access control for diamond functions."}
href="/docs/library/access/AccessControl/AccessControlMod"
icon={<Icon name="book" size={28} />}
size="medium"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
sidebar_position: 2
title: "AccessControlPausableFacet"
description: "Control role access and pause/unpause specific roles."
description: "Role-based pausing and unpausing of access control."
gitSource: "https://github.com/Perfect-Abstractions/Compose/tree/main/src/access/AccessControlPausable/AccessControlPausableFacet.sol"
---

Expand All @@ -21,18 +21,18 @@ import GradientText from '@site/src/components/ui/GradientText';
import GradientButton from '@site/src/components/ui/GradientButton';

<DocSubtitle>
Control role access and pause/unpause specific roles.
Role-based pausing and unpausing of access control.
</DocSubtitle>

<Callout type="info" title="Key Features">
- Allows pausing and unpausing of specific roles, preventing execution of role-bound functions.
- Integrates seamlessly with existing AccessControl mechanisms.
- Provides view functions to check the current paused status of any role.
- Enables temporary disabling of specific roles to halt associated operations.
- Integrates seamlessly with existing access control mechanisms.
- Emits `RolePaused` and `RoleUnpaused` events for on-chain monitoring and off-chain reactions.
</Callout>

## Overview

This facet provides granular control over role-based access, allowing specific roles to be temporarily paused. It integrates with the core AccessControl logic to enforce role permissions and adds a pausing mechanism for enhanced operational flexibility. Use this facet to manage temporary disruptions or maintenance periods for specific functionalities tied to roles.
This facet provides granular control over role execution within the diamond by allowing specific roles to be temporarily paused. It integrates with the underlying access control system to enforce pausing, ensuring critical functions are only callable when active. This enhances security and operational flexibility by enabling controlled downtime for specific role functionalities.

---

Expand Down Expand Up @@ -282,59 +282,53 @@ error AccessControlRolePaused(bytes32 _role);
<ExpandableCode language="solidity" maxLines={20} title="Example Implementation">
{`pragma solidity ^0.8.30;

import { Diamond } from "@compose/diamond/Diamond";
import { AccessControlPausableFacet } from "@compose/access/AccessControlPausable/AccessControlPausableFacet";
import { AccessControlFacet } from "@compose/access/AccessControl/AccessControlFacet";
import { Diamond } from "@compose/diamond/Diamond.sol";
import { AccessControlPausableFacet } from "@compose/access/AccessControlPausable/AccessControlPausableFacet.sol";
import { AccessControlFacet } from "@compose/access/AccessControl/AccessControlFacet.sol";
import { Role } from "@compose/access/AccessControl/Roles.sol";

contract MyDiamond is Diamond {
constructor(address _diamondAdmin) Diamond( _diamondAdmin) {
// ... deployment logic ...
}
// ... deployment logic ...

function upgrade() public {
// Example: Adding AccessControlPausableFacet
address[] memory facetsToAdd = new address[](1);
facetsToAdd[0] = address(new AccessControlPausableFacet());
function deploy() external payable {
// ... other facet deployments ...

bytes[] memory selectorsToAdd = new bytes[](3);
selectorsToAdd[0] = AccessControlPausableFacet.pauseRole.selector;
selectorsToAdd[1] = AccessControlPausableFacet.unpauseRole.selector;
selectorsToAdd[2] = AccessControlPausableFacet.isRolePaused.selector;
address accessControlPausableFacet = deployFacet(AccessControlPausableFacet.contractId(), AccessControlPausableFacet);
address accessControlFacet = deployFacet(AccessControlFacet.contractId(), AccessControlFacet);

facetCut(facetsToAdd, selectorsToAdd, new address[](0), new bytes[](0));
}
// Grant roles and set up access control (example)
AccessControlFacet(accessControlFacet).grantRole(Role.ADMIN, msg.sender);

function pauseMyRole() external {
AccessControlPausableFacet pausableFacet = AccessControlPausableFacet(address(this));
bytes32 myRole = keccak256("MY_ROLE");
pausableFacet.pauseRole(myRole);
// Example: Pause a role
AccessControlPausableFacet(accessControlPausableFacet).pauseRole(Role.MAINTENANCE);
}

function unpauseMyRole() external {
AccessControlPausableFacet pausableFacet = AccessControlPausableFacet(address(this));
bytes32 myRole = keccak256("MY_ROLE");
pausableFacet.unpauseRole(myRole);
// Function to check if a role is paused
function isRolePaused(bytes32 _role) external view returns (bool) {
return AccessControlPausableFacet(getFacet(AccessControlPausableFacet.contractId())).isRolePaused(_role);
}

function checkRoleStatus(bytes32 _role) external view returns (bool) {
AccessControlPausableFacet pausableFacet = AccessControlPausableFacet(address(this));
return pausableFacet.isRolePaused(_role);
// Function to require a role is not paused
function requireRoleNotPaused(bytes32 _role, address _account) external view {
AccessControlPausableFacet(getFacet(AccessControlPausableFacet.contractId())).requireRoleNotPaused(_role, _account);
}

// ... other diamond functions ...
}`}
</ExpandableCode>

## Best Practices

<Callout type="tip" title="Best Practice">
- Initialize or upgrade the diamond to include this facet to enable role pausing capabilities.
- Ensure the caller invoking `pauseRole` and `unpauseRole` has the necessary administrative privileges for the target role.
- Leverage `requireRoleNotPaused` within other facets or contract logic to dynamically enforce pausing states.
- Initialize roles and their pausing status during diamond deployment or through administrative functions.
- Ensure the caller has the necessary permissions (typically role admin) to pause or unpause roles.
- Leverage `requireRoleNotPaused` within other facets to enforce active status for critical operations tied to specific roles.
</Callout>

## Security Considerations

<Callout type="warning" title="Security">
The `pauseRole` and `unpauseRole` functions are restricted to the admin of the respective role, preventing unauthorized pausing. The `requireRoleNotPaused` function reverts with `AccessControlRolePaused` if the role is paused, ensuring that paused roles cannot be utilized. Ensure that any critical functions protected by roles properly call `requireRoleNotPaused` or equivalent logic to respect the paused state.
The `pauseRole` and `unpauseRole` functions are protected by access control, ensuring only authorized administrators can modify the pausing state of a role. The `requireRoleNotPaused` function reverts with `AccessControlRolePaused` if the specified role is currently paused, preventing unauthorized execution. Reentrancy is not a concern as these functions only modify internal state or perform checks without external calls.
</Callout>

<div style={{marginTop: "3rem", paddingTop: "2rem", borderTop: "1px solid var(--ifm-color-emphasis-200)"}}>
Expand All @@ -360,4 +354,4 @@ The `pauseRole` and `unpauseRole` functions are restricted to the admin of the r
<WasThisHelpful pageId="AccessControlPausableFacet" />
</div>

<LastUpdated date="2025-12-30T15:54:02.317Z" />
<LastUpdated date="2025-12-30T17:09:00.756Z" />
Loading