For the complete documentation index, see llms.txt. This page is also available as Markdown.

25. Commission a suite and grant roles

Commissioning wires a deployed suite to its access manager: it maps every privileged function to a role of the Issuer's domain and sets which role administers which. Granting then gives those roles to the Issuer's operators. The Issuer triggers both, right after deployment. Until they are done, the suite is not operable: every privileged function answers to the holder of ADMIN_ROLE only, the token holds no AGENT role and the registry no IRS_WRITER.

When the TREXFactory deployed the access manager, the suite is already commissioned: step 2 is skipped.

An Issuer that supplied its own manager at deployment commissions the suite itself, in step 2. Such a manager comes from one of two sources.

Source of the manager
Who answers for its code

The access manager factory of the T-REX Network [[TBC: name of the access manager factory and of its deployment function]]

The T-REX Network. The factory deploys the reference TREXAccessManager of the network.

Any other deployment

The Issuer. The T-REX Network does not review that contract.

In both cases the Issuer decides who holds which role. The protocol sets the roles and what each one gates. It does not prescribe how an Issuer splits them between its teams and its providers.

At a glance

Triggered by

Issuer

Actors

Issuer, Token Agent, Registry Agent, Compliance Owner, Platform

Contracts

TREXAccessManager, Token, TREXRegistry, IdentityRegistryStorage, ModularCompliance

Preconditions

The token suite is deployed (see 01); the Issuer's account holds ADMIN_ROLE on the suite's TREXAccessManager; the Issuer has decided which account receives which role

Result

Every privileged function of the suite is mapped to a role of the Issuer's domain, and the accounts the Issuer chose hold those roles

Actors and roles

Actor
Role in this flow
What they hold

Issuer

Commissions the suite and grants the administrative roles.

ADMIN_ROLE on the TREXAccessManager

Token Agent

Receives agent roles on the token. Does not transact in this flow.

An account or an ONCHAINID that receives the roles

Registry Agent

Receives the AGENT role. Does not transact. Typically the same operator as the Token Agent.

An account that receives the role

Compliance Owner

Receives OWNER. Usually the Issuer itself.

An account that receives the role

Platform

Computes role identifiers, runs the reads and submits with the Issuer's key.

The Issuer's signing key, or a key authorized for it

Sequence

Step by step

Step 1. Read the starting state

Who: Platform, on behalf of the Issuer

Call: Off-chain, using read calls

Before the call: The Platform knows the token's address.

What happens: The Platform reads Token.authority() to find the manager, TREXAccessManager.domainOf(token) to find the domain, and TREXAccessManager.getTargetFunctionRole(token, selector) for one privileged function, for example mint. A domain of zero, or a function still mapped to ADMIN_ROLE, means the suite is not commissioned.

What changes: Nothing on-chain.

Step 2. Commission the suite

Skip this step when the factory deployed the manager.

Who: Issuer (ADMIN_ROLE)

Call: The commissioning of AccessManagerSetupLib.commissionSuite(accessManager, token), executed from a script or a contract that holds ADMIN_ROLE. Before it: TREXAccessManager.createDomain(name) for a new domain, then TREXAccessManager.assign(domainId, token) in every case. The commissioning then makes these calls on the manager and on the storage:

  • assign(domainId, storage), when the storage has no domain yet;

  • grantRole of AGENT to the token, and of IRS_WRITER to the registry;

  • setTargetFunctionRole(target, selectors, roleId) for the token, the registry, the compliance and the storage;

  • setRoleAdmin(roleId, adminRoleId) for each role;

  • IdentityRegistryStorage.bindIdentityRegistry(registry), unless the registry is already bound.

Before the call: The Issuer chooses the domain: a new one for this asset, or an existing one, in which case the asset shares the agents of that domain.

What the contract checks:

  1. The caller holds ADMIN_ROLE on the manager, for every mapping and for the two grants. Otherwise the call reverts with AccessManagerUnauthorizedAccount.

  2. The domain exists and the token is assigned to one. Otherwise DomainNotFound or NotAssigned.

  3. When the storage is already in use by another suite: the caller holds IRS_BINDER in the storage's domain. Otherwise the binding reverts with AccessManagedUnauthorized.

What changes: Every privileged function of the four contracts is mapped to its role in the domain. AGENT_ADMIN administers the agent roles, IRS_BINDER and VALIDATION_KEEPER. SUITE_ADMIN administers TOKEN_MANAGER, IDENTITY_MANAGER and COMPLIANCE_MANAGER. The token holds AGENT and the registry holds IRS_WRITER. The registry is bound to its storage. The manager emits DomainCreated, DomainAssigned, TargetFunctionRoleUpdated, RoleAdminChanged and RoleGranted.

Step 3. Grant the administrative roles

Who: Issuer (ADMIN_ROLE)

Call: TREXAccessManager.grantRole(roleId, account, executionDelay), once per role and account

Before the call: The Platform computes each role identifier from the domain and the role number:

roleId = domainId * 2^32 + roleNumber

Role
Number
Role
Number

OWNER

1

TOKEN_MANAGER

10

AGENT

2

IDENTITY_MANAGER

11

AGENT_MINTER

3

AGENT_ADMIN

12

AGENT_BURNER

4

SUITE_ADMIN

13

AGENT_PARTIAL_FREEZER

5

IRS_BINDER

14

AGENT_ADDRESS_FREEZER

6

IRS_WRITER

15

AGENT_RECOVERY_ADDRESS

7

COMPLIANCE_MANAGER

16

AGENT_FORCED_TRANSFER

8

