Documentation

External Access Control (EAC)

External Access Control (EAC) is Railnet’s central Role-Based Access Control (RBAC) system. Based on OpenZeppelin’s AccessControlDefaultAdminRules, it manages permissions across all vehicles and protocol components, ensuring secure and granular control over system operations.

Role Types

EAC supports three distinct types of roles to provide flexible permission management:

Global Roles

Global roles are standard bytes32 identifiers that apply across the entire protocol. These are managed using the standard grantRole and revokeRole methods. When an account is granted a global role, it holds that permission for all protocol components that check for it.

Scoped Roles

Scoped roles are restricted to a specific contract address (the scope). This allows for fine-grained permissions, such as granting an account the ability to manage a specific vehicle without giving it permissions over all vehicles. Internally, a scoped role is represented as keccak256(abi.encodePacked(role, scope)). These are managed via grantScopedRole and revokeScopedRole.

Public Roles

Public roles are effectively granted to everyone. When a role is made public, hasRole and hasScopedRole checks for that role will always return true, regardless of the account being checked. This is useful for features that should be accessible to any user. Note that the DEFAULT_ADMIN_ROLE cannot be made public.

Admin Management

EAC implements a secure, time-delayed mechanism for transferring the default admin role:

  1. Initiation: beginDefaultAdminTransfer(newAdmin) starts the transfer process.
  2. Completion: acceptDefaultAdminTransfer() completes the transfer. This must be called by the pending admin after the required delay has passed.
  3. Delay Configuration: The delay period can be updated using changeDefaultAdminDelay(newDelay).

Key API Methods

MethodParametersDescription
grantRolerole, accountGrants a global role
revokeRolerole, accountRevokes a global role
grantScopedRolerole, scope, accountGrants a role for specific scope
revokeScopedRolerole, scope, accountRevokes a scoped role
hasRolerole, accountChecks global role (true if public)
hasScopedRolerole, scope, accountChecks scoped role (true if public)
hasRoleOrScopedRolerole, scope, accountChecks either global OR scoped
setRolePublicrole, isPublicMakes a global role public
setScopedRolePublicrole, scope, isPublicMakes a scoped role public

FreezablePausableBeacon

The EAC also manages the implementation address for beacon proxies (vehicle clones) through the FreezablePausableBeacon functionality. This component has two critical states:

  • Freeze: A permanent and irreversible state. Once frozen, the implementation address can never be upgraded again, providing a “trustless” guarantee to users that the contract logic is immutable.
  • Pause: A temporary and reversible state. While paused, the implementation() method reverts, effectively disabling all proxies that rely on this beacon.

Beacon API

  • upgradeTo(newImpl): Upgrades the implementation address (requires BEACON_UPGRADE role).
  • freeze(): Permanently freezes the beacon (requires BEACON_FREEZE role, irreversible).
  • pause() / pauseFor(period): Pauses beacon operations (requires BEACON_PAUSE role).
  • unpause(): Resumes paused beacon operations (requires BEACON_UNPAUSE role).

Complete Roles Reference

Factory Roles

RoleDescription
FACTORY_SPAWNDeploy new vehicles via a vehicle factory
FACTORY_DEPRECATEDeprecate a factory, blocking further spawns

FACTORY_SPAWN does not cover conduits. ConduitFactory.spawn checks CONDUIT_SPAWN instead, and holding FACTORY_SPAWN grants nothing there — the call reverts MissingRole(CONDUIT_SPAWN, <factory>, <caller>).

Beacon & Proxy Roles

RoleDescription
BEACON_UPGRADEUpgrade beacon implementation
BEACON_FREEZEPermanently freeze beacon (irreversible)
BEACON_PAUSEPause beacon operations
BEACON_UNPAUSEResume paused beacon

Vehicle Roles

