defi-tracker-lifecycle
Pure-logic crate for DeFi order lifecycle tracking on Solana. No IO, no database — just classification, correlation, and state machine logic.
Supported Protocols
| Protocol | Program | Description |
|---|---|---|
| DCA | DCA265Vj8a9CEuX1eb1LWRnDT7uK6q1xMipnNyatn23M |
Jupiter Dollar-Cost Averaging |
| Limit V1 | jupoNjAxXgZ4rjzxzPMP4oxduvQsQtZzyknqvzYNrNu |
Jupiter Limit Orders V1 |
| Limit V2 | j1o2qRpjcyUwEvwtcfhEQefh773ZgjxcVRry7LDqg5X |
Jupiter Limit Orders V2 |
| Kamino | LiMoM9rMhrdYrfzUCxQppvxCSG1FcrUK9G8uLq4A1GF |
Kamino Limit Orders |
Architecture
Event Processing Pipeline
flowchart TD
subgraph Input
Raw["RawInstruction / RawEvent"]
end
subgraph Dispatch
Lookup["from_program_id()"] --> Adapter["adapter_for()"]
end
subgraph Classify
CI["classify_instruction()"]
CE["classify_and_resolve_event()"]
end
subgraph Output
ET["EventType"]
CO["CorrelationOutcome"]
EP["EventPayload"]
end
Raw --> Lookup
Adapter --> CI & CE
CI --> ET
CE --> ET & CO & EP
Order Lifecycle State Machine
flowchart TD
Start(( )) -->|Create| Active
Active -->|FillDelta / MetadataOnly| Active
Active -->|"Close(Completed)"| Completed
Active -->|"Close(Cancelled)"| Cancelled
Active -->|"Close(Expired)"| Expired
subgraph Terminal ["Terminal — only MetadataOnly accepted"]
Completed
Cancelled
Expired
end
Core Concepts
ProtocolAdapter — trait implemented by each protocol. Two phases:
- Classify: maps instruction/event names to
EventType(Created, FillCompleted, Closed, etc.) - Resolve: extracts order PDAs (
CorrelationOutcome) and structured data (EventPayload)
LifecycleEngine — stateless state machine that enforces transition rules:
- Non-terminal orders accept all transitions
- Terminal orders (Completed/Cancelled/Expired) only accept
MetadataOnly - Snapshot deltas are always non-negative; regressions tracked separately
ResolveContext — carries pre-fetched data needed for correlation (Kamino requires pre-fetched order PDAs since its events don't contain them directly)
Usage
use ;
// 1. Identify protocol from program ID
let protocol = from_program_id
.ok_or?;
let adapter = adapter_for;
// 2. Classify + resolve an event in one pass
let ctx = ResolveContext ;
let = adapter
.classify_and_resolve_event
.ok_or? // None = unknown event variant
.map_err?; // Err = malformed known event payload
// 3. Map EventType to LifecycleTransition via the canonical mapping
let transition = event_type_to_transition;
// 4. Check state transition (pass None if not terminal)
let current_terminal: = None;
let decision = decide_transition;
match decision
Testing
Test Layers
| Layer | What it catches |
|---|---|
Compile-time (classify_decoded()) |
Upstream Carbon adds a new variant |
| Mirror enum alignment | Mirror enum drifts from Carbon variants |
| EventType reachability | A variant becomes dead/unreachable |
| Unit tests | Individual classify/resolve logic per protocol |
| Fixture tests | Real JSON from defi-tracker parses and classifies correctly |
| End-to-end lifecycle | Full pipeline: raw JSON → adapter → state machine → status tracking |
Coverage (requires cargo-llvm-cov)