Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 42 additions & 13 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,26 +182,55 @@ Databases: `mainnet`, `arbitrum-one`, `base`, `linea`, `polygon`, `xdai`, `sepol

Use `$ETH_MAINNET_RPC` from `.env.claude` for mainnet. Use `cast` or whatever tools you want freely.

## Grafana Logs Access
## Victoria Logs Access

Use the `scripts/vlogs` wrapper to query Victoria Logs.
Use the `CoW-Prod` MCP tools to query Victoria Logs directly.

**IMPORTANT**: When running `scripts/vlogs`, do NOT use bash comments before the command (e.g., `# comment\nscripts/vlogs ...`) as this causes unnecessary permission prompts. Just run the command directly.
**Timestamps**: MCP requires RFC3339 format (e.g., `2026-04-09T00:00:00Z`). Compute absolute timestamps from the current date rather than using relative time.

**IMPORTANT**: Order UIDs and other structured fields (like `quote_id`, `auction_id`) live inside the `all` field in Victoria Logs. You MUST prefix them with `all:` to match. Plain text terms (like `order created`, `filtered`) match the log message directly and don't need the prefix.
**IMPORTANT**: Order UIDs and other structured fields (like `quote_id`, `auction_id`) live inside the `all` field in Victoria Logs. You MUST prefix them with `all:` to match. Plain text terms (like `order created`, `filtered`) match the log message directly and don't need the prefix. You can also use parsed fields directly (e.g., `parsed.fields.order_uid:0x...`) for more precise matching.

```bash
scripts/vlogs "<expr>" [--from <time>] [--to <time>] [--max <lines>] [--env <prod|staging>] [--raw]
**IMPORTANT — Protect context window**: Raw log entries contain ~4KB of kubernetes/ec2 metadata each. **Always** append `| fields _time, _msg, all` (or specific `parsed.fields.*`) to strip noise. Use small `limit` values (10-20) and only increase if needed. Examples:
- General order search: `... | fields _time, _msg, all`
- When you only need specific parsed fields: `... | fields _time, _msg, parsed.fields.err, parsed.fields.driver, parsed.spans.auction.auction_id`

scripts/vlogs "NOT container:controller order created all:0xabc..." --from now-24h
scripts/vlogs "NOT container:controller network:mainnet settlement failed" --from now-6h --max 50
scripts/vlogs "error" --env staging --from now-1h
scripts/vlogs "NOT container:controller all:0xabc..." --raw
```
**Available MCP tools:**
- `victorialogs_query` — Main log search (LogsQL expression + time range + limit)
- `victorialogs_hits` — Count matching logs grouped by time buckets
- `victorialogs_field_names` / `victorialogs_field_values` — Explore available fields
- `victorialogs_facets` — Most frequent values per field
- `victorialogs_stats_query` / `victorialogs_stats_query_range` — Aggregation queries
- `victorialogs_stream_field_names` / `victorialogs_stream_field_values` — Stream metadata

Defaults: `--from now-12h`, `--to now`, `--max 100`, `--env prod`
**Key fields:**
- Stream fields (efficient filters): `container`, `namespace`, `pod`
- `network` — chain name (mainnet, arbitrum-one, base, etc.)
- `all` — full structured JSON log (search with `all:` prefix for UIDs)
- `parsed.fields.*` — individual parsed fields (e.g., `parsed.fields.order_uid`, `parsed.fields.quote_id`)
- `_msg` — the log message text

Datasource UIDs (hardcoded in script): `vm-auth-prod` (production), `vm-auth-staging` (staging)
**Example queries:**
```
# Search for order logs (exclude nginx controller, strip metadata)
query: "container:!controller AND network:mainnet AND all:0xabc... | fields _time, _msg, all"
start: "<COMPUTED_RFC3339>"
limit: 20

# Search for order creation on mainnet
query: "container:!controller AND network:mainnet AND \"order created\" AND all:0xabc... | fields _time, _msg, all"
start: "<COMPUTED_RFC3339>"
limit: 10

# Settlement failures with just error details
query: "container:!controller AND network:mainnet AND \"settlement failed\" | fields _time, _msg, parsed.fields.err, parsed.fields.driver, parsed.spans.auction.auction_id"
start: "<COMPUTED_RFC3339>"
limit: 10

# Sort results by time
query: "container:!controller AND network:mainnet AND all:0xabc... | fields _time, _msg, all | sort by (_time) asc"
start: "<COMPUTED_RFC3339>"
limit: 20
```

## Etherscan API (V2)

Expand Down
95 changes: 53 additions & 42 deletions docs/COW_ORDER_DEBUG_SKILL.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# CoW Protocol Order Debug Skill

Debug why CoW Protocol orders fail to match. Requires DB access + Victoria Logs access (via Grafana).
Debug why CoW Protocol orders fail to match. Requires DB access + Victoria Logs access (via CoW-Prod MCP).

