MultiVehicle Technical Reference
MultiVehicle is a sophisticated meta-strategy vehicle designed to orchestrate multiple sub-vehicles (yield sources) through a unified, queue-based allocation system. It serves as a high-level aggregator that implements the STEAM (Standardized Tokenized Execution & Accounting Model) standard, providing a consistent interface for users while managing the complexities of multi-protocol deployments.
By abstracting the underlying complexity of various yield-generating strategies, MultiVehicle allows users to interact with a single vault while benefiting from diversified risk and optimized returns across multiple DeFi protocols. It handles the heavy lifting of rebalancing, liquidity management, and asynchronous execution, ensuring a seamless experience for both end-users and automated managers.
Architecture Components
The MultiVehicle system is built on a modular architecture consisting of the core MultiVehicle plus five specialised contracts — SectorAccountingEngine, QueueStrategyEngine, SubQueryEngine, QueryRedeemQueue and VehicleManager. This separation of concerns ensures that accounting, strategy logic, and execution lifecycles are handled by specialized components, improving both security and maintainability.
┌─────────────┐
│ MultiVehicle│ ← User-facing STEAM entry point
└──────┬──────┘
│
├──────────────────┬──────────────────┬────────────────┐
│ │ │ │
┌──────▼──────┐ ┌────────▼────────┐ ┌─────▼──────┐ ┌─────▼─────┐
│SectorAcctEng│ │QueueStrategyEng │ │SubQueryEng │ │QueryRdmQu │
│ │ │ │ │ │ │ │
│Double-entry │ │Priority queues │ │STEAM mgmt │ │Async redm │
│accounting │ │allocation logic │ │Sub-queries │ │FIFO queue │
└─────────────┘ └─────────────────┘ └────────────┘ └───────────┘ Detailed Engine Descriptions
1. MultiVehicle (Core)
The primary entry point for all user interactions. It is fully STEAM-compliant and manages the high-level lifecycle of user queries. It handles:
- User Deposits/Redeems: Processing incoming assets and outgoing redemption requests.
- Share Management: Minting and burning of vault shares in an ERC4626-compatible manner.
- Query Orchestration: Coordinating between the various engines to fulfill user requests.
- Liquidity Management: Ensuring that the vehicle maintains enough idle assets to satisfy immediate redemption demands when possible.
2. SectorAccountingEngine
A robust double-entry bookkeeping system that tracks every asset and share movement within the vehicle.
- Sector Transfers: All assets are categorized into “sectors” (
ENTRY,AVAILABLE,RESERVED,ALLOCATION,EXIT, plus per-vehicle staging sectors). - Invariants: Ensures that the sum of all sectors always matches the total assets held by the contract, preventing accounting leaks.
- Transparency: Provides a clear view of where assets are located at any point in the execution lifecycle.
- Double-Entry: Every “move” operation is a balanced transfer between a source and destination sector.
3. QueueStrategyEngine
The “brain” of the MultiVehicle, defining how assets should be distributed among sub-strategies.
- Priority Queues: Uses configurable lists of sub-vehicles to determine allocation priority.
- Ceiling/Floor Targets: The deposit queue defines maximum allocation targets, while the redeem queue defines minimum liquidity thresholds.
- Dynamic Rebalancing: Allows managers to update strategy parameters without pausing the entire vehicle.
- Target Optimization: Strategists can fine-tune targets based on current market yields and risk profiles.
4. SubQueryEngine
Manages the complex lifecycle of STEAM queries sent to underlying sub-vehicles.
- Ephemeral Accounting: Tracks assets that are “in-flight” between the MultiVehicle and its sub-strategies.
- State Management: Handles the transition of sub-queries from
CREATEDtoPROCESSINGand finallyCOMPLETED. - Error Handling: Provides mechanisms to handle failed or timed-out sub-queries gracefully.
- Query Mapping: Maintains a 1-to-N mapping between a user’s MultiVehicle query and the multiple sub-queries it may trigger.
5. QueryRedeemQueue
A specialized FIFO (First-In-First-Out) queue designed to handle asynchronous redemptions efficiently.
- Demand Tracking: Records redemption requests in the order they are received.
- Binary Search Matching: Uses optimized algorithms to match available liquidity with pending demands, even with thousands of queue items.
- Fairness: Ensures that early redeemers are prioritized when liquidity becomes available from sub-strategies.
- Position-Based: Users can track their exact position in the queue and estimate time to fulfillment.
STEAM Query Lifecycle
The MultiVehicle follows a standardized 3-step lifecycle for all user operations, ensuring compatibility with both synchronous and asynchronous yield sources.
1. Creation (create)
The user submits a Query struct specifying their intent (Deposit or Redeem) and the amount.
- Deposit: Assets are transferred from the user to the MultiVehicle and placed in the
AVAILABLEsector. - Redeem: A redeem query is created; the shares being unallocated move into the relevant vehicle’s staging sector.
- Sub-Queries: The MultiVehicle may immediately trigger sub-queries to underlying vehicles if needed.
2. Progression (resume)
If the operation cannot be completed immediately (e.g., waiting for a sub-vehicle to process a withdrawal), the query enters a “waiting” state.
- Keepers: Automated bots monitor the state and call
resumewhen conditions are met. - State Transitions: The query moves through internal states as sub-queries complete.
- Accounting: Assets move between sectors (e.g. from
AVAILABLEinto a vehicle’s staging sector, then toALLOCATIONon settlement).
3. Settlement (unlock)
Once all internal requirements are met, the query is marked as COMPLETED.
- Final Transfer: The user calls
unlockto receive their shares (for deposits) or assets (for redemptions). - Cleanup: Ephemeral accounting records are cleared, and the query is archived.
Key Operations API Reference
User Operations
| Operation | Contract | Parameters | Description |
|---|---|---|---|
create(query) | MultiVehicle | Query struct | Initiates a new deposit or redemption query. |
resume(query) | MultiVehicle | Query struct | Advances a query waiting for external conditions. |
unlock(query) | MultiVehicle | Query struct | Finalizes a completed query and settles assets/shares. |
Asset Management (Role Restricted)
| Operation | Contract | Required Role | Description |
|---|---|---|---|
move(MoveParams) | SectorAccountingEngine | MULTI_VEHICLE_MOVE | Transfers assets or shares between sectors. {from, to, asset, amount, operationId}. |
dispatch(DispatchParams) | SectorAccountingEngine | MULTI_VEHICLE_DISPATCH | Creates a query on a sub-vehicle from its staging sector. {vehicle, mode, amount, settledDestination, rejectedDestination, minOutput, data, operationId}. |
deposit(amount, allocate) | SectorAccountingEngine | MULTI_VEHICLE_DEPOSIT | Direct asset injection (e.g., reward reinvestment). |
multicall(bytes[]) | SectorAccountingEngine | per inner call | Batches the above, so a multi-step operation can be atomic. |
moveAssets and moveShares were collapsed into move(), which takes the asset
explicitly. dispatch takes one struct rather than a bare address, and the
direction is now explicit rather than implied by the vehicle. rebalance() was
removed entirely — a rebalance is move + dispatch(REDEEM) + dispatch(DEPOSIT), optionally batched through multicall.
Vehicle Authorization
| Operation | Contract | Required Role | Description |
|---|---|---|---|
authorize(vehicle) | VehicleManager | MULTI_VEHICLE_SET_VEHICLE_AUTHORIZATION | Authorizes a sub-vehicle. |
unauthorize(vehicle) | VehicleManager | MULTI_VEHICLE_SET_VEHICLE_AUTHORIZATION | Unauthorizes a sub-vehicle. |
authorizeAndConfigure(vehicle, config) | VehicleManager | MULTI_VEHICLE_SET_VEHICLE_AUTHORIZATION | Authorizes and configures in one call. |
Authorization moved off the SectorAccountingEngine onto the VehicleManager (formerly VehicleRegistry), which also owns setThresholds, setMaxTotalAssets, feedQueryRedeemQueue() and retrieveQueryRedeemQueueAssets(uint256).
Queue Management
| Operation | Contract | Required Role | Description |
|---|---|---|---|
setQueues(depQ, redQ) | QueueStrategyEngine | SET_QUEUES | Updates priority queues and allocation targets. |
Detailed Role Definitions
The MultiVehicle system uses a granular role-based access control (RBAC) system managed by the ExternalAccessControl contract.
| Role | Description |
|---|---|
MULTI_VEHICLE_MOVE | Permission to move assets or shares between sectors. Highly sensitive. |
MULTI_VEHICLE_DISPATCH | Permission to trigger asset dispatch to sub-vehicles. |
MULTI_VEHICLE_DEPOSIT | Permission to inject assets directly into the accounting system. |
MULTI_VEHICLE_SET_VEHICLE_AUTHORIZATION | Permission to manage the list of allowed sub-strategies. |
MULTI_VEHICLE_SET_QUEUES | Permission to update allocation and redemption priority queues. |
MULTI_VEHICLE_SET_THRESHOLDS | Permission to configure the Multi-Vehicle thresholds. |
MULTI_VEHICLE_PROGRESS_QUERY | Permission to progress in-flight queries in the SubQueryEngine. |
MULTI_VEHICLE_FEED_QUERY_REDEEM_QUEUE | Permission to feed the query redeem queue. |
MULTI_VEHICLE_RETRIEVE_QUERY_REDEEM_QUEUE_ASSETS | Permission to pull redeem-queue assets back into the accounting engine. |
MODULE_MANAGER | Permission to register and manage external execution modules. |
EXEC | Permission to trigger the execution of an authorized module. |
CANCEL_MODULE | Permission to abort a pending module registration. |
Sector Accounting Invariants
The SectorAccountingEngine maintains several critical invariants to ensure the integrity of the vault’s assets:
- Total Assets Invariant:
sum(all_asset_sectors) == total_assets_held. - Total Shares Invariant:
sum(all_share_sectors) == total_shares_minted. - Sector Specificity: Assets in the
ALLOCATIONsector must always be represented by shares in sub-vehicles. - Redemption Liquidity: Assets in the
EXITsector are strictly reserved for fulfilling theQueryRedeemQueue.
ModulesManager
The ModulesManager is an extensibility framework that allows the MultiVehicle to execute arbitrary external logic in a secure, governed manner.
Module Lifecycle
- Registration:
MODULE_MANAGERregisters a module ID and address. Starts a timelock. - Finalization: After the timelock, the module is approved and becomes “active”.
- Authorization: Each MultiVehicle must call
allowModule(id)to grant it permission to execute logic on its assets.
Key API
| Method | Role Required | Description |
|---|---|---|
addModule(id, module) | MODULE_MANAGER | Registers a new module and starts the timelock. |
updateModule(id, module) | MODULE_MANAGER | Updates a module’s address, restarting the timelock. |
approvePendingModule(id) | None | Finalizes the registration after the timelock. |
cancelPendingModule(id) | CANCEL_MODULE | Aborts a pending registration request. |
removeModule(id) | MODULE_MANAGER | Deactivates a module globally. |
exec(target, id, data) | EXEC | Executes the module’s logic on the target vehicle. |
Keeper System
Keepers are off-chain agents that automate the progression of STEAM queries and maintain the vehicle’s strategy.
Typical Keeper Loop
- Scan: Iterate through active sub-queries in
SubQueryEngine. - Verify: Call
ready(query)on the target sub-vehicle. - Execute: If
ready, callprogressQuery. - Queue Check: Check
QueryRedeemQueuefor pending demands. - Fulfill: If liquidity is available, call
feedQueryRedeemQueue.
Accounting Engine Sectors
The SectorAccountingEngine uses a set of predefined sectors to track the state of assets and shares. Understanding these sectors is key to auditing the vehicle’s internal state.
| Sector | Type | Description |
|---|---|---|
ENTRY | Virtual | Assets crossing into the system. Carries negative balances, so it is a flow marker, not a holding. |
AVAILABLE | Asset | Idle base assets, from user deposits or harvested rewards. Ready for dispatch, and withdrawable. |
RESERVED | Asset | Base assets the operator has earmarked. Counted in totalAssets() but not withdrawable(), and asset-only — share moves in are rejected on-chain. |
ALLOCATION | Share | Sub-vehicle shares from settled deposits: capital deployed and earning yield. |
EXIT | Virtual | Assets crossing out of the system. |
| Vehicle sector | Either | Per-vehicle staging, 0x01 + 11 zero bytes + the address. Value waits here for a query, and while that query is in flight. |
| Query sector | Either | 0x02-prefixed and ephemeral, used only while recovering a failed sub-query. |
PENDING, PRE_ALLOCATION and RESERVE do not exist. Note RESERVED is not the
old RESERVE: it is operator-earmarked capital, not a fee or liquidity buffer.
Sector Transitions
Assets move between these sectors based on the operation being performed:
- Deposit:
ENTRY->AVAILABLE->vehicle sector->ALLOCATION. - Redeem:
ALLOCATION->vehicle sector->AVAILABLE->EXIT. - Rebalance:
ALLOCATION->sector(A)->sector(B)->ALLOCATION. The redeem’ssettledDestinationpoints straight at B’s sector, so the value does not pass back throughAVAILABLE.
Security Considerations
Timelocks
All sensitive operations, including module registration and significant strategy changes, are protected by mandatory timelocks. This allows stakeholders to exit the vehicle if they disagree with a proposed change. The default timelock is configured during deployment but can be adjusted by governance.
Dead Shares
To prevent share price manipulation, the first deposit always mints a small amount of “dead shares” to address(0). This creates a permanent floor for the share supply, making it economically impossible to perform a “donation attack” to inflate the share price. This is a standard security pattern for ERC-4626 vaults.
Role Separation
By separating roles like STRATEGIST, KEEPER, and ADMIN, the system minimizes the impact of a single compromised account. For example, a KEEPER can advance queries but cannot change the allocation strategy or authorize new sub-vehicles.
Oracle Safety
MultiVehicle relies on the underlying sub-vehicles for pricing. It is recommended to only authorize sub-strategies that use robust, manipulation-resistant oracles (e.g., Chainlink or Uniswap V3 TWAP).
Event Reference
Monitoring these events is crucial for tracking the state of a MultiVehicle deployment and building responsive user interfaces.
| Event | Contract | Description |
|---|---|---|
QueryCreated | MultiVehicle | Emitted when a user starts a new deposit or redeem operation. |
QueryResumed | MultiVehicle | Emitted when a query advances to its next state in the lifecycle. |
QueryUnlocked | MultiVehicle | Emitted when a query is finalized and assets/shares are settled. |
SectorTransfer | SectorAccountingEngine | Emitted whenever assets or shares move between internal sectors. |
QueueUpdated | QueueStrategyEngine | Emitted when the allocation or redemption priority queues are changed. |
ModuleRegistered | ModulesManager | Emitted when a new module registration starts its timelock. |
ModuleApproved | ModulesManager | Emitted when a module becomes active after the timelock. |
VehicleAuthorized | VehicleManager | Emitted when a new sub-strategy is added to the allowed list. |
Factory & Deployment
CoreFactory Pattern
- Deterministic Addresses: Uses
CREATE2for predictable deployment across different chains. - Atomic Initialization: Deploys the core MultiVehicle and all five satellite contracts in a single transaction.
- Standardization: Ensures all instances use the same audited bytecode, simplifying security reviews.
Deployment Sequence
- Access Control: Deploy
ExternalAccessControlto manage the administrative hierarchy. - Infrastructure: Deploy
FeeManagerandModulesManagerif required for the specific deployment. - MultiVehicle Core: Call
MultiVehicleFactoryfor atomic deployment of the core and engines. - Permissions: Grant
KEEPER,STRATEGIST, andMOVE_ASSETSroles to the appropriate addresses. - Strategy Setup: Authorize sub-vehicles and configure the initial priority queues to begin earning yield.
Integration Patterns
For Frontend Developers
When building interfaces for MultiVehicle, always:
- Monitor Events: Listen for
QueryCreated,QueryResumed, andQueryUnlockedevents to provide real-time feedback. - Check Queue Position: There is no single
getPositioncall. Uselookup(id)to resolve a demand,pending(id)for what is still outstanding, andredeemable(id)for what can be claimed now;demandsCount()andfulfillmentsCount()bound the FIFO.retrievable()reports what an operator can pull back out withretrieve(). - Handle Asynchronicity: Inform users that their deposit/redeem might take multiple blocks or even hours to complete depending on sub-vehicle liquidity and keeper activity.
For Smart Contract Integrators
- STEAM Compliance: Ensure your contract handles the
Querystruct correctly when callingcreate. - Callback Handling: If your contract is a sub-vehicle, implement the
readyandprogresslogic to support the MultiVehicle’s automated progression. - Role Management: Use the
ExternalAccessControlcontract to manage permissions for your integration, ensuring that only authorized addresses can trigger sensitive operations.