> ## Documentation Index
> Fetch the complete documentation index at: https://docs.railnet.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Operate an Allocation Strategy

> Manage allocations, rebalance across yield sources, and handle day-to-day operations

<Info>In Railnet smart contracts, an Allocation Strategy is implemented as a **MultiVehicle**. See [Glossary](/developers/glossary) for all terminology.</Info>

This guide covers how to authorize yield sources, configure allocation queues, and run day-to-day operations for your Allocation Strategy — moving assets between sectors, dispatching to yield sources, rebalancing allocations, handling redemptions, and integrating with keepers for automation.

## Prerequisites

* A deployed Allocation Strategy ecosystem (see [Create an Allocation Strategy](/strategies/allocation/create))
* Your External Access Control (EAC) contract address
* At least one authorized yield source
* The following roles on your EAC, scoped to the **Sector Accounting Engine**:
  * `MULTI_VEHICLE_MOVE_ASSETS`
  * `MULTI_VEHICLE_DISPATCH`
  * `MULTI_VEHICLE_REBALANCE` (for rebalancing operations)

## Operating a platform-owned Allocation Strategy

If a Conduit owner deployed the Allocation Strategy and invited you to manage it, be aware of the guardrails:

* **Yield source authorization** is controlled by the owner. You manage allocations within the set of sources they have authorized.
* **Fee structure** is set by the owner. You earn through the configured performance fee share.
* **Admin access** remains with the owner. You cannot grant roles to others or change the access control configuration.

Your operational roles are scoped to specific contracts — you can allocate, rebalance, and manage queues, but cannot change the strategic boundaries. See [Guardrails](/strategies/allocation/guardrails) for details.

## Authorize yield sources

Before your Allocation Strategy can allocate assets to a yield source, you must authorize that source in the Vehicle Registry.

<Info>
  The Vehicle Registry validates that yield sources use the same base asset as the Allocation Strategy and implement the STEAM standard as `SingleAsset` vehicles.
</Info>

**Requires:** `MULTI_VEHICLE_SET_VEHICLE_AUTHORIZATION` role scoped to the Sector Accounting Engine.

<Steps>
  <Step title="Find your Sector Accounting Engine address">
    Yield source authorization is performed on the Sector Accounting Engine. You can find its address from the MultiVehicle contract or via the Railnet subgraph.

    <CodeGroup>
      ```solidity Solidity theme={null}
      ISectorAccountingEngine accounting = MultiVehicle(multiVehicle).accountingEngine();
      IVehicleRegistry registry = accounting.vehicleRegistry();
      ```

      ```typescript TypeScript theme={null}
      // Coming soon
      ```
    </CodeGroup>
  </Step>

  <Step title="Authorize a yield source">
    Call `syncVehicleActivationStatus` on the Sector Accounting Engine to authorize a yield source.

    <CodeGroup>
      ```solidity Solidity theme={null}
      // Authorize an Aave V3 vehicle
      address aaveVehicle = 0x...; // The sub-vehicle address
      sectorAccountingEngine.syncVehicleActivationStatus(aaveVehicle, true);

      // Authorize a Compound V3 vehicle
      address compoundVehicle = 0x...;
      sectorAccountingEngine.syncVehicleActivationStatus(compoundVehicle, true);
      ```

      ```typescript TypeScript theme={null}
      // Coming soon
      ```
    </CodeGroup>
  </Step>

  <Step title="Unauthorize a yield source">
    To remove a yield source, first rebalance or redeem all assets from it, then unauthorize it.

    <CodeGroup>
      ```solidity Solidity theme={null}
      // Unauthorize a vehicle (ensure no funds remain allocated)
      sectorAccountingEngine.syncVehicleActivationStatus(vehicleToRemove, false);
      ```

      ```typescript TypeScript theme={null}
      // Coming soon
      ```
    </CodeGroup>

    <Warning>
      Unauthorizing a yield source does not automatically redeem existing positions. Make sure to withdraw all funds from the source before removing it.
    </Warning>
  </Step>
</Steps>

## Configure allocation queues

The Queue Strategy Engine determines how assets are distributed across authorized yield sources using deposit and redeem queues.

### Target semantics