## Quick Checklist

Run through these in order:

1. [ ] **Order status** — Check API status first (cancelled/expired/fulfilled/open)
2. [ ] **User cancellation** — If cancelled, search logs for `order cancelled all:ORDER_UID` FIRST
2. [ ] **User cancellation** — If cancelled, search logs for `"order cancelled" AND all:ORDER_UID` FIRST
3. [ ] **Order in auction** — Was order in autopilot auction? When?
4. [ ] **Solver bids** — Did any solver bid? What happened to their solution?
5. [ ] **Settlement outcome** — Did settlement succeed/fail/timeout?
Expand Down Expand Up @@ -81,43 +81,54 @@ cast call $SETTLEMENT_CONTRACT "preSignature(bytes)" $ORDER_UID --rpc-url $RPC

---

## 3. Check Logs (Victoria Logs via Grafana)
## 3. Check Logs (Victoria Logs via MCP)

Logs are stored in Victoria Logs and accessible via Grafana API.
Logs are stored in Victoria Logs and accessible via the `CoW-Prod` MCP tools. Use `mcp__CoW-Prod__victorialogs_query` for log searches. Timestamps must be RFC3339 format (compute from current date).

**Query using `scripts/vlogs`:**
```bash
scripts/vlogs "NOT container:controller all:ORDER_UID"
**IMPORTANT — Protect context window**: Always append `| fields _time, _msg, all` to queries to strip kubernetes/ec2 metadata (~4KB per entry). Use small `limit` values (10-20). When you only need specific fields, use `| fields _time, _msg, parsed.fields.err, parsed.fields.driver` etc.

**Example queries (use `victorialogs_query` tool):**
```
# All order logs (exclude nginx controller, filter by network, strip metadata)
query: "container:!controller AND network:$NETWORK AND all:ORDER_UID | fields _time, _msg, all"
start: "<24h-ago-RFC3339>"
limit: 20

scripts/vlogs "NOT container:controller network:bnb all:ORDER_UID"
# Search by quote ID
query: "container:!controller AND network:$NETWORK AND all:22788649 | fields _time, _msg, all"

scripts/vlogs "NOT container:controller all:22788649"
# Search specific solver
query: "container:!controller AND network:$NETWORK AND baseline AND all:22788649 | fields _time, _msg, all"
```

**Useful filters (part of the LogsQL expression):**
- `container:!controller` — excludes nginx access logs (REQUIRED for order UID searches)
- `network:$NETWORK` — **always include when debugging an order** to filter by chain (mainnet, bnb, arbitrum-one, base, etc). Reduces noise and speeds up queries.
- `all:` — prefix for searching structured fields (order UIDs, auction IDs, quote IDs). Without a field prefix, Victoria Logs only searches the log message text, not structured fields. You can also use `parsed.fields.order_uid:0x...` for precise matching, but `all:` works universally.
- `| fields _time, _msg, all` — **always append** to strip k8s metadata and protect context window

scripts/vlogs "NOT container:controller baseline all:22788649"
**Note:** Always use the **full order UID with 0x prefix** and the `all:` field prefix for reliable matching.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The instruction to always use the 0x prefix contradicts the specific instruction on line 131 to use the UID without the 0x prefix for calldata searches. Update this note to acknowledge the exception for calldata to avoid model confusion.

Suggested change
**Note:** Always use the **full order UID with 0x prefix** and the `all:` field prefix for reliable matching.
**Note:** Generally use the **full order UID with 0x prefix** and the `all:` field prefix for reliable matching (except when searching for UIDs in raw calldata).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably a good suggestion!


scripts/vlogs "NOT container:controller all:ORDER_UID" --from now-24h --max 200
**IMPORTANT - Run targeted lifecycle queries in parallel** (use FULL order UID with 0x). Call multiple `victorialogs_query` MCP tools simultaneously. Always include `network:$NETWORK` and `| fields` pipe:

scripts/vlogs "NOT container:controller all:ORDER_UID" --raw
```
# Order creation
query: "container:!controller AND network:$NETWORK AND \"order created\" AND all:ORDER_UID | fields _time, _msg, all"

**Useful filters (part of the expr):**
- `NOT container:controller` — excludes nginx access logs (REQUIRED for order UID searches)
- `network:$NETWORK` — filter by chain (mainnet, bnb, arbitrum-one, base, etc)
- `all:` — prefix for searching structured fields (order UIDs, auction IDs, quote IDs). Without a field prefix, Victoria Logs only searches the log message text, not structured fields. You can also use specific field names (e.g., `order_uid:0x...`) but `all:` works universally.
# Order cancellation
query: "container:!controller AND network:$NETWORK AND \"order cancelled\" AND all:ORDER_UID | fields _time, _msg, all"