RoleDescription
VEHICLE_STEAM_DEPOSITUse the STEAM deposit functions on a vehicle
VEHICLE_STEAM_REDEEMUse the STEAM redeem functions on a vehicle
VEHICLE_PROCESS_QUEUESubmit a size-bounded request from a vehicle’s async queues
VEHICLE_EXECTrigger module executions
VEHICLE_SET_INTERCEPTIONSConfigure reward interception rules
VEHICLE_ALLOWAllow/disallow modules on a vehicle

FeeManager Roles

RoleDescription
FEE_MANAGER_SET_FEESUpdate fee percentages
FEE_MANAGER_SET_FEE_RECIPIENTSUpdate fee recipient addresses
FEE_MANAGER_DISPATCH_ERC20Distribute collected fees

MultiVehicle Roles

RoleDescription
MULTI_VEHICLE_SET_VEHICLE_AUTHORIZATIONAuthorize/unauthorize sub-vehicles
MULTI_VEHICLE_MOVEMove assets or shares between sectors or vehicles
MULTI_VEHICLE_DISPATCHDispatch assets to sub-vehicles
MULTI_VEHICLE_SET_QUEUESConfigure deposit/redeem queues
MULTI_VEHICLE_SET_THRESHOLDSConfigure the Multi-Vehicle thresholds
MULTI_VEHICLE_DEPOSITDeposit assets into accounting engine
MULTI_VEHICLE_PROGRESS_QUERYProgress queries in the SubQueryEngine
MULTI_VEHICLE_FEED_QUERY_REDEEM_QUEUEFeed the query redeem queue
MULTI_VEHICLE_RETRIEVE_QUERY_REDEEM_QUEUE_ASSETSRetrieve redeem-queue assets back into the accounting engine

MULTI_VEHICLE_MOVE_ASSETS and MULTI_VEHICLE_MOVE_SHARES were collapsed into MULTI_VEHICLE_MOVE, and MULTI_VEHICLE_REBALANCE was removed along with the rebalance() entrypoint. Granting a removed name still succeeds and guards nothing — see the note above.

Conduit Roles

RoleDescription
CONDUIT_SPAWNDeploy a new Conduit via ConduitFactory.spawn
CONDUIT_PROCESSAdvance a Conduit query through the STEAM lifecycle
CONDUIT_FORCE_REDEEMEject a blocked or sanctioned holder
CONDUIT_SET_INTERCEPTIONSConfigure reward routing on a Conduit
CONDUIT_SET_TRANSFER_ENABLEDFlip the one-way share-transfer latch

Modules & Registry Roles

RoleDescription
MODULE_MANAGERAdd/update/remove modules
ACCOUNT_LIST_MANAGERManage an AccountList’s allow-list, block-list and sanctions oracle
ASSET_REGISTRY_SET_ASSETRegister an asset and its initial deposit amount

CANCEL_MODULE and UPDATE_TIMELOCK were listed here previously and do not exist in Roles.sol. As with the removed MultiVehicle names, granting them succeeds and guards nothing.

Keeper & Job Roles

RoleDescription
KEEPER_ON_REPORTSubmit a keeper report
JOB_LISTING_REGISTERRegister a keeper job
JOB_LISTING_UNREGISTERUnregister a keeper job
JOB_LISTING_EXECUTEExecute a listed keeper job

Usage Examples

Granting a Scoped Role

In this example, Alice is granted the VEHICLE_STEAM_DEPOSIT role specifically for a single vehicle address.

// Grant VEHICLE_STEAM_DEPOSIT to Alice for a specific vehicle
eac.grantScopedRole(VEHICLE_STEAM_DEPOSIT, vehicleAddress, aliceAddress);

Making a Role Public

In this example, the VEHICLE_STEAM_DEPOSIT role is made public for a specific vehicle, allowing anyone to perform STEAM queries on it.

// Make VEHICLE_STEAM_DEPOSIT public for a specific vehicle
eac.setScopedRolePublic(VEHICLE_STEAM_DEPOSIT, vehicleAddress, true);