docs: complete code-reality alignment for remaining docs + reconcile issue set
Remaining docs updated to match code (the docs that the first pass had not covered):
- Flows: Chat, Referral, Rating, Registration, Google OAuth, Negotiation, Payout,
Trezor Safekeeping — corrected endpoints, socket events, status enums, auth gaps
- API Reference: User API, Trezor API — admin route prefix/verb/status corrections,
added undocumented endpoints (ton-proof challenge, profile email verify,
GET /trezor/account, POST /trezor/verify-operation)
- Data Models: Chat, Notification, Payment, PointTransaction, User — corrected
enums (PaymentProvider, escrowState, PointTransaction.type, User.status),
90-day notification TTL, soft-delete semantics, wallet fields
Trezor "zero frontend" finding (audit C31/C32) corrected as STALE:
- Verified current code HAS a full frontend Trezor implementation (admin/trezor
page, TrezorSettingsView, trezorConnector via @trezor/connect-web,
TrezorSignDialog, actions/trezor.ts building the {message,signature} object)
- Fixed Trezor Safekeeping Flow doc (removed false "no frontend" warnings)
- Reclassified ISSUE-012 as invalid/superseded with explanation
Issue set reconciled to a single canonical numbering (ISSUE-001..054):
- Adopted the comprehensive 51-issue set (long-slug, fully indexed)
- Removed 35 superseded short-slug duplicates from the first pass
- Removed a duplicate ISSUE-046 file
- Added 3 issues the 51-set lacked: ISSUE-052 (completed-not-counted-in-stats),
ISSUE-053 (axios 401-only interceptor), ISSUE-054 (rate limiter counts all attempts)
- Regenerated Issues Index: 53 open (14 critical, 39 major) + 1 invalid
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,8 @@ related_apis: ["POST /api/payment/:id/release", "POST /api/payment/:id/release/c
|
||||
|
||||
# Payout Flow
|
||||
|
||||
> **Last updated:** 2026-05-29 — aligned with code (see [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md))
|
||||
|
||||
This page describes how escrowed funds leave Amanat custody after an order is complete or a dispute is resolved.
|
||||
|
||||
The current flow is no longer SHKeeper payout-task centric. Release and refund are instruction-based:
|
||||
@@ -34,7 +36,7 @@ Today the custody signer can be an admin/Trezor path when enabled. The roadmap t
|
||||
- The release/refund amount is positive and does not exceed available ledger balance.
|
||||
- No active dispute hold blocks the operation, unless the operation is the explicit dispute resolution path.
|
||||
- Recipient wallet is known and verified.
|
||||
- If `TREZOR_SAFEKEEPING_REQUIRED=true`, the confirm step includes the expected Trezor operation signature.
|
||||
- If `TREZOR_SAFEKEEPING_REQUIRED=true`, the confirm step **must** include the expected Trezor operation signature (see gate below).
|
||||
- Production target: Safe multisig execution is required for custody movement.
|
||||
|
||||
## Release Narrative
|
||||
@@ -43,7 +45,7 @@ Today the custody signer can be an admin/Trezor path when enabled. The roadmap t
|
||||
2. Admin calls `POST /api/payment/:id/release` with optional partial amount.
|
||||
3. Backend loads the `Payment`, validates ledger availability when `PAYMENT_LEDGER_ENFORCEMENT=true`, and returns an instruction payload.
|
||||
4. Custody signer broadcasts the seller payment transaction.
|
||||
5. Admin calls `POST /api/payment/:id/release/confirm` with `txHash` and optional Trezor proof.
|
||||
5. Admin calls `POST /api/payment/:id/release/confirm` with `txHash` and (when safekeeping is enabled) a Trezor signature proof.
|
||||
6. Backend verifies signer proof when required, confirms adapter state, appends a `release` ledger entry, and marks escrow released.
|
||||
|
||||
## Refund Narrative
|
||||
@@ -52,7 +54,7 @@ Today the custody signer can be an admin/Trezor path when enabled. The roadmap t
|
||||
2. Admin calls `POST /api/payment/:id/refund`.
|
||||
3. Backend validates available funds and policy.
|
||||
4. Custody signer broadcasts the refund transaction.
|
||||
5. Admin calls `POST /api/payment/:id/refund/confirm` with `txHash` and optional Trezor proof.
|
||||
5. Admin calls `POST /api/payment/:id/refund/confirm` with `txHash` and (when safekeeping is enabled) a Trezor signature proof.
|
||||
6. Backend appends a `refund` ledger entry and marks escrow refunded.
|
||||
|
||||
## Sequence Diagram
|
||||
@@ -74,15 +76,19 @@ sequenceDiagram
|
||||
A->>C: Request Trezor/Safe execution
|
||||
C->>BC: Broadcast transfer
|
||||
BC-->>C: txHash
|
||||
A->>BE: POST /confirm { txHash, signer proof }
|
||||
A->>BE: POST /confirm { txHash, trezor proof if safekeeping }
|
||||
BE->>BE: Verify proof if required
|
||||
BE->>DB: append release/refund ledger entry
|
||||
BE->>DB: update Payment escrowState
|
||||
BE-->>R: notification
|
||||
BE-->>R: notification (no realtime socket listener — see gap below)
|
||||
```
|
||||
|
||||
## API Calls
|
||||
|
||||
### Release / Refund (custody) — correct paths
|
||||
|
||||
These are mounted on `paymentControllerRouter` at `/api/payment` (`backend/src/services/payment/paymentControllerRoutes.ts:23-26`). Note: **no `/shkeeper/` segment**.
|
||||
|
||||
| Method | Endpoint | Purpose |
|
||||
|---|---|---|
|
||||
| `POST` | `/api/payment/:id/release` | Build release instruction |
|
||||
@@ -92,6 +98,44 @@ sequenceDiagram
|
||||
| `GET` | `/api/admin/payments/awaiting-confirmation` | Admin view of payments blocked on confirmation depth |
|
||||
| `GET` | `/api/payment/derived-destinations` | Admin view of derived destination sweep state |
|
||||
|
||||
### Request Network — actually implemented routes
|
||||
|
||||
Mounted at `/api/payment/request-network` (`app.ts:428` → `requestNetwork/requestNetworkRoutes.ts`). Only these exist:
|
||||
|
||||
| Method | Endpoint | Purpose |
|
||||
|---|---|---|
|
||||
| `POST` | `/api/payment/request-network/pay-in` | Create a pay-in intent (authenticated) — `requestNetworkRoutes.ts:111` |
|
||||
| `POST` | `/api/payment/request-network/intents` | Create checkout intent — `requestNetworkRoutes.ts:289` |
|
||||
| `GET` | `/api/payment/request-network/:paymentId/checkout` | In-house checkout block fetcher — `requestNetworkRoutes.ts:152` |
|
||||
| `POST` | `/api/payment/request-network/webhook` | Provider webhook (raw body) — `requestNetworkRoutes.ts:330` |
|
||||
|
||||
> [!warning] ⚠️ NOT IMPLEMENTED — Request Network payout/release/refund sub-routes
|
||||
> The following routes are **not registered anywhere** and return **404**:
|
||||
> - `POST /api/payment/request-network/:id/payout/initiate`
|
||||
> - `POST /api/payment/request-network/:id/payout/confirm`
|
||||
> - `POST /api/payment/request-network/:id/release/confirm`
|
||||
> - `POST /api/payment/request-network/:id/refund/confirm`
|
||||
>
|
||||
> Release and refund are handled exclusively by the custody routes under `/api/payment/:id/...` listed above — **not** under the `request-network` namespace.
|
||||
|
||||
## Custody-signer / Trezor safekeeping gate
|
||||
|
||||
> [!warning] Safekeeping gate blocks the legacy non-custodial helpers
|
||||
> When `TREZOR_SAFEKEEPING_REQUIRED=true` (`backend/src/services/trezor/trezorService.ts:214`), the release/refund `confirm` endpoints require a Trezor operation signature in the request body.
|
||||
>
|
||||
> - The **active admin UI** path uses `TrezorSignDialog` (`frontend/src/components/trezor-sign-dialog/TrezorSignDialog.tsx`), wired into the awaiting-confirmation list view. It builds the signed payload via `getTrezorOperationMessage` + `trezorSignMessage` and posts `{ txHash, amount, trezor: { message, signature } }` through `confirmRelease` / `confirmRefund` (`frontend/src/actions/trezor.ts:108,133`). This path satisfies the gate.
|
||||
> - The **legacy helpers** `confirmReleaseTx` / `confirmRefundTx` (`frontend/src/actions/payment.ts:487,503`) post only `{ txHash, ...extra }` — by default **no Trezor proof**. They have **no UI callers** today, but if used with safekeeping enabled the backend will **reject** the payout. Prefer the `TrezorSignDialog` flow; remove or retrofit the legacy helpers to attach the signature.
|
||||
|
||||
## Derived-destinations sweep
|
||||
|
||||
HD-wallet derived-destination sweep infrastructure exists but is **admin-tooling only**:
|
||||
|
||||
- Routes: `GET /api/payment/derived-destinations` (`app.ts:546` → `wallets/derivedDestinationRoutes`).
|
||||
- Cron: `startSweepCron()` auto-starts only when `DERIVED_DESTINATION_SWEEP_AUTOSTART=true` (`app.ts:578-582`, `wallets/sweepService.ts`).
|
||||
- Model: `DerivedDestination` with statuses `active`/`swept`/`sweeping`/`quarantined` (`models/DerivedDestination.ts:35`).
|
||||
|
||||
This is not part of the buyer/seller payout UX; it consolidates funds from per-payment derived addresses.
|
||||
|
||||
## Database Writes
|
||||
|
||||
- **`payments`** -- status, `escrowState`, `blockchain.transactionHash`, signer metadata.
|
||||
@@ -99,14 +143,24 @@ sequenceDiagram
|
||||
- **`purchaserequests`** -- terminal business state after release/refund completes.
|
||||
- **`notifications`** -- release/refund receipt to the relevant party.
|
||||
|
||||
## Socket events emitted
|
||||
|
||||
> [!warning] Real-time payout/payment events have NO frontend listeners
|
||||
> Two seller-facing socket events are emitted by the backend but **no frontend code subscribes to them**, so sellers receive no real-time notification:
|
||||
> - **`payout-completed`** → `user-{sellerId}`, emitted after admin wallet payout (`backend/src/services/payment/decentralizedPaymentService.ts:911`). No frontend listener.
|
||||
> - **`payment-received`** → `user-{sellerId}`, emitted on Web3 verify (`backend/src/services/payment/paymentRoutes.ts:622`) and from `marketplace/routes.ts:2611`. No frontend listener.
|
||||
>
|
||||
> Until the frontend socket layer registers handlers for these, sellers must refresh / poll to see payout and incoming-payment state. Persisted DB notifications still surface through the standard notification channel.
|
||||
|
||||
## Error / Edge Cases
|
||||
|
||||
- **Insufficient ledger balance** -- reject instruction build/confirm.
|
||||
- **Active dispute hold** -- reject release/refund unless the operation is the explicit dispute outcome.
|
||||
- **Missing signer proof** -- reject when `TREZOR_SAFEKEEPING_REQUIRED=true`.
|
||||
- **Missing signer proof** -- reject confirm when `TREZOR_SAFEKEEPING_REQUIRED=true` (legacy `confirmReleaseTx`/`confirmRefundTx` helpers omit it — see gate above).
|
||||
- **Custody tx sent but not confirmed in app** -- reconcile by tx hash and append the missing ledger entry once verified.
|
||||
- **Partial split** -- build separate release and refund instructions whose sum does not exceed available balance.
|
||||
- **Payout reverted** -- leave escrow in failed/retryable state and do not append the terminal ledger entry.
|
||||
- **Wrong namespace** -- calling release/refund under `/api/payment/request-network/:id/...` returns 404 (those routes do not exist).
|
||||
|
||||
## Legacy SHKeeper Note
|
||||
|
||||
@@ -122,9 +176,15 @@ Older versions used SHKeeper payout tasks and scripts such as `fix-transaction-h
|
||||
|
||||
## Source Files
|
||||
|
||||
- Backend: `backend/src/services/payment/paymentControllerRoutes.ts:23-26` (release/refund routes)
|
||||
- Backend: `backend/src/services/payment/requestNetwork/requestNetworkRoutes.ts:111,152,289,330` (implemented RN routes)
|
||||
- Backend: `backend/src/services/payment/orchestration/releaseRefundService.ts`
|
||||
- Backend: `backend/src/services/payment/ledger/fundsLedgerService.ts`
|
||||
- Backend: `backend/src/services/payment/adapters/requestNetworkAdapter.ts`
|
||||
- Backend: `backend/src/services/trezor/trezorService.ts`
|
||||
- Backend: `backend/src/services/trezor/trezorService.ts:214` (safekeeping gate)
|
||||
- Backend: `backend/src/services/dispute/releaseHoldService.ts`
|
||||
- Frontend: admin payment/release/refund surfaces under `frontend/src/sections/`
|
||||
- Backend: `backend/src/services/payment/decentralizedPaymentService.ts:911` (`payout-completed` emit)
|
||||
- Backend: `backend/src/services/payment/paymentRoutes.ts:622` (`payment-received` emit)
|
||||
- Backend: `backend/src/services/payment/wallets/sweepService.ts`, `models/DerivedDestination.ts` (sweep infra)
|
||||
- Frontend: `frontend/src/components/trezor-sign-dialog/TrezorSignDialog.tsx`, `frontend/src/actions/trezor.ts:108,133` (active Trezor confirm path)
|
||||
- Frontend: `frontend/src/actions/payment.ts:487,503` (legacy `confirmReleaseTx`/`confirmRefundTx`, no Trezor proof)
|
||||
|
||||
Reference in New Issue
Block a user