Crypto Training
Mellow Flexible Vaults: Architecture, Workflows, and Security Model
A code-level deep dive into Mellow Flexible Vaults: core modules, queue-driven fund flows, curator execution, oracle reporting, and security boundaries.
Mellow Flexible Vaults are not a single vault contract. They are a modular system where accounting, risk, queue processing, oracle reporting, and strategy execution are split across specialized contracts.
This post maps that system from code, then follows funds end-to-end across deposits, strategy execution, and redemptions.
All contract links in this article point to the public repository:
Why this architecture exists#
The design goal is to separate:
- user onboarding/offboarding (queue contracts)
- share accounting and fees (share manager + fee manager)
- risk limits (risk manager)
- strategy execution (subvault + verifier + call module)
- report ingestion and settlement cadence (oracle)
That separation lets a single core vault support multiple assets and multiple curator strategies while keeping strict role boundaries.
Contract map by responsibility#
| Responsibility | Key contracts |
|---|---|
| Core vault composition | src/vaults/Vault.sol, src/modules/VaultModule.sol, src/modules/ShareModule.sol |
| Strategy container | src/vaults/Subvault.sol, src/modules/SubvaultModule.sol, src/modules/CallModule.sol, src/modules/VerifierModule.sol |
| Call permissions | src/permissions/Verifier.sol, src/permissions/BitmaskVerifier.sol |
| Async onboarding/offboarding | src/queues/DepositQueue.sol, src/queues/RedeemQueue.sol, src/queues/Queue.sol |
| Oracle/report processing | src/oracles/Oracle.sol, src/oracles/OracleHelper.sol, src/oracles/OracleSubmitter.sol |
| Accounting and limits | src/managers/ShareManager.sol, src/managers/TokenizedShareManager.sol, src/managers/FeeManager.sol, src/managers/RiskManager.sol |
| Liquidity hooks | src/hooks/BasicRedeemHook.sol, src/hooks/RedirectingDepositHook.sol, src/hooks/LidoDepositHook.sol |
| Deployment wiring | src/vaults/VaultConfigurator.sol, src/factories/Factory.sol |
Roles and authority boundaries#
The ACL root sits on the Vault (ACLModule + MellowACL), and many dependent contracts check Vault roles directly.
Example: Verifier.sol enforces call policies, but allowCalls, disallowCalls, setMerkleRoot are authorized by vault().hasRole(...).
Key role families:
- Vault lifecycle and structure:
CREATE_SUBVAULT_ROLE,DISCONNECT_SUBVAULT_ROLE,RECONNECT_SUBVAULT_ROLE,PUSH_LIQUIDITY_ROLE,PULL_LIQUIDITY_ROLEinVaultModule.sol - Queue lifecycle:
CREATE_QUEUE_ROLE,SET_QUEUE_STATUS_ROLE,REMOVE_QUEUE_ROLEinShareModule.sol - Oracle operations:
SUBMIT_REPORTS_ROLE,ACCEPT_REPORT_ROLE,SET_SECURITY_PARAMS_ROLEinOracle.sol - Strategy call permissions:
CALLER_ROLE,ALLOW_CALL_ROLE,DISALLOW_CALL_ROLE,SET_MERKLE_ROOT_ROLEinVerifier.sol
Deployment workflow (what gets wired first)#
VaultConfigurator.create(...) deploys managers and oracle via factories, then vault, then back-links manager/oracle to the vault.
Reference: VaultConfigurator.sol.
Async deposit flow (request -> report -> claim shares)#
Step-by-step#
- User calls
DepositQueue.deposit(...). - Queue checks depositor whitelist through ShareManager (
isDepositorWhitelisted). - Assets are received by queue and pending balances are updated in RiskManager.
- Oracle report arrives, ShareModule routes it to deposit queues with
depositTimestamp. - Queue settles eligible requests, transfers settled assets to Vault, allocates/mints shares, emits claimability.
- User or any caller executes
claimShares(account)on Vault/ShareModule.
References:
Deposit queue state machine#
Async redeem flow (request -> batches -> claim assets)#
RedeemQueue is batch-oriented:
- user locks shares
- oracle report converts pending shares into asset demand batches
handleBatches(n)releases only what liquid assets can satisfy- users claim per timestamp once batch index is handled
References:
Important nuance: what the hook can and cannot pull#
BasicRedeemHook can pull balances already sitting in subvault addresses. It does not itself unwind Aave/Morpho/other positions.
So if assets are in external protocols, curator automation must first execute protocol-specific withdrawals through Subvault call(...), then hook/vault pull can move those returned tokens back.
Curator strategy execution path (how arbitrary protocols are reached)#
Subvault does not have protocol adapters hardcoded. It exposes generic call(where, value, data, payload) through CallModule.
The security boundary is Verifier:
- caller must have
CALLER_ROLE - call must match allowlist policy (compact/onchain, merkle compact, merkle extended, custom verifier)
References:
Oracle model: push-based reports with bounded deviations#
The Oracle contract does not pull Chainlink/Aave prices by itself. It accepts submitted Report[], applies timing/deviation checks, and triggers settlement on the vault.
Suspicious reports are stored but not settled until explicit acceptance.
References:
Risk model and limit enforcement#
RiskManager tracks:
- vault-level share-denominated exposure limit
- per-subvault share-denominated limits
- pending queue balances
- allowed assets per subvault
All asset deltas are converted to shares using latest non-suspicious oracle report (convertToShares), so limits are enforced in a common unit.
Reference: RiskManager.sol.
Fee model and where fees are minted#
Fees are share-based in core flows:
- deposit fee: applied during deposit queue settlement (
calculateDepositFee) - redeem fee: applied during redeem request (
calculateRedeemFee) - performance/protocol fees: minted on base asset report handling (
calculateFee)
Reference: FeeManager.sol.
Queue variants and execution patterns#
Mellow ships multiple queue modes:
- asynchronous request/claim queues:
DepositQueue,RedeemQueue - synchronous variants:
SyncDepositQueue - signature-authorized order execution:
SignatureDepositQueue,SignatureRedeemQueueusingConsensus
References:
End-to-end fund flow (macro view)#
Security considerations and real trust assumptions#
1) Oracle trust is bounded, not eliminated#
Oracle.sol enforces role checks and deviation windows. It does not cryptographically prove that each report was sourced from a specific feed. Governance chooses submitters and acceptance operators.
2) Curator freedom is policy-constrained#
Subvault calls are generic, but verifier policies tightly gate who can call which target/selectors/calldata classes. The policy surface is critical and should be managed with timelocks, diff tooling, and monitoring.
3) Liquidity liveness depends on unwind operations#
User redemption safety has two legs:
- on-chain queue accounting correctness
- operational ability to unwind external protocol positions in time
If curators stop unwinding, queues can stall even when accounting is correct.
4) Role hygiene matters as much as Solidity#
Most catastrophic failures in modular vault systems come from role misconfiguration, not arithmetic bugs.
Practical use cases this architecture enables#
- institutional curator vaults where users deposit into core vault and strategy execution is delegated
- multi-asset entry/exit with unified share accounting
- policy-enforced execution over multiple external protocols from isolated strategy accounts
- queue-based settlement windows suited for strategies that cannot guarantee instant withdrawals
Final mental model#
Mellow Flexible Vaults are best understood as an orchestration layer:
- queues encode user intent over time
- oracle reports define settlement points
- risk manager keeps a share-denominated exposure ledger
- subvaults execute strategy logic through guarded generic calls
If you audit or integrate this system, focus first on cross-contract invariants and role topology, then on per-contract correctness.