Documentation

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 CREATED to PROCESSING and finally COMPLETED.
  • 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 AVAILABLE sector.
  • 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 resume when conditions are met.
  • State Transitions: The query moves through internal states as sub-queries complete.
  • Accounting: Assets move between sectors (e.g. from AVAILABLE into a vehicle’s staging sector, then to ALLOCATION on settlement).

3. Settlement (unlock)

Once all internal requirements are met, the query is marked as COMPLETED.

  • Final Transfer: The user calls unlock to 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

OperationContractParametersDescription
create(query)MultiVehicleQuery structInitiates a new deposit or redemption query.
resume(query)MultiVehicleQuery structAdvances a query waiting for external conditions.
unlock(query)MultiVehicleQuery structFinalizes a completed query and settles assets/shares.

Asset Management (Role Restricted)

OperationContractRequired RoleDescription
move(MoveParams)SectorAccountingEngineMULTI_VEHICLE_MOVETransfers assets or shares between sectors. {from, to, asset, amount, operationId}.
dispatch(DispatchParams)SectorAccountingEngineMULTI_VEHICLE_DISPATCHCreates a query on a sub-vehicle from its staging sector. {vehicle, mode, amount, settledDestination, rejectedDestination, minOutput, data, operationId}.
deposit(amount, allocate)SectorAccountingEngineMULTI_VEHICLE_DEPOSITDirect asset injection (e.g., reward reinvestment).
multicall(bytes[])SectorAccountingEngineper inner callBatches 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

OperationContractRequired RoleDescription
authorize(vehicle)VehicleManagerMULTI_VEHICLE_SET_VEHICLE_AUTHORIZATIONAuthorizes a sub-vehicle.
unauthorize(vehicle)VehicleManagerMULTI_VEHICLE_SET_VEHICLE_AUTHORIZATIONUnauthorizes a sub-vehicle.
authorizeAndConfigure(vehicle, config)VehicleManagerMULTI_VEHICLE_SET_VEHICLE_AUTHORIZATIONAuthorizes 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

OperationContractRequired RoleDescription
setQueues(depQ, redQ)QueueStrategyEngineSET_QUEUESUpdates 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.

RoleDescription
MULTI_VEHICLE_MOVEPermission to move assets or shares between sectors. Highly sensitive.
MULTI_VEHICLE_DISPATCHPermission to trigger asset dispatch to sub-vehicles.
MULTI_VEHICLE_DEPOSITPermission to inject assets directly into the accounting system.
MULTI_VEHICLE_SET_VEHICLE_AUTHORIZATIONPermission to manage the list of allowed sub-strategies.
MULTI_VEHICLE_SET_QUEUESPermission to update allocation and redemption priority queues.
MULTI_VEHICLE_SET_THRESHOLDSPermission to configure the Multi-Vehicle thresholds.
MULTI_VEHICLE_PROGRESS_QUERYPermission to progress in-flight queries in the SubQueryEngine.
MULTI_VEHICLE_FEED_QUERY_REDEEM_QUEUEPermission to feed the query redeem queue.
MULTI_VEHICLE_RETRIEVE_QUERY_REDEEM_QUEUE_ASSETSPermission to pull redeem-queue assets back into the accounting engine.
MODULE_MANAGERPermission to register and manage external execution modules.
EXECPermission to trigger the execution of an authorized module.
CANCEL_MODULEPermission to abort a pending module registration.

Sector Accounting Invariants

The SectorAccountingEngine maintains several critical invariants to ensure the integrity of the vault’s assets:

  1. Total Assets Invariant: sum(all_asset_sectors) == total_assets_held.
  2. Total Shares Invariant: sum(all_share_sectors) == total_shares_minted.
  3. Sector Specificity: Assets in the ALLOCATION sector must always be represented by shares in sub-vehicles.
  4. Redemption Liquidity: Assets in the EXIT sector are strictly reserved for fulfilling the QueryRedeemQueue.

ModulesManager

