Skip to main content
This page covers the smart contract implementation details. See Glossary.
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

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

Register the Multi-Vehicle

// Register with thresholds (in base asset units)
jobListing.registerMultiVehicle(
    multiVehicle,    // MultiVehicle address
    100e18,          // Redemption threshold
    100e18           // Retrieval threshold
);
You can also register via CLI:
cast send $JOB_LISTING_ADDRESS \
  "registerMultiVehicle(address,uint256,uint256)" \
  $MULTI_VEHICLE_ADDRESS $REDEMPTION_THRESHOLD $RETRIEVAL_THRESHOLD \
  --private-key $ADMIN_PK
2

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.

Job types

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
Automates retrieving assets from the redemption queue back to the Multi-Vehicle accounting engine.
  • Status check: retrievalStatus(multiVehicle)
  • Execution: retrieveQueryRedeemQueueAssets(multiVehicle)
  • Condition: retrievableAssets >= threshold
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)
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 WAITING

Job status values

StatusMeaning
POLLNot ready — check again later
EXECReady — submit the execution report
STOPFinished or unregistered — stop monitoring

Integrate with the Keeper contract

The Keeper processes batches of executions via reports — arrays of ReportDataItem structs.
struct ReportDataItem {
    address execTarget;    // Contract to call
    bytes execCalldata;    // Encoded function call
}

// Submit a report (requires KEEPER_ON_REPORT role)
keeper.onReport(metadata, encodedReport);
If any call in the report reverts, the entire transaction reverts. This ensures atomicity for the batch.

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

VariableDescription
RPC_URLEthereum node RPC URL
KEEPER_ADDRESSAddress of the Keeper contract
FORWARDER_PRIVATE_KEYPrivate key of the forwarder account
GRAPHQL_ENGINE_URLURL of the GraphQL indexer

Deploy with Docker

# Build the image
docker build -t railnet-keeper tools/keeper/

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

Required roles

RoleRequired for
JOB_LISTING_REGISTERRegistering new jobs
JOB_LISTING_UNREGISTERRemoving jobs
JOB_LISTING_EXECUTEExecuting registered jobs
KEEPER_ON_REPORTSubmitting reports to the Keeper