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.
Examples:
  • Aave V3 Vehicle — Supplies and withdraws assets from Aave V3 lending pools
  • Morpho Blue Vehicle — Supplies to and withdraws from a Morpho Blue market
  • ERC-4626 Vehicle — Wraps any standard ERC-4626 vault into a STEAM-compliant interface
  • Wrapper Vehicle — 1:1 wrap of any ERC-20 for STEAM compatibility (utility, no yield)
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.
Examples:
  • ERC-7540 Vehicle — Wraps any ERC-7540 async vault, driving its request queues through the STEAM lifecycle
  • Lagoon Vehicle — An ERC7540Vehicle subclass for Lagoon’s hybrid vaults. It picks the sync or async path per call and adds the closed-vault recovery leg.
  • Ethena Vehicle — Handles sUSDe cooldown periods when active. Operates synchronously when cooldown is disabled.

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.
An ERC-7540 vault does not settle a deposit or redemption on request. requestDeposit and requestRedeem only register a request; a curator settles it later, in batches, and only then can the result be claimed.The ERC-7540 Vehicle keeps its own demand queue, registering one demand per Query and batching them into a single vault request under the Vehicle’s own address. Each Query holds a demand ID, and state() reports UNLOCKING once that demand becomes claimable.Lagoon vaults are hybrid. The Lagoon Vehicle reads syncMode() and isTotalAssetsValid() on every call and takes the synchronous syncDeposit or syncRedeem path when both allow it, falling back to the async request path when they do not — or when the vault’s runtime gates reject the sync attempt.
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, and the Query Registry commits the pending leg at that point — see State resolution and the storedState lag. If an external condition must be met before processing can continue, the Query may enter PAUSED. 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: a new cooldown started from the same address overrides the previous one, so concurrent redemptions driven from a single Vehicle address would clobber each other. Railnet solves this with the Account Clone pattern, built on the minimal Account contract:
1

Deploy clone

The Vehicle clones Account through the CoreFactory, using the query ID as the salt, and calls initialize(owner) with itself as owner.
2

Transfer assets

The position (for Ethena, the sUSDe being cooled down) is transferred to that Account, and the Vehicle’s accounting is decreased accordingly.
3

Initiate protocol interaction

The Vehicle drives the protocol through performCall(target, value, data), which only the owner may call — for Ethena, cooldownShares on entry and unstake at settlement.
4

Track in query

The Vehicle records the Account’s address in its own per-query storage. The Query Registry record holds no such field.
This provides per-query isolation: each redemption gets its own identity on the underlying protocol, letting Railnet run many concurrent asynchronous requests without address conflicts.
Account Clones are one tool among several, used where a protocol binds operations to an address. Today only the Ethena Vehicle needs them, on its async redeem leg. The ERC-7540 and Lagoon Vehicles instead batch per-Query demands through their own request queue under the Vehicle’s own address.

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.

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:
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.