Risk Framework
Data Integrity
Finality depths, reorg safety, reconciliation, and snapshot intervals.
Risk scores are only as good as the data feeding them. Philidor enforces strict data integrity guarantees.
Finality Depths
Per-chain confirmation depths prevent reading unfinalized (potentially reorganized) data:
| Chain | Chain ID | Confirmation Depth | Notes |
|---|---|---|---|
| Ethereum | 1 | 64 blocks | 2 epochs post-Merge |
| Polygon | 137 | 128 blocks | Heimdall checkpoints |
| Avalanche | 43114 | 1 block | Sub-second finality |
| Optimism | 10 | 0 | L2 sequencer, finality via L1 |
| Arbitrum | 42161 | 0 | L2 sequencer, finality via L1 |
| Base | 8453 | 0 | L2 sequencer, finality via L1 |
Reorg Safety
Six invariants protect against data corruption from chain reorganizations:
- Finalized blocks only —
toBlockcapped atgetFinalizedBlockNumber, nevergetBlockNumber - Persist-then-advance — events written to database before sync cursor advances. If persistence fails, cursor stays put
- All-or-nothing — any batch/module failure means no state advancement. Retry next cycle
- Reorg rollback never jumps forward — uses
Math.min(lastFinalizedBlock, lastProcessedBlock) - DB write failures propagate — RPC read failures are swallowed; DB write failures are exceptions
- Deduplication —
ON CONFLICT (tx_hash, log_index) DO NOTHING. Re-fetching is safe
Reconciliation
Automated checks run every 30 minutes to detect:
- Sync gaps — missing block ranges in the event log
- Event density drift — unusual changes in event frequency
- Stale cursors — sync state that hasn't advanced
- Data anomalies — inconsistencies between expected and observed data
Anomalies trigger alerts before they affect risk scores.
Sync Intervals
| Process | Interval | Description |
|---|---|---|
| API sync | 30 minutes | Pull from protocol APIs |
| On-chain indexer | 30 minutes | Poll RPCs for events |
| Risk calculator | 30 minutes | Recompute all risk scores |
| Oracle freshness | 15 seconds | Poll Chainlink feeds |
| Reconciliation | 30 minutes | Verify data consistency |
Oracle Freshness Monitoring
A dedicated worker polls Chainlink price feeds every 15 seconds and writes freshness data to Redis. This provides:
- Real-time staleness detection for oracle-dependent vaults
- Historical freshness data for the Oracle Freshness API
- Automatic score adjustment when feeds go stale
APR Data Sources
APR is sourced from on-chain share price reads (ERC-4626) or protocol APIs (Aave, Compound). Forward-looking estimates and boosted marketing figures are never used.
- Base APR: native protocol return (lending interest, share price accrual)
- Rewards: token emissions, points, trading fees — sourced from Morpho rewards API, Aavescan, and protocol subgraphs
- Invariant:
apr_net = base_apr + SUM(reward APRs)