<Tabs>
  <Tab title="Deposit queue">
    In the deposit queue, `target` acts as a **ceiling** — the maximum shares to allocate to a yield source before moving to the next entry.

    * The queue processes in order: the first entry is filled first, up to its target, then the second entry, and so on.
    * `type(uint256).max` means no limit (allocate all available to this source).
    * The queue does **not** enforce ongoing ratios. If yields diverge across sources, allocations will drift.

    **Example:** With deposit queue `[{Aave, target: 80000e18}, {Compound, target: 20000e18}]`:

    1. First 80,000 shares go to Aave
    2. Next 20,000 shares go to Compound
    3. Any additional shares overflow to subsequent entries
  </Tab>

  <Tab title="Redeem queue">
    In the redeem queue, `target` acts as a **floor** — the minimum shares to maintain in a yield source before withdrawing from it.

    * The queue processes in order: the first entry is drained first, down to its target, then the second entry.
    * `0` means no minimum (the source can be fully drained).
    * Withdrawals prioritize earlier entries while respecting minimum thresholds.

    **Example:** With redeem queue `[{Compound, target: 0}, {Aave, target: 0}]`:

    1. Withdrawals come from Compound first, down to 0 shares
    2. Then Aave is drained if more is needed
  </Tab>
</Tabs>

### Set queues

**Requires:** `MULTI_VEHICLE_SET_QUEUES` role scoped to the Queue Strategy Engine.

<CodeGroup>
  ```solidity Solidity theme={null}
  IQueueStrategyEngine strategy = MultiVehicle(multiVehicle).accountingEngine().strategyEngine();

  // Define deposit queue: Aave first (up to 80,000 shares), then Compound (unlimited)
  IQueueStrategyEngine.QueueEntry[] memory depositQueue = new IQueueStrategyEngine.QueueEntry[](2);
  depositQueue[0] = IQueueStrategyEngine.QueueEntry({
      vehicle: aaveVehicle,
      target: Target({ value: 80_000e18, mode: TargetMode.Absolute, threshold: 0 })
  });
  depositQueue[1] = IQueueStrategyEngine.QueueEntry({
      vehicle: compoundVehicle,
      target: TargetLib.unlimited()
  });

  // Define redeem queue: Compound first, then Aave
  IQueueStrategyEngine.QueueEntry[] memory redeemQueue = new IQueueStrategyEngine.QueueEntry[](2);
  redeemQueue[0] = IQueueStrategyEngine.QueueEntry({
      vehicle: compoundVehicle,
      target: TargetLib.zero()
  });
  redeemQueue[1] = IQueueStrategyEngine.QueueEntry({
      vehicle: aaveVehicle,
      target: TargetLib.zero()
  });

  strategy.setQueues(depositQueue, redeemQueue);
  ```

  ```typescript TypeScript theme={null}
  // Coming soon
  ```
</CodeGroup>

<Tip>
  A common pattern is to set the redeem queue in reverse order of the deposit queue. This ensures that the last yield source to receive deposits is the first to be drained during redemptions.
</Tip>

## How asset flow works

Assets in an Allocation Strategy flow through distinct sectors tracked by the Sector Accounting Engine:

1. **Deposit sector** — idle liquidity waiting to be allocated
2. **Vehicle pending sector** — assets earmarked for a specific yield source but not yet deposited
3. **Vehicle active sector** — assets deposited and earning yield in a yield source
4. **Redeem sector** — assets withdrawn from yield sources and awaiting user claims

The typical operator workflow is: **move assets** from idle to a yield source sector, then **dispatch** to execute the deposit into the yield source.

## View holdings and allocations

Before operating, check the current state of your Allocation Strategy's sectors and allocations.

<CodeGroup>
  ```solidity Solidity theme={null}
  ISectorAccountingEngine accounting = MultiVehicle(multiVehicle).accountingEngine();

  // Check total assets across all sectors
  uint256 totalAssets = MultiVehicle(multiVehicle).totalAssets();

  // Check holdings for a specific yield source
  (
      uint256 shares,
      uint256 assets,
      uint256 pendingDeposit,
      uint256 pendingRedeem,
      ,
      ,
  ) = accounting.vehicleHoldings(aaveVehicle);
  ```

  ```typescript TypeScript theme={null}
  // Coming soon
  ```
</CodeGroup>

You can also query the Railnet subgraph:

```graphql theme={null}
query SectorBalances($address: String!) {
  SectorBalance(
    where: {
      sector: {
        accountingEngine: {
          multiVehicle: { id: { _ilike: $address } }
        }
      }
    }
  ) {
    asset
    value
    sector {
      name
      sectorId
    }
  }
}
```

## Move assets to a yield source

Use `moveAssets` to transfer the deposit asset (e.g. USDC) from the idle deposit sector to a yield source's pending sector. This stages the assets for dispatch.

<Note>
  Moving assets does not deposit them into the yield source yet. You must call `dispatch` afterward to execute the deposit.
</Note>

