You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CLAUDE.md
+98-83Lines changed: 98 additions & 83 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
4
4
5
5
## Project Overview
6
6
7
-
This is a Subsquid-based notification system for Origin Protocol. It monitors blockchain events across Ethereum mainnet, Base, and Sonic chains and sends notifications to Discord webhooks. The database is minimal—this squid focuses on real-time event processing, not data storage.
7
+
This is a Subsquid-based notification system for Origin Protocol. It monitors blockchain events and traces across Ethereum mainnet, Base, and Sonic chains, persists them to a database, and sends notifications to Discord webhooks based on configurable alert rules stored in a separate Postgres database.
8
+
9
+
## User Interaction
10
+
11
+
You are encouraged to ask the user questions in order to save time and effort.
8
12
9
13
## Common Commands
10
14
@@ -14,126 +18,137 @@ pnpm run process # Build & start mainnet processor (spins up local DB v
14
18
pnpm run process:base # Build & start Base chain processor
15
19
pnpm run process:sonic # Build & start Sonic chain processor
16
20
pnpm run resume # Resume without rebuild/DB setup
17
-
pnpm run generate-abis # Generate TypeScript from ABI JSON files in abi/
18
21
pnpm run prettier-fix # Format code
22
+
pnpm run backfill # Backfill EventRecord/TraceRecord for specific rules (see below)
23
+
pnpm run digest-db # Output all DB-driven alert rules and code-driven processors
24
+
pnpm run generate-seed # Regenerate seed-rules.sql from code-driven processors
25
+
pnpm run generate-abi-seed # Regenerate seed-abis.sql from abi/*.json files
19
26
sqd deploy . --update # Deploy to Subsquid Cloud (use --update to prevent gaps)
20
27
```
21
28
22
29
### Environment Variables for Development
23
30
24
31
-`BLOCK_FROM=123456` - Start processing from specific block
25
-
-`PROCESSOR=Name` - Filter to processors matching "Name"
-`ALERT=Name` - Filter config-driven alert rules by display name or ID (substring match)
34
+
-`ALERT_CONFIG_DB_MIGRATION=true` - Run DB migration + seed on startup (for local dev)
26
35
27
-
Example: `BLOCK_FROM=18102886 PROCESSOR=Trace pnpm run process`
36
+
Examples:
37
+
```shell
38
+
BLOCK_FROM=21540000 ALERT="Lido ARM" pnpm run process # Debug specific alert rules
39
+
BLOCK_FROM=21540000 PROCESSOR=Buyback pnpm run process # Debug code-driven processors
40
+
```
41
+
42
+
### Backfill Command
43
+
44
+
Backfills EventRecord/TraceRecord for alert rules without sending notifications:
45
+
```shell
46
+
pnpm run backfill -- --chain 1 --from 21525891 # All rules on mainnet
47
+
pnpm run backfill -- --chain 8453 --from 24450127 --rule oeth-vault # Specific rule on Base
48
+
```
28
49
29
50
## Architecture
30
51
52
+
### Two Databases
53
+
54
+
|| Squid DB (Subsquid Cloud Postgres) | Alert Config DB (Separate Postgres) |
55
+
|---|---|---|
56
+
|**Purpose**| Raw on-chain data (EventRecord, TraceRecord) + notification dedup | Alert rules, ABIs, topic definitions |
57
+
|**Managed by**| Subsquid migrations, TypeORM |`migration.sql`, seeded at startup |
58
+
|**Connection**|`DB_URL` or `DB_HOST`/`DB_PORT`/etc. |`ALERT_CONFIG_DB_URL`|
59
+
31
60
### Entry Points (Chain-Specific)
32
61
-`src/main.ts` - Ethereum mainnet processor
33
62
-`src/main-base.ts` - Base chain processor
34
63
-`src/main-sonic.ts` - Sonic chain processor
64
+
-`src/backfill.ts` - Standalone backfill script
65
+
66
+
Each entry point runs this startup sequence:
67
+
1.`initAlertConfigDb()` — creates DB, runs migration, seeds data (when `ALERT_CONFIG_DB_MIGRATION=true`)
68
+
2.`abiRegistry.loadFromDb()` — loads ABIs from alert_config DB, builds decode maps
69
+
3.`loadWalletLabels()` — loads address names from Railway DB
70
+
71
+
### Processors (`src/processors/`)
72
+
-**`config-alert.ts`** - Config-driven alert processor. Loads rules from alert_config DB, subscribes to matching events/traces, evaluates filters, sends notifications. This is the primary processor for all chains.
73
+
-**`persistence.ts`** - Persists all events and traces to EventRecord/TraceRecord tables in the squid DB. Runs alongside config-alert on every chain.
35
74
36
-
### Topics System (`src/topics/`)
37
-
Topics group related notifications by product (OETH, OUSD, OGN, etc.). Each topic folder contains processor definitions organized by concern:
-`config-loader.ts` - Loads rules from DB with 5-minute cache refresh, `initAlertConfigDb()` for migration
85
+
-`evaluate-filter.ts` - Evaluates AND/OR filter expressions against decoded event/trace data
86
+
-`types.ts` - TypeScript types for AlertRule, FilterExpression
87
+
-`seed-rules.sql` - Generated seed data for alert rules
88
+
-`seed-abis.sql` - Generated seed data for ABI storage
89
+
90
+
Admin UI: See `../alert-config-admin` — a React + Hono app for managing alert rules via a web interface.
91
+
92
+
### ABI Registry (`src/utils/abi-registry.ts`)
93
+
Dual-mode ABI loading:
94
+
1.**DB-loaded (primary)** — Full ABIs stored in the `abi` table, decoded at runtime via viem. Supports fallback decoding when multiple ABIs share the same selector (e.g., different `Deposit` events with different indexed params).
95
+
2.**Subsquid-compiled (fallback)** — `src/abi/*.ts` files loaded at import time for code-driven processors. Only 3 remain: `erc20.ts`, `exponential-staking.ts`, `multicall.ts`.
53
96
54
97
### Notification System (`src/notify/`)
55
98
-`discord.ts` - Discord webhook integration with message queue
56
-
-`const.ts` - Topics, severities, and webhook mappings
57
-
-`event/` - Event rendering and formatting for Discord embeds
This is the core workflow for understanding and expanding notification coverage:
117
+
The primary way to add notification coverage is through the alert_config database:
69
118
70
-
### 1. Check What We Currently Notify On
119
+
### 1. Ensure the ABI is loaded
120
+
If the contract's ABI isn't already in the `abi` table, fetch it and add it:
71
121
```shell
72
-
pnpm run digest > digest.log
122
+
pnpm run fetch-abi <address><name> [chain] # Saves to abi/<name>.json
123
+
pnpm run generate-abi-seed # Regenerates seed-abis.sql
73
124
```
74
-
Outputs all registered processors with their tracked addresses, events, and topics. Review `digest.log` to see current coverage.
75
125
76
-
### 2. Check What We Should Be Notifying On
77
-
```shell
78
-
pnpm run registry
79
-
```
80
-
Scrapes the [Origin Protocol contract registry](https://docs.originprotocol.com/registry/contracts) and compares against our tracking. Outputs `registry-comparison.md` showing:
81
-
- Which contracts have proxy monitoring vs event handlers
82
-
- Contracts needing event tracking (have proxy but no events)
83
-
- Completely untracked contracts
126
+
### 2. Create the alert rule
127
+
Use the admin UI (`../alert-config-admin`) or insert directly into the `alert_rule` table:
Fetches verified contract ABI from Etherscan/block explorer and saves to `abi/`.
137
+
Rules are cached for 5 minutes. Changes take effect without redeployment.
90
138
91
-
Examples:
92
-
```shell
93
-
pnpm run fetch-abi 0x703118c4cbcccbf2ab31913e0f8075fbbb15f563 oeth-eth-price-feed
94
-
pnpm run fetch-abi 0xdbfefd2e8460a6ee4955a68582f85708baea60a3 super-oeth base
95
-
```
96
-
Requires `ETHERSCAN_API_KEY` env var (free at etherscan.io/apis).
139
+
### 3. Add human-readable names (optional)
140
+
For new addresses, add entries to `CONTRACT_ADDR_TO_NAME` in `src/utils/addresses/names.ts`, or add them to the `wallet_label` table in the Railway database.
When adding new contract addresses, register human-readable names in `src/utils/addresses/names.ts`. This file maps addresses to display names used in Discord notifications.
118
-
119
-
Add entries to `CONTRACT_ADDR_TO_NAME` under the appropriate chain:
120
-
```typescript
121
-
[mainnet.id]: {
122
-
[MY_NEW_CONTRACT]: 'My New Contract',
123
-
// ...
124
-
},
125
-
[base.id]: {
126
-
[baseAddresses.myContract]: 'My Base Contract',
127
-
// ...
128
-
},
129
-
[sonic.id]: {
130
-
// ...
131
-
},
144
+
pnpm run backfill -- --chain <id> --from <block>
132
145
```
133
146
134
147
## Key Concepts
135
148
136
-
-**Topic** - Product area (OETH, OUSD, OGN, etc.) that maps to a Discord channel
3. Rules are cached for 5 minutes — changes take effect without redeployment.
38
+
39
+
### Code-driven processors
40
+
41
+
For alerts requiring custom business logic (e.g., OGN buybacks with USD calculations), add processors in `src/topics/`. See `src/topics/ogn-buybacks/` for an example.
0 commit comments