This page covers the smart contract implementation details. See Glossary.
Why STEAM exists
Traditional vault standards like ERC-4626 assume synchronous operations: deposit assets, receive shares instantly. But many DeFi operations are inherently asynchronous:- Cooldown periods — Ethena requires waiting before unstaking sUSDe
- Withdrawal queues — Syrup processes withdrawals in a FIFO queue
- Multi-step strategies — Multi-Vehicles coordinate across multiple protocols
STEAM is more than an interface — it is a framework for building reliable DeFi infrastructure. By standardizing how time, failure, and complex state are handled, STEAM enables Railnet to orchestrate assets across diverse yield sources under a single operational model.
The Query model
The core of STEAM is the Query — a structured request representing a deposit or redemption operation. Each Query carries its own identity, ownership, and state.keccak256(abi.encode(chainId, vehicleAddress, query)). The salt field ensures that repeated operations with identical parameters produce unique IDs.
The state machine
Every Query moves through a defined set of states. This makes the status of any operation transparent and auditable at all times.States
State diagram
Transition types
State transitions are categorized by their trigger mechanism:- Method-driven (synchronous) — Occur within the same transaction as a direct call to a Vehicle method (
create(),resume(),unlock(),recover()) - Protocol-driven (asynchronous) — Triggered by external protocol events, off-chain verification, or settlement delays
The Query lifecycle
Every operation follows three phases:1
Creation
You call
create() with a Query struct. The Vehicle pulls all input assets from the owner and starts the operation.- For sync protocols (Aave, Compound): the Query transitions directly to UNLOCKING
- For async protocols (Ethena, Syrup): the Query enters PROCESSING — see Sync vs async operations
create() fails for any reason, the entire transaction reverts. No assets are transferred, no query is created.2
Execution
The Vehicle interacts with the underlying protocol. For async operations, the Query may pass through PAUSED if an external condition must be met (cooldown period, oracle update).Once the condition is satisfied,
resume() moves the Query back to PROCESSING, and eventually the protocol signals success (UNLOCKING) or failure (RECOVERING).3
Settlement
You call
unlock() to claim the output assets. The Query transitions to SETTLED and assets or shares are distributed to the receiver.If the operation failed, you call recover() instead. The Query transitions to REJECTED and input assets are returned.Lifecycle methods
Events
Vehicles emit two events to enable off-chain tracking and automation:
The
possibleNext array in the Updated event signals whether the state may change asynchronously:
- Empty array — The state is stable. No further transitions will occur until the owner calls a method (
unlock(),recover(),resume()). - Non-empty array — The state may change asynchronously via protocol-driven transitions. Off-chain systems should monitor for further
Updatedevents.
Transition flows
Synchronous flow (Aave, Compound, ERC-4626)
create(), immediately reaching UNLOCKING. Call unlock() to finalize.
Asynchronous flow (Ethena, Syrup)
Error recovery
recover() to reclaim assets.
Partial settlement
Whenunlock() or recover() cannot fully distribute assets in a single call, the Query returns to PROCESSING instead of reaching a terminal state.
Asset[] showing what was distributed in that step. The cycle repeats until all assets are fully claimed or recovered.
Critical constraints
View methods
Vehicles provide methods to inspect state and simulate operations:estimate() provides a best-effort preview, not a commitment. Always implement slippage protection when using estimates for transaction previews.Fee semantics
Theestimate() and convert() methods serve different purposes:
estimate()includes all applicable entry/exit fees, slippage, and operational costsconvert()excludes all fees, providing a pure share-to-asset conversion
create() when assets are pulled. They are not applied during recovery operations, allowing users to reclaim assets without additional charges.
Next steps
Sync vs async operations
How synchronous and asynchronous Vehicles differ in practice
Accounting and flow of funds
How assets move through Multi-Vehicles and Sectors
Create a sync Vehicle
Build a Vehicle for protocols with instant settlement
Create an async Vehicle
Build a Vehicle for protocols with delayed settlement