**Note:** Always use the **full order UID with 0x prefix** and the `all:` field prefix for reliable matching.
# Proposed solutions
query: "container:!controller AND network:$NETWORK AND \"proposed solution\" AND all:ORDER_UID | fields _time, _msg, all"

**IMPORTANT - Run targeted lifecycle queries in parallel** (use FULL order UID with 0x):
# Settlement failures (use specific parsed fields for concise output)
query: "container:!controller AND network:$NETWORK AND \"settlement failed\" AND all:ORDER_UID | fields _time, _msg, parsed.fields.err, parsed.fields.driver, parsed.spans.auction.auction_id"

```bash
scripts/vlogs "NOT container:controller order created all:ORDER_UID"
scripts/vlogs "NOT container:controller order cancelled all:ORDER_UID"
scripts/vlogs "NOT container:controller proposed solution all:ORDER_UID"
scripts/vlogs "NOT container:controller settlement failed all:ORDER_UID"
scripts/vlogs "NOT container:controller filtered all:ORDER_UID"
# Filtering
query: "container:!controller AND network:$NETWORK AND filtered AND all:ORDER_UID | fields _time, _msg, all"

# Find discarded solutions where order appears in calldata (use order UID bytes without 0x prefix)
scripts/vlogs "discarded all:ORDER_UID_WITHOUT_0X"
# Find discarded solutions (use order UID bytes without 0x prefix)
query: "container:!controller AND network:$NETWORK AND discarded AND all:ORDER_UID_WITHOUT_0X | fields _time, _msg, all"
```

**What to look for:**
Expand Down Expand Up @@ -191,10 +202,10 @@ WHERE oq.order_uid = '\x$ORDER_UID_HEX';
```

### Method 3: Logs (fallback)
Find the quote_id from the "order created" log:
Find the quote_id from the "order created" log using `victorialogs_query`:

```bash
scripts/vlogs "NOT container:controller order created all:ORDER_UID"
```
query: "container:!controller AND network:$NETWORK AND \"order created\" AND all:ORDER_UID | fields _time, _msg, all"
```

**Example log line:**
Expand All @@ -203,8 +214,8 @@ orderbook::api::post_order: order created order_uid=0x... quote_id=Some(2720468)
```

Then search for quote details by ID:
```bash
scripts/vlogs "NOT container:controller all:$QUOTE_ID"
```
query: "container:!controller AND network:$NETWORK AND all:$QUOTE_ID | fields _time, _msg, all"
```

---
Expand Down Expand Up @@ -297,13 +308,13 @@ surplusFeeTimestamp is within last 10 minutes
```

**If missing/stale, check surplus fee computation logs:**
```bash
scripts/vlogs "surplus_fee all:ORDER_UID"
```
query: "network:$NETWORK AND surplus_fee AND all:ORDER_UID | fields _time, _msg, all"
```

**Surplus fee error logs:**
```bash
scripts/vlogs "surplus_fee error"
```
query: "network:$NETWORK AND surplus_fee AND error | fields _time, _msg, all"
```

### 9.2 Auction Filtering Check
Expand All @@ -314,8 +325,8 @@ curl -s "https://api.cow.fi/$NETWORK/api/v1/auction" | jq '.orders[] | select(.u
```

If not present, order is filtered. Check filter logs:
```bash
scripts/vlogs "filtered all:ORDER_UID"
```
query: "network:$NETWORK AND filtered AND all:ORDER_UID | fields _time, _msg, all"
```

**Common filter reasons:**
Expand Down Expand Up @@ -403,13 +414,13 @@ settle(
Order is in auction but still not matching?

**Auction orders log:**
```bash
scripts/vlogs "all:$AUCTION_ID"
```
query: "network:$NETWORK AND all:$AUCTION_ID | fields _time, _msg, all"
```

**Specific auction run:**
```bash
scripts/vlogs "all:$RUN_ID"
```
query: "network:$NETWORK AND all:$RUN_ID | fields _time, _msg, all"
```

### JIT Orders & CoW AMMs
Expand Down Expand Up @@ -560,7 +571,7 @@ curl -s "https://api.cow.fi/$NETWORK/api/v1/app_data/$APP_DATA_HASH"
| Resource | URL |
|----------|-----|
| Order Explorer | `https://explorer.cow.fi/orders/$ORDER_UID` |
| Grafana Logs (Victoria Logs) | `$GRAFANA_URL/explore` (see .env.claude) |
| Victoria Logs | Via `CoW-Prod` MCP tools (`victorialogs_query`, etc.) |
| API Docs | `https://api.cow.fi/docs/` |
| Block-to-Date | `https://etherscan.io/blockdateconverter` |
| Barn (Staging) | `https://barn.cow.fi` |
Expand Down
84 changes: 0 additions & 84 deletions scripts/vlogs

This file was deleted.

Loading