docs: sync from backend 22ae0bd — scanner balance watches
This commit is contained in:
130
02 - Data Models/ScannerBalanceWatch.md
Normal file
130
02 - Data Models/ScannerBalanceWatch.md
Normal file
@@ -0,0 +1,130 @@
|
||||
---
|
||||
title: ScannerBalanceWatch (Scanner DB model)
|
||||
tags: [data-model, scanner, payment]
|
||||
created: 2026-06-03
|
||||
---
|
||||
|
||||
# ScannerBalanceWatch
|
||||
|
||||
SQLite row in the AMN Pay Scanner's `balance_watches` table. One row represents a direct-address token balance watch requested by the backend for non-smart-contract payment detection.
|
||||
|
||||
This is scanner-internal state. It is not a Mongoose model and lives in the scanner SQLite database (`/data/scanner.db`).
|
||||
|
||||
---
|
||||
|
||||
## Schema
|
||||
|
||||
```sql
|
||||
CREATE TABLE balance_watches (
|
||||
watch_id TEXT PRIMARY KEY,
|
||||
chain_id INTEGER NOT NULL,
|
||||
chain_type TEXT NOT NULL DEFAULT 'evm',
|
||||
token_address TEXT NOT NULL,
|
||||
token_symbol TEXT,
|
||||
decimals INTEGER NOT NULL DEFAULT 0,
|
||||
address TEXT NOT NULL,
|
||||
baseline_balance TEXT NOT NULL,
|
||||
current_balance TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'watching',
|
||||
callback_url TEXT NOT NULL,
|
||||
callback_secret TEXT NOT NULL,
|
||||
last_checked_at DATETIME,
|
||||
next_check_at DATETIME NOT NULL,
|
||||
change_count INTEGER NOT NULL DEFAULT 0,
|
||||
last_notified_at DATETIME,
|
||||
expires_at DATETIME NOT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_balance_watches_status_next
|
||||
ON balance_watches(status, next_check_at);
|
||||
|
||||
CREATE INDEX idx_balance_watches_chain_status
|
||||
ON balance_watches(chain_id, status);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|---|---|---|
|
||||
| `watch_id` | TEXT PK | Caller-supplied or scanner-generated idempotency key. Backend should use a payment-scoped value such as `<paymentId>-balance-c56-USDT` when it wants webhook correlation by prefix. |
|
||||
| `chain_id` | INTEGER | Numeric EVM chain ID. Direct balance reads currently support EVM ERC-20 only. |
|
||||
| `chain_type` | TEXT | Currently `evm` for balance watches. Kept for future Tron/TON support. |
|
||||
| `token_address` | TEXT | ERC-20 token contract address, normalized to lowercase `0x` hex. |
|
||||
| `token_symbol` | TEXT NULL | Optional token symbol resolved from `tokens.json`. |
|
||||
| `decimals` | INTEGER | Token decimals resolved from registry when available. |
|
||||
| `address` | TEXT | Watched holder address, normalized to lowercase `0x` hex. |
|
||||
| `baseline_balance` | TEXT | Base-unit integer string captured or supplied when the watch is created. |
|
||||
| `current_balance` | TEXT | Last scanner-accepted base-unit balance. For changed balances, this advances only after webhook delivery succeeds. |
|
||||
| `status` | TEXT | Watch lifecycle state. |
|
||||
| `callback_url` | TEXT | Backend webhook endpoint. Validated with the same callback URL guard as scanner intents. |
|
||||
| `callback_secret` | TEXT | HMAC-SHA256 key for the balance watch webhook signature. Never returned in API responses. |
|
||||
| `last_checked_at` | DATETIME NULL | Last time the scanner attempted a balance read. |
|
||||
| `next_check_at` | DATETIME | Scheduler due time. |
|
||||
| `change_count` | INTEGER | Count of successfully delivered balance-change notifications. |
|
||||
| `last_notified_at` | DATETIME NULL | Time of the last successful balance-change notification. |
|
||||
| `expires_at` | DATETIME | Hard stop timestamp, currently 7 days after creation. |
|
||||
| `created_at` / `updated_at` | DATETIME | UTC timestamps. |
|
||||
|
||||
---
|
||||
|
||||
## Status values
|
||||
|
||||
| Status | Description |
|
||||
|---|---|
|
||||
| `watching` | Scheduler polls the address/token when `next_check_at` is due. |
|
||||
| `stopped` | Backend explicitly stopped the watch after payment success, cancellation, or manual resolution. |
|
||||
| `expired` | Scanner stopped the watch automatically after 7 days. |
|
||||
|
||||
---
|
||||
|
||||
## Polling cadence
|
||||
|
||||
| Age from `created_at` | Interval |
|
||||
|---|---|
|
||||
| `< 24h` | 5 min |
|
||||
| `24h–48h` | 10 min |
|
||||
| `48h–72h` | 20 min |
|
||||
| `> 72h` | 40 min until expiry |
|
||||
|
||||
`BALANCE_WATCH_TICK_SEC` controls how often the scheduler queries for due watches. `BALANCE_WATCH_BATCH_SIZE` controls how many due watches are processed per tick.
|
||||
|
||||
---
|
||||
|
||||
## Webhook semantics
|
||||
|
||||
When `current_balance` changes, scanner sends:
|
||||
|
||||
```json
|
||||
{
|
||||
"eventType": "balance_changed",
|
||||
"watchId": "6840fabc-balance-c56-USDT",
|
||||
"chainId": 56,
|
||||
"chainType": "evm",
|
||||
"address": "0x...",
|
||||
"tokenAddress": "0x...",
|
||||
"tokenSymbol": "USDT",
|
||||
"decimals": 18,
|
||||
"previousBalance": "25000000000000000000",
|
||||
"currentBalance": "35000000000000000000",
|
||||
"delta": "10000000000000000000",
|
||||
"changeCount": 1,
|
||||
"checkedAt": "2026-06-03T10:05:00Z",
|
||||
"status": "balance_changed"
|
||||
}
|
||||
```
|
||||
|
||||
The backend must not treat this webhook alone as final escrow funding. It should compare `delta` or `(currentBalance - baselineBalance)` to the expected amount, apply token/chain/address checks, persist evidence, and stop the watch when the payment is accepted or cancelled.
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- [Scanner Architecture](../01%20-%20Architecture/Scanner%20Architecture.md)
|
||||
- [Scanner API](../03%20-%20API%20Reference/Scanner%20API.md)
|
||||
- [Payment Flow - Scanner](../04%20-%20Flows/Payment%20Flow%20-%20Scanner.md)
|
||||
- [ScannerIntent](ScannerIntent.md)
|
||||
- [Payment](Payment.md) — backend MongoDB/DTO model that stores payment metadata
|
||||
@@ -111,4 +111,5 @@ A backfill pass recomputes `topic_ref` for existing EVM intents that had it as N
|
||||
- [Scanner Architecture](../01%20-%20Architecture/Scanner%20Architecture.md)
|
||||
- [Scanner API](../03%20-%20API%20Reference/Scanner%20API.md)
|
||||
- [Payment Flow - Scanner](../04%20-%20Flows/Payment%20Flow%20-%20Scanner.md)
|
||||
- [ScannerBalanceWatch](ScannerBalanceWatch.md) — direct-address balance-watch model for non-smart-contract payment rails
|
||||
- [Payment](Payment.md) — the backend MongoDB model that triggers intent creation
|
||||
|
||||
Reference in New Issue
Block a user