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

# Set up keeper automation

> Automate Vehicle operations with keeper bots

<Info>This page covers the smart contract implementation details. See [Glossary](/developers/glossary).</Info>

Keepers are off-chain bots that monitor on-chain conditions and execute automated operations like redemption queue processing and asset retrieval. This guide walks you through setting up keeper automation for your Vehicles and Multi-Vehicles.

## How keepers work

The keeper system has three components:

1. **Job Listing contracts** — on-chain registries that define what needs to be automated and when
2. **Keeper contract** — processes batches of job executions submitted by authorized forwarders
3. **Keeper bot** — off-chain service that polls job status and submits execution reports

```mermaid theme={null}
sequenceDiagram
    participant JL as JobListing
    participant K as Keeper
    participant Bot as Keeper Bot
    participant MV as MultiVehicle

    JL->>Bot: JobStarted event
    loop Monitoring
        Bot->>JL: Check status
        JL-->>Bot: POLL / EXEC / STOP
    end
    Bot->>K: onReport(executions)
    K->>JL: Execute job
    JL->>MV: feedQueryRedeemQueue()
```

## Register a Multi-Vehicle for automation

To enable automation, register your Multi-Vehicle with the `MultiVehicleJobListing` contract. This creates two persistent jobs: one for feeding the redemption queue and one for retrieving assets.

<Steps>
  <Step title="Register the Multi-Vehicle">
    <CodeGroup>
      ```solidity Solidity theme={null}
      // Register with thresholds (in base asset units)
      jobListing.registerMultiVehicle(
          multiVehicle,    // MultiVehicle address
          100e18,          // Redemption threshold
          100e18           // Retrieval threshold
      );
      ```

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

    You can also register via CLI:

    ```bash theme={null}
    cast send $JOB_LISTING_ADDRESS \
      "registerMultiVehicle(address,uint256,uint256)" \
      $MULTI_VEHICLE_ADDRESS $REDEMPTION_THRESHOLD $RETRIEVAL_THRESHOLD \
      --private-key $ADMIN_PK
    ```
  </Step>

  <Step title="Configure thresholds">
    Thresholds prevent the keeper from executing transactions for trivial amounts, optimizing gas costs.

    **Redemption threshold** — the job triggers when both:

    * Withdrawable assets in the Multi-Vehicle exceed the threshold
    * Pending demand in the `QueryRedeemQueue` exceeds the threshold

    **Retrieval threshold** — the job triggers when:

    * Retrievable assets in the `QueryRedeemQueue` exceed the threshold

    To update thresholds, call `registerMultiVehicle` again with new values.
  </Step>
</Steps>

## Job types

<AccordionGroup>
  <Accordion title="Redemption Queue Feed">
    Automates providing liquidity to the redemption queue when there is pending demand and available withdrawable assets.

    * **Status check**: `redemptionStatus(multiVehicle)`
    * **Execution**: `feedQueryRedeemQueue(multiVehicle)`
    * **Condition**: `withdrawableAssets >= threshold` AND `pendingDemand >= threshold`
  </Accordion>

  <Accordion title="Asset Retrieval">
    Automates retrieving assets from the redemption queue back to the Multi-Vehicle accounting engine.

    * **Status check**: `retrievalStatus(multiVehicle)`
    * **Execution**: `retrieveQueryRedeemQueueAssets(multiVehicle)`
    * **Condition**: `retrievableAssets >= threshold`
  </Accordion>

  <Accordion title="Fee Share Redemption">
    Automates progressing redemption queries created when fee shares are redeemed.

    * **Status check**: `queryRedemptionStatus(vehicle, query)`
    * **Execution**: `progressQuery(feeManager, vehicle, query)`
    * **Condition**: Query is in an actionable STEAM state (`PROCESSING`, `UNLOCKING`, or `RECOVERING`)
  </Accordion>

  <Accordion title="Sub-Query Progression">
    Automates progressing individual sub-queries sent to sub-vehicles (e.g., async protocols like Ethena).

    * **Status check**: `subqueryStatus(subQuery, query)`
    * **Execution**: `progressQuery(subQuery, query)`
    * **Condition**: Sub-vehicle query has moved past `PROCESSING` or `PAUSED`
  </Accordion>
</AccordionGroup>

## Job status values

| Status | Meaning                                    |
| ------ | ------------------------------------------ |
| `POLL` | Not ready — check again later              |
| `EXEC` | Ready — submit the execution report        |
| `STOP` | Finished or unregistered — stop monitoring |

## Integrate with the Keeper contract

The Keeper processes batches of executions via **reports** — arrays of `ReportDataItem` structs.

<CodeGroup>
  ```solidity Solidity theme={null}
  struct ReportDataItem {
      address execTarget;    // Contract to call
      bytes execCalldata;    // Encoded function call
  }

  // Submit a report (requires KEEPER_ON_REPORT role)
  keeper.onReport(metadata, encodedReport);
  ```

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

<Warning>
  If any call in the report reverts, the entire transaction reverts. This ensures atomicity for the batch.
</Warning>

## Run the keeper bot

The keeper bot is a Python service that polls the indexer for `JobStarted` events and executes jobs when ready.

### Environment variables

| Variable                | Description                          |
| ----------------------- | ------------------------------------ |
| `RPC_URL`               | Ethereum node RPC URL                |
| `KEEPER_ADDRESS`        | Address of the Keeper contract       |
| `FORWARDER_PRIVATE_KEY` | Private key of the forwarder account |
| `GRAPHQL_ENGINE_URL`    | URL of the GraphQL indexer           |

### Deploy with Docker

```bash theme={null}
# Build the image
docker build -t railnet-keeper tools/keeper/

# Run the container
docker run -it --env-file .env railnet-keeper
```

## Required roles

| Role                     | Required for                     |
| ------------------------ | -------------------------------- |
| `JOB_LISTING_REGISTER`   | Registering new jobs             |
| `JOB_LISTING_UNREGISTER` | Removing jobs                    |
| `JOB_LISTING_EXECUTE`    | Executing registered jobs        |
| `KEEPER_ON_REPORT`       | Submitting reports to the Keeper |
