Introduction
The Role Assignment module is the native object module that stores an object's permissions. Every globalized object carries one, and its state is deliberately small: a single field holding the owner role, and one key-value collection mapping a role key to an access rule. Blueprints declare which roles guard which methods; this module holds what each role currently means, and can be updated after deployment without touching the code.
Storing permissions as module state rather than as component fields is what makes them readable from outside. The rules of any live component can be queried through the Gateway like any other substate, so the current authority over a mint, a withdrawal, or a metadata change is a matter of public record rather than of reading the blueprint and trusting it.
The owner role
The owner role is declared once at instantiation, as one of three values:
OwnerRole::None– no owner at allOwnerRole::Fixed(rule)– an owner rule that can never be changed by anyoneOwnerRole::Updatable(rule)– an owner rule the owner may change
Internally these become an OwnerRoleEntry of a rule plus an updater, where the updater is None, Owner, or Object. When the updater is None, the field is written immutable at creation rather than merely guarded, so the immutability is a property of the substate and not of a rule that could later be relaxed.
The third value, Object, lets the object itself rotate its owner, and it is what makes a pre-allocated smart account upgradable into a badge-controlled one. A pre-securified object is created with its owner rule set to the virtual signature badge of the key that addresses it and the updater set to Object, plus a securify role guarded by the same rule. Calling securify does three things in order: it sets the securify role to DenyAll, mints the owner badge, and sets the owner role to require that badge. The first step is what makes the conversion one-way; after it, nothing can call securify again.
The owner role also decides more than it appears to. Because an undefined role resolves to the owner rule, the owner is the effective default authority over every role the blueprint declares and the instantiator did not assign.
Roles, names, and the reserved namespace
Beyond the owner, roles are ordinary named entries. The module validates them on the way in rather than on use, and the validation is worth knowing before designing a role set:
- At most
MAX_ROLES, 50 roles per module. - A role name is at most
MAX_ROLE_NAME_LEN, 100 bytes, and must pass the same name check as other identifiers. - Every name beginning with an underscore is reserved. Attempting to define or set one fails with
UsedReservedRole. Only two reserved names are defined by the system,_owner_and_self_, and both may be referenced in a role list even though neither can be assigned. - The Role Assignment module cannot hold roles for itself. Passing it as a target module fails with
UsedReservedSpace. - The rule attached to a role is validated for depth and node count at assignment time, so an over-complex rule is rejected when it is set, not when it is tested.
Roles are also mutable by design. A role's rule can be reassigned later by whoever the object's permissions allow, which is how a project rotates a compromised admin badge or hands an authority to a governance component without redeploying. The audit trail for such a change is the transaction that made it.
How blueprints use it
A blueprint does not check roles in its method bodies. It declares, per method, one of four method accessibility values: Public, RoleProtected with a list of role names, OwnPackageOnly, or OuterObjectOnly, the last used by the Validator blueprint so that only the Consensus Manager can reach certain methods. The engine resolves the declaration to a rule through this module and tests it before the body runs.
For resources the same machinery appears under fixed names. The mint, burn, freeze, recall, deposit, withdraw, and non-fungible-data-update authorities are seven named roles on the resource manager, each with a paired _updater role, which is why a token's permissions can be read on-ledger as a set of rules and reported as locked when the updater is DenyAll. That reading is how this wiki dates a token's authorities without relying on the issuing team's description of them.
The common patterns fall out of the same two pieces: a badge requirement for admin authority, a CountOf requirement for N-of-M multi-signature, and a global_caller requirement to let one named component act on another.
External Links
- Radix Docs: Access Rules & Roles
- radixdlt-scrypto:
role_assignment.rs(OwnerRole, RoleKey, MethodAccessibility) - radixdlt-scrypto: role assignment native package (validation and reserved names)
- radixdlt-scrypto: role assignment substates (the stored shape)
- radixdlt-scrypto:
securify.rs(presecurified owner roles and the one-way securify step) - radixdlt-scrypto:
authorization.rs(role resolution and the owner fallback)