VALIDATION_KEEPER

17

AGENT_PAUSER

9

The Issuer grants OWNER, SUITE_ADMIN and AGENT_ADMIN. executionDelay is zero for a role whose holder acts at once, or a number of seconds for a role whose holder must schedule its calls.

What the contract checks:

  1. The caller holds the role that administers roleId. For these three roles that is ADMIN_ROLE. Otherwise AccessManagerUnauthorizedAccount.

What changes: The account holds the role in the domain. The manager emits RoleGranted(roleId, account, delay, since, newMember).

Step 4. Grant the operational roles

Who: The holders of SUITE_ADMIN and of AGENT_ADMIN, or the Issuer after granting itself those roles

Call: TREXAccessManager.grantRole(roleId, account, executionDelay)

Before the call: Step 3 is done. The Issuer has decided how to split duties.

What the contract checks:

  1. The caller holds the role that administers roleId: SUITE_ADMIN for TOKEN_MANAGER, IDENTITY_MANAGER and COMPLIANCE_MANAGER; AGENT_ADMIN for AGENT, the seven agent roles, IRS_BINDER and VALIDATION_KEEPER. Otherwise AccessManagerUnauthorizedAccount.

What changes: Each account holds its role. One RoleGranted event per grant.

Step 5. Verify

Who: Platform

Call: Off-chain, using read calls

Before the call: Steps 3 and 4 are confirmed.

What happens: For each grant, the Platform reads TREXAccessManager.hasRole(roleId, account), which returns whether the account is a member and with what delay. For one function per role, it reads TREXAccessManager.canCall(account, target, selector).

What changes: Nothing on-chain.

State after the flow

  • TREXAccessManager.domainOf(token) returns the Issuer's domain.

  • getTargetFunctionRole returns a role of that domain for every privileged function of the token, the registry, the compliance and the storage.

  • hasRole is true for each account and role the Issuer granted.

  • The token holds AGENT and the registry holds IRS_WRITER.

  • The token is still paused and has no supply.

Failure modes

Symptom
Cause
Fix

A privileged call on the suite reverts with AccessManagedUnauthorized

The caller does not hold the role, or holds it in another domain

Read hasRole with the identifier of the token's domain. Grant the role

A privileged call reverts with AccessManagerNotScheduled

The caller holds the role with an execution delay and did not schedule the call

Schedule the call on the manager, wait for the delay, then call

Every privileged call by an operator reverts, although its role is granted

The suite is not commissioned: its functions are not mapped, and answer to ADMIN_ROLE only (step 2)

Commission the suite

Commissioning reverts with NotAssigned

The token is not assigned to a domain (step 2, check 2)

assign(domainId, token) first

grantRole reverts with AccessManagerUnauthorizedAccount

The caller does not hold the administering role (steps 3 and 4)

Use the account that holds ADMIN_ROLE, SUITE_ADMIN or AGENT_ADMIN, as the role requires

A recovery reverts when it registers the new wallet

The token does not hold AGENT in its domain

Commission the suite again. It grants the role

A registration reverts in the storage

The registry does not hold IRS_WRITER, or is not bound to the storage

Commission the suite again

An operator can act on another asset of the Issuer

Both assets are in the same domain

Intended for a shared team. Otherwise place the assets in separate domains

A batch call reverts for a holder that has a delay

A batch function is authorized by the role of its single operation and requires immediate permission. batchRegisterIdentity is the exception: it has its own mapping and can be scheduled

Use the single operation, scheduled, or grant the role without delay

Common misunderstandings

Wrong: "The admin of the manager can mint."

Right: ADMIN_ROLE maps functions to roles and grants roles. Once the suite is commissioned, mint is gated by AGENT_MINTER, and the admin does not hold it unless it grants it to itself. Administering the suite and operating the token are separate powers.

Wrong: "Granting AGENT makes someone the token's agent."

Right: AGENT gates registrations in the registry and requests of cross-chain validations on behalf of holders. Minting, burning, freezing, forced transfers, recovery and the pause are seven separate roles, each granted on its own.

Wrong: "A role is granted on a token."

Right: A role is granted in a domain. It applies to every token assigned to that domain. Two tokens in one domain share their agents. To separate the teams of two assets, place the assets in two domains.

Wrong: "Assigning a token to a domain gives that domain's roles power over it."

Right: The domain registry is a directory. Authority comes from the mapping of each function to a role, which commissioning writes. assign alone maps nothing and revokes nothing.

Integration notes

  • Compute role identifiers from the domain read on-chain, never from a constant. The same role has a different identifier in each domain.

  • Decode RoleGranted and RoleRevoked events to maintain the list of role holders: the domain is the upper half of the identifier and the role number the lower half.

  • Group the grants of steps 3 and 4 in one transaction with the manager's multicall.

  • Give the sensitive roles a delay and the emergency roles none. A pauser acts at once. A change of compliance rules can wait.

  • A role can be held by an ONCHAINID. The role check applies to the identity that makes the call, not to the key that instructed it.

  • Commissioning can be run again. It applies the same mappings.

  • Hold ADMIN_ROLE in a multisig or in the Issuer's governance. It has no on-chain fallback.

  • For an asset open on satellites, grant VALIDATION_KEEPER to the keeper that the T-REX Network runs: 35. [[TBC: the address of the keeper of the T-REX Network]]

  • createDomain, assign and domainOf are functions of TREXAccessManager. A manager from another source may not have them. The Issuer then chooses the domain number of each asset and keeps it in its own records. A manager from the access manager factory of the T-REX Network avoids this.

Last updated