How guardrails constrain what an asset manager can do within an Allocation Strategy — authorized sources, allocation caps, and RBAC
In Railnet smart contracts, an Allocation Strategy is implemented as a MultiVehicle. See Glossary for all terminology.
This page covers guardrails for Allocation Strategies, which use role-based access control via the External Access Control (EAC) contract. For Advanced Strategy guardrails, see Policy engine.
Guardrails define the trust boundary between the party that owns an Allocation Strategy (typically the platform deploying the Conduit) and the asset manager who operates it day-to-day. The owner sets the rules. The asset manager executes within them.
The owner retains admin control while granting the asset manager scoped operational roles. The asset manager can execute the strategy within the boundaries the owner defines — they cannot change the rules.
These controls remain exclusively with the Allocation Strategy owner and form the guardrails:
Guardrail
Role (retained by owner)
Why
Authorized yield sources
MULTI_VEHICLE_SET_VEHICLE_AUTHORIZATION
The owner decides which yield sources the strategy can use
Fee rates
FEE_MANAGER_SET_FEES
The owner controls the economics
Fee recipients
FEE_MANAGER_SET_FEE_RECIPIENTS
The owner controls revenue distribution
Role assignments
DEFAULT_ADMIN_ROLE
The owner controls who has access
Infrastructure upgrades
BEACON_UPGRADE
The owner controls contract upgrades
The asset manager operates within these boundaries. They can allocate capital, rebalance positions, and manage queues — but they cannot authorize new yield sources, change fees, or grant roles to others.
Grant the asset manager scoped roles on the appropriate contracts. All Allocation Strategy operational roles are scoped to the Sector Accounting Engine, except queue management (scoped to the Queue Strategy Engine) and query progression roles.
address am = 0x...; // Asset manager addressISectorAccountingEngine accounting = MultiVehicle(multiVehicle).accountingEngine();IQueueStrategyEngine strategy = accounting.strategyEngine();ISubQueryEngine subQueryEngine = accounting.subQueryEngine();// Core operational roles (scoped to Sector Accounting Engine)eac.grantScopedRole(keccak256("MULTI_VEHICLE_DISPATCH"), address(accounting), am);eac.grantScopedRole(keccak256("MULTI_VEHICLE_REBALANCE"), address(accounting), am);eac.grantScopedRole(keccak256("MULTI_VEHICLE_MOVE_ASSETS"), address(accounting), am);eac.grantScopedRole(keccak256("MULTI_VEHICLE_MOVE_SHARES"), address(accounting), am);// Queue management (scoped to Queue Strategy Engine)eac.grantScopedRole(keccak256("MULTI_VEHICLE_SET_QUEUES"), address(strategy), am);// Query progression (scoped to Sub Query Engine)eac.grantScopedRole(keccak256("MULTI_VEHICLE_PROGRESS_QUERY"), address(subQueryEngine), am);// Redemption queue (scoped to Multi-Vehicle)eac.grantScopedRole(keccak256("MULTI_VEHICLE_FEED_QUERY_REDEEM_QUEUE"), address(multiVehicle), am);eac.grantScopedRole(keccak256("MULTI_VEHICLE_RETRIEVE_QUERY_REDEEM_QUEUE_ASSETS"), address(multiVehicle), am);
Always verify the scope parameter matches the correct contract. Granting a role with the wrong scope will not authorize the intended operation.
You may want the asset manager (or a keeper) to handle routine fee collection:
// Allow the AM to trigger fee distribution (but NOT change fee rates or recipients)eac.grantScopedRole(keccak256("FEE_MANAGER_DISPATCH_ERC20"), address(feeManager), am);eac.grantScopedRole(keccak256("FEE_MANAGER_REDEEM_VEHICLE_SHARES"), address(feeManager), am);
To offboard an asset manager, revoke all scoped roles. Pending operations will complete, but the asset manager cannot initiate new ones.
address am = 0x...; // Asset manager to offboard// Revoke all operational roleseac.revokeScopedRole(keccak256("MULTI_VEHICLE_DISPATCH"), address(accounting), am);eac.revokeScopedRole(keccak256("MULTI_VEHICLE_REBALANCE"), address(accounting), am);eac.revokeScopedRole(keccak256("MULTI_VEHICLE_MOVE_ASSETS"), address(accounting), am);eac.revokeScopedRole(keccak256("MULTI_VEHICLE_MOVE_SHARES"), address(accounting), am);eac.revokeScopedRole(keccak256("MULTI_VEHICLE_SET_QUEUES"), address(strategy), am);eac.revokeScopedRole(keccak256("MULTI_VEHICLE_PROGRESS_QUERY"), address(subQueryEngine), am);eac.revokeScopedRole(keccak256("MULTI_VEHICLE_FEED_QUERY_REDEEM_QUEUE"), address(multiVehicle), am);eac.revokeScopedRole(keccak256("MULTI_VEHICLE_RETRIEVE_QUERY_REDEEM_QUEUE_ASSETS"), address(multiVehicle), am);// Revoke fee collection roles if grantedeac.revokeScopedRole(keccak256("FEE_MANAGER_DISPATCH_ERC20"), address(feeManager), am);eac.revokeScopedRole(keccak256("FEE_MANAGER_REDEEM_VEHICLE_SHARES"), address(feeManager), am);
Before offboarding, ensure there are no in-progress queries that require the asset manager’s roles to complete. Check the query state via the subgraph.