docs: sync from backend 22ae0bd — scanner balance watches

This commit is contained in:
Siavash Sameni
2026-06-03 21:23:50 +04:00
parent 4b1d8ea36d
commit 9dcdb420fc
9 changed files with 866 additions and 13 deletions

View File

@@ -6,11 +6,11 @@ created: 2026-05-30
# Payment Flow — AMN Pay Scanner (In-House)
> **Last updated:** 2026-05-31 — documented backend `2.6.82` / scanner `0.1.7` capped accepted confirmation floors.
> **Last updated:** 2026-06-03 — documented backend/frontend `2.8.60` and scanner `0.1.8` direct-address balance checks and balance watches.
End-to-end payment flow using the in-house AMN Pay Scanner, replacing the Request Network integration. The scanner is a separate microservice; the backend talks to it over an internal HTTP API.
See also: [Scanner Architecture](../01%20-%20Architecture/Scanner%20Architecture.md), [Scanner API](../03%20-%20API%20Reference/Scanner%20API.md)
See also: [Scanner Architecture](../01%20-%20Architecture/Scanner%20Architecture.md), [Scanner API](../03%20-%20API%20Reference/Scanner%20API.md), [PRD - Direct Address Token Payments via Scanner Balance Watches](../PRD%20-%20Direct%20Address%20Token%20Payments%20via%20Scanner%20Balance%20Watches.md)
---
@@ -133,7 +133,85 @@ Backend returns a 2xx response. Scanner records `webhook_delivered_at` and the i
---
## 3. Failure paths
## 3. Direct-address payment mode
Scanner `0.1.8` adds a non-smart-contract rail for cases where the buyer transfers tokens directly to a backend-assigned address instead of calling `ERC20FeeProxy`.
This rail is currently EVM ERC-20 only. Tron/TON direct balance reads are future scope.
### Mode A — synchronous balance check
```
Buyer Backend Scanner EVM RPC
│ │ │ │
│ open checkout │ │ │
│────────────────────►│ │ │
│ │ POST /balances/check │
│ │───────────────────►│ eth_call balanceOf │
│ │◄───────────────────│◄────────────────── │
│ address + amount │ │ │
│◄────────────────────│ │ │
│ direct token transfer ──────────────────────────────────────►│
│ click "I paid" │ │ │
│────────────────────►│ │ │
│ │ POST /balances/check │
│ │───────────────────►│ eth_call balanceOf │
│ │◄───────────────────│◄────────────────── │
│ payment accepted if delta >= expected amount │
```
Backend responsibilities:
1. Allocate or select the payment address.
2. Call scanner `POST /balances/check` to store a base-unit `baselineBalance`.
3. Show the address/token/amount to the buyer.
4. When buyer clicks "I paid", call `POST /balances/check` again.
5. Compare `(currentBalance - baselineBalance)` to the expected base-unit amount.
6. Persist evidence and run the normal payment/ledger transition only after chain, token, address, and amount checks pass.
### Mode B — balance watch
```
Backend Scanner EVM RPC
│ POST /balance-watches │ │
│──────────────────────►│ initial balanceOf │
│◄──────────────────────│ │
│ │ every 5m, then 10/20/40m
│ │───────────────────►│
│ │ balance changed │
│◄──────────────────────│ signed webhook │
│ payment accepted │ │
│ DELETE /balance-watches/{watchId} │
│──────────────────────►│ status=stopped │
```
Backend `2.8.60` exposes scanner helper functions in `amnPayAdapter.ts`:
| Helper | Scanner endpoint |
|---|---|
| `checkScannerTokenBalance` | `POST /balances/check` |
| `createScannerBalanceWatch` | `POST /balance-watches` |
| `stopScannerBalanceWatch` | `DELETE /balance-watches/{watchId}` |
Backend `2.8.60` also accepts signed `balance_changed` scanner webhooks on the existing AMN scanner webhook route. The current webhook handler records `amnScannerBalanceWatch` metadata and returns `202`; it does not yet mark the payment funded on balance change alone. The product decision rule still needs to be implemented by the backend work described in the PRD.
Recommended watch ID shape: `<paymentId>-balance-c<chainId>-<TOKEN>`. The webhook handler maps this back to the payment ID prefix.
Scanner cadence:
| Age | Interval |
|---|---|
| First 24h | 5 min |
| 2448h | 10 min |
| 4872h | 20 min |
| 72h7d | 40 min |
| After 7d | `expired` |
Backend must stop a watch when payment is accepted, cancelled, manually resolved, or no longer relevant.
---
## 4. Failure paths
### Webhook delivery failure
@@ -166,9 +244,18 @@ Transfers where the on-chain amount is less than `intent.Amount` are silently sk
The EVM log decoder validates all three fields (token, destination, amount). Mismatches are logged as `REJECT` and skipped. The intent remains `pending`.
### Balance watch change but payment not complete
`balance_changed` means the watched balance changed; it is not a final paid signal by itself. Backend must reject or keep waiting when:
- `delta` is less than the expected payment amount.
- The balance decreased or moved by an unrelated amount.
- The watch address/token/chain do not match the payment metadata.
- The payment was already completed, cancelled, refunded, or superseded.
---
## 4. Key differences from Request Network integration
## 5. Key differences from Request Network integration
| Dimension | Request Network | AMN Pay Scanner |
|---|---|---|
@@ -180,3 +267,4 @@ The EVM log decoder validates all three fields (token, destination, amount). Mis
| Confirmations | RN handled | Per-chain configurable |
| Webhook | RN webhook → backend adapter | Scanner → backend directly |
| State store | External (RN cloud) | Internal SQLite |
| Direct address payments | Not supported | EVM ERC-20 balance check/watch rail |