Document payment verification and trezor safekeeping

This commit is contained in:
Siavash Sameni
2026-05-24 11:12:17 +04:00
parent 1a2b9f1f5d
commit b824ca0435
7 changed files with 569 additions and 54 deletions

View File

@@ -0,0 +1,119 @@
# 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`.
## Goals
- Generate a fresh receive address per user/payment from a registered Trezor xpub.
- Require a Trezor-produced signature before release/refund confirmation when safekeeping enforcement is enabled.
- Keep SHKeeper and Request Network optional provider paths intact.
- Preserve the existing `Payment` model and orchestration surface.
## Registration
1. User connects a Trezor in the frontend and exports an Ethereum account xpub, for example `m/44'/60'/0'`.
2. Backend builds a registration challenge:
- `GET /api/trezor/registration-message?xpub=...&registrationAddress=...`
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.
5. Frontend submits:
- `POST /api/trezor/register`
- `xpub`
- `registrationAddress`
- `proofMessage`
- `proofSignature`
- optional `basePath`, `deviceLabel`
6. Backend verifies:
- 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
## Address Generation
To issue the next payment address:
```http
POST /api/trezor/addresses/next
{
"purpose": "deposit",
"paymentId": "..."
}
```
The backend derives non-hardened receive addresses from the registered xpub:
```text
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
Before a release/refund confirmation, the admin asks the backend for the exact operation message:
```http
POST /api/trezor/operation-message
{
"operation": "release",
"paymentId": "...",
"transactionHash": "0x...",
"amount": 100,
"currency": "USDT",
"provider": "request.network"
}
```
The Trezor signs that message. Release/refund confirmation then includes:
```json
{
"txHash": "0x...",
"trezor": {
"message": "Amanat escrow Trezor transaction approval\n...",
"signature": "0x..."
}
}
```
When `TREZOR_SAFEKEEPING_REQUIRED=true`, `confirmReleaseRefundInstruction` verifies the signature before calling the payment adapter confirmation path.
## Enforcement Flag
```env
TREZOR_SAFEKEEPING_REQUIRED=false
```
Default is permissive so existing SHKeeper and Request Network 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.
## Safety Rules
- Never store Trezor seed words, private keys, or xprv/tprv values.
- Reject private extended keys at registration.
- Verify every signature locally before accepting it.
- Use exact transaction-intent messages; do not accept free-form signatures.
- Treat generated deposit addresses as public routing metadata, not as proof of payment.
- Keep ledger availability checks enabled for release/refund accounting.
## Upgrade Path To Multisig
The current design stores a single `trezor-eoa` signer. Later, replace the signer policy with:
- `addressType: safe-multisig`
- a Safe address per tenant/admin group
- threshold policy, such as `2-of-3`
- Trezor owners as Safe signers
- release/refund flow creates a Safe transaction and records collected signatures before execution
The payment orchestration API should stay the same: build instruction, collect hardware-backed approval, confirm release/refund, append ledger entry.