Skip to main content
In user-facing documentation, a Vehicle is referred to as a Yield Source. See Glossary.
A fundamental architectural decision in Railnet is whether a Vehicle operates synchronously or asynchronously. This distinction determines how Queries move through the STEAM state machine and what operational patterns you need to follow.

The core distinction

The difference between sync and async Vehicles lies in the Query lifecycle.
For the complete state machine reference — all seven states, every valid transition, and the critical constraints — see The STEAM standard.

Synchronous Vehicles

Sync Vehicles complete their primary operation within a single transaction. A Query transitions directly from EMPTY to UNLOCKING via create() and then to SETTLED via unlock(). There is no waiting period or external dependency.
// Sync flow: single transaction
// EMPTY -> UNLOCKING -> SETTLED
Examples:
  • Aave V3 Vehicle — Supplies and withdraws assets from Aave V3 lending pools
  • Compound V3 Vehicle — Interacts with Compound V3 markets
  • ERC-4626 Vehicle — Wraps any standard ERC-4626 vault into a STEAM-compliant interface
Sync Vehicles provide the best user experience with the lowest operational overhead.

Asynchronous Vehicles

Async Vehicles handle operations that cannot complete immediately due to protocol-level constraints. A Query enters PROCESSING after creation and remains there until external conditions are met.
// Async flow: multiple transactions
// EMPTY -> PROCESSING -> (WAITING ->) UNLOCKING -> SETTLED
Examples:
  • Ethena Vehicle — Handles sUSDe cooldown periods when active. Operates synchronously when cooldown is disabled.
  • Syrup Vehicle — Interacts with Maple/Syrup withdrawal queues, which may have per-address limitations

Why some operations must be async

Asynchronicity is rarely a choice. It is a requirement imposed by the underlying protocol’s design.
Ethena’s sUSDe protocol implements a cooldownDuration. When you want to unstake USDe, you must first initiate a cooldown. The assets are only available for withdrawal after this period elapses.The Ethena Vehicle tracks this period, keeping the Query in PROCESSING until the cooldown ends.
When Ethena’s cooldownDuration is set to zero, the Ethena Vehicle operates synchronously — no PROCESSING state, no Account Clone needed.
Syrup (Maple Finance) uses a withdrawal queue system to manage pool liquidity. The protocol processes withdrawals in a FIFO queue, meaning you must wait for sufficient liquidity.Additionally, Syrup often imposes a “one-request-per-account” limitation. Without Railnet’s Account Clone pattern, the entire protocol would be limited to one active withdrawal at a time.
Complex yield strategies might involve multiple swaps, bridge operations, or liquidity provisioning steps that cannot safely be compressed into a single atomic transaction.

The PROCESSING state

The PROCESSING state is the hallmark of an asynchronous operation.
  • In sync Vehicles, create() moves the Query directly to UNLOCKING because assets are immediately deposited and ready to claim
  • In async Vehicles, create() moves the Query to PROCESSING, signaling that the operation is underway but not yet ready for settlement
The transition from PROCESSING to UNLOCKING is detected through the Vehicle’s state() view function, which checks the underlying protocol’s status. If conditions are met (e.g., block.timestamp >= cooldownEnd), state() reports UNLOCKING. A Keeper or caller then calls unlock() to finalize. If an external condition must be met before processing can continue, the Query may enter WAITING. Once the condition is satisfied, resume() moves it back to PROCESSING.

Error handling: sync vs async

How errors surface depends on the Vehicle type:
  • Sync Vehicles — if create() fails, the entire transaction reverts. No query is created, no assets are transferred. There is nothing to recover.
  • Async Vehicles — if the underlying protocol operation fails after entering PROCESSING, the Query transitions to RECOVERING. The owner calls recover() to reclaim input assets, and the Query terminates in REJECTED.
This distinction matters operationally: sync errors are invisible (reverted transactions), while async errors require active monitoring and recovery.

Account Clones: isolating async operations

Some protocols restrict operations to the address that initiated them. Ethena’s cooldownShares is address-specific — multiple cooldowns from the same address override each other. Syrup’s withdrawal manager allows only one active request per address. In both cases, concurrent operations from a single Vehicle address would conflict. Railnet solves this with the Account Clone pattern:
1

Deploy clone

The Vehicle deploys a minimalistic Account contract clone when an async redemption is initiated.
2

Transfer assets

Assets (such as pool tokens) are transferred to this specific Account.
3

Initiate protocol interaction

The Account initiates the protocol operation (e.g., requestRedeem or cooldownShares).
4

Track in query

The Query state stores the address of this dedicated Account, linking the operation to its isolated identity.
This provides per-query isolation. Each redemption has its own identity on the underlying protocol, enabling Railnet to handle hundreds of concurrent asynchronous requests without address conflicts.

Impact on callers

When interacting with async Vehicles, you follow a multi-step process:
1

Create the query

Call create(). The Query enters the PROCESSING state. Assets are transferred to the Vehicle (or its Account Clone).
2

Monitor readiness

Poll state(query) to check the current state. The Vehicle evaluates underlying protocol conditions on each call.
3

Finalize the operation

  • On success (state is UNLOCKING): call unlock() to claim output assets. The Query transitions to SETTLED.
  • On failure (state is RECOVERING): call recover() to reclaim input assets. The Query transitions to REJECTED.
In most deployments, a Keeper network automates steps 2 and 3. You create the Query and the Keeper handles monitoring and finalization. See Keeper setup for details.

Multi-Vehicle handling of async sub-vehicles

When a Multi-Vehicle dispatches operations to async sub-vehicles, the SubQueryEngine manages the nested STEAM lifecycle. If a sub-vehicle enters PROCESSING, the Multi-Vehicle’s own Query may remain open until settlement completes. Ephemeral accounting tracks expected outputs during in-flight operations to prevent share price distortion. See Accounting and flow of funds for how this works. The Keeper system automates monitoring and advancing nested sub-queries. See Multi-Vehicle architecture for the full operational picture.

Choosing between sync and async

When integrating a new protocol into Railnet, the choice is dictated by the protocol’s deposit and withdrawal mechanics:
FactorSync VehicleAsync Vehicle
OperationsImmediate entry and exitDelays, queues, or per-address restrictions
User experienceBest (single transaction)Requires monitoring or Keeper automation
Operational overheadLowestHigher (clone management, state tracking)
Use whenProtocol allows instant deposit/withdrawProtocol has cooldowns, queues, or address limits
Async is not a limitation — it is what allows Railnet to provide institutional-grade access to the full spectrum of DeFi yield sources, regardless of their underlying complexity.