docs: sync from backend 22ae0bd — scanner balance watches
This commit is contained in:
@@ -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 |
|
||||
| 24–48h | 10 min |
|
||||
| 48–72h | 20 min |
|
||||
| 72h–7d | 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 |
|
||||
|
||||
Reference in New Issue
Block a user