The ModulesManager is an extensibility framework that allows the MultiVehicle to execute arbitrary external logic in a secure, governed manner.

Module Lifecycle

  1. Registration: MODULE_MANAGER registers a module ID and address. Starts a timelock.
  2. Finalization: After the timelock, the module is approved and becomes “active”.
  3. Authorization: Each MultiVehicle must call allowModule(id) to grant it permission to execute logic on its assets.

Key API

MethodRole RequiredDescription
addModule(id, module)MODULE_MANAGERRegisters a new module and starts the timelock.
updateModule(id, module)MODULE_MANAGERUpdates a module’s address, restarting the timelock.
approvePendingModule(id)NoneFinalizes the registration after the timelock.
cancelPendingModule(id)CANCEL_MODULEAborts a pending registration request.
removeModule(id)MODULE_MANAGERDeactivates a module globally.
exec(target, id, data)EXECExecutes 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

  1. Scan: Iterate through active sub-queries in SubQueryEngine.
  2. Verify: Call ready(query) on the target sub-vehicle.
  3. Execute: If ready, call progressQuery.
  4. Queue Check: Check QueryRedeemQueue for pending demands.
  5. 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.

SectorTypeDescription
ENTRYVirtualAssets crossing into the system. Carries negative balances, so it is a flow marker, not a holding.
AVAILABLEAssetIdle base assets, from user deposits or harvested rewards. Ready for dispatch, and withdrawable.
RESERVEDAssetBase assets the operator has earmarked. Counted in totalAssets() but not withdrawable(), and asset-only — share moves in are rejected on-chain.
ALLOCATIONShareSub-vehicle shares from settled deposits: capital deployed and earning yield.
EXITVirtualAssets crossing out of the system.
Vehicle sectorEitherPer-vehicle staging, 0x01 + 11 zero bytes + the address. Value waits here for a query, and while that query is in flight.
Query sectorEither0x02-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’s settledDestination points straight at B’s sector, so the value does not pass back through AVAILABLE.

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.

EventContractDescription
QueryCreatedMultiVehicleEmitted when a user starts a new deposit or redeem operation.
QueryResumedMultiVehicleEmitted when a query advances to its next state in the lifecycle.
QueryUnlockedMultiVehicleEmitted when a query is finalized and assets/shares are settled.
SectorTransferSectorAccountingEngineEmitted whenever assets or shares move between internal sectors.
QueueUpdatedQueueStrategyEngineEmitted when the allocation or redemption priority queues are changed.
ModuleRegisteredModulesManagerEmitted when a new module registration starts its timelock.
ModuleApprovedModulesManagerEmitted when a module becomes active after the timelock.
VehicleAuthorizedVehicleManagerEmitted when a new sub-strategy is added to the allowed list.

Factory & Deployment

CoreFactory Pattern

  • Deterministic Addresses: Uses CREATE2 for 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

  1. Access Control: Deploy ExternalAccessControl to manage the administrative hierarchy.
  2. Infrastructure: Deploy FeeManager and ModulesManager if required for the specific deployment.
  3. MultiVehicle Core: Call MultiVehicleFactory for atomic deployment of the core and engines.
  4. Permissions: Grant KEEPER, STRATEGIST, and MOVE_ASSETS roles to the appropriate addresses.
  5. 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, and QueryUnlocked events to provide real-time feedback.
  • Check Queue Position: There is no single getPosition call. Use lookup(id) to resolve a demand, pending(id) for what is still outstanding, and redeemable(id) for what can be claimed now; demandsCount() and fulfillmentsCount() bound the FIFO. retrievable() reports what an operator can pull back out with retrieve().
  • 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 Query struct correctly when calling create.
  • Callback Handling: If your contract is a sub-vehicle, implement the ready and progress logic to support the MultiVehicle’s automated progression.
  • Role Management: Use the ExternalAccessControl contract to manage permissions for your integration, ensuring that only authorized addresses can trigger sensitive operations.