115 lines
5.3 KiB
Markdown
115 lines
5.3 KiB
Markdown
---
|
|
title: ScannerIntent (Scanner DB model)
|
|
tags: [data-model, scanner, payment]
|
|
created: 2026-05-30
|
|
---
|
|
|
|
# ScannerIntent
|
|
|
|
SQLite row in the AMN Pay Scanner's `intents` table. One row per payment intent registered by the backend. This is internal scanner state — it is not a Mongoose model and lives in a separate SQLite database (`/data/scanner.db`).
|
|
|
|
---
|
|
|
|
## Schema
|
|
|
|
```sql
|
|
CREATE TABLE intents (
|
|
intent_id TEXT PRIMARY KEY,
|
|
chain_id INTEGER NOT NULL,
|
|
chain_type TEXT NOT NULL DEFAULT 'evm',
|
|
token_address TEXT NOT NULL,
|
|
destination TEXT NOT NULL,
|
|
amount TEXT NOT NULL,
|
|
payment_reference TEXT NOT NULL,
|
|
topic_ref TEXT,
|
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
callback_url TEXT NOT NULL,
|
|
callback_secret TEXT NOT NULL,
|
|
confirmations_required INTEGER NOT NULL DEFAULT 12,
|
|
tx_hash TEXT,
|
|
log_index INTEGER,
|
|
block_number INTEGER,
|
|
confirmations INTEGER NOT NULL DEFAULT 0,
|
|
salt TEXT NOT NULL,
|
|
webhook_delivered_at TEXT,
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
## Fields
|
|
|
|
| Field | Type | Description |
|
|
|---|---|---|
|
|
| `intent_id` | TEXT PK | Caller-supplied unique ID (typically the backend Payment `_id`) |
|
|
| `chain_id` | INTEGER | Numeric chain ID. EVM standard (56, 137, 1, 42161, 8453), Tron (728126428), TON (1100) |
|
|
| `chain_type` | TEXT | `evm` / `tron` / `ton`. Determines which worker handles this intent |
|
|
| `token_address` | TEXT | ERC20 / TRC20 contract address. EVM/Tron: lowercase `0x` hex. TON: exact base64url |
|
|
| `destination` | TEXT | Recipient wallet address. EVM/Tron: lowercase `0x` hex. TON: base64url (case-sensitive) |
|
|
| `amount` | TEXT | Required amount in smallest token unit (wei / 10^decimals), stored as base-10 integer string |
|
|
| `payment_reference` | TEXT | 8-byte hex EVM payment reference (`0x` + 16 hex chars). Derived as `last8(keccak256(intentId + salt + destination))` |
|
|
| `topic_ref` | TEXT | `keccak256(paymentReferenceBytes)` — matches `Topics[1]` in EVM logs. Pre-computed for indexed DB lookup. NULL for Tron/TON |
|
|
| `status` | TEXT | Intent lifecycle state (see below) |
|
|
| `callback_url` | TEXT | URL the scanner POSTs to on confirmation |
|
|
| `callback_secret` | TEXT | HMAC-SHA256 key for webhook signature. Never returned in API responses |
|
|
| `confirmations_required` | INTEGER | Accepted confirmation floor for the intent. Defaults to chain config and cannot be lowered below the chain floor by the create-intent request |
|
|
| `tx_hash` | TEXT NULL | Transaction hash once a matching transfer is detected |
|
|
| `log_index` | INTEGER NULL | Log position within the transaction (EVM only; 0 for Tron/TON) |
|
|
| `block_number` | INTEGER NULL | Block number (EVM/Tron) or Unix timestamp seconds (TON) when the tx was seen |
|
|
| `confirmations` | INTEGER | Current confirmation depth while `confirming`; capped at `confirmations_required` once the intent is `confirmed` |
|
|
| `salt` | TEXT | 32-byte random hex. Combined with `intent_id` and `destination` to derive `payment_reference`. Prevents reference collisions across retried payments |
|
|
| `webhook_delivered_at` | TEXT NULL | RFC3339 timestamp when the webhook was successfully delivered. Used for startup crash recovery |
|
|
| `created_at` / `updated_at` | DATETIME | UTC timestamps |
|
|
|
|
---
|
|
|
|
## Status values
|
|
|
|
| Status | Description |
|
|
|---|---|
|
|
| `pending` | Registered; scanner is watching for a matching on-chain transfer |
|
|
| `confirming` | EVM only — matching tx seen, waiting for `confirmations_required` blocks |
|
|
| `confirmed` | Payment confirmed; webhook delivery attempted |
|
|
| `expired` | TTL exceeded while still in `pending` or `confirming` |
|
|
| `webhook_failed` | All webhook delivery retries exhausted; manual retry or periodic auto-retry needed |
|
|
|
|
---
|
|
|
|
## Indexes
|
|
|
|
```sql
|
|
CREATE INDEX idx_intents_status ON intents(status);
|
|
CREATE INDEX idx_intents_chain_status ON intents(chain_id, status);
|
|
CREATE INDEX idx_intents_payment_ref ON intents(payment_reference);
|
|
CREATE INDEX idx_intents_topic_ref ON intents(topic_ref);
|
|
CREATE UNIQUE INDEX idx_intents_tx_log ON intents(tx_hash, log_index)
|
|
WHERE tx_hash IS NOT NULL;
|
|
```
|
|
|
|
`idx_intents_topic_ref` is the performance-critical index — the EVM scanner's inner loop does a single indexed lookup per log entry.
|
|
|
|
The unique index on `(tx_hash, log_index)` prevents two intents being confirmed from the same on-chain event (double-spend protection).
|
|
|
|
---
|
|
|
|
## Migrations
|
|
|
|
Three additive migrations run at startup (idempotent):
|
|
|
|
1. `ADD COLUMN topic_ref TEXT` — added after initial schema
|
|
2. `ADD COLUMN chain_type TEXT NOT NULL DEFAULT 'evm'` — added for Tron/TON support
|
|
3. `ADD COLUMN webhook_delivered_at TEXT` — added for crash recovery
|
|
|
|
A backfill pass recomputes `topic_ref` for existing EVM intents that had it as NULL.
|
|
|
|
---
|
|
|
|
## 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)
|
|
- [Payment](Payment.md) — the backend MongoDB model that triggers intent creation
|