Skip to main content

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 addresses
  • roles: 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 addresses
  • roles: 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 implementing IEmergencyShutdown

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 update
  • lendingIds: Array of new lending module identifiers
  • bearingTokens: 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 addresses
  • params: Array of initialization parameters (empty to skip initialization)

Process:

  1. Gets latest implementation from VaultFactory
  2. Upgrades each vault proxy
  3. 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 addresses
  • admins: 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

  1. Test role changes on testnets before mainnet execution
  2. Use timelock contracts for critical parameter changes
  3. Coordinate with community before emergency shutdowns
  4. Validate all addresses before batch operations

For Upgrades

  1. Audit new implementations thoroughly
  2. Test migration procedures on testnets
  3. Prepare rollback plans for failed upgrades
  4. Communicate upgrade schedules to users

Security Considerations

  1. Manager has elevated privileges across the protocol
  2. Compromise of Manager could affect entire protocol
  3. Consider multi-signature wallet for Manager admin role
  4. 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.