ROP uses Somnia Reactivity as the event intake layer.
The architecture does not run cron jobs or polling loops to discover contract changes. Instead:
- real mode subscribes to contract events through Somnia Reactivity
- mock mode simulates the same callback path for deterministic local demos
The rule engine is identical in both modes once an event has been normalized.
All Somnia-specific wiring is isolated to:
apps/watcher/src/reactivity.ts
That file decides between:
REALmode via@somnia-chain/reactivityMOCK_MODE=truevia local contract listeners inapps/watcher/src/mock-mode.ts
The current watcher subscribes to:
PriceUpdatedonMockPriceFeedHealthFactorChangedonMockVault
Those are enough to show:
- price-threshold automation
- vault-health automation
- multi-rule Guardian workflows
The real Somnia adapter is designed to use ethCalls alongside the event subscription where useful.
Current examples:
latestPrice()bundled withPriceUpdated- optional
getHealthFactor(user)bundled withHealthFactorChanged
That keeps the architecture aligned with Somnia’s event-plus-state model even though the watcher still owns final rule matching and transaction dispatch.
MOCK_MODE=true exists for demo reliability:
- it avoids blocking local development on testnet credentials
- it keeps the watcher UI and feed fully usable
- it preserves the same rule normalization and executor dispatch path
This is the correct hackathon tradeoff: the product story stays reactive, but the repo remains runnable anywhere.