# Accounting and flow of funds \[How Railnet tracks assets across yield sources with sector-based accounting]

:::info
In user-facing documentation, a MultiVehicle implements an **Allocation Strategy**. See [Glossary](/developers/glossary).
:::

A MultiVehicle's assets are rarely all in one place: some idle, some staged for a deposit, some held as sub-vehicle shares, some in flight to a protocol that has not settled. Balance tracking cannot tell those apart, so the SectorAccountingEngine partitions them into **sectors** and books every movement as a transfer between two of them: decrement the source, increment the destination, emit `SectorTransfer`. Accounted assets are conserved across internal transfers, so nothing goes missing between books. The engine is one of the [MultiVehicle components](/developers/contracts/multi-vehicle).

## Sectors

| Sector | Type | Contents |
|--------|------|----------|
| `ENTRY` | Virtual | Assets entering the system. Source for deposits, not tracked in balances. |
| `AVAILABLE` | Physical | Idle base assets. Counted in both `totalAssets()` and `withdrawable()`. |
| `RESERVED` | Physical | Base assets you earmarked. In `totalAssets()`, excluded from `withdrawable()`. Asset-only: share moves in are rejected. |
| `ALLOCATION` | Physical | Sub-vehicle shares from settled deposits, i.e. deployed capital. |
| `EXIT` | Virtual | Assets leaving the system. Destination for withdrawals, not tracked in balances. |
| Vehicle sector | Staging | `SectorLib.toSector(vehicle)`, the `0x01` prefix plus the vehicle address. Holds assets or shares between `AVAILABLE`/`ALLOCATION` and the sub-vehicle. |
| Query sector | Temporary | Keyed by sub-query, used when recovering from a failed one. |

`RESERVED` exists so you can park liquidity nothing spends by itself: the auto-fulfill path and the QueueStrategyEngine both spend against `withdrawable()`, which reads only `AVAILABLE`. Nothing lands there implicitly. You `move` assets in and out, or route a redeem's `settledDestination` there.

## Deposit flow

1. **Reception**: the user's base assets land in `AVAILABLE` (`ENTRY -> AVAILABLE`).
2. **Allocation**: the QueueStrategyEngine walks the deposit queue and picks the target sub-vehicle.
3. **Staging**: `AVAILABLE -> SectorLib.toSector(vehicle)`, where the assets wait for a query.
4. **Dispatch**: `dispatch` creates the [STEAM query](/developers/contracts/steam-standard) and sends the assets to the sub-vehicle, so they leave the vehicle sector and the accounting system at once. Ephemeral accounting estimates the shares to come.
5. **Settlement**: shares arrive as `ENTRY -> ALLOCATION` and the estimate is replaced by the real value.

Redemption runs the same path backwards: `ALLOCATION -> vehicle sector`, dispatch a REDEEM query (ephemeral now estimates base assets), settle into the query's `settledDestination` (`AVAILABLE` by default, `RESERVED`, or another vehicle's sector), then `AVAILABLE -> EXIT` when the user withdraws.

```mermaid
graph LR
    A[ENTRY] -->|deposit| B[AVAILABLE]
    B -->|stage| C["Vehicle sector"]
    C -->|dispatch| D["Sub-vehicle (outside accounting)"]
    E[ENTRY] -->|settle| F[ALLOCATION]
    F -->|unallocate| C
    B -->|withdraw| G[EXIT]
```

## Ephemeral accounting

Between dispatch and settlement the assets are gone and the shares have not arrived. Left alone, `totalAssets()` would drop by the full amount and new depositors would buy in too cheaply. The SubQueryEngine covers the gap: a sub-query entering `PROCESSING` records the sub-vehicle's `estimate()` of the expected output against the query's `settledDestination`, cleared when the real amount lands.

```text
// Deposit of 10k, T0 totalAssets = 100k (AVAILABLE 20k, ALLOCATION 80k)
dispatch  -> assets leave the system
ephemeral  = estimate({usdc, 10k}, DEPOSIT, OUTPUT) ~= 9,950 aUSDC
T1 totalAssets = 100k + convert(9,950) ~= 110k

settle    -> 9,980 aUSDC actually received, ENTRY -> ALLOCATION, ephemeral cleared
T2 totalAssets = 100k + convert(9,980) ~= 110k
```

## Share price

Pricing is ERC-4626: `shares = assets * totalSupply / totalAssets()`. The denominator aggregates settled and in-flight value across every sector.

```text
totalAssets =
    AVAILABLE balance                               // idle base assets
  + RESERVED balance                                // earmarked base assets
  + for each active vehicle:
      + assets in vehicle sector                    // awaiting deposit query creation
      + expected assets from PROCESSING redeems     // ephemeral
      + estimateSingleAssetAssets(                  // redeem-output estimate, post-fee
          shares in ALLOCATION                      // settled
        + shares in vehicle sector                  // awaiting redeem query
        + expected shares from PROCESSING deposits  // ephemeral
      )
```

`withdrawable()` is narrower: `AVAILABLE` only. Reaching `RESERVED`, vehicle-sector residuals or `ALLOCATION` shares takes an explicit `move` or `dispatch`, so none of them count as immediate liquidity.

## Queued redemptions

When a redemption exceeds `withdrawable()`, the immediate portion settles out of `AVAILABLE` and the rest becomes a demand in the QueryRedeemQueue. An operator or keeper calls `feedQueryRedeemQueue()` on the VehicleManager to provide liquidity, demands and fulfillments match FIFO by position overlap, and the user claims as each tranche lands. Over-provisioned liquidity accumulates as `retrievable()`, pulled back with `retrieveQueryRedeemQueueAssets`.

## Reading the books

```solidity [Solidity]
IVehicleManager manager = MultiVehicle(multiVehicle).manager();
ISectorAccountingEngine accounting = manager.accountingEngine();

uint256 idle      = accounting.getSectorBalance(SectorLib.AVAILABLE, IERC20(baseAsset));
uint256 parked    = accounting.getSectorBalance(SectorLib.RESERVED, IERC20(baseAsset));
uint256 liquidity = accounting.withdrawable();   // equals idle
uint256 staged    = accounting.getSectorBalance(SectorLib.toSector(vehicle), IERC20(baseAsset));

(
    uint256 sharesAfterUnlocks,          // settled shares in ALLOCATION
    uint256 sharesBeforeCreates,         // shares staged for new redeem queries
    uint256 expectedSharesAfterUnlocks,  // ephemeral shares from in-flight deposits
    uint256 expectedAssetsAfterUnlocks,  // projected assets from in-flight redeems
    uint256 assetsBeforeCreates          // assets staged for new deposit queries
) = accounting.vehicleHoldings(vehicle);
```

A vehicle sector balance that lingers means queries are settling slowly. Pending demand outliving your target wait time means `AVAILABLE` is too thin for the redemption flow you are taking.

## Next steps

[MultiVehicle architecture](/developers/contracts/multi-vehicle) covers the engines driving these flows; [Operate an Allocation Strategy](/strategies/allocation/operate) covers the day-to-day.