<CodeGroup>
  ```solidity Solidity theme={null}
  ISectorAccountingEngine accounting = MultiVehicle(multiVehicle).accountingEngine();

  // Sector IDs
  bytes32 depositSector = 0x6465706f73697400000000000000000000000000000000000000000000000000;
  bytes32 vehicleSector = bytes32(uint256(uint160(targetVehicle)));

  // Move 10,000 USDC from idle to vehicle pending sector
  uint256 amount = 10_000e6; // USDC has 6 decimals
  accounting.moveAssets(depositSector, vehicleSector, amount);
  ```

  ```typescript TypeScript theme={null}
  // Coming soon
  ```
</CodeGroup>

## Dispatch assets to a yield source

After moving assets to a yield source's pending sector, call `dispatch` to create a deposit query on the yield source. This executes the actual deposit.

<CodeGroup>
  ```solidity Solidity theme={null}
  ISectorAccountingEngine accounting = MultiVehicle(multiVehicle).accountingEngine();

  // Dispatch pending assets to the target vehicle
  address targetVehicle = 0x...; // The authorized sub-vehicle
  accounting.dispatch(targetVehicle);
  ```

  ```typescript TypeScript theme={null}
  // Coming soon
  ```
</CodeGroup>

<Tip>
  You can batch `moveAssets` and `dispatch` operations. Move assets to multiple yield source sectors first, then dispatch to each source in sequence.
</Tip>

## Rebalance between yield sources

Rebalancing moves assets directly from one yield source to another in a single atomic transaction. The Sector Accounting Engine handles the redeem from the source and deposit into the destination.

<CodeGroup>
  ```solidity Solidity theme={null}
  ISectorAccountingEngine accounting = MultiVehicle(multiVehicle).accountingEngine();

  address sourceVehicle = 0x...; // Vehicle to withdraw from
  address targetVehicle = 0x...; // Vehicle to deposit into
  uint256 shareAmount = 5_000e18; // Amount of shares to move

  // Atomic rebalance: redeem from source, deposit into destination
  accounting.rebalance(sourceVehicle, targetVehicle, shareAmount);
  ```

  ```typescript TypeScript theme={null}
  // Coming soon
  ```
</CodeGroup>

<Warning>
  If the source yield source's redemption is asynchronous, the assets are staged in the destination sector until the redemption settles. The deposit into the destination happens automatically once the assets arrive.
</Warning>

## Handle user deposits

When users deposit into the Allocation Strategy, assets flow through the STEAM lifecycle. With allocation queues configured, deposits are automatically distributed to yield sources based on the deposit queue priority.

<CodeGroup>
  ```solidity Solidity theme={null}
  // User creates a deposit query
  Query memory query = Query({
      owner: depositor,
      receiver: depositor,
      mode: Mode.DEPOSIT,
      input: [Asset({ asset: address(usdc), value: 500e6 })],
      output: [Asset({ asset: address(multiVehicle), value: 0 })],
      salt: keccak256("deposit-001"),
      data: ""
  });

  // STEAM lifecycle: create → unlock
  multiVehicle.create(query);
  multiVehicle.unlock(query);
  ```

  ```typescript TypeScript theme={null}
  // Coming soon
  ```
</CodeGroup>

## Handle redemptions

Redemptions follow the STEAM lifecycle. The Queue Strategy Engine processes redeems according to the redeem queue priority.

<CodeGroup>
  ```solidity Solidity theme={null}
  // User creates a redeem query
  Query memory query = Query({
      owner: depositor,
      receiver: depositor,
      mode: Mode.REDEEM,
      input: [Asset({ asset: address(multiVehicle), value: 1_000e18 })],
      output: [Asset({ asset: address(usdc), value: 0 })],
      salt: keccak256("redeem-001"),
      data: ""
  });

  multiVehicle.create(query);

  // For async redemptions, the query progresses through the redeem queue
  // Once assets are available:
  multiVehicle.unlock(query);
  ```

  ```typescript TypeScript theme={null}
  // Coming soon
  ```
</CodeGroup>

## Keeper integration

Keepers are off-chain bots that automate routine operations. As an operator, understanding keeper integration helps you decide what to automate vs manage manually.

### What keepers automate

| Operation                | Description                                                             |
| ------------------------ | ----------------------------------------------------------------------- |
| Redemption queue feeding | Provides liquidity to the redemption queue when there is pending demand |
| Asset retrieval          | Retrieves settled assets from the redemption queue back to accounting   |
| Fee share redemption     | Progresses redemption queries for fee shares                            |
| Sub-query progression    | Advances async sub-queries (e.g. Ethena withdrawals)                    |

### What remains manual

