Sources:src/modules/ACLModule.sol·FundRoles.sol·FundSpokeACLModule.sol·FundACLModule.sol·FundManagerACLModule.sol·StrategyACLModule.sol
The two auth patterns
- Local ACL (`ACLModule`)
- Spoke callback ACL (`FundSpokeACLModule`)
OpenZeppelin
AccessControlEnumerable + Multicall, plus batch grantRoles/revokeRoles (admin-only) and constructor-time role seeding via RoleHolder[] {role, account}.Used directly by contracts that own their role state:Fund role table (FundRoles)
All identifiers are keccak256("<NAME>"). “Enforced by” shows where the guarded function lives.
Other role tables
Upgrade authority
Every contract is aTransparentUpgradeableProxy; upgrade rights belong to whoever owns each proxy’s auto-deployed ProxyAdmin — the proxyAdmin address chosen at tenant/fund creation.
Roles govern behavior; ProxyAdmin ownership governs code.The two are deliberately independent: an operator can hold rich behavioral roles without any ability to change contract code, and the upgrade authority can change code without holding any operational role.
Separation-of-duties guidance
Because roles can be split across parties and keys, funds should distribute them rather than concentrating everything in one account. Common splits:- Keep the reporter (
SUBMIT_REPORT_ROLE) separate from the acceptor (ACCEPT_REPORT_ROLE). - Give a third party the reviewer veto (
REJECT_REPORT_ROLE). - Hold
ACCEPT_SUSPICIOUS_REPORT_ROLEandEMERGENCY_PAUSE_ROLEon more secure keys. - Keep
DEFAULT_ADMIN_ROLEand ProxyAdmin ownership on the most protected keys of all.