Manager
Overview
The Manager contract (src/Manager.sol) serves as the centralized access control and governance hub for the Citadel Finance protocol. It provides administrative functions for role management, emergency controls, and protocol maintenance across multiple contracts.
Purpose
- Centralized Governance: Single point for protocol-wide administrative actions
- Role Management: Batch operations for granting/revoking roles across contracts
- Emergency Controls: Circuit breakers and emergency shutdown capabilities
- Protocol Upgrades: Coordinated upgrades for vaults and lending modules
Contract Details
- File:
src/Manager.sol - Inheritance:
ISynthereumManager,ReentrancyGuard,AccessControlEnumerable - License: AGPL-3.0-only
Key Functions
Role Management
grantSynthereumRole
function grantSynthereumRole(
address[] calldata contracts,
bytes32[] calldata roles,
address[] calldata accounts
) external override onlyMaintainerOrDeployer nonReentrant
Purpose: Grants roles across multiple contracts in a single transaction.
Parameters:
contracts: Array of contract addressesroles: Array of role identifiers (bytes32)accounts: Array of addresses to receive roles
Requirements: All arrays must have same length Access Control: Maintainer or Deployer only
revokeSynthereumRole
function revokeSynthereumRole(
address[] calldata contracts,
bytes32[] calldata roles,
address[] calldata accounts
) external override onlyMaintainerOrDeployer nonReentrant
Purpose: Revokes roles across multiple contracts in a single transaction.
Parameters: Same as grantSynthereumRole
Access Control: Maintainer or Deployer only
renounceSynthereumRole
function renounceSynthereumRole(
address[] calldata contracts,
bytes32[] calldata roles
) external override onlyMaintainerOrDeployer nonReentrant
Purpose: Renounces Manager's own roles across multiple contracts.
Parameters:
contracts: Array of contract addressesroles: Array of role identifiers to renounce
Access Control: Maintainer or Deployer only
Emergency Controls
emergencyShutdown
function emergencyShutdown(IEmergencyShutdown[] calldata contracts)
external
override
onlyMaintainer
nonReentrant
Purpose: Triggers emergency shutdown on multiple pools or derivatives.
Parameters:
contracts: Array of contracts implementingIEmergencyShutdown
Access Control: Maintainer only Use Case: Market crisis, security breach, or critical bug discovery
Protocol Operations
switchLendingModule
function switchLendingModule(
ISynthereumLendingSwitch[] calldata pools,
string[] calldata lendingIds,
address[] calldata bearingTokens
) external override onlyMaintainer nonReentrant
Purpose: Changes lending protocol for multiple pools simultaneously.
Parameters:
pools: Array of pools to updatelendingIds: Array of new lending module identifiersbearingTokens: Array of interest-bearing tokens
Requirements: All arrays must have same length Access Control: Maintainer only
Vault Management
upgradePublicVault
function upgradePublicVault(address[] memory vaults, bytes[] memory params)
external
override
onlyMaintainer
nonReentrant
Purpose: Upgrades implementation logic for multiple vaults to the latest version.
Parameters:
vaults: Array of vault proxy addressesparams: Array of initialization parameters (empty to skip initialization)
Process:
- Gets latest implementation from VaultFactory
- Upgrades each vault proxy
- Optionally initializes with new parameters
Access Control: Maintainer only
changePublicVaultAdmin
function changePublicVaultAdmin(
address[] memory vaults,
address[] memory admins
) external override onlyMaintainer nonReentrant
Purpose: Updates proxy admin addresses for multiple vaults.
Parameters:
vaults: Array of vault proxy addressesadmins: Array of new admin addresses
Requirements: Arrays must have same length Access Control: Maintainer only
getCurrentVaultImplementation
function getCurrentVaultImplementation(address vaultProxy)
external
override
view
returns (address)
Purpose: Returns the current implementation address for a vault proxy.
Parameters:
vaultProxy: Address of the vault proxy
Returns: Address of current implementation contract
Access Control
Roles
- DEFAULT_ADMIN_ROLE: Can manage role assignments and set role admins
- MAINTAINER_ROLE: Can perform most operational functions
Modifiers
onlyMaintainer
modifier onlyMaintainer() {
require(
hasRole(MAINTAINER_ROLE, msg.sender),
'Sender must be the maintainer'
);
_;
}
onlyMaintainerOrDeployer
modifier onlyMaintainerOrDeployer() {
require(
hasRole(MAINTAINER_ROLE, msg.sender) ||
synthereumFinder.getImplementationAddress(SynthereumInterfaces.Deployer) == msg.sender,
'Sender must be the maintainer or the deployer'
);
_;
}
Role Structure
struct Roles {
address admin;
address maintainer;
}
Storage
ISynthereumFinder public immutable synthereumFinder;
The Manager maintains a reference to the Finder for service discovery, particularly for identifying the Deployer contract.
Security Features
Reentrancy Protection
All external functions use nonReentrant modifier to prevent reentrancy attacks.
Batch Validation
- Array length validation prevents mismatched parameters
- Non-empty array requirements prevent no-op transactions
Role Verification
- Deployer identification through Finder contract
- Hierarchical role structure with admin oversight
Usage Examples
Batch Role Grant
address[] memory contracts = [poolA, poolB, poolC];
bytes32[] memory roles = [MAINTAINER_ROLE, MAINTAINER_ROLE, MAINTAINER_ROLE];
address[] memory accounts = [newMaintainer, newMaintainer, newMaintainer];
manager.grantSynthereumRole(contracts, roles, accounts);
Emergency Shutdown
IEmergencyShutdown[] memory pools = [poolA, poolB];
manager.emergencyShutdown(pools);
Lending Module Switch
ISynthereumLendingSwitch[] memory pools = [poolA];
string[] memory lendingIds = ["Compound"];
address[] memory bearingTokens = [cUSDC];
manager.switchLendingModule(pools, lendingIds, bearingTokens);
Integration Points
Dependencies
- Finder: Service discovery for Deployer and VaultFactory
- AccessControlEnumerable: Role management infrastructure
- ReentrancyGuard: Security protection
Used By
- Protocol Governance: For administrative actions
- Emergency Response: For crisis management
- Upgrade Procedures: For protocol evolution
Events
The Manager contract inherits events from OpenZeppelin's AccessControlEnumerable:
RoleGranted(bytes32 indexed role, address indexed account, address indexed sender)RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender)
Best Practices
For Governance
- Test role changes on testnets before mainnet execution
- Use timelock contracts for critical parameter changes
- Coordinate with community before emergency shutdowns
- Validate all addresses before batch operations
For Upgrades
- Audit new implementations thoroughly
- Test migration procedures on testnets
- Prepare rollback plans for failed upgrades
- Communicate upgrade schedules to users
Security Considerations
- Manager has elevated privileges across the protocol
- Compromise of Manager could affect entire protocol
- Consider multi-signature wallet for Manager admin role
- Monitor all Manager transactions for suspicious activity
The Manager contract is the governance backbone of Citadel Finance, providing secure and efficient administration across the entire protocol ecosystem.