For the complete documentation index, see llms.txt. This page is also available as Markdown.

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:

Item
Getter
Purpose

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:

Constant
Value
Meaning

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:

Operation
Adjustment storage key

updateTokenConfig()

n.cToken

updateDynamicIRM()

managedAddress DynamicIRM

setGuardedPriceConfig()

asset

setGuardedPriceConfigCombined()

asset

Period Limit Fields

The manager validates requested limits against hard maximums before storing them:

Constant
Value

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.

  • liqIncMin is at least MINIMUM_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.

  • timestampStart and ips match the current guard values.

  • basePrice and minPrice movements 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:

  1. The caller has normal authority over the aggregator and asset.

  2. centralRegistry.oracleManager() returns the oracle manager.

  3. IOracleManager.getPricingAdaptors(asset)[0] returns a chainlink-style adaptor.

  4. IChainlinkStyleAdaptor.assetConfig(asset, inUSD) points to managedAddress as 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:

Action
Scope
Target call

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:

Error
Meaning

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 == false can still pause any pause scope it is authorized for, but it cannot unpause through setPaused().

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?