API Reference

AccessControl API

This page provides the full AccessControl module API.

Roles are referred to by their Bytes<32> identifier. These should be exposed in the top-level contract and be unique. The best way to achieve this is by using export sealed ledger hash digests that are initialized in the top-level contract:

import CompactStandardLibrary;
import "./node_modules/@openzeppelin/compact-contracts/access/AccessControl"
  prefix AccessControl_;

export sealed ledger MY_ROLE: Bytes<32>;

constructor() {
  MY_ROLE = persistentHash<Bytes<32>>(pad(32, "MY_ROLE"));
}

To restrict access to a circuit, use assertOnlyRole:

circuit foo(): [] {
  AccessControl_assertOnlyRole(MY_ROLE);
}

Roles can be granted and revoked dynamically via the grantRole and revokeRole circuits. Each role has an associated admin role, and only accounts that have a role's admin role can call grantRole and revokeRole.

By default, the admin role for all roles is DEFAULT_ADMIN_ROLE (zero bytes), which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using _setRoleAdmin.

The DEFAULT_ADMIN_ROLE is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it.

For an overview of the module, read the AccessControl guide.

import "./node_modules/@openzeppelin/compact-contracts/access/AccessControl";

Ledger

_operatorRoles: Map<Bytes<32>, Map<Either<Bytes<32>, ContractAddress>, Boolean>>

ledger

#

Mapping from a role identifier -> account -> its permissions.

_adminRoles: Map<Bytes<32>, Bytes<32>>

ledger

#

Mapping from a role identifier to an admin role identifier.

Witnesses

Witness implementations are authored by the consuming DApp. The TypeScript witnesses in the repository are test-only and are not published with the package.

wit_AccessControlSK() → Bytes<32>

witness

#

Returns the caller's secret key used in deriving the account identifier.

The same key produces the same account identifier across all contracts. Users who desire cross-contract unlinkability should use different keys per contract.

Circuits

DEFAULT_ADMIN_ROLE() → Bytes<32>

pure

#

The default admin role for all roles. Only accounts with this role will be able to grant or revoke other roles unless custom admin roles are created via _setRoleAdmin.

hasRole(roleId: Bytes<32>, account: Either<Bytes<32>, ContractAddress>) → Boolean

circuit

#

Returns true if account has been granted roleId.

k=10, rows=1017

assertOnlyRole(roleId: Bytes<32>) → []

circuit

#

Reverts if the caller cannot prove ownership of roleId. In the case of an external (non-contract) caller, the caller’s identity is derived from the wit_AccessControlSK witness as persistentHash(secretKey).

Requirements:

  • The caller must have roleId.
k=13, rows=2660

_checkRole(roleId: Bytes<32>, account: Either<Bytes<32>, ContractAddress>) → []

circuit

#

Reverts if account is missing roleId.

Requirements:

  • account must have roleId.
k=10, rows=997

getRoleAdmin(roleId: Bytes<32>) → Bytes<32>

circuit

#

Returns the admin role that controls roleId or a byte array with all zero bytes if roleId doesn't exist. See grantRole and revokeRole.

To change a role's admin use _setRoleAdmin.

k=9, rows=371

grantRole(roleId: Bytes<32>, account: Either<Bytes<32>, ContractAddress>) → []

circuit

#

Grants roleId to account.

Requirements:

  • account must not be a ContractAddress.
  • The caller must have roleId's admin role.
k=13, rows=3527

revokeRole(roleId: Bytes<32>, account: Either<Bytes<32>, ContractAddress>) → []

circuit

#

Revokes roleId from account.

Requirements:

  • The caller must have roleId's admin role.
k=13, rows=3457

renounceRole(
  roleId: Bytes<32>,
  callerConfirmation: Either<Bytes<32>, ContractAddress>
) → []

circuit

#

Revokes roleId from the calling account.

Roles are often managed via grantRole and revokeRole: this circuit's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced).

The caller's identity is derived from the wit_AccessControlSK witness as persistentHash(secretKey). The callerConfirmation parameter must match the caller's computed account identifier to prevent accidental renunciation.

Requirements:

  • The caller's computed account identifier must match callerConfirmation.
  • The caller must not be a ContractAddress.
k=13, rows=3313

_setRoleAdmin(roleId: Bytes<32>, adminRole: Bytes<32>) → []

circuit

#

Sets adminRole as roleId's admin role.

k=10, rows=579

_grantRole(roleId: Bytes<32>, account: Either<Bytes<32>, ContractAddress>) → Boolean

circuit

#

Attempts to grant roleId to account and returns a boolean indicating if roleId was granted. Internal circuit without access restriction.

Requirements:

  • account must not be a ContractAddress.
k=11, rows=1141

_unsafeGrantRole(roleId: Bytes<32>, account: Either<Bytes<32>, ContractAddress>) → Boolean

circuit

#

Attempts to grant roleId to account and returns a boolean indicating if roleId was granted. Internal circuit without access restriction. It does NOT check if the role is granted to a ContractAddress.

External smart contracts cannot call the access control contract at this time, so granting a role to a ContractAddress may render a circuit permanently inaccessible.

k=11, rows=1140

_revokeRole(roleId: Bytes<32>, account: Either<Bytes<32>, ContractAddress>) → Boolean

circuit

#

Attempts to revoke roleId from account and returns a boolean indicating if roleId was revoked. Internal circuit without access restriction.

k=11, rows=1071