How echenim/yieldhunter works
This is a Rust workspace for real-time DeFi monitoring and automated action. The system is split into small domain crates plus one server binary that wires them together, with shared infrastructure for config, persistence, and eventing.
1. Overall shape
- The repository is organized around a pipeline:
- on-chain data ingestion
- borrower risk monitoring
- liquidation opportunity evaluation
- transaction execution
- yield allocation evaluation
- A separate backtesting engine reuses the same domain concepts against historical data.
2. Shared foundation: defily-common
- This crate holds the cross-cutting primitives used by all services:
- configuration loading
- database access
- cache abstraction
- event definitions
- NATS integration
- shared domain types and error handling
- Architecturally, this is the common boundary that keeps the services from duplicating infrastructure code.
3. Protocol ingestion: defily-indexer
- The indexer is the on-chain data intake layer.
- It contains protocol-specific adapters, with explicit support code for Aave V3 and an adapter abstraction for additional protocols.
- Its job is to translate blockchain/protocol state into normalized internal events or stored records that downstream services can consume.
4. Risk monitoring: defily-risk
- This service watches indexed positions and computes borrower health/risk state.
- It is the first decisioning layer after ingestion: it determines whether a borrower has crossed a liquidation threshold.
- The monitor and store modules suggest a stateful service that reads persisted position data, derives health metrics, and emits risk updates.
5. Liquidation analysis: defily-liquidation
- This crate takes risky positions and evaluates whether a liquidation is economically worthwhile.
- The profitability module indicates it factors in liquidation bonus, gas, slippage, and likely protocol-specific constraints before declaring an opportunity actionable.
- This is the business-rule boundary between “at risk” and “worth executing.”
6. Execution: defily-executor
- Once an opportunity is approved, the executor is responsible for carrying out the action.
- The presence of a circuit_breaker module shows an operational safety boundary: execution can be throttled or stopped under adverse conditions.
- This service is the only layer that should interact with transaction submission / live execution mechanics.
7. Yield optimization: defily-yield
- Separate from liquidation, this crate evaluates lending protocol yields and incentives.
- It supports the allocation side of the system: deciding where capital should be deployed for best return.
- In the architecture, it consumes market/protocol state but produces allocation recommendations rather than liquidation actions.
8. Event-driven coupling
- The repository’s architecture is explicitly event-driven:
- indexer publishes normalized updates
- risk, liquidation, and yield services consume those updates
- shared event types ensure the services stay loosely coupled
- NATS is the likely message backbone for runtime coordination, while the database acts as the durable state layer.
9. Durable state and schema
- migrations/001_initial.sql plus defily-common/src/db.rs indicate a relational database-backed state store.
- This store likely holds indexed protocol state, borrower positions, computed risk snapshots, and historical observations used by both live services and backtests.
- The architecture uses persistence as the source of truth, not just in-memory streaming.
10. Backtesting: defily-backtest
- The backtesting crate replays stored historical data to evaluate strategies offline.
- Its engine and report modules suggest a simulation core plus post-run analytics/output.
- This is a separate execution mode that validates liquidation and yield strategies before they are used in production.
11. Service orchestration: defily-server
- The only binary in the tree is defily-server/src/main.rs, which likely bootstraps the service graph.
- In practice, this is the composition root that loads config, connects to infrastructure, and starts the relevant agents.
12. Runtime and deployment boundaries
- The workspace is configured through config/default.toml.
- docker-compose.yml implies local infrastructure dependencies are containerized for development/testing.
- The presence of Cargo workspace files and multiple service crates shows a modular Rust runtime, not a monolith.
13. Key data flow for an architecture diagram
- Blockchain nodes feed protocol indexers.
- Indexers normalize and persist protocol state, and publish events.
- Risk monitoring consumes the state/events to identify under-collateralized accounts.
- Liquidation logic filters those accounts for profitability.
- Executor submits transactions for approved opportunities.
- Yield evaluator reads the same market/protocol state to recommend capital allocation.
- Backtesting reads historical state from storage and reuses the same strategy logic offline.
14. Main architectural boundaries
- Protocol-specific vs protocol-agnostic: adapters in the indexer isolate Aave/other protocol details from the shared risk/liquidation logic.
- Decisioning vs execution: liquidation profitability and risk computation are separated from live transaction submission.
- Live system vs simulation: backtesting is isolated so it can reuse logic without touching execution infrastructure.
- Shared infra vs domain services: defily-common centralizes plumbing and contracts.
15. What to draw as primary nodes
- External: blockchain nodes / lending protocols, database, message bus.
- Core services: indexer, risk monitor, liquidation engine, executor, yield evaluator, backtest engine.
- Shared layer: common config/db/event types/cache/NATS.
- Orchestrator: server binary that assembles the live services.
Main entry points: src/service.rs Indexer · src/service.rs Liquidation · src/service.rs Risk monitor · main.rs Server
Components 22
External systems
Blockchain, storage, and messaging dependencies outside the Rust workspace.
- Blockchain · On-chain protocols and nodes that produce the raw DeFi state.
- Database · Relational state store backed by the workspace migrations.
migrations/001_initial.sql - NATS · Event backbone used for loose coupling between services.
Shared foundation
Cross-cutting primitives reused by all services.
- Config · Configuration loading and environment wiring.
crates/defily-common/src/config.rs - DB layer · Database access and repository primitives.
crates/defily-common/src/db.rs - Cache · Cache abstraction used across services.
crates/defily-common/src/cache.rs - Events · Normalized event definitions passed between services.
crates/defily-common/src/events.rs - NATS client · Integration layer for publishing and consuming events.
crates/defily-common/src/nats.rs - Domain types · Common domain data structures and error handling boundary.
crates/defily-common/src/types.rs
Live pipeline
Runtime services that ingest, assess, decide, and execute actions.
- Indexer · Normalizes on-chain protocol state into internal records and events.
crates/defily-indexer/src/service.rs - Aave V3 · Protocol-specific ingestion logic for Aave V3.
crates/defily-indexer/src/aave_v3.rs - Adapters · Abstraction for supporting additional lending protocols.
crates/defily-indexer/src/adapter.rs - Risk monitor · Computes borrower health and detects liquidation thresholds.
crates/defily-risk/src/service.rs - Monitor · Derives health metrics from stored positions and market state.
crates/defily-risk/src/monitor.rs - Liquidation · Evaluates whether a risky position is profitable to liquidate.
crates/defily-liquidation/src/service.rs - Profitability · Applies bonus, gas, slippage, and protocol constraints.
crates/defily-liquidation/src/profitability.rs - Executor · Submits approved actions to live transaction mechanics.
crates/defily-executor/src/service.rs - Circuit breaker · Operational guardrail that can throttle or stop execution.
crates/defily-executor/src/circuit_breaker.rs - Yield eval · Evaluates protocol yields and incentives for capital allocation.
crates/defily-yield/src/evaluator.rs - Server · Binary that loads config and starts the live service graph.
crates/defily-server/src/main.rs
Connections 35
- Blockchain → Indexer: on-chain data · Raw protocol state is ingested by the indexer.
- Indexer → Database: persist · Normalized state is written to durable storage.
- Indexer → NATS: publish · Index updates are emitted as events.
- Indexer → Risk monitor: positions · Risk monitoring consumes indexed position updates.
- Indexer → Liquidation: market state · Liquidation analysis reads the same normalized state.
- Indexer → Yield eval: protocol state · Yield evaluation consumes market and protocol data.
- Config → Server: loads · Shared configuration is used to bootstrap the runtime.
- DB layer → Indexer: reads/writes · The indexer uses the shared persistence layer.
- DB layer → Risk monitor: reads/writes · Risk monitoring persists and reads borrower state.
- DB layer → Liquidation: reads · Liquidation service consults stored state.
- DB layer → Yield eval: reads · Yield evaluation consults stored market state.
- Events → NATS: contracts · Shared events define the message payloads.
- NATS client → Indexer: connects · The indexer publishes and subscribes through NATS.
- NATS client → Risk monitor: connects · Risk service consumes updates through NATS.
- NATS client → Liquidation: connects · Liquidation service consumes updates through NATS.
- NATS client → Yield eval: connects · Yield service consumes updates through NATS.
- Domain types → Risk monitor: models · Risk logic relies on shared domain types.
- Domain types → Liquidation: models · Liquidation logic relies on shared domain types.
- Domain types → Executor: models · Execution uses shared domain types and errors.
- Aave V3 → Adapters: implements · Aave V3 is one protocol-specific adapter implementation.
- Adapters → Indexer: abstraction · Protocol adapters plug into the indexer boundary.
- Risk monitor → Monitor: uses · The service delegates health computation to monitoring logic.
- Risk monitor → Liquidation: risky positions · Detected risk states feed liquidation evaluation.
- Liquidation → Profitability: filters · Profitability rules decide whether liquidation is actionable.
- Liquidation → Executor: approved ops · Actionable opportunities are passed to execution.
- Executor → Circuit breaker: guards · Execution is constrained by safety controls.
- Server → Indexer: starts · The binary composes and starts the indexer.
- Server → Risk monitor: starts · The binary composes and starts risk monitoring.
- Server → Liquidation: starts · The binary composes and starts liquidation analysis.
- Server → Executor: starts · The binary composes and starts execution.
- Server → Yield eval: starts · The binary composes and starts yield evaluation.
- Database → Backtest: historical data · Backtesting replays stored historical state.
- Backtest → Report: outputs · Simulation results are summarized by reporting.
- Backtest → Liquidation: reuses logic · Offline simulation reuses liquidation strategy concepts.
- Backtest → Yield eval: reuses logic · Offline simulation reuses yield evaluation concepts.