ProtocolManager
Overview
ProtocolManager is a capability-gated configuration hub for designated Curvance protocol addresses. It lets a configured authority address modify approved market, IRM, oracle guard, pause, and position-manager settings while enforcing per-period adjustment limits where the manager supports bounded changes.
The contract is intended for internal governance operations. It does not own the target contracts by itself; the target contracts still check CentralRegistry permissions when ProtocolManager calls them.
Core Architecture
ProtocolManager stores:
Central registry
centralRegistry()
Permission hub used by this manager and downstream target contracts.
Operational authority
protocolManager()
Address allowed to call the bounded operational functions.
Capability flags
canModifyTokenConfig(), canModifyPriceGuards(), and related getters
Immutable switches that decide which operation families this manager can perform.
Managed address config
config(address)
Per-address authority bit and PeriodLimits.
Period adjustments
getMarketPeriodAdjustments() and getPriceGuardPeriodAdjustments()
Per-period accounting used to enforce bounded configuration movement.
Only elevated-permission addresses can call updateManagementConfig(). All other mutating operations require msg.sender == protocolManager, the matching capability flag, and authority over the managed address.
Managed Configuration
The constructor accepts a PermsConfig, an initial list of managed addresses, and one PeriodLimits struct for each address.
struct ManagementConfig {
bool hasAuthority;
PeriodLimits limits;
}
struct PermsConfig {
bool canModifyPriceGuards;
bool canDisablePriceGuards;
bool canModifyTokenConfig;
bool canModifyIRM;
bool canUnpause;
bool canModifyMintStatus;
bool canModifyCollateralizationStatus;
bool canModifyBorrowStatus;
bool canModifyLiquidationStatus;
bool canModifyRedeemStatus;
bool canModifyTransferStatus;
bool canModifyPositionManagers;
}updateManagementConfig() can add or remove authority for addresses. When hasAuthority is false, the manager deletes that address's stored limits.
Period Limit Model
ProtocolManager buckets adjustments into one-week periods:
PERIOD_DURATION
604800
Period length in seconds.
_UNIX_START_TIMESTAMP
1766966400
Internal timestamp anchor used to derive period starts.
For bounded changes, the manager computes:
The absolute value of that adjustment must be less than or equal to the relevant PeriodLimits field. If it exceeds the limit, the call reverts with ProtocolManager__ParametersAreInvalid().
The adjustment key depends on the operation:
updateTokenConfig()
n.cToken
updateDynamicIRM()
managedAddress DynamicIRM
setGuardedPriceConfig()
asset
setGuardedPriceConfigCombined()
asset
Period Limit Fields
The manager validates requested limits against hard maximums before storing them:
MAXIMUM_COLL_RATIO_LIMIT
500
MAXIMUM_COLL_REQ_LIMIT
500
MAXIMUM_COLL_CAP_LIMIT
type(uint112).max
MAXIMUM_DEBT_CAP_LIMIT
type(uint104).max
MAXIMUM_INTEREST_RATE_LIMIT
1000
MAXIMUM_ADJUSTMENT_VELOCITY_LIMIT
300
MAXIMUM_DECAY_RATE_LIMIT
120
MAXIMUM_VERTEX_MULTIPLIER_MAX_LIMIT
50000
MAXIMUM_PRICE_GUARD_PRICE_LIMIT
type(uint88).max
MINIMUM_LIQUIDATION_INCENTIVE is 150; updateTokenConfig() rejects any token config where liqIncMin is below that floor.
Operation Groups
Market Token Config
updateTokenConfig() forwards a MarketManagerIsolated.TokenConfig to a managed market manager after checking:
This manager can modify token configs.
The managed market manager has authority.
The cToken in the config has authority.
The cToken is listed in the target market.
liqIncMinis at leastMINIMUM_LIQUIDATION_INCENTIVE.The period adjustments for collateral ratio, collateral requirements, collateral cap, and debt cap stay within the cToken's limits.
The TokenConfig field order is:
Dynamic IRM Config
updateDynamicIRM() updates a managed DynamicIRM. Inputs use per-year and BPS values, while the target DynamicIRM stores per-second rate fields internally. Before forwarding the update, ProtocolManager converts the current per-second rates back to BPS for period-limit accounting.
The tracked fields are baseRatePerYear, vertexRatePerYear, vertexStart, adjustmentVelocity, decayPerAdjustment, and vertexMultiplierMax.
Price Guards
setGuardedPriceConfig() changes a BaseOracleAdaptor guard for a specific (asset, inUSD) route. The manager requires:
Authority over the adaptor address.
Authority over the asset.
canModifyPriceGuards == true.The adaptor supports the asset.
timestampStartandipsmatch the current guard values.basePriceandminPricemovements stay within the asset's period limits.
disableGuardedPriceConfig() removes an adaptor guard for (asset, inUSD). It uses canDisablePriceGuards, not canModifyPriceGuards, and does not apply period limits.
Combined Aggregator Guards
setGuardedPriceConfigCombined() and disableGuardedPriceConfigCombined() operate on CombinedAggregator, which has one global pg() guard instead of per-asset guard storage.
Before mutating the aggregator, _checkCombinedAggregatorAuthority() confirms:
The caller has normal authority over the aggregator and asset.
centralRegistry.oracleManager()returns the oracle manager.IOracleManager.getPricingAdaptors(asset)[0]returns a chainlink-style adaptor.IChainlinkStyleAdaptor.assetConfig(asset, inUSD)points tomanagedAddressas the configured aggregator.
This route check prevents a manager from changing a combined aggregator guard without proving that the aggregator is the active route for the authorized asset and denomination.
Pause Flags
setPaused() maps action values to market pause setters:
0
Market-wide liquidation
setLiquidationPaused(state)
1
Market-wide redeem
setRedeemPaused(state)
2
Market-wide transfer
setTransferPaused(state)
3
Token-level mint
setMintPaused(cToken, state)
4
Token-level collateralization
setCollateralizationPaused(cToken, state)
5
Token-level borrow
setBorrowPaused(cToken, state)
For token-level actions, the cToken must also have authority. If state is false, canUnpause must be true or the call reverts.
Position Managers
updatePositionManager() adds or removes a position manager on a managed market manager. The operation requires canModifyPositionManagers and authority over the market manager.
Events and Errors
ProtocolManager emits ManagementAuthorityUpdated(address addressManaged, bool manages, PeriodLimits limits) whenever management configuration changes.
The contract defines these custom errors:
ProtocolManager__ParametersAreInvalid()
Input validation, limit validation, asset support, or action ID checks failed.
ProtocolManager__Unauthorized()
Caller, capability flag, managed address, or asset authority check failed.
ProtocolManager__MulDivFailed()
Internal multiplication/division helper failed.
ProtocolManager__UintToIntError()
Internal signed conversion would overflow.
Integration Considerations
Confirm the manager contract itself has market permissions before expecting downstream writes to succeed.
Configure both the target address and any relevant asset address in
config(address)before using asset-scoped functions.Use the current
getPeriodTimestamp()value when querying period adjustments for the active period.Query token config adjustments by cToken address, not by market manager address.
Query PriceGuard adjustments by asset address, not by adaptor or aggregator address.
Do not use
disableGuardedPriceConfig*()as a bounded PriceGuard update. Disabling guards is a separate capability that bypasses period-limit accounting.A manager with
canUnpause == falsecan still pause any pause scope it is authorized for, but it cannot unpause throughsetPaused().
Callable Functions
Constructor
Deploys the manager, validates the central registry, stores the operational authority, configures the initial managed addresses, and stores immutable capability flags.
Configuration Reads
Use these reads to inspect the configured managed set, current period bucket, and tracked adjustments. Compiler-generated getters also expose the immutable capability flags, constants, centralRegistry(), and protocolManager().
Management Configuration
Adds or removes managed-address authority. Only an address with elevated permissions in the central registry can call this function.
Token Config
Applies a token config to a managed MarketManagerIsolated. Requires token-config capability, authority over the market and cToken, and period-limit compliance for the tracked fields.
Dynamic IRM
Updates a managed DynamicIRM after applying period-limit accounting to the IRM parameters.
Price Guards
The set* functions enforce PriceGuard period limits. The disable* functions use the separate disable capability and bypass period-limit accounting.
Pause Flags
Sets one market-wide or token-level pause flag. Pass address(0) for cToken when action is 0, 1, or 2.
Position Managers
Adds or removes pm as a position manager on a managed MarketManagerIsolated.
Last updated
Was this helpful?