Multi-Vehicle Architecture
MultiVehicle is a sophisticated vault system built on the STEAM protocol, designed to manage multiple sub-vehicles (yield strategies) with advanced allocation and redemption capabilities. It provides a unified interface for users while intelligently distributing assets across different DeFi protocols.
Architecture Overview
The factory spawns six contracts per MultiVehicle, which work together to provide seamless asset management:
┌─────────────┐
│ MultiVehicle│ ← User-facing STEAM entry point
└──────┬──────┘
│
├──────────────────┬─────────────────┬──────────────┬──────────────┐
│ │ │ │ │
┌──────▼──────┐ ┌────────▼───────┐ ┌──────▼────┐ ┌──────▼────┐ ┌──────▼──────┐
│SectorAcctEng│ │QueueStrategyEng│ │SubQueryEng│ │QueryRdmQu │ │VehicleManager│
│ │ │ │ │ │ │ │ │ │
│Double-entry │ │Priority queues │ │STEAM mgmt │ │Async redm │ │Authorization │
│accounting │ │allocation logic│ │Ephemeral │ │FIFO queue │ │& config │
└─────────────┘ └────────────────┘ └───────────┘ └───────────┘ └──────────────┘ VehicleManager (formerly VehicleRegistry) is the contract you configure the
MultiVehicle through. As well as authorize/unauthorize/configure/ authorizeAndConfigure, it absorbed thresholds/setThresholds, exitSupplies, maxTotalAssets/setMaxTotalAssets, feedQueryRedeemQueue() and retrieveQueryRedeemQueueAssets(uint256) from the MultiVehicle.
Component Details
1. MultiVehicle (Main Contract)
The STEAM-compliant entry point that users interact with directly.
User Operations:
- Deposit assets → receive MultiVehicle shares
- Redeem shares → receive assets back
Key Responsibilities:
- User-facing STEAM operations (create, resume, unlock, recover)
- Share minting/burning using ERC4626-style exchange rate
- Integration with QueryRedeemQueue for asynchronous redemptions
2. SectorAccountingEngine
The central accounting system implementing double-entry bookkeeping principles.
Sectors (Asset/Share States):
| Sector | Type | Description |
|---|---|---|
ENTRY | Virtual | Assets entering the system (accounting only) |
AVAILABLE | Physical | Idle base assets awaiting allocation |
RESERVED | Physical | Operator-earmarked base assets; asset-only, and excluded from withdrawable() |
ALLOCATION | Physical | Sub-vehicle shares (successful deposits) |
EXIT | Virtual | Assets leaving the system (accounting only) |
| Vehicle sectors | Staging | Per-vehicle staging areas: 0x01 + 11 zero bytes + the vehicle address |
| Query sectors | Ephemeral | 0x02-prefixed, used only while recovering a failed sub-query |
Key Functions:
SectorAccountingEngine.deposit- Receives assets from MultiVehicleSectorAccountingEngine.withdraw- Transfers assets to MultiVehicleSectorAccountingEngine.requestWithdrawable- Triggers unallocationsSectorAccountingEngine.totalAssets- Calculates total value
3. QueueStrategyEngine
Defines the allocation strategy through configurable priority queues.
Deposit Queue
A prioritized list: {vehicle, target}[]
Processing Logic:
- Processes in order (index 0 = highest priority)
target= maximum shares to allocate to this vehicle before moving to next entry- Stops when:
- Vehicle reaches target, OR
- Vehicle reaches
maxDepositable, OR - Assets are exhausted
Important Behavior:
- Does NOT enforce ongoing ratios
- If vehicle A has 80k target and grows to 90k from yield, NEW deposits skip A and go to next queue entry
- Only considers current holdings vs target for new allocations
Redeem Queue
A prioritized list: {vehicle, target}[]
Processing Logic:
- Processes in order (index 0 = highest priority)
target= minimum shares to maintain in this vehicle (floor)- Stops when:
- Vehicle reaches target (floor), OR
- Vehicle reaches
maxRedeemable, OR - Needed assets are obtained
Behavior:
- Vehicle will be redeemed from down to its target
- Then queue moves to next entry
Queue Processing Example
// Initial state
depositQueue = [{aave, 60k}, {morpho, 30k}]
currentHoldings = {aave: 50k, morpho: 20k}
newDeposit = 20k shares
// Algorithm execution:
// 1. Check aave: 50k < 60k target
// → allocate min(20k available, 10k to reach target) = 10k to aave
// → aave now has 60k
// 2. Remaining: 10k shares
// 3. Check morpho: 20k < 30k target
// → allocate min(10k available, 10k to reach target) = 10k to morpho
// → morpho now has 30k
// 4. Done: aave=60k, morpho=30k Key Function:
QueueStrategyEngine.setQueues- Configure both deposit and redeem queues
4. SubQueryEngine
Manages the STEAM query lifecycle to sub-vehicles and tracks ephemeral accounting.
Ephemeral Accounting:
Prevents double-counting during asynchronous operations:
- Tracks expected outputs from in-flight queries (PROCESSING state)
- Included in
totalAssets()for accurate share price - Cleared when queries settle
Key Function:
SubQueryEngine.progressQuery- Advances query states through STEAM lifecycle
5. QueryRedeemQueue
Handles asynchronous redemptions when immediate liquidity is insufficient.
FIFO Queue Implementation:
Position-based with binary search matching:
- Demands: User redemption requests (created during redeem commit)
- Fulfillments: Liquidity provisions (created by keeper/operator)
- Partial redemptions supported across multiple fulfillments
Key Function:
VehicleManager.feedQueryRedeemQueue()- Provides liquidity to fulfill outstanding redemptions; takes no arguments
Component Interactions
The components work together in coordinated flows:
Deposit Flow
- User calls MultiVehicle
- SectorAccountingEngine records asset movement
- QueueStrategyEngine determines allocation
- SubQueryEngine creates queries to sub-vehicles
- Queries settle and ALLOCATION sector updated
Redeem Flow
- User initiates redemption
- QueueStrategyEngine determines which vehicles to unallocate from
- SubQueryEngine creates redeem queries
- If insufficient immediate liquidity → QueryRedeemQueue handles async fulfillment
- Assets flow back to user
Design Principles
- Separation of Concerns: Each component has a single, well-defined responsibility
- Double-Entry Accounting: All asset movements are tracked through sector transfers
- Asynchronous by Design: STEAM protocol handles both sync and async operations gracefully
- Queue-Based Strategy: Flexible, operator-controlled allocation and redemption logic
- Accurate Pricing: Ephemeral accounting ensures share price accuracy during in-flight operations
Synchronous vs Asynchronous Sub-Vehicles
MultiVehicle can orchestrate both synchronous and asynchronous sub-vehicles. Understanding the distinction is important for operators.
Synchronous Vehicles
Vehicles like Aave V3, Morpho Blue, and ERC4626 complete operations in a single transaction. When MultiVehicle dispatches assets to these vehicles, the sub-query immediately reaches UNLOCKING and settles:
EMPTY → UNLOCKING → SETTLED // Single transaction These provide the best user experience with lowest overhead.
Asynchronous Vehicles
Vehicles like ERC7540 (request queues) and Lagoon (epoch settlement) require multiple transactions. Sub-queries enter PROCESSING and wait for external conditions:
EMPTY → PROCESSING → (PAUSED →) UNLOCKING → SETTLED The query may enter PAUSED if a cooldown or external condition must be met before proceeding; call resume() once it is.
The Account Clone Pattern
Some protocols have per-address limitations (e.g. only one active request per address). Railnet solves this by deploying lightweight Account contract clones — each clone acts as a temporary wallet for a single query, enabling hundreds of concurrent operations without address conflicts.
Impact on MultiVehicle Operations
When MultiVehicle interacts with async sub-vehicles:
- Sub-queries remain in PROCESSING until the underlying protocol is ready
- Ephemeral accounting tracks expected outputs to prevent share price distortion
- The Keeper system automates monitoring and advancing these nested operations
- Operators should monitor vehicle staging sectors for high balances indicating slow settlement
Trade-offs to Consider
While MultiVehicle offers powerful capabilities, consider these factors:
- Gas Costs: More automation means higher gas costs. Queue-based strategies execute more transactions, which is important to factor in on mainnet.
- Complexity: More vehicles mean more monitoring and management overhead. Start simple and scale up.
- Async Operations: Sub-vehicle operations may not settle immediately. Design your flows with async handling in mind.