RiskManager
On-chain risk control and allocation policy manager for modular vaults.
The RiskManager
contract defines and enforces asset deposit limits across a Vault
and its associated Subvaults
. It maintains internal accounting of balances, limits and allowed subvault assets.
Purpose
This contract is a centralized module responsible for:
Defining and enforcing deposit limits at vault and subvault levels.
Allowlisting or disallowing specific assets per subvault.
Tracking pending balances (deposits/withdrawals that are not yet finalized).
Validating risk assumptions through oracle price reports.
Core Concepts
Vault Limit: Global cap across all assets managed by the vault (in shares).
Subvault Limit: Individual cap per subvault, enforced independently (in shares).
Allowed Assets: Only explicitly allowlisted assets are permitted in a given subvault.
Pending Assets: Temporarily tracked assets, e.g., during deposit queueing
Shares Conversion: All balances are internally tracked in shares, calculated using latest report in the
Oracle
contract.
Storage Slot
Utilizes a deterministic storage slot computed via SlotLibrary.getSlot("RiskManager", name, version)
to ensure safe upgrades and modular deployment.
Roles and Permissions
The contract uses fine-grained access roles:
SET_VAULT_LIMIT_ROLE
: Can modify global vault capacity.SET_SUBVAULT_LIMIT_ROLE
: Can change limits on individual subvaults.ALLOW_SUBVAULT_ASSETS_ROLE
: Can whitelist assets for specific subvaults.DISALLOW_SUBVAULT_ASSETS_ROLE
: Can revoke asset approval from subvaults.MODIFY_PENDING_ASSETS_ROLE
: Can manipulate pending balance delta.MODIFY_VAULT_BALANCE_ROLE
: Can update the vault's live balance.MODIFY_SUBVAULT_BALANCE_ROLE
: Can update a subvault’s internal balance.
Roles are verified via the vault's ACL module (IACLModule
) or allowed queues (IShareModule
).
Key Methods
View
vault()
: Returns the vault address.vaultState()
: Returns the global vault state (limit, balance).pendingBalance()
: Returns the pending share balance across all assets and deposit queues.subvaultState(address)
: Returns per-subvault state.pendingAssets(address)
: Returns currently pending asset amount.pendingShares(address)
: Returns share-equivalent of pending assets.allowedAssets(address)
: Count of allowed assets in subvault.allowedAssetAt(address, index)
: Indexed lookup of allowed asset.isAllowedAsset(address, asset)
: Checks asset permission for subvault.convertToShares(asset, value)
: Converts amount to share units using oracle.maxDeposit(subvault, asset)
: Calculates max deposit amount given limits and prices.
Mutable
initialize(bytes data)
: Initializes vault-wide limit.setVault(address)
: Assigns the vault address (one-time only).setVaultLimit(int256 limit)
: Updates vault's global limit.setSubvaultLimit(address, int256)
: Updates limit for a specific subvault.allowSubvaultAssets(address, address[])
: Adds assets to subvault's allowlist.disallowSubvaultAssets(address, address[])
: Removes assets from allowlist.modifyPendingAssets(address, int256)
: Adjusts pending assets and updates internal shares.modifyVaultBalance(address, int256)
: Applies a delta to vault's current balance (with limit checks).modifySubvaultBalance(address, asset, int256)
: Same as above, but scoped to a specific subvault.
Internal Mechanics
Conversion to Shares
Conversion is done with oracle price data, where:
shares = (value * priceD18) / 1e18
Assumptions
The system assumes that:
The vault and its subvaults operate exclusively with correlated assets, and
Protocol-level delegations performed by the curator do not introduce extreme APR variance or significant principal loss.
Given this, all vault- and subvault-level limits are treated as approximate and are computed using the most recent oracle report available at the time of the state update (e.g., on pull/push or deposit/redeem operations).
If actual balances deviate significantly from the stored balance
values due to oracle drift, delayed execution, or protocol-side changes, a trusted actor can apply a ‘corrections’ to mitigate the difference:
modifyVaultBalance
for the Vault, ormodifySubvaultBalance
for individual Subvaults.
Since the system is expected to hold only correlated assets, such manual adjustments are assumed to be rare under normal operating conditions.