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:
@@ -1,9 +1,19 @@
|
||||
> **Last updated:** 2026-05-29 — aligned with code (see Doc vs Code Audit Report)
|
||||
|
||||
# Trezor Safekeeping Flow
|
||||
|
||||
This flow adds hardware-backed custody controls without replacing the current payment model. The backend never stores private keys. Trezor support starts as a single hardware signer and is designed to upgrade to multisig later.
|
||||
|
||||
Default mode: optional. Existing release/refund flows do not require Trezor proof unless `TREZOR_SAFEKEEPING_REQUIRED=true`.
|
||||
|
||||
> **Note (corrected 2026-05-29):** The frontend Trezor implementation **does exist** in current code — the 2026-05-29 audit's "zero frontend implementation" claim was based on an older snapshot. The active surface is:
|
||||
> - `src/app/dashboard/admin/trezor/page.tsx` → `TrezorSettingsView` (registration + re-register UI)
|
||||
> - `src/web3/trezor/trezorConnector.ts` → lazy-imports `@trezor/connect-web` (`trezorGetXpub`, `trezorGetAddress`, `trezorSignMessage`)
|
||||
> - `src/components/trezor-sign-dialog/TrezorSignDialog.tsx` → build-instruction → sign-on-Trezor → enter-txHash → confirm
|
||||
> - `src/actions/trezor.ts` → full API client (`getTrezorAccount`, `getTrezorRegistrationMessage`, `registerTrezor`, `getTrezorOperationMessage`, `confirmRelease`/`confirmRefund`) that **builds the `trezor: { message, signature }` object**
|
||||
>
|
||||
> The legacy `confirmReleaseTx`/`confirmRefundTx` helpers in `src/actions/payment.ts` post only `{ txHash }` (no `trezor` field), but they have **no UI callers** — the active admin release/refund path goes through `TrezorSignDialog` → `actions/trezor.ts`, which satisfies the `assertTrezorSignatureForOperation` guard when `TREZOR_SAFEKEEPING_REQUIRED=true`.
|
||||
|
||||
## Goals
|
||||
|
||||
- Generate a fresh receive address per user/payment from a registered Trezor xpub.
|
||||
@@ -11,14 +21,19 @@ Default mode: optional. Existing release/refund flows do not require Trezor proo
|
||||
- Keep the Request Network payment adapter and legacy provider abstractions intact while adding custody controls.
|
||||
- Preserve the existing `Payment` model and orchestration surface.
|
||||
|
||||
## Actors
|
||||
|
||||
- **Admin** — the only party who can request operation messages and submit verify-operation calls. The registered Trezor must belong to an admin account; the safekeeping guard validates against the admin's `TrezorAccount.registrationAddress`.
|
||||
- **Any authenticated user** — may call `POST /api/trezor/register` (no role restriction on that endpoint).
|
||||
|
||||
## Registration
|
||||
|
||||
1. User connects a Trezor in the frontend and exports an Ethereum account xpub, for example `m/44'/60'/0'`.
|
||||
1. The Trezor owner (typically an admin) connects a Trezor and exports an Ethereum account xpub, for example `m/44'/60'/0'`.
|
||||
2. Backend builds a registration challenge:
|
||||
- `GET /api/trezor/registration-message?xpub=...®istrationAddress=...`
|
||||
3. The registration address must be the first derived address from the xpub:
|
||||
- `m/44'/60'/0'/0/0`
|
||||
4. User signs the challenge with that Trezor address.
|
||||
4. The owner signs the challenge with that Trezor address.
|
||||
5. Frontend submits:
|
||||
- `POST /api/trezor/register`
|
||||
- `xpub`
|
||||
@@ -30,14 +45,7 @@ Default mode: optional. Existing release/refund flows do not require Trezor proo
|
||||
- xpub is public, not private.
|
||||
- registration address matches xpub-derived index `0`.
|
||||
- signature recovers the registration address.
|
||||
7. Backend stores only:
|
||||
- `userId`
|
||||
- xpub fingerprint
|
||||
- xpub
|
||||
- base derivation path
|
||||
- registration address
|
||||
- next address index
|
||||
- issued address records
|
||||
7. Backend stores / updates the `TrezorAccount` record. **Upsert behaviour:** if a record already exists for the user, `xpub`, `basePath`, and `label` are updated, but `nextAddressIndex` and the existing `addresses` array are preserved via `$setOnInsert`. Old address records continue to reference the previous xpub — a xpub mismatch is therefore possible after re-registration.
|
||||
|
||||
## Address Generation
|
||||
|
||||
@@ -51,6 +59,15 @@ POST /api/trezor/addresses/next
|
||||
}
|
||||
```
|
||||
|
||||
Valid values for `purpose` (as enumerated in the schema):
|
||||
|
||||
| Value | Description |
|
||||
|---|---|
|
||||
| `deposit` | Incoming payment address |
|
||||
| `release` | Address used in a release operation |
|
||||
| `refund` | Address used in a refund operation |
|
||||
| `other` | General-purpose address |
|
||||
|
||||
The backend derives non-hardened receive addresses from the registered xpub:
|
||||
|
||||
```text
|
||||
@@ -59,9 +76,9 @@ m/44'/60'/0'/0/{index}
|
||||
|
||||
If a `paymentId` already has an address, the endpoint returns the same address instead of incrementing the index.
|
||||
|
||||
## Transaction Approval
|
||||
## Transaction Approval (Admin-only)
|
||||
|
||||
Before a release/refund confirmation, the admin asks the backend for the exact operation message:
|
||||
`POST /api/trezor/operation-message` and `POST /api/trezor/verify-operation` are admin-only endpoints. Before a release/refund confirmation, the admin asks the backend for the exact operation message:
|
||||
|
||||
```http
|
||||
POST /api/trezor/operation-message
|
||||
@@ -75,19 +92,17 @@ POST /api/trezor/operation-message
|
||||
}
|
||||
```
|
||||
|
||||
The Trezor signs that message. Release/refund confirmation then includes:
|
||||
The Trezor signs that message and the admin submits it. **The frontend implements this flow** via `TrezorSignDialog`, which calls `getTrezorOperationMessage()`, prompts the Trezor to sign, and then submits the release/refund confirmation through `confirmRelease()` / `confirmRefund()` in `src/actions/trezor.ts` with the full payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"txHash": "0x...",
|
||||
"trezor": {
|
||||
"message": "Amanat escrow Trezor transaction approval\n...",
|
||||
"signature": "0x..."
|
||||
}
|
||||
"amount": 100,
|
||||
"trezor": { "message": "<canonical operation message>", "signature": "0x..." }
|
||||
}
|
||||
```
|
||||
|
||||
When `TREZOR_SAFEKEEPING_REQUIRED=true`, `confirmReleaseRefundInstruction` verifies the signature before calling the payment adapter confirmation path.
|
||||
The `trezor` object is included whenever a signature was produced, satisfying the backend `assertTrezorSignatureForOperation` guard. (The older `confirmReleaseTx`/`confirmRefundTx` helpers in `src/actions/payment.ts` post only `{ txHash }`, but they are unused legacy code with no UI callers.)
|
||||
|
||||
## Enforcement Flag
|
||||
|
||||
@@ -95,7 +110,7 @@ When `TREZOR_SAFEKEEPING_REQUIRED=true`, `confirmReleaseRefundInstruction` verif
|
||||
TREZOR_SAFEKEEPING_REQUIRED=false
|
||||
```
|
||||
|
||||
Default is permissive so existing Request Network release/refund flows continue to work. Set it to `true` only after registering the operating admin's Trezor account and testing the signing path. Any value other than the literal string `true` is treated as disabled.
|
||||
Default is permissive so existing Request Network release/refund flows continue to work. Set it to `true` only after registering the operating admin's Trezor account (the frontend signing flow via `TrezorSignDialog` is already implemented). Any value other than the literal string `true` is treated as disabled.
|
||||
|
||||
## Safety Rules
|
||||
|
||||
|
||||
Reference in New Issue
Block a user