| Operation                       | Why                            |
| ------------------------------- | ------------------------------ |
| Capital allocation (moveAssets) | Requires strategic judgment    |
| Dispatching to yield sources    | Depends on allocation strategy |
| Rebalancing                     | Market-driven decision         |
| Queue configuration changes     | Strategic decision             |

### Check keeper status

If your Allocation Strategy is registered with the keeper system, verify automation is running:

```graphql theme={null}
query KeeperJobs($address: String!) {
  Job(where: { target: { _ilike: $address } }) {
    status
    lastExecution
    jobType
  }
}
```

If keepers are not processing redemptions, you can handle them manually (see [Troubleshooting](#troubleshooting) below).

For full keeper setup details, see [Set up keeper automation](/developers/contracts/keeper).

## Update queue priorities

You can change the allocation strategy at any time by updating the deposit and redeem queues.

<CodeGroup>
  ```solidity Solidity theme={null}
  IQueueStrategyEngine strategy = MultiVehicle(multiVehicle).accountingEngine().strategyEngine();

  // New deposit queue: prioritize Compound, then Aave
  IQueueStrategyEngine.QueueEntry[] memory newDepositQueue = new IQueueStrategyEngine.QueueEntry[](2);
  newDepositQueue[0] = IQueueStrategyEngine.QueueEntry({
      vehicle: compoundVehicle,
      target: TargetLib.unlimited()
  });
  newDepositQueue[1] = IQueueStrategyEngine.QueueEntry({
      vehicle: aaveVehicle,
      target: TargetLib.unlimited()
  });

  // New redeem queue: drain Aave first, then Compound
  IQueueStrategyEngine.QueueEntry[] memory newRedeemQueue = new IQueueStrategyEngine.QueueEntry[](2);
  newRedeemQueue[0] = IQueueStrategyEngine.QueueEntry({
      vehicle: aaveVehicle,
      target: TargetLib.zero()
  });
  newRedeemQueue[1] = IQueueStrategyEngine.QueueEntry({
      vehicle: compoundVehicle,
      target: TargetLib.zero()
  });

  strategy.setQueues(newDepositQueue, newRedeemQueue);
  ```

  ```typescript TypeScript theme={null}
  // Coming soon
  ```
</CodeGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Stuck redemptions">
    If redemptions are not progressing (e.g. due to keeper failure or insufficient liquidity):

    **1. Feed the redeem queue** — If withdrawable assets are available:

    ```solidity theme={null}
    multiVehicle.feedQueryRedeemQueue();
    ```

    **2. Progress stuck sub-queries** — If a sub-query is stuck in a non-terminal state:

    ```solidity theme={null}
    ISubQueryEngine subQueryEngine = MultiVehicle(multiVehicle).accountingEngine().subQueryEngine();
    subQueryEngine.progressQuery(subQuery, query);
    ```

    **3. Dispatch staged assets** — If assets are in a yield source sector with no active query:

    ```solidity theme={null}
    accounting.dispatch(targetVehicle);
    ```
  </Accordion>

  <Accordion title="Stuck deposits">
    If a deposit query is stuck in `PROCESSING` state, the yield source may require manual progression (common with async protocols like Ethena):

    ```solidity theme={null}
    ISubQueryEngine subQueryEngine = MultiVehicle(multiVehicle).accountingEngine().subQueryEngine();
    subQueryEngine.progressQuery(subQuery, query);
    ```

    Check the yield source's STEAM state to understand what transition is needed.
  </Accordion>

  <Accordion title="Failed dispatches">
    If `dispatch` reverts, common causes include:

    * **No pending assets** — Check the yield source's pending sector has a non-zero balance
    * **Source not authorized** — Verify the yield source is still authorized in the Vehicle Registry
    * **Missing role** — Confirm you have `MULTI_VEHICLE_DISPATCH` scoped to the Sector Accounting Engine
    * **Source rejection** — The yield source's `create` function may be reverting (check the underlying protocol's status)
  </Accordion>

  <Accordion title="Allocation queue not behaving as expected">
    Remember that queues use **ceiling** (deposit) and **floor** (redeem) semantics:

    * Deposit queue targets are maximums, not ratios — allocations will drift with yield
    * If all yield sources have reached their ceiling, new deposits stay in the idle sector
    * Redeem queue targets are minimums — a source won't be drained below its target

    Update queue targets as your strategy evolves. See [Configure allocation queues](#configure-allocation-queues).
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Risk management" icon="shield-check" href="/strategies/risk-management">
    Evaluate yield sources, manage concentration risk, and handle emergencies.
  </Card>

  <Card title="Configure fees" icon="percent" href="/developers/contracts/fee-manager">
    Set up performance, management, and transactional fee structures.
  </Card>
</CardGroup>
