Sources:src/modules/ACLModule.sol·FundRoles.sol·FundSpokeACLModule.sol·FundACLModule.sol·FundManagerACLModule.sol·StrategyACLModule.sol
Two auth patterns
- Local ACL (`ACLModule`)
- Spoke callback ACL (`FundSpokeACLModule`)
OpenZeppelin
AccessControlEnumerable + Multicall, with batch grantRoles/revokeRoles (admin-only) and constructor seeding via RoleHolder[] {role, account}.Contracts that own 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. An operator can hold operational roles without upgrade rights; upgrade authority need not hold operational roles.
Separation of duties
Prefer split keys over one account holding everything:- Reporter (
SUBMIT_REPORT_ROLE) ≠ acceptor (ACCEPT_REPORT_ROLE) - Third party for reviewer veto (
REJECT_REPORT_ROLE) ACCEPT_SUSPICIOUS_REPORT_ROLEandEMERGENCY_PAUSE_ROLEon higher-security keysDEFAULT_ADMIN_ROLEand ProxyAdmin ownership on the most protected keys