docs: ship in-house RN checkout, scope 5 follow-up tasks (#7-11)

In-house Request Network checkout went fully end-to-end on dev today.
A real 0.01 USDC payment flowed through wallet connect -> approve ->
ERC20FeeProxy.transferFromWithReferenceAndFee -> RN webhook ->
TransactionSafetyProvider -> Payment.status=completed -> page success
state. Tx 0x494c77a29161b5100d8e0b1ac675f1822955d0bb3633ecdbfafb886f84f2f320.

Docs:
- New PRD: Wallet, Multichain, Confirmations, AML, Trezor
  (5 follow-ups, each sized for an independent contributor)
- Updated PRD: Request Network In-House Checkout (phases 0..3 done,
  phase 4 partial, phases 5-6 not started)
- Updated handoff: deployed versions, what is working end-to-end,
  follow-up tasks index

Taskmaster: 5 new top-level tasks (#7..#11) covering ephemeral
destination wallets, multichain proxy registry + USDC/USDT, runtime
confirmation thresholds, optional seller-paid AML screening, and
Trezor signing for admin actions. Tasks are scoped fine-grained so
each is independent enough for kimi to pick up.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-05-28 15:50:24 +04:00
parent 37f946fc23
commit 0060b16912
69 changed files with 1513 additions and 147 deletions

View File

@@ -0,0 +1,280 @@
# PRD: Request Network In-House Checkout
**Status:** Draft — updated after 2026-05-28 dev webhook probe
**Date:** 2026-05-27
**Related:** `01 - Architecture/Request Network Integration Constraints.md` §1; `PRD - Request Network Migration and Funds Management.md`
**Owner:** Backend payments + Frontend
---
## 1. Problem
Buyers paying through Request Network (RN) are redirected from Amanat to RN's hosted page at `pay.request.network/?token=…`. That page has three concrete problems:
1. **Rabby is not supported.** A meaningful portion of our user base pays from Rabby. The hosted page does not detect it (no EIP-6963 enumeration, hard-coded MetaMask/WalletConnect/Coinbase). For those users, checkout fails before a transaction is even attempted.
2. **The page is brand-divergent.** Buyers leave the Amanat domain mid-flow, which is a trust and conversion cost we can avoid.
3. **The page relies on RN's choice of infrastructure.** Observed in our own probe: their UI wraps the payment in Safe smart accounts + ERC-4337 + a Pimlico paymaster, hitting public BSC RPCs that already rate-limited us once ("RPC endpoint returned too many errors"). We have no control to fix that.
The core RN protocol is sound. The hosted UI on top of it is the problem.
### 2026-05-28 reality update
The first dev BSC probe did not fail because RN stayed silent. It failed because Amanat dropped the provider callback:
- Test transaction: `0x3a23febd9abd43d7e0851c1ea86c4ceaf08c11098852cb0425fa074e9c88350b`.
- On-chain result: successful BSC USDC transfer to Amanat's configured destination wallet.
- RN webhook result: RN called `POST /api/payment/request-network/webhook` on `dev.amn.gg` four times from `34.34.233.192`.
- Backend result: nginx/backend returned `404` because the handler did not correlate all Request Network identifiers stored on the `Payment` record.
- Frontend result: the callback page stayed on the processing state and later hit `429` from 3-second polling.
The pre-implementation gate therefore changes from "prove RN calls us" to "deploy and smoke-test the webhook correlation repair, callback polling repair, and transaction-safety gate before another paid probe".
## 2. Goal
Replace the redirect to RN's hosted page with an Amanat-rendered checkout that:
- Connects any EVM wallet (Rabby, MetaMask, OKX, Trust, WalletConnect — anything wagmi's `injected()` connector enumerates).
- Builds and submits the exact same on-chain calls RN's hosted page makes, so RN's existing webhook fires unchanged.
- Stays on `dev.amn.gg` (or prod equivalent) for the entire flow.
- Falls back gracefully to the hosted page for buyers who explicitly request it.
Settlement, webhook handling, and the backend `Payment` lifecycle do not change. Only the buyer-facing checkout surface changes.
Webhook delivery alone is not a sufficient trust signal. Amanat must run a **Transaction Safety Provider** gate before marking escrow funded. The initial provider checks: transaction hash present, configured confirmation depth, transfer recipient/token/amount match on-chain evidence, and future AML/sanctions provider approval.
## 3. Non-goals
- Per-seller multi-chain configuration (covered in `Request Network Integration Constraints.md` §2 — separate PRD).
- Per-`(buyer, merchant)` ephemeral wallets / wallet abstraction layer (§3 — separate PRD).
- Replacing RN entirely with our own chain watcher (§4 — depends on this PRD's outcome).
- Gasless / sponsored transactions for the buyer. Buyer pays own gas via their EOA. We can revisit paymaster integration in a follow-up.
## 4. Background: what RN's protocol actually requires
Cold-inspected from a real `$12` BSC payment on RN's hosted page:
| Item | Value |
|---|---|
| Proxy contract (BSC, and same address on most EVMs via deterministic CREATE2) | `0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9` |
| Function | `transferFromWithReferenceAndFee(address token, address to, uint256 amount, bytes reference, uint256 feeAmount, address feeAddress)` |
| Selector | `0xc219a14d` |
| Emitted event | `TransferWithReferenceAndFee(token, to, amount, reference, feeAmount, feeAddress)` |
| `paymentReference` derivation | `last8Bytes(keccak256(lowercase(requestId + salt + destinationAddress)))` |
| Fee config seen on RN's UI | `feeAmount = 0`, `feeAddress = 0x…dEaD` |
RN's webhook listens for `TransferWithReferenceAndFee`. If we emit it ourselves with the correct `paymentReference`, the webhook fires. The hosted UI is a UI-only convenience — not a settlement requirement.
## 5. Proposed flow (buyer perspective)
1. Buyer clicks "Pay with Request Network" on the request page.
2. Frontend calls existing `POST /payment/request-network/intents` (unchanged endpoint, expanded response — see §6).
3. Frontend navigates to new in-house page: `/checkout/request-network/:paymentId`.
4. Page shows: amount, token, chain, recipient (truncated, copyable), countdown timer.
5. "Connect wallet" — wagmi `injected()` + `metaMask()` (already configured). Rabby works automatically via EIP-6963.
6. Once connected, page checks the buyer's wallet is on the correct chain. If not, prompts `switchChain` (wagmi).
7. Page also checks current allowance. If `allowance(buyer, RN_PROXY) >= amount`, skip approve.
8. Buyer signs **transaction 1: `USDC.approve(RN_PROXY, amount)`**. UI shows "Approving…" → "Approved".
9. Buyer signs **transaction 2: `RN_PROXY.transferFromWithReferenceAndFee(token, dest, amount, ref, 0, 0x…dEaD)`**. UI shows "Submitting payment…" → "Confirmed on-chain".
10. Page waits for backend `payment-confirmed` socket event (already emitted on RN webhook → `Payment.status='paid'`). Shows success state.
11. Redirect to existing payment-success route.
Escape hatches surfaced as secondary links on the page:
- **"Continue on Request Network's hosted page"** → falls through to `securePaymentUrl` (unchanged behavior).
- **"Copy payment details"** → exposes destination, amount, token, chain, paymentReference for manual entry into any wallet.
## 6. Backend changes
### 6.1 Intent response payload
Expand `PayInIntentResult` for RN. Today it returns `paymentUrl`, `paymentId`, `providerPaymentId`, `amount`, `config.networks`, `config.allowedTokens`, `raw`. Add:
```ts
inHouseCheckout: {
destination: '0x05E280d7f3cA954f37afA8B1E4d2a51D167c573e',
tokenAddress: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',
tokenSymbol: 'USDC',
decimals: 18, // BSC USDC quirk; varies per token+chain
chainId: 56,
proxyAddress: '0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9',
paymentReference: '0xa826e248f5de5463', // 8-byte hex, computed from RN's requestId + salt
feeAmount: '0',
feeAddress: '0x000000000000000000000000000000000000dEaD',
amountWei: '12000000000000000000', // pre-multiplied by decimals, frontend doesn't compute
}
```
### 6.2 Sources for each field
| Field | Source |
|---|---|
| `destination`, `tokenAddress`, `chainId` | Parse `REQUEST_NETWORK_MERCHANT_REFERENCE` env (`address@eip155:chainId#ref:tokenAddr`). Today done once at startup; extract into a helper. |
| `decimals` | Token registry lookup. Hardcode the few we care about (USDC/USDT × BSC/ETH/Arb/Polygon) in a constant map; fall back to on-chain `decimals()` if missing. |
| `proxyAddress` | Constant per chain. Use canonical `0x0DfbEe14…0aC9` for all EVMs unless RN deploys a non-canonical address (open question — see §10). |
| `paymentReference` | Computed from RN's `/v2/secure-payments` response. `salt` is in their `raw` payload. Use `keccak256` + slice-to-8-bytes. |
| `feeAmount`, `feeAddress` | Constants matching what RN's hosted UI submits. Verify via cold inspection on each new chain we enable. |
| `amountWei` | `BigInt(amount) * 10n ** BigInt(decimals)`. Done backend-side to avoid frontend rounding bugs. |
### 6.3 Files touched
- `backend/src/services/payment/requestNetwork/contract.ts` — extend `PayInIntentResult` (or a new `inHouseCheckout` sub-object).
- `backend/src/services/payment/requestNetwork/requestNetworkPayInService.ts` — populate the new fields.
- `backend/src/services/payment/requestNetwork/merchantReference.ts` (new) — parser for the `address@chain#ref:token` format. Currently this is implicit in env lookups; promote to a named helper.
- `backend/src/services/payment/requestNetwork/tokens.ts` (new) — `{ chainId, tokenAddr } → { symbol, decimals }` lookup.
- `backend/src/services/payment/requestNetwork/paymentReference.ts` (new) — `computePaymentReference(requestId, salt, destination)`.
- Unit tests for each new helper.
### 6.4 Webhook handler
The route remains `/api/payment/request-network/webhook`, but the handler must be hardened before more paid probes:
- Correlate against every RN identifier we persist: `providerPaymentId`, `metadata.requestNetworkRequestId`, `metadata.requestNetworkPaymentReference`, and nested `metadata.requestNetworkData` ids/references.
- Reject unsigned or test-header callbacks unless explicit test mode is enabled.
- Store raw webhook evidence on the `Payment` record for support/replay.
- Call the Transaction Safety Provider before marking `Payment.status='completed'` / `escrowState='funded'`.
- Return a successful pending response when safety is not yet satisfied, so the delivery is not lost but escrow is not credited.
## 7. Frontend changes
### 7.1 New page
`frontend/src/pages/checkout/request-network/[paymentId].tsx` (or whatever the router convention is).
State machine (one component, reducer or zustand):
```
idle
→ connecting (wallet not connected)
→ wrong-chain (connected, chain mismatch)
→ ready (correct chain, allowance unknown)
→ checking-allowance
→ needs-approve → approving → approve-confirming → ready-to-pay
→ ready-to-pay
→ paying → pay-confirming → confirmed
→ error (with retry)
→ expired (timer ran out)
```
### 7.2 Reusable parts from SHKeeper
`frontend/src/web3/components/manual-payment.tsx` already implements: address-with-QR, copy-to-clipboard, countdown timer, localStorage persistence per request, socket-driven status update. Reuse the layout chrome. The wallet-interaction half is new.
### 7.3 Wagmi calls
Two contracts. The ERC-20 ABI is already in viem/wagmi. RN proxy ABI is a single function — define it inline.
```ts
const RN_PROXY_ABI = [{
inputs: [
{ name: 'tokenAddress', type: 'address' },
{ name: 'to', type: 'address' },
{ name: 'amount', type: 'uint256' },
{ name: 'paymentReference', type: 'bytes' },
{ name: 'feeAmount', type: 'uint256' },
{ name: 'feeAddress', type: 'address' },
],
name: 'transferFromWithReferenceAndFee',
outputs: [], stateMutability: 'nonpayable', type: 'function',
}] as const;
```
Hooks used:
- `useAccount`, `useChainId`, `useSwitchChain`
- `useReadContract` for `allowance`
- `useWriteContract` + `useWaitForTransactionReceipt` for approve and proxy call
### 7.4 Routing change
Today, `createRequestNetworkIntent` consumers do `window.location = response.paymentUrl`. Replace with `router.push('/checkout/request-network/' + response.paymentId)`. Keep `response.paymentUrl` available so the in-house page can render the escape-hatch link.
### 7.5 Files touched
- `frontend/src/pages/checkout/request-network/[paymentId].tsx` — new page.
- `frontend/src/web3/components/rn-in-house-checkout.tsx` — new component holding the state machine.
- `frontend/src/web3/contracts/rn-fee-proxy.ts` — ABI + address-per-chain constants.
- `frontend/src/sections/request/components/buyer-steps/…` — change the existing RN button handler from `window.location` to `router.push`.
- Tests/Storybook for the new component.
## 8. Acceptance criteria
1. A buyer using **Rabby** can complete an RN payment end-to-end on `dev.amn.gg` without leaving the domain.
2. The two on-chain transactions emit a `TransferWithReferenceAndFee` event with the same `paymentReference` RN's hosted page would have produced.
3. RN's existing webhook fires on the event and the `Payment` doc transitions to `completed` / `escrowState='funded'` after safety approval.
4. If buyer connects on the wrong chain, they see a one-click "Switch network" CTA.
5. If buyer already has sufficient allowance, the approve step is skipped.
6. If the buyer abandons the page, returning to it restores their state from localStorage and resumes from the correct step.
7. "Continue on Request Network's hosted page" link is visible on the in-house page and works exactly like today's redirect.
8. Page handles tx failure (user reject, insufficient gas, RPC error) with a clear retry path that does not corrupt the `Payment` doc.
9. Existing non-RN payment flows (SHKeeper, others) are untouched.
## 9. Out of scope (explicit non-decisions)
- Multi-chain at checkout (BSC + Arb + ETH together) — needs the per-seller `acceptedChains` config; separate PRD.
- WalletConnect integration — currently disabled in `web3/config.ts` for SSR reasons; not regressed but not added either.
- Migration plan to remove RN entirely — kept as `§4` open option in the architecture doc.
- Mobile Mini App rendering of the checkout (different surface — handled in Task 5.4).
## 10. Open questions for review
These are the items we should discuss with the second developer before starting implementation.
1. **Proxy address universality.** Is `0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9` the RN ERC20FeeProxy address on **every** chain we plan to support (BSC, Arb, ETH mainnet, Polygon, Base)? We confirmed BSC + Arbitrum from RN's payments-subgraph repo. The other chains need explicit confirmation — preferably an on-chain probe per chain.
2. **API pricing for hosted-UI vs API-only.** RN's pricing model may assume hosted-UI usage. If we use them as a notification primitive only, are we still in their pricing terms? Worth a direct question to RN account management.
3. **Approval UX.** RN's hosted UI uses `approve(spender, MAX_UINT256)` for gas efficiency. Some Amanat users have voiced concern in past audits about unbounded approvals. Options:
- Mirror RN: `MAX_UINT256` (best UX, repeat payments don't need re-approve).
- Exact-amount: `approve(spender, amount)`. Slightly worse UX (every payment requires an approve), better security posture.
- Recommend: exact-amount by default, opt-in "remember this approval" for power users. Discuss.
4. **Tokens with non-standard ERC-20 behavior.** USDT on Ethereum mainnet famously requires `approve(0)` before changing a non-zero allowance. We need to handle this if we add USDT-ETH later. Not relevant on day one (BSC config is USDC), but worth flagging now.
5. **Cancel and timeout semantics.** Today the `Payment` doc transitions on the webhook. If the buyer signs the approve but bails on the proxy call, the doc sits in `pending` forever. Options:
- 30-minute TTL on the `pending` doc (existing partial unique index would let a re-attempt succeed).
- "Cancel intent" button on the in-house page that calls a new backend endpoint to mark the doc `cancelled`.
- Both. Discuss.
6. **Manual reconciliation.** If a buyer pays the correct amount to the correct destination but bypasses the proxy (e.g., raw `transfer`), no event fires and no webhook arrives. They'll think they paid but our system won't know. Today RN's hosted UI prevents this; our in-house UI inherits the same risk only if we add a "raw transfer" escape hatch — which we won't. But: should we proactively detect orphan transfers (chain watcher) and surface them in support? Out of scope for v1.
7. **Feature flag and rollout.** Ship behind a flag and A/B against the current redirect for one week of dev usage? Or hard-cut once acceptance criteria pass? Recommend A/B for at least one full release cycle.
8. **Telemetry.** What events do we instrument so we can prove the in-house page outperforms the redirect on conversion? Suggested: `rn_checkout_opened`, `rn_wallet_connected`, `rn_approve_signed`, `rn_pay_signed`, `rn_pay_confirmed`, `rn_pay_failed{reason}`, `rn_escape_to_hosted_clicked`.
## 11. Risks
- **Webhook handling failure.** RN delivered the 2026-05-28 dev webhook, but Amanat returned `404`. A deployed correlation fix and smoke test are now the load-bearing gate before another paid probe.
- **Webhook durability.** The main app is too unstable to be the only callback landing zone. Put a Cloudflare Worker in front of Request Network webhooks to durably store raw delivery evidence, forward to the backend, and replay after outages.
- **False-positive payment credit.** A signed provider event must not be enough to fund escrow. Transaction Safety Provider gates completion on on-chain evidence, confirmation depth, transfer matching, and future AML/sanctions checks.
- **Chain-specific divergences.** RN may have deployed non-canonical proxy contracts on some chains. We mitigate by hard-coding per-chain proxy addresses and treating "unknown chain → fall back to hosted page" as the safe default.
- **Wallet support drift.** EIP-6963 is mature but not universal. We rely on wagmi's `injected()` connector enumeration; if a wallet doesn't implement EIP-6963, it falls into the generic `window.ethereum` slot. Acceptable.
- **Buyer signs approve, then we change ABI before they sign the proxy call.** Not really a risk if both txs are in the same session, but worth a smoke test on a long-lived session.
## 12. Implementation phases
Roughly two weeks of checkout work, now gated on confirmation reliability repair.
| Phase | Work | Gate |
|---|---|---|
| 0 — Probe | Fire one real dev BSC payment and inspect nginx/backend logs | Completed: RN webhook reached nginx/backend; app returned `404` |
| 0A — Confirmation repair | Deploy correlation fix, callback polling fix, signed-webhook smoke test, and Transaction Safety Provider | Unsigned/test callbacks rejected unless explicitly enabled; real webhook can find the `Payment` |
| 1 — Backend | Expand intent response with `inHouseCheckout` fields; add helpers and tests | Existing RN smoke test still passes; new unit tests pass |
| 2 — Frontend skeleton | New page + state machine + wallet-connect; no on-chain calls yet, mocked confirmations | Local clickthrough on `dev.amn.gg` with Rabby connected |
| 3 — On-chain wiring | Real `approve` + `transferFromWithReferenceAndFee` calls; allowance check; chain-switch | One real end-to-end payment on dev BSC, webhook fires, `Payment.status='completed'`, safety approved |
| 4 — Hardening | Error handling, timer, persistence, telemetry, escape-hatch link | Acceptance criteria 19 demonstrably pass |
| 5 — Durable ingress | Cloudflare Worker receives RN webhooks, stores delivery records, forwards to backend, supports replay | Backend outage no longer loses webhook evidence |
| 6 — Rollout | Behind feature flag, A/B in dev for one cycle, then prod | Conversion telemetry; no regressions in non-RN flows |
## 13. Durable webhook ingress roadmap
Add a Cloudflare Worker as the public Request Network webhook target:
1. Receive the raw RN webhook body, headers, request id, delivery id, source IP, and timestamp.
2. Verify the RN signature at the edge if raw-body secret handling is straightforward; otherwise store first and let the backend perform canonical verification.
3. Write an immutable delivery record to durable storage. Candidate stack: Cloudflare Queues for handoff plus D1/R2/KV for indexed replay metadata and raw payload retention.
4. Forward to the primary backend and optionally a secondary endpoint.
5. Return `2xx` only after durable enqueue/store succeeds.
6. Provide operator replay by delivery id, payment reference, request id, or time window.
The Worker is only ingress/evidence buffering. The backend remains the trust boundary for signature verification, idempotency, Transaction Safety Provider checks, ledger updates, and marketplace state transitions.
## 14. References
- Cold-inspected transaction (real `$12` BSC payment on RN hosted page): in conversation history, dated 2026-05-27.
- RN ERC20FeeProxy spec: <https://github.com/RequestNetwork/requestNetwork/blob/master/packages/advanced-logic/specs/payment-network-erc20-fee-proxy-contract-0.1.0.md>
- Arbitrum proxy deployment: <https://github.com/RequestNetwork/payments-subgraph/blob/main/subgraph.arbitrum-one.yaml>
- Architecture constraints doc: `01 - Architecture/Request Network Integration Constraints.md`
- Previous RN work: `PRD - Request Network Migration and Funds Management.md`

View File

@@ -2,7 +2,7 @@
"master": { "master": {
"tasks": [ "tasks": [
{ {
"id": "1", "id": 1,
"title": "Stabilize Mermaid diagram rendering across documentation vault", "title": "Stabilize Mermaid diagram rendering across documentation vault",
"description": "Correct Mermaid syntax/rendering issues across the documentation vault and validate all Mermaid blocks.", "description": "Correct Mermaid syntax/rendering issues across the documentation vault and validate all Mermaid blocks.",
"details": "Source PRD: .taskmaster/docs/prd-mermaid-diagram-rendering-stabilization.md. Scope covered 57 Mermaid blocks and 11 failing blocks. The source PRD records that all targeted files now pass mmdc parse validation and the full vault sweep passes.", "details": "Source PRD: .taskmaster/docs/prd-mermaid-diagram-rendering-stabilization.md. Scope covered 57 Mermaid blocks and 11 failing blocks. The source PRD records that all targeted files now pass mmdc parse validation and the full vault sweep passes.",
@@ -47,7 +47,7 @@
] ]
}, },
{ {
"id": "2", "id": 2,
"title": "Implement platform audit remediation plan", "title": "Implement platform audit remediation plan",
"description": "Address the code-backed security and consistency issues identified in the 2026-05-24 platform audit remediation PRD.", "description": "Address the code-backed security and consistency issues identified in the 2026-05-24 platform audit remediation PRD.",
"details": "Source PRD: .taskmaster/docs/prd-platform-audit-remediation-plan-2026-05-24.md. Target backend hardening first, then documentation/runtime alignment. Delivery order suggested by PRD: security/auth, rate limiting, passkeys, Web3 verification, socket hardening, dispute hold controls, docs/API alignment.", "details": "Source PRD: .taskmaster/docs/prd-platform-audit-remediation-plan-2026-05-24.md. Target backend hardening first, then documentation/runtime alignment. Delivery order suggested by PRD: security/auth, rate limiting, passkeys, Web3 verification, socket hardening, dispute hold controls, docs/API alignment.",
@@ -154,7 +154,7 @@
] ]
}, },
{ {
"id": "3", "id": 3,
"title": "Migrate payment architecture toward Request Network and internal funds management", "title": "Migrate payment architecture toward Request Network and internal funds management",
"description": "Plan and implement provider-neutral payment flows, Request Network pay-in support, funds ledger, webhook reconciliation, release/refund orchestration, UI migration, and SHKeeper decommissioning.", "description": "Plan and implement provider-neutral payment flows, Request Network pay-in support, funds ledger, webhook reconciliation, release/refund orchestration, UI migration, and SHKeeper decommissioning.",
"details": "Source PRD: .taskmaster/docs/prd-request-network-migration-and-funds-management.md. The PRD recommends phased migration behind a provider adapter, Secure Payment Pages first, platform-controlled escrow/payee destination, and a first-class internal funds ledger before release/refund enforcement.\n\nPost-completion update: Task 3 now includes a CI-safe focused verification command for the provider-neutral payment migration plus optional Trezor safekeeping. Trezor safekeeping is optional by default via TREZOR_SAFEKEEPING_REQUIRED=false and only gates release/refund confirmation when explicitly enabled. Vault references: 04 - Flows/Trezor Safekeeping Flow.md, 03 - API Reference/Trezor API.md, and 08 - Operations/Payment and Trezor Verification Report.md.", "details": "Source PRD: .taskmaster/docs/prd-request-network-migration-and-funds-management.md. The PRD recommends phased migration behind a provider adapter, Secure Payment Pages first, platform-controlled escrow/payee destination, and a first-class internal funds ledger before release/refund enforcement.\n\nPost-completion update: Task 3 now includes a CI-safe focused verification command for the provider-neutral payment migration plus optional Trezor safekeeping. Trezor safekeeping is optional by default via TREZOR_SAFEKEEPING_REQUIRED=false and only gates release/refund confirmation when explicitly enabled. Vault references: 04 - Flows/Trezor Safekeeping Flow.md, 03 - API Reference/Trezor API.md, and 08 - Operations/Payment and Trezor Verification Report.md.",
@@ -326,12 +326,22 @@
"parentTaskId": 3, "parentTaskId": 3,
"parentId": "undefined", "parentId": "undefined",
"updatedAt": "2026-05-24T06:51:00.615Z" "updatedAt": "2026-05-24T06:51:00.615Z"
},
{
"id": 13,
"title": "Add durable RN webhook ingress and transaction safety",
"description": "Roadmap follow-up from the 2026-05-28 dev payment probe: Request Network delivered the webhook but Amanat returned 404. Add Cloudflare Worker durable webhook ingress with storage/replay and keep backend Transaction Safety Provider checks as the trust boundary before marking escrow funded.",
"details": "",
"status": "pending",
"dependencies": [],
"parentTaskId": 3,
"parentId": "undefined"
} }
], ],
"updatedAt": "2026-05-24T07:04:01.906Z" "updatedAt": "2026-05-24T07:04:01.906Z"
}, },
{ {
"id": "4", "id": 4,
"title": "Define backend security and refactor strategy from latest audit", "title": "Define backend security and refactor strategy from latest audit",
"description": "Convert the backend stack security/refactor assessment into concrete architecture decisions, documentation deliverables, and developer handoff criteria.", "description": "Convert the backend stack security/refactor assessment into concrete architecture decisions, documentation deliverables, and developer handoff criteria.",
"details": "Source audit: .taskmaster/docs/audit-backend-stack-security-and-refactor-assessment-2026-05-24.md. This task is advisory/architecture-focused and should run in parallel with immediate hardening. It should produce the decision artifacts needed before any backend-core rewrite or provider migration is started.", "details": "Source audit: .taskmaster/docs/audit-backend-stack-security-and-refactor-assessment-2026-05-24.md. This task is advisory/architecture-focused and should run in parallel with immediate hardening. It should produce the decision artifacts needed before any backend-core rewrite or provider migration is started.",
@@ -473,7 +483,7 @@
"updatedAt": "2026-05-24T07:23:44.643Z" "updatedAt": "2026-05-24T07:23:44.643Z"
}, },
{ {
"id": "5", "id": 5,
"title": "Deliver Telegram-native app, bot, and wallet experience", "title": "Deliver Telegram-native app, bot, and wallet experience",
"description": "Create a Telegram bot plus Mini App surface so users can complete Amanat buyer, seller, escrow, chat, dispute, payment, release/refund, and support workflows from inside Telegram.", "description": "Create a Telegram bot plus Mini App surface so users can complete Amanat buyer, seller, escrow, chat, dispute, payment, release/refund, and support workflows from inside Telegram.",
"details": "Source PRD: .taskmaster/docs/prd-telegram-native-app-bot-wallet.md. Keep this as a separate delivery track from security remediation and Request Network migration. Identity, bot navigation, Mini App shell, and notifications can start behind flags; wallet/payment crediting and release/refund actions must use canonical backend authorization, provider adapter, funds ledger, escrow state machine, idempotency, and dispute holds.", "details": "Source PRD: .taskmaster/docs/prd-telegram-native-app-bot-wallet.md. Keep this as a separate delivery track from security remediation and Request Network migration. Identity, bot navigation, Mini App shell, and notifications can start behind flags; wallet/payment crediting and release/refund actions must use canonical backend authorization, provider adapter, funds ledger, escrow state machine, idempotency, and dispute holds.",
@@ -635,16 +645,98 @@
} }
], ],
"updatedAt": "2026-05-24T13:46:14.458Z" "updatedAt": "2026-05-24T13:46:14.458Z"
},
{
"id": 6,
"title": "Request Network in-house checkout (Rabby-supporting)",
"description": "Replace the redirect to pay.request.network with an Amanat-rendered checkout page that submits the same on-chain calls as RN's hosted UI, so RN's webhook fires unchanged but buyers stay on amn.gg and Rabby works.",
"details": "See PRD: nick-doc/.taskmaster/docs/prd-request-network-in-house-checkout.md (summary at nick-doc/PRD - Request Network In-House Checkout.md). Status: draft, pending review with second developer. Approach: replicate the two on-chain calls (approve + RN_FEE_PROXY.transferFromWithReferenceAndFee) using wagmi v2 with existing injected()/metaMask() connectors (Rabby works via EIP-6963). Hard-known: proxy 0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9, selector 0xc219a14d, paymentRef = last8Bytes(keccak256(requestId+salt+dest)), feeAmount=0, feeAddress=0x...dEaD. Backend: extend POST /payment/request-network/intents response with inHouseCheckout object (destination, tokenAddress, decimals, chainId, proxyAddress, paymentReference, feeAmount, feeAddress, amountWei). Frontend: new page /checkout/request-network/:paymentId with state machine reusing manual-payment.tsx layout chrome, hosted-page link kept as escape hatch. Implementation gated on a $0.50 cold probe on dev BSC to confirm RN's webhook fires for an externally-built tx. Out of scope: per-seller multi-chain config (§2), ephemeral wallets (§3), full RN removal (§4), gasless. Open questions in PRD §10.",
"testStrategy": "",
"status": "done",
"dependencies": [],
"priority": "high",
"subtasks": [
{
"id": 1,
"title": "Deploy confirmation repair before next paid probe",
"description": "2026-05-28 dev BSC transaction succeeded and RN delivered four webhooks, but Amanat returned 404 due Request Network reference-correlation mismatch. Before another paid payment test, deploy the backend correlation fix, callback polling fix, signed-webhook smoke test, and Transaction Safety Provider gate; then repeat the probe and inspect safety decision state.",
"details": "",
"status": "done",
"dependencies": [],
"parentTaskId": 6,
"updatedAt": "2026-05-28T07:34:40.368Z",
"parentId": "undefined"
}
],
"updatedAt": "2026-05-28T07:34:40.368Z"
},
{
"id": 7,
"title": "Per-(buyer, sellerOffer) ephemeral RN destination wallets",
"description": "Replace the single shared Amanat destination wallet with a per-(buyerId, sellerOfferId) HD-derived address sent to Request Network on intent creation, plus sweep-on-approval and an admin UI.",
"details": "See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §1. Files: new backend/src/services/payment/wallets/derivedDestinations.ts (getDestinationFor(buyerId, sellerOfferId) → {address, derivationPath, chainId}); Payment schema add metadata.derivedDestination; requestNetworkPayInService.ts override destinationId before POST /v2/secure-payments (we confirmed RN accepts different destinations per intent); new sweep cron + admin manual-trigger endpoint gated on Transaction Safety Provider; admin UI at /dashboard/admin/derived-destinations with address, balance, last sweep tx (BscScan link), ownership status. Open questions to settle first: HD vs disposable EOAs vs smart-forwarder (recommended HD); sweep cadence (recommended immediate); granularity (recommended per-(buyer, seller), not per-payment); re-use vs rotate after sweep. KMS-rooted seed; backend never holds raw private keys; signing via KMS API (Task #11 Trezor flow is the longer-term replacement). Acceptance: two payments from one buyer to two sellers land on two different addresses; RN webhook fires for both; sweep is idempotent; master seed never leaves KMS.",
"testStrategy": "",
"status": "pending",
"dependencies": [],
"priority": "high",
"subtasks": []
},
{
"id": 8,
"title": "Multichain RN proxy registry + USDC/USDT support",
"description": "Probe and persist RN ERC20FeeProxy addresses on BSC/Arb/ETH/Polygon/Base, add USDC + USDT token entries with correct decimals per chain, and surface an admin networks page. Include the USDT-mainnet approve(0) reset quirk in the frontend approve step.",
"details": "See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §2. Tasks: new backend/scripts/probe-rn-chains.ts that walks each chain in supported-chains.json and verifies the canonical 0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9 proxy is the real RN proxy via a known view fn (CREATE2 is deterministic, but verify); promote backend/src/services/payment/requestNetwork/tokens.ts to load from JSON + admin override; add USDT entries on all 5 chains (BSC USDT 18-dec quirk, mainnet/Arb/Polygon/Base USDT 6-dec); buildInHouseCheckoutBlock returns reason='unsupported_chain:<id>' for unknowns; new admin route GET /api/admin/rn/networks + frontend page /dashboard/admin/networks rendering the registry with per-row 'probe again'. Frontend approve flow: if buyer is on Ethereum mainnet AND token is USDT AND current allowance > 0, do approve(spender, 0) first then approve(spender, amount). Acceptance: probe succeeds on at least BSC/Arb/Polygon/ETH/Base; one paid probe on BSC USDT end-to-end; mainnet USDT approve(0) reset works; admin page reflects registry. Dependencies: none — runs in parallel with #9. This is task #8 in the PRD.",
"testStrategy": "",
"status": "pending",
"dependencies": [],
"priority": "high",
"subtasks": []
},
{
"id": 9,
"title": "Per-chain confirmation thresholds + admin UI",
"description": "Make TransactionSafetyProvider's confirmation threshold tunable at runtime per chain via admin UI, with an awaiting-confirmation payments view that shows live confirmations vs threshold.",
"details": "See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §3. Today TRANSACTION_SAFETY_MIN_CONFIRMATIONS is a global env var, default 12, baked in until redeploy. Move to runtime config: new Setting docs keyed 'confirmation_threshold:<chainId>' or extend existing model; cache reads in transactionSafetyProvider.ts for 30s; GET/PATCH /api/admin/settings/confirmation-thresholds (auth: admin); new admin page /dashboard/admin/confirmation-thresholds (table: chain, current, recommended default, edit-in-place with confirm dialog, audit log of changes); new admin page /dashboard/admin/payments/awaiting-confirmation (payments where escrowState !== 'funded' AND metadata.transactionSafety.lastCheck.status === 'pending'; for each show tx hash linked to explorer, current confirmations via 12s poll on BSC, threshold, ETA). Acceptance: admin lowers BSC threshold from 12 to 3 on dev, next webhook honors new value within 30s; awaiting-confirmation table updates live; audit log records every change. Non-goals: per-asset, per-seller thresholds. Dependencies: none. This is task #9 in the PRD.",
"testStrategy": "",
"status": "pending",
"dependencies": [],
"priority": "medium",
"subtasks": []
},
{
"id": 10,
"title": "Optional AML screening on incoming payments (seller-paid)",
"description": "Turn the existing aml_screening placeholder in TransactionSafetyProvider into a real Chainalysis (or equivalent) Address Screening call that the seller opts into per-offer and pays the per-check cost for.",
"details": "See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §4. Default provider recommendation: Chainalysis Address Screening (cheapest, simplest). Files: new backend/src/services/payment/safety/amlProvider.ts interface + chainalysisProvider.ts impl behind env TRANSACTION_SAFETY_AML_PROVIDER=chainalysis with API_KEY in KMS; transactionSafetyProvider's evaluateAmlPlaceholder() becomes real, persists raw provider response on Payment.metadata.amlResult; Offer schema add requireAmlCheck + amlBlockOnFailure booleans; offer-edit UI toggle 'Require AML on incoming payments ($X per payment, paid by you)'; admin global config UI for provider selection + API key rotation + per-chain enabled flag; cost accounting: deduct per-check cost from seller's escrow on completion as a separate ledger line item, surfaced on payment-details. Open questions before code: pick provider (Chainalysis vs TRM vs Elliptic — need 1-page comparison of cost/latency/coverage); failure mode (fail-closed only when seller opted in AND amlBlockOnFailure=true, else warn/log); cost batching cadence. Acceptance: seller toggles AML on an offer; incoming payment triggers a real Chainalysis call; sanctions verdict blocks the safety gate; clean verdict passes; seller's settled amount reduced by check cost; admin can rotate API key without redeploy; provider-down + amlBlockOnFailure=true keeps payment pending with provider_unavailable reason. Dependencies: none. This is task #10 in the PRD.",
"testStrategy": "",
"status": "pending",
"dependencies": [],
"priority": "medium",
"subtasks": []
},
{
"id": 11,
"title": "Trezor signing for admin actions (release/refund/sweep)",
"description": "Replace the hot-key admin signing flow with a WebUSB-based Trezor flow so the backend never holds a private key. All admin-side txes are built backend, signed via Trezor in the browser, broadcast from the browser.",
"details": "See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §5. Lib: @trezor/connect-web (WebUSB; Chromium-only — Firefox users need Trezor Bridge native helper). Files: new frontend/src/web3/trezor/trezorConnector.ts wrapping @trezor/connect-web; existing admin actions (release/refund/sweep when #7 lands) get a 'Sign with Trezor' button that flows: POST /api/admin/actions/build-tx → returns unsigned tx bytes → send to Trezor → sign → wagmi sendTransaction broadcasts → POST /api/admin/actions/confirm-tx with hash; admin settings page to register Trezor address(es) (backend rejects signatures from unauthorized devices); audit log on every Trezor-signed action; break-glass hot-key path requires explicit admin toggle, expires after 1h, fires Telegram alarm. Open questions: m-of-n multi-admin signing — default single-signer for v1; Trezor One vs Model T — lib abstracts; fallback when Trezor unavailable — break-glass with alarm. Acceptance: admin registers Trezor address; release flow uses Trezor end-to-end; backend rejects signatures from unregistered devices; audit log captures admin user + Trezor addr + tx hash + before/after escrow state; break-glass works and alarms. Non-goals: mobile Trezor flow, buyer-side Trezor (buyer uses wagmi injected). Dependencies: task #7 (ephemeral wallets) for the sweep step — but task #11 can ship the release/refund flows first. This is task #11 in the PRD.",
"testStrategy": "",
"status": "pending",
"dependencies": [],
"priority": "high",
"subtasks": []
} }
], ],
"metadata": { "metadata": {
"version": "1.0.0", "version": "1.0.0",
"lastModified": "2026-05-24T13:46:14.458Z", "lastModified": "2026-05-28T07:34:40.369Z",
"taskCount": 5, "taskCount": 6,
"completedCount": 4, "completedCount": 5,
"tags": [ "tags": [
"master" "master"
] ],
"created": "2026-05-28T11:47:32.273Z",
"description": "Tasks for master context",
"updated": "2026-05-28T11:48:22.144Z"
} }
} }
} }

View File

@@ -1,10 +1,10 @@
# Request Network Integration — Constraints and Design Implications # Request Network Integration — Constraints and Design Implications
**Date:** 2026-05-27 **Date:** 2026-05-27
**Status:** Active concerns; mitigations partially designed, partially blocked on RN clarifications **Status:** Active concerns; 2026-05-28 probe confirmed RN webhook delivery but exposed Amanat confirmation handling gaps
**Owners:** Backend payments (Amanat), product **Owners:** Backend payments (Amanat), product
This document captures four payment-flow issues that surfaced while integrating Request Network (RN) into the Amanat escrow stack. Each one is either a show-stopper or a non-trivial architectural constraint. Listed in priority order. This document captures payment-flow issues that surfaced while integrating Request Network (RN) into the Amanat escrow stack. Each one is either a show-stopper or a non-trivial architectural constraint. Listed in priority order.
--- ---
@@ -24,8 +24,8 @@ So the new flow becomes:
2. **We render our own checkout screen** that: 2. **We render our own checkout screen** that:
- Shows the buyer the wallet address to pay to (the destination resolved from the merchant reference / chain / token). - Shows the buyer the wallet address to pay to (the destination resolved from the merchant reference / chain / token).
- Lets the buyer connect *any* wallet — Rabby, MetaMask, OKX, Phantom-bridged, WalletConnect. - Lets the buyer connect *any* wallet — Rabby, MetaMask, OKX, Phantom-bridged, WalletConnect.
- Builds the transfer transaction client-side (standard ERC-20 transfer) and asks the wallet to sign. - Builds the two RN-compatible transactions client-side: token `approve(proxy, amount)`, then `transferFromWithReferenceAndFee(...)` on RN's ERC20FeeProxy.
3. RN's webhook (`/v2/request/{id}`-style polling fallback) tells us when the payment lands. 3. RN's webhook tells us when the proxy event lands; Request Network search/status APIs remain the polling fallback.
### Why this is acceptable ### Why this is acceptable
@@ -34,7 +34,7 @@ So the new flow becomes:
### Open ### Open
- Need to confirm RN actually settles a payment that arrives from a *transaction we built*, not from their hosted page. Their pricing/fees may be tied to going through their UI. **Test required** before committing to this path. - Need to confirm RN settles a payment that arrives from a *proxy transaction we built*, not from their hosted page. The 2026-05-28 probe confirms RN webhook delivery to Amanat, but the app returned `404`; repeat the probe only after the confirmation repair is deployed.
- Need a fallback for the buyer who insists on the RN hosted UI (some users will already have the link copied). Keep `securePaymentUrl` exposed as a "advanced / pay with RN" link. - Need a fallback for the buyer who insists on the RN hosted UI (some users will already have the link copied). Keep `securePaymentUrl` exposed as a "advanced / pay with RN" link.
--- ---
@@ -143,15 +143,36 @@ Until #5 is confirmed, the rest is just paper architecture.
--- ---
## 5. Webhook durability and transaction safety are P0 before more paid probes
### What the 2026-05-28 probe proved
The dev test transaction `0x3a23febd9abd43d7e0851c1ea86c4ceaf08c11098852cb0425fa074e9c88350b` succeeded on BSC. RN then called `POST /api/payment/request-network/webhook` on `dev.amn.gg` four times from `34.34.233.192`. Amanat returned `404` because backend correlation looked up the wrong reference shape; the `Payment` record held RN request/payment-reference values that the handler did not search.
### Design implication
Do not treat the main Express app as the only webhook landing zone, and do not treat a signed provider callback as enough to credit escrow.
### Required mitigation
1. **Correlation repair:** lookup Request Network payments by every persisted reference shape, including `providerPaymentId`, top-level RN request id/payment reference, and nested raw RN data.
2. **Callback repair:** payment callback polling must unwrap the backend response shape, clear polling after terminal states, and avoid a 3-second loop that self-rate-limits.
3. **Transaction Safety Provider:** completion must pass configured safety checks: transaction hash present, minimum confirmations, token/recipient/amount transfer match, and future AML/sanctions provider approval.
4. **Durable ingress:** put a Cloudflare Worker in front of RN webhooks. The Worker stores raw delivery evidence durably, forwards to the backend, and supports replay. It is not the trust oracle; the backend still verifies, deduplicates, and applies safety/ledger transitions.
---
## Cross-cutting next actions ## Cross-cutting next actions
| # | Action | Blocker / Owner | | # | Action | Blocker / Owner |
|---|---|---| |---|---|---|
| 1 | Test: payment via wallet-built transfer triggers RN webhook | Backend payments | | 1 | Deploy confirmation repair and repeat the dev payment probe | Backend payments |
| 2 | Test: `/v2/secure-payments` accepts a per-request destination wallet | Backend payments | | 2 | Test: `/v2/secure-payments` accepts a per-request destination wallet | Backend payments |
| 3 | Confirm RN doesn't auto-bridge when buyer pays on the destination chain natively | Backend payments | | 3 | Confirm RN doesn't auto-bridge when buyer pays on the destination chain natively | Backend payments |
| 4 | Get RN's webhook P99 latency + delivery guarantees in writing | Product / RN account manager | | 4 | Get RN's webhook P99 latency + delivery guarantees in writing | Product / RN account manager |
| 5 | Spec the wallet-abstraction layer (HD derivation + sweep job + key policy) | Backend, before going live | | 5 | Spec the wallet-abstraction layer (HD derivation + sweep job + key policy) | Backend, before going live |
| 6 | Spec the seller-side accepted-chains config | Backend + frontend | | 6 | Spec the seller-side accepted-chains config | Backend + frontend |
| 7 | Add Cloudflare Worker durable webhook ingress to the roadmap | Backend / platform |
| 8 | Add AML/sanctions adapter behind Transaction Safety Provider | Compliance / backend |
Actions 14 are *information-gathering* and should run in parallel before any more architectural commitment to RN. Actions 56 are blocked on 13 confirming RN can actually support this shape. Actions 14 are *information-gathering* and should run in parallel before any more architectural commitment to RN. Actions 56 are blocked on 13 confirming RN can actually support this shape.

View File

@@ -55,6 +55,7 @@ Records every monetary movement in the marketplace: buyer pay-ins, seller payout
| `metadata.requestNetworkPaymentReference` | String | no | — | — | — | Request Network payment reference. | | `metadata.requestNetworkPaymentReference` | String | no | — | — | — | Request Network payment reference. |
| `metadata.requestNetworkSecurePaymentUrl` | String | no | — | — | — | Request Network secure payment URL. | | `metadata.requestNetworkSecurePaymentUrl` | String | no | — | — | — | Request Network secure payment URL. |
| `metadata.requestNetworkData` | Mixed | no | — | — | — | Raw Request Network payload. | | `metadata.requestNetworkData` | Mixed | no | — | — | — | Raw Request Network payload. |
| `metadata.transactionSafety` | Mixed | no | — | — | — | Last Transaction Safety Provider decision, checks, evidence, and blocker reason. |
| `metadata.lastWebhookAt` | Date | no | — | — | — | Last webhook timestamp. | | `metadata.lastWebhookAt` | Date | no | — | — | — | Last webhook timestamp. |
| `metadata.webhookPayload` | Mixed | no | — | — | — | Last webhook body. | | `metadata.webhookPayload` | Mixed | no | — | — | — | Last webhook body. |
| `metadata.createdVia` | String | no | — | — | — | Origin marker. | | `metadata.createdVia` | String | no | — | — | — | Origin marker. |

View File

@@ -113,6 +113,12 @@ SHKeeper is the crypto payment gateway. See [[Payment Flow]] and [[SHKeeper Inte
| `PAYMENT_PROVIDER_MODE` | backend | optional | `live` | `dry-run` | Provider mode: `live`, `dry-run`, or `read-only` | | `PAYMENT_PROVIDER_MODE` | backend | optional | `live` | `dry-run` | Provider mode: `live`, `dry-run`, or `read-only` |
| `REQUEST_NETWORK_ENABLED` | backend | optional | `false` | `true` | Adds `request.network` to enabled providers when no explicit list is set | | `REQUEST_NETWORK_ENABLED` | backend | optional | `false` | `true` | Adds `request.network` to enabled providers when no explicit list is set |
| `PAYMENT_REQUEST_NETWORK_COHORT_PERCENT` | backend | optional | `0` | `10` | Percent of new checkout cohort eligible for Request Network | | `PAYMENT_REQUEST_NETWORK_COHORT_PERCENT` | backend | optional | `0` | `10` | Percent of new checkout cohort eligible for Request Network |
| `REQUEST_NETWORK_ALLOW_TEST_WEBHOOKS` | backend | optional | `false` | `false` | Allows `x-request-network-test` webhook bypass only in explicit test mode. Keep false in dev/prod unless running a controlled smoke test. |
| `TRANSACTION_SAFETY_ENABLED` | backend | optional | `true` | `true` | Enables the Transaction Safety Provider gate before Request Network pay-ins are marked completed. |
| `TRANSACTION_SAFETY_REQUIRE_TX_HASH` | backend | optional | `true` | `true` | Blocks completion when provider evidence does not include a transaction hash. |
| `TRANSACTION_SAFETY_REQUIRE_TRANSFER_MATCH` | backend | optional | `true` | `true` | Requires on-chain token/recipient/amount evidence to match the expected payment. |
| `TRANSACTION_SAFETY_MIN_CONFIRMATIONS` | backend | optional | `12` | `12` | Minimum chain confirmations required by the Transaction Safety Provider. |
| `TRANSACTION_SAFETY_AML_PROVIDER` | backend | optional | `none` | `none` | AML/sanctions provider adapter name. Non-`none` values should block until implemented/configured. |
| `PAYMENT_LEDGER_ENFORCEMENT` | backend | optional | `false` | `true` | Enforce ledger gates for release/refund | | `PAYMENT_LEDGER_ENFORCEMENT` | backend | optional | `false` | `true` | Enforce ledger gates for release/refund |
| `PAYMENT_RECONCILIATION_ENABLED` | backend | optional | `false` | `true` | Enable scheduled provider reconciliation jobs | | `PAYMENT_RECONCILIATION_ENABLED` | backend | optional | `false` | `true` | Enable scheduled provider reconciliation jobs |
| `TREZOR_SAFEKEEPING_REQUIRED` | backend | optional | `false` | `true` | Optional hardware-signature gate for release/refund confirmation. Only the literal value `true` enforces Trezor proof. | | `TREZOR_SAFEKEEPING_REQUIRED` | backend | optional | `false` | `true` | Optional hardware-signature gate for release/refund confirmation. Only the literal value `true` enforces Trezor proof. |

View File

@@ -0,0 +1,212 @@
---
title: Handoff - Request Network Confirmation Repair - 2026-05-28
tags: [handoff, operations, payments, request-network, webhook]
created: 2026-05-28
---
# Handoff - Request Network Confirmation Repair - 2026-05-28
## Scope
This handoff covers the Request Network dev payment probe where the buyer callback stayed stuck on "processing payment", plus the local confirmation repair work and the documentation/roadmap updates that followed.
Primary user-reported issue:
- A real BSC Request Network test payment completed on-chain, but Amanat never showed confirmation on `https://dev.amn.gg/payment/callback/?paymentId=6a17e08f1485c1de0ff3cd15`.
## Current Answer
Do **not** run another paid payment test against dev until the local `2.6.26` changes are deployed and the webhook smoke test passes against the deployed stack.
After deploy:
- The original webhook `404` correlation bug should be fixed.
- If Request Network includes a transaction hash and the safety checks pass, the payment should complete.
- If Request Network omits the transaction hash, the webhook should be captured but the payment will remain `transactionSafety.pending` instead of being falsely credited.
## Repositories Touched
Backend:
- `backend/src/services/payment/requestNetwork/requestNetworkRoutes.ts`
- `backend/src/services/payment/requestNetwork/signature.ts`
- `backend/src/services/payment/adapters/requestNetworkAdapter.ts`
- `backend/src/services/payment/reconciliation/requestNetworkReconciliationService.ts`
- `backend/src/services/payment/decentralizedPaymentService.ts`
- `backend/src/services/payment/safety/transactionSafetyProvider.ts`
- `backend/src/models/Payment.ts`
- `backend/scripts/smoke/rn-webhook.sh`
- Request Network webhook/reconciliation tests
- `backend/.env.example`
- `backend/package.json`, `backend/package-lock.json`
Frontend:
- `frontend/src/app/payment/callback/page.tsx`
- Frontend version/env files and Dockerfile
Deployment:
- `deployment/docker-compose.yml`
Docs / Taskmaster:
- `nick-doc/PRD - Request Network In-House Checkout.md`
- `nick-doc/.taskmaster/docs/prd-request-network-in-house-checkout.md`
- `nick-doc/01 - Architecture/Request Network Integration Constraints.md`
- `nick-doc/PRD - Request Network Migration and Funds Management.md`
- `nick-doc/07 - Development/Environment Variables.md`
- `nick-doc/02 - Data Models/Payment.md`
- `nick-doc/08 - Operations/Incident Response.md`
- `nick-doc/08 - Operations/Monitoring.md`
- `nick-doc/README.md`
- Taskmaster subtask `3.13` for durable RN webhook ingress and transaction safety
- Taskmaster subtask `6.1` for deploying confirmation repair before the next paid probe
## Evidence From Dev
Test transaction:
```text
0x3a23febd9abd43d7e0851c1ea86c4ceaf08c11098852cb0425fa074e9c88350b
```
Payment document:
```text
paymentId: 6a17e08f1485c1de0ff3cd15
providerPaymentId: rq-af2d092e18cb41bb39ce4b0c
metadata.requestNetworkRequestId: 011ae38f7b99ef135514b987c9629b520b08e7a740f60d92d682f2f06466993a3f
metadata.requestNetworkPaymentReference: rq-af2d092e18cb41bb39ce4b0c
status before repair: pending
```
Nginx/backend evidence:
```text
POST /api/payment/request-network/webhook -> 404
source IP: 34.34.233.192
observed deliveries: four retries on 2026-05-28
```
Conclusion:
- Request Network did call Amanat.
- The payment succeeded on-chain.
- Amanat failed local confirmation because the webhook handler looked up the wrong reference shape and returned `404`.
- The frontend then kept polling too aggressively and eventually hit `429`.
## Implemented Locally
### Backend confirmation repair
- Webhook lookup now searches all known Request Network correlation keys:
- `providerPaymentId`
- `metadata.requestNetworkRequestId`
- `metadata.requestNetworkPaymentReference`
- nested `metadata.requestNetworkData.requestId`
- nested `metadata.requestNetworkData.paymentReference`
- Test webhook bypass is no longer enabled by default.
- New `REQUEST_NETWORK_ALLOW_TEST_WEBHOOKS` env flag controls explicit test-mode acceptance.
- Request Network adapter uses the same test-mode rule.
### Transaction Safety Provider
Added `TransactionSafetyProvider` as the gate between provider event and escrow credit.
Initial checks:
- transaction hash required by default,
- minimum confirmations required by default,
- transfer recipient/token/amount match required by default,
- AML provider placeholder defaults to `none`; non-`none` values block until implemented.
Webhook and reconciliation completion paths both run through the same safety gate.
### Frontend callback repair
- Callback page now unwraps the backend `{ data: { payment } }` shape.
- Socket events handle both `requestId` and `purchaseRequestId`.
- Polling backs off from 3 seconds to 10 seconds.
- Polling stops after terminal states.
- `429`, `401`, and `403` no longer trap the page in misleading behavior.
- Dashboard redirect paths were corrected.
### Deployment/env
New env vars added to backend/deployment docs:
```text
REQUEST_NETWORK_ALLOW_TEST_WEBHOOKS=false
TRANSACTION_SAFETY_ENABLED=true
TRANSACTION_SAFETY_REQUIRE_TX_HASH=true
TRANSACTION_SAFETY_REQUIRE_TRANSFER_MATCH=true
TRANSACTION_SAFETY_MIN_CONFIRMATIONS=12
TRANSACTION_SAFETY_AML_PROVIDER=none
```
Versions were bumped together:
```text
frontend: 2.6.26
backend: 2.6.26
```
## Verification Already Run
Backend:
```bash
npm test -- __tests__/request-network-webhook.test.ts __tests__/request-network-adapter.test.ts __tests__/payment-reconciliation.service.test.ts --runInBand
npm run typecheck
REQUEST_NETWORK_ALLOW_TEST_WEBHOOKS=true BASE_URL=https://dev.amn.gg ./scripts/smoke/rn-webhook.sh
git diff --check
```
Frontend:
```bash
npx eslint src/app/payment/callback/page.tsx
npx tsc --noEmit -p tsconfig.json
git diff --check
```
Deployment/docs:
```bash
git diff --check
```
Important note: the smoke test against `dev.amn.gg` used `REQUEST_NETWORK_ALLOW_TEST_WEBHOOKS=true` because the currently deployed dev stack is still old and unsafe. After deploy, rerun without that override and expect unsigned/test callbacks to be rejected.
## Deploy Gate
Before another paid payment:
1. Commit/push/deploy backend, frontend, and deployment changes.
2. Set the new env vars in Arcane/dev deployment.
3. Confirm backend and frontend report `2.6.26`.
4. Run the RN webhook smoke test against dev without test bypass.
5. Tail nginx and backend logs during the next probe.
6. Inspect `Payment.metadata.transactionSafety` if the callback still waits.
## Recommended Next Work
1. Deploy and verify the confirmation repair.
2. Repeat one small dev BSC payment.
3. If it lands in `transactionSafety.pending` due missing transaction hash, add Request Network status/search enrichment so safety can resolve the tx hash.
4. Build the Cloudflare Worker durable webhook ingress:
- receive raw RN payload and headers,
- durably store delivery evidence,
- forward to backend,
- replay by delivery id/time window/payment reference.
5. Pick the first AML/sanctions provider and wire it behind `TRANSACTION_SAFETY_AML_PROVIDER`.
## Operational Rule
For Request Network incidents:
- Real provider webhook returning `404`: stop paid testing; fix correlation/config.
- Webhook returning `202` with `transactionSafety.pending`: evidence was captured, but payment is not safe to credit yet.
- Webhook returning `200`/completed with safety approved: proceed to normal marketplace state checks.

View File

@@ -0,0 +1,70 @@
# Handoff: Request Network In-House Checkout — 2026-05-28
Status: **fully end-to-end working on dev.amn.gg as of 2.6.38 backend / 2.6.41 frontend**. A 0.01 USDC payment (tx `0x494c77a2…`) flowed: page render → wallet connect (Rabby/injected) → approve → `transferFromWithReferenceAndFee` → RN webhook → backend marks completed → page flips to "پرداخت تأیید شد ✓" → continue → `/dashboard/payment/<id>`.
## What's live
- **Backend 2.6.38** — `/api/payment/request-network/intents` returns an `inHouseCheckout` block (destination, tokenAddress, decimals, chainId, proxyAddress, paymentReference 8-byte hex, feeAmount, feeAddress, amountWei). `GET /api/payment/request-network/:paymentId/checkout` rehydrates the block for an existing Payment record (lazy-enriches legacy records that pre-date 2.6.34 by calling RN's `GET /v2/request/:id`). Public `GET /api/version` for the version badge. `PaymentCoordinator.updatePurchaseRequestStatus` guards both `template-checkout-` and `template-tc-` prefixes (plus regex fallback for any non-ObjectId) — earlier the `template-tc-` blindspot crashed webhook processing on template-checkout payments and stranded escrow.
- **Frontend 2.6.41** — `/checkout/request-network/[paymentId]` page with wagmi state machine: connect → switch-chain → check-allowance → approve → pay → wait-for-webhook. Destination + payment-reference + approve-tx + pay-tx hashes are copyable and click through to BscScan. Once a pay tx is in flight the page no longer reverts to "approve" even though the proxy call consumed the allowance. A 10-second `GET /api/payment/:id` poll runs as a fallback when the socket misses `payment-update`. Success-state continue button handles synthetic purchaseRequestId prefixes (`template-checkout-`, `template-tc-`) by routing to `/dashboard/payment/<id>` instead of the 404-prone `/dashboard/request/<syntheticId>`. WagmiProvider is now rendered unconditionally + the checkout page also self-wraps in its own WagmiProvider for defensive isolation.
Verify which versions are running by hovering the version chip at bottom-left of any page on dev.amn.gg, or `curl https://dev.amn.gg/api/version`.
## Where things stand
A real 0.01 USDC payment ran clean through the in-house path on 2026-05-28. Webhook delivery is durable enough for dev usage; durability for prod is Phase 5 (Cloudflare Worker ingress, not started). Five follow-up tasks were scoped immediately after — see `PRD - Wallet, Multichain, Confirmations, AML, Trezor.md` and Taskmaster `#7..#11`.
## Known issues / open work
- **TypeScript-error CI false-success**: pipelines #40 and #41 reported ✅ green in Woodpecker while `yarn build` was actually failing at the TS step and no image was pushed. Memory entry: `woodpecker_silent_build_fail.md`. **Always verify** `dev-<version>` exists in `git.manko.yoga` before trusting CI green. The wagmi `chainId` field requires `as any` because of its literal-union type — keep that pattern when adding new wagmi calls.
- **Existing/legacy Payment records** (created before backend 2.6.34) don't have RN's request details cached. The GET endpoint lazy-enriches them via `GET /v2/request/:requestId` on first visit, then persists. If RN's API is down at that moment, falls back to the hosted-page link.
- **Mongo access is denied** to the auto-mode classifier on dev — debugging payment records currently requires either the user's mongo creds or relying on the 409 `debug` block surfaced through the frontend.
- **Wagmi provider isolation (2.6.39)**: The checkout page wraps itself in its own `WagmiProvider`. The root `Web3Provider` also renders `WagmiProvider` unconditionally as of 2.6.38. The doubling is intentional defensiveness — if one provider has an issue, the other still serves the checkout flow. Can be simplified later if both prove stable.
- **PRD Phase 5 — Cloudflare Worker durable webhook ingress** — not started. Taskmaster `3.13`. Current dev relies on `dev.amn.gg` being up at the moment RN's webhook fires. For prod, RN webhooks need to land in a durable Cloudflare Worker that buffers + replays into the backend.
## Files changed (recent)
Backend (`/Users/manwe/CascadeProjects/escrow/backend`):
- `src/services/payment/requestNetwork/contract.ts` — spreads full RN response into `raw`
- `src/services/payment/requestNetwork/inHouseCheckout.ts` — block builder, reads `paymentReference` from `rnRaw.requestDetails.paymentReference`
- `src/services/payment/requestNetwork/merchantReference.ts`, `tokens.ts`, `proxyAddresses.ts`, `paymentReference.ts` — helpers
- `src/services/payment/requestNetwork/requestNetworkPayInService.ts` — calls `GET /v2/request` after intent creation
- `src/services/payment/requestNetwork/requestNetworkRoutes.ts``GET /:paymentId/checkout` + lazy enrichment + debug response
- `src/services/payment/requestNetwork/networkClient.ts` — already had `getRequestStatus`
- `src/app.ts``GET /api/version`, exempt from rate limit
- `__tests__/rn-in-house-checkout.test.ts` — 12 unit tests, all green
Frontend (`/Users/manwe/CascadeProjects/escrow/frontend`):
- `src/web3/contracts/rn-fee-proxy.ts` — RN proxy + ERC20 ABIs
- `src/web3/context/wagmi-provider.tsx` — removed the mount-gate that caused `WagmiProviderNotFoundError`
- `src/web3/components/provider-payment.tsx``router.push` to in-house page + sessionStorage stash
- `src/sections/payment/checkout/types.ts` + `rn-in-house-checkout-view.tsx` — state machine, local WagmiProvider wrap
- `src/app/checkout/request-network/[paymentId]/page.tsx` — app router entry
- `src/components/version-logger.tsx` — version chip + tooltip showing backend version
## Memory entries added
- `MEMORY.md` index updated with:
- `arcane_dev_stack.md` (env/project IDs, two-step deploy note)
- `woodpecker_silent_build_fail.md` (CI green ≠ image pushed)
- and existing `rn_webhook_event_field.md`, `backend_rate_limits.md`, `telegram_notify_no_parse_mode.md`, `devEscrow_nginx_after_redeploy.md`, `parallel_agents_on_escrow.md`
## Open PRD questions still to decide
From `PRD - Request Network In-House Checkout.md` §10:
- Proxy address universality across chains (currently BSC + Arb confirmed; Task #8 will probe Polygon/ETH/Base)
- API pricing for hosted-UI-less usage (need RN account-mgmt question)
- Approval UX — exact-amount vs MAX_UINT256 (current: exact-amount)
- Cancel / timeout semantics for abandoned intents
- Telemetry events for in-house vs hosted A/B
## Follow-up tasks (Taskmaster + PRD)
Five follow-ups scoped for kimi to pick up independently. Full spec in `PRD - Wallet, Multichain, Confirmations, AML, Trezor.md`. Quick index:
| # | Task | Priority | Depends on |
|---|---------------------------------------------------------------|----------|------------|
| 7 | Per-(buyer, sellerOffer) ephemeral RN destination wallets | high | (sweep step soft-depends on #11) |
| 8 | Multichain RN proxy registry + USDC/USDT support | high | — |
| 9 | Per-chain confirmation thresholds + admin UI | medium | — |
| 10 | Optional AML screening on incoming payments (seller-paid) | medium | — |
| 11 | Trezor signing for admin actions (release/refund/sweep) | high | — |

View File

@@ -260,6 +260,20 @@ If user data may have leaked, treat as sev 1 and follow your data-breach disclos
Use when Request Network payments are failing, stalled, or out of sync with local payment state. Use when Request Network payments are failing, stalled, or out of sync with local payment state.
**First triage:**
1. Check whether RN reached nginx:
```bash
grep '/api/payment/request-network/webhook' /opt/backend/nginx/logs/access.log | tail -50
```
2. If RN deliveries returned `404`, treat it as a backend correlation/config bug. Do not run another paid probe until the correlation fix is deployed and smoke-tested.
3. If deliveries returned `202` or `200` but the payment is still pending, inspect `metadata.transactionSafety` on the `Payment` document. A safety-pending payment is captured but not credited; look for missing tx hash, insufficient confirmations, transfer mismatch, or AML provider blockers.
4. If Cloudflare Worker durable ingress is enabled, replay from the Worker delivery id/time window after backend repair instead of asking the buyer to pay again.
**Immediate rollback (minutes):** **Immediate rollback (minutes):**
1. Stop routing new intents to Request Network by setting: 1. Stop routing new intents to Request Network by setting:

View File

@@ -181,6 +181,8 @@ Today these are read manually from logs / Sentry. As Prometheus is added, encode
|--------|-------|---------|-------| |--------|-------|---------|-------|
| Payment success rate | `db.payments.aggregate([{$group:{_id:"$status",n:{$sum:1}}}])` | > 95 % completed of 24h-old payments | < 90 % | | Payment success rate | `db.payments.aggregate([{$group:{_id:"$status",n:{$sum:1}}}])` | > 95 % completed of 24h-old payments | < 90 % |
| Webhook signature failures | log `Webhook verification failed` | 0 | > 0 | | Webhook signature failures | log `Webhook verification failed` | 0 | > 0 |
| Request Network webhook 4xx | nginx access log `/api/payment/request-network/webhook` | 0 | any real provider delivery returning 4xx |
| Request Network safety-pending payments | `db.payments.find({"metadata.transactionSafety.status":"pending"})` | explained/short-lived | pending > 10 min without operator note |
| SHKeeper API errors (5xx) | log + Sentry | 0 | > 5/min sustained | | SHKeeper API errors (5xx) | log + Sentry | 0 | > 5/min sustained |
| Payouts stuck in `pending` > 30 min | `db.payments.find({type:'payout',status:'pending',createdAt:{$lt:ISODate(30 min ago)}})` | empty | non-empty | | Payouts stuck in `pending` > 30 min | `db.payments.find({type:'payout',status:'pending',createdAt:{$lt:ISODate(30 min ago)}})` | empty | non-empty |
| Missing `transactionHash` after `completed` | the same query that drives `fix-transaction-hashes.js` | empty | non-empty | | Missing `transactionHash` after `completed` | the same query that drives `fix-transaction-hashes.js` | empty | non-empty |

View File

@@ -0,0 +1,127 @@
# PRD: Request Network In-House Checkout
> Source spec: `.taskmaster/docs/prd-request-network-in-house-checkout.md`
> Status: **Draft — updated after 2026-05-28 dev webhook probe**
> Related: `01 - Architecture/Request Network Integration Constraints.md` §1
---
## Problem
Buyers paying through Request Network are redirected to `pay.request.network/?token=…`. That page doesn't support **Rabby** (a meaningful slice of our user base), takes the buyer off `amn.gg` mid-flow, and wraps the payment in Safe + ERC-4337 + Pimlico paymaster + public BSC RPC — a stack we already saw rate-limit in real use.
The RN *protocol* is fine. Their *UI* is the problem.
## 2026-05-28 reality update
The dev BSC probe changed the risk model:
- Test transaction: `0x3a23febd9abd43d7e0851c1ea86c4ceaf08c11098852cb0425fa074e9c88350b`.
- On-chain result: successful BSC USDC transfer to Amanat's configured destination wallet.
- RN webhook result: RN did call `POST /api/payment/request-network/webhook` on `dev.amn.gg` four times from `34.34.233.192`.
- Application result: backend returned `404` because the handler only correlated one local provider id shape and missed the RN request/payment-reference fields stored on the `Payment` record.
- Frontend result: callback stayed on "processing payment" and the 3-second polling loop later hit `429`.
So the original "webhook silence" risk is no longer the observed failure. RN delivered the webhook; Amanat dropped it. Before another paid probe, dev must run the correlation fix and the callback polling fix, then pass the Request Network webhook smoke test.
## Core idea
RN's webhook detects payments by listening for a single on-chain event — `TransferWithReferenceAndFee` — emitted by their `ERC20FeeProxy` contract. We confirmed this by cold-inspecting an actual `$12` payment on their hosted page: under the Safe/4337 wrapper, the real work is two calls — `approve(proxy, amount)` and `transferFromWithReferenceAndFee(...)`.
If we make those same two calls from our own UI, RN's webhook fires. The hosted page is decorative.
However, webhook delivery alone is not enough to credit escrow. The backend now needs a **Transaction Safety Provider** gate between "provider says paid" and "Amanat marks funded". That provider approves only after configured checks pass: transaction hash present, chain confirmations deep enough, transfer recipient/token/amount matched on-chain, and any external AML/sanctions provider response is acceptable.
## What we replace
| Today | Proposed |
|---|---|
| Click "Pay with RN" → `window.location = securePaymentUrl` | Click "Pay with RN" → `/checkout/request-network/:paymentId` (Amanat-rendered) |
| RN's wallet picker (no Rabby) | wagmi `injected()` + `metaMask()` — Rabby works via EIP-6963 |
| Safe + 4337 + paymaster | Buyer's EOA, two direct txs, buyer pays own gas |
| Public BSC RPC | Whatever the buyer's wallet uses (under their control) |
## What does NOT change
- Backend webhook route stays the same, but the handler must correlate every RN reference shape (`providerPaymentId`, request id, payment reference, nested raw data) and pass the Transaction Safety Provider before marking a payment funded.
- `Payment` lifecycle is unchanged.
- Settlement, refunds, dispute paths are unchanged.
- Non-RN payment providers (SHKeeper, etc.) are unaffected.
- Buyer can still opt out: hosted-page link stays available as an escape hatch.
## Hard-known protocol facts (from inspection)
| Item | Value |
|---|---|
| RN ERC20FeeProxy (BSC + Arb, likely all EVMs) | `0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9` |
| Function | `transferFromWithReferenceAndFee(token, to, amount, ref, feeAmount, feeAddress)` |
| Selector | `0xc219a14d` |
| `paymentReference` derivation | `last8Bytes(keccak256(requestId + salt + destination))` |
| Fee config currently used | `feeAmount = 0`, `feeAddress = 0x…dEaD` |
## Backend deliverables (sketch)
Extend `POST /payment/request-network/intents` response with an `inHouseCheckout` object containing: `destination`, `tokenAddress`, `decimals`, `chainId`, `proxyAddress`, `paymentReference`, `feeAmount`, `feeAddress`, `amountWei`. Full field sourcing in the spec.
## Frontend deliverables (sketch)
New page `/checkout/request-network/:paymentId` with a wagmi-driven state machine: connect → switch-chain → check-allowance → approve → pay → wait-for-webhook → done. Reuses layout chrome from `web3/components/manual-payment.tsx` (SHKeeper). Escape-hatch link to the hosted page stays visible.
## Acceptance criteria (short list)
1. A Rabby user completes an RN payment without leaving `amn.gg`.
2. RN's webhook fires from a transaction built and submitted by our UI.
3. The `Payment` doc transitions to `completed` / `escrowState='funded'` exactly as it does today, but only after safety checks pass.
4. Wrong-chain → one-click switch. Sufficient allowance → approve step skipped. Abandoned page → resumable.
5. Hosted-page link still works and is documented as the fallback.
Full list in the spec.
## Open questions for the review
1. Is the proxy address identical on every chain we plan to support, or only some?
2. RN's pricing — are we still in their terms if we never use their hosted UI?
3. `approve(MAX_UINT256)` (RN's pattern, best UX) vs exact-amount approve (better security)?
4. Cancel / timeout semantics for abandoned intents — TTL, explicit cancel endpoint, or both?
5. Feature flag + A/B in dev for one cycle before prod, or hard-cut once acceptance passes?
## Risks
- **Webhook handling failure.** RN did deliver the 2026-05-28 dev webhook, but Amanat returned `404`. A deployed correlation fix and smoke test are now the gate before any more paid probes.
- **Webhook durability.** The main app is too unstable to be the only webhook landing zone. Roadmap item: put a Cloudflare Worker in front of RN webhooks, store raw delivery metadata durably, then forward/replay into the backend.
- **False-positive payment credit.** A signed webhook must not be enough to credit escrow. Transaction Safety Provider gates payment completion on on-chain transfer verification, confirmation depth, and future AML/sanctions checks.
- Chain-specific proxy address divergence (mitigation: per-chain constants, fall back to hosted page for unknown chains).
## Implementation phases
| # | Phase | Gate |
|---|---|---|
| 0 | Probe — real dev BSC payment | ✅ Completed: RN webhook reached nginx/backend, but app returned `404` |
| 0A | Confirmation repair — deploy correlation fix, callback polling fix, and Transaction Safety Provider | ✅ Completed: smoke test passes; unsigned/test webhooks rejected |
| 1 | Backend: expand intent payload + helpers | ✅ Completed (2.6.32 → 2.6.38) |
| 2 | Frontend: page skeleton + wallet connect | ✅ Completed (2.6.30 → 2.6.41) |
| 3 | On-chain wiring (approve + proxy call) | ✅ Completed: real 0.01 USDC payment on dev BSC 2026-05-28 (tx `0x494c77a2…`), Payment.status=completed, safety approved |
| 4 | Hardening: errors, timer, persistence, telemetry, escape hatch | 🟡 Partial — copy/BscScan links, pay-button trap, 10s status poll, template-tc routing fix shipped 2.6.41. Timer + persistence + telemetry left. |
| 5 | Durable ingress — Cloudflare Worker receives RN webhooks, stores delivery record, forwards to backend, exposes replay | ⏳ Not started (Taskmaster `3.13`) |
| 6 | Rollout: flag + A/B | ⏳ Not started |
Five follow-up workstreams scoped 2026-05-28 in `PRD - Wallet, Multichain, Confirmations, AML, Trezor.md` (Taskmaster `#7…#11`) cover ephemeral destination wallets, multichain proxy registry, runtime confirmation thresholds, optional AML screening, and Trezor signing for admin actions.
## Durable webhook ingress roadmap
Add a small Cloudflare Worker as the public Request Network webhook target:
1. Receive RN webhook with raw body, headers, request id, delivery id, source IP, timestamp.
2. Verify RN signature at the edge if secret handling/raw-body verification is compatible; otherwise store first and let backend perform canonical verification.
3. Write an immutable delivery record to durable storage (Cloudflare Queues + D1/R2/KV, final choice TBD).
4. Forward to the primary backend and optionally a secondary backend endpoint.
5. Return `2xx` only after durable enqueue/store succeeds.
6. Provide operator replay by delivery id or time window.
The Worker is an ingress and evidence buffer, not the trust oracle. The backend still owns signature verification, idempotency, Transaction Safety Provider checks, ledger updates, and marketplace state transitions.
## See also
- `.taskmaster/docs/prd-request-network-in-house-checkout.md` — full spec with field sources, file lists, state-machine details, telemetry events.
- `01 - Architecture/Request Network Integration Constraints.md` — §1 (this PRD addresses), §2/§3/§4 are explicitly out of scope here.
- `PRD - Request Network Migration and Funds Management.md` — the broader RN context.

View File

@@ -13,6 +13,8 @@ Request Network is request/payment-reference based. The platform creates a Reque
Primary recommendation: run a phased migration behind a provider adapter. Introduce Request Network for new pay-ins first using Secure Payment Pages, keep SHKeeper read-only for existing payments, then add funds ledger, release/refund gates, and Request Network payout flows. Primary recommendation: run a phased migration behind a provider adapter. Introduce Request Network for new pay-ins first using Secure Payment Pages, keep SHKeeper read-only for existing payments, then add funds ledger, release/refund gates, and Request Network payout flows.
2026-05-28 update: the first dev BSC payment probe confirmed Request Network did deliver webhooks to `dev.amn.gg`, but Amanat returned `404` because local correlation did not search all RN reference fields. The migration roadmap now needs two P0 additions before wider RN testing: a Transaction Safety Provider gate before escrow funding, and durable webhook ingress (Cloudflare Worker) so backend instability does not lose callback evidence.
## Source Findings ## Source Findings
Current code: Current code:
@@ -219,6 +221,36 @@ Risk Assessment:
- Mitigation: raw-body middleware scoped to webhook route, event fixture tests, dead-letter queue/table, operator replay endpoint. - Mitigation: raw-body middleware scoped to webhook route, event fixture tests, dead-letter queue/table, operator replay endpoint.
- Rollback: pause webhook processor and rely on manual/admin reconciliation for Request Network records. - Rollback: pause webhook processor and rely on manual/admin reconciliation for Request Network records.
## PRD 4A - Transaction Safety Provider and Durable Webhook Ingress
Priority: P0
Goal: prevent false-positive payment credit and prevent webhook loss when the main app is unstable.
Scope:
- Add a Transaction Safety Provider invoked by Request Network webhook and reconciliation paths before marking pay-ins completed.
- Require configurable checks: transaction hash present, minimum confirmations, on-chain transfer recipient/token/amount match, and AML/sanctions provider approval when configured.
- Store `metadata.transactionSafety`, last webhook payload, and safety-blocker reason for support/replay.
- Add a Cloudflare Worker as the public Request Network webhook target.
- Worker stores raw body, headers, delivery id, request id/payment reference, source IP, and timestamp in durable storage before forwarding to the backend.
- Provide replay by delivery id/time window/payment reference.
Acceptance Criteria:
- A signed RN webhook cannot set `Payment.status='completed'` unless safety checks approve.
- If tx hash is missing, webhook evidence is retained and the payment remains pending/safety-blocked rather than lost.
- Reconciliation uses the same safety gate as webhook processing.
- Unsigned/test callbacks are rejected unless explicit test mode is enabled.
- Backend outage still leaves a durable webhook record that an operator can replay.
Risk Assessment:
- Impact: Very High. This controls when escrow is credited.
- Likelihood: High. The 2026-05-28 probe already produced a dropped webhook.
- Main risks: accidentally blocking legitimate payments while tx hash/source evidence is missing, or accidentally trusting the Worker as the payment authority.
- Mitigation: safety decisions are explicit (`approved`, `pending`, `rejected`, `skipped`), backend remains the trust boundary, and operators can replay stored deliveries after fixes deploy.
## PRD 5 - Release, Refund, and Payout Orchestration ## PRD 5 - Release, Refund, and Payout Orchestration
Priority: P1 Priority: P1
@@ -313,11 +345,13 @@ Risk Assessment:
2. Add funds ledger models/services and dry-run backfill report. 2. Add funds ledger models/services and dry-run backfill report.
3. Implement Request Network secure pay-in flow behind feature flag. 3. Implement Request Network secure pay-in flow behind feature flag.
4. Implement signed webhook receiver and reconciliation job. 4. Implement signed webhook receiver and reconciliation job.
5. Enable Request Network for limited new checkout cohort. 5. Add Transaction Safety Provider to webhook and reconciliation completion paths.
6. Add release/refund orchestration using ledger gates. 6. Add durable Request Network webhook ingress, preferably Cloudflare Worker + queue/storage + replay.
7. Migrate admin/frontend views. 7. Enable Request Network for limited new checkout cohort.
8. Backfill legacy records. 8. Add release/refund orchestration using ledger gates.
9. Decommission SHKeeper once no active records depend on it. 9. Migrate admin/frontend views.
10. Backfill legacy records.
11. Decommission SHKeeper once no active records depend on it.
## Open Decisions ## Open Decisions
@@ -326,8 +360,9 @@ Risk Assessment:
- Which chains/currencies are required for launch: BSC USDT parity with today, or Request Network supported stablecoin routes first? - Which chains/currencies are required for launch: BSC USDT parity with today, or Request Network supported stablecoin routes first?
- Should platform fee be paid by buyer, seller, or absorbed by Amanat? - Should platform fee be paid by buyer, seller, or absorbed by Amanat?
- Does Amanat need crypto-to-fiat/offramp later, which adds KYC/payment detail requirements? - Does Amanat need crypto-to-fiat/offramp later, which adds KYC/payment detail requirements?
- Which AML/sanctions provider should back the first Transaction Safety Provider implementation?
- Which Cloudflare durable primitive should store webhook evidence: Queues plus D1, R2 raw payloads, or another append-only store?
## Recommendation ## Recommendation
Start with Secure Payment Pages and a platform escrow/payee destination controlled by Amanat. This best matches the current escrow mental model while reducing frontend transaction-building risk. Do not route pay-ins directly to sellers until dispute handling, refund logic, and service fee economics are fully redesigned. Start with Secure Payment Pages and a platform escrow/payee destination controlled by Amanat. This best matches the current escrow mental model while reducing frontend transaction-building risk. Do not route pay-ins directly to sellers until dispute handling, refund logic, and service fee economics are fully redesigned.

View File

@@ -0,0 +1,225 @@
# PRD: Wallet, Multichain, Confirmations, AML, Trezor
> Status: **Draft — 2026-05-28**
> Author: nick + claude (after in-house RN checkout shipped on dev 2.6.38/2.6.41)
> Owner: backend (payments) + frontend (admin UI + checkout)
> Related: `PRD - Request Network In-House Checkout.md`, `01 - Architecture/Request Network Integration Constraints.md`
Five follow-ups to the in-house Request Network checkout. They are sized so a single contributor can pick up any one of them in isolation. Each is its own Taskmaster top-level task — see `#7…#11`.
---
## 1. Per-(buyer, seller) ephemeral destination wallets — Task #7
### Problem
Today the in-house checkout sends *all* RN-routed payments to one Amanat-controlled wallet (env: `REQUEST_NETWORK_MERCHANT_REFERENCE`). That wallet is shared across every buyer, every seller, every offer. It's both an audit nightmare (no buyer↔settlement linkage at the wallet level) and a single point of compromise.
### Goal
For each `(buyerId, sellerOfferId)` (or `(buyerId, sellerId)` — see open questions), generate a fresh on-chain destination address, persist it on the `Payment` record, and tell Request Network to expect funds on that address. RN's webhook flows unchanged.
### Hard-known facts (from RN docs we've cold-inspected so far)
- The "destination" in RN is the `destinationId` inside the merchant reference: `<address>@eip155:<chainId>#<contractId>:<tokenAddress>`. RN doesn't bind this to an Amanat-level identity; it's just where the funds end up.
- Each `POST /v2/secure-payments` request *can* pass a different `destinationId`. RN doesn't reject divergent destinations across requests from the same client.
- `paymentReference` is derived per request (`last8Bytes(keccak256(requestId+salt+destination))`), so different destinations naturally produce different on-chain refs. The webhook listener keys on the ref + tx hash.
### Open questions to settle before code
1. **Key custody model.** Options:
- **Deterministic HD wallet** rooted at one Amanat master seed; derive per-`(buyer, seller)` path (e.g. `m/44'/60'/0'/<buyerIdx>/<sellerIdx>`). Keys live in the backend, single seed in KMS/HSM. Sweep is one tx per derived addr.
- **One-shot disposable EOAs**, encrypted and stored in Mongo (or KMS), keyed by `(buyer, seller)`. Sweep then forget.
- **Smart contract per offer** that auto-forwards to the master wallet on receive. Avoids holding keys at all, but costs gas + an extra hop.
- Recommended starting point: HD wallet, with sweep-on-confirmation. Cheapest, most auditable.
2. **Sweep strategy.** Sweep immediately on webhook confirmation, or batch sweep cron'd nightly? Trade gas vs. exposure window. Default: sweep immediately under Transaction Safety Provider approval.
3. **Granularity.** Per `(buyer, seller)`, per `(buyer, seller, offer)`, or per single payment? Per-offer gives clean audit lineage; per-payment is overkill (extra derivations); per-`(buyer, seller)` is reusable across multi-step deals.
4. **Re-use vs. expire.** If a derived address has funds in it after sweep, do we still re-use for the same pair's next payment, or rotate? Re-use = simpler, slight privacy hit.
### Scope
1. New module `backend/src/services/payment/wallets/derivedDestinations.ts` with `getDestinationFor(buyerId, sellerOfferId)` returning `{ address, derivationPath, chainId }`.
2. Migration on `Payment` schema to add `metadata.derivedDestination` (address + derivation path snapshot).
3. RN intent creation calls `getDestinationFor(...)` and overrides the destination half of `REQUEST_NETWORK_MERCHANT_REFERENCE`.
4. Sweep job (cron + manual-trigger admin endpoint) under Transaction Safety Provider gate.
5. Admin UI (table) to view derived destinations, their balances, sweep status, and last sweep tx.
### Non-goals
- Multi-chain destinations (covered in Task #8).
- Buyer-side ephemeral keys (covered in `Request Network Integration Constraints.md` §3, separate PRD).
- Hardware-wallet-signed sweeps (covered in Task #11).
### Acceptance criteria
1. Two payments from the same buyer to two different sellers land on two different addresses on-chain.
2. RN's webhook fires correctly for both, regardless of the destination divergence.
3. Sweep runs idempotently — re-running it on an already-swept address is a no-op.
4. Admin UI shows the address, its balance, last sweep tx (link to BscScan), and current ownership status.
5. Master seed never leaves the KMS/secret store. Backend reads derivation paths only; signs sweep txes via KMS API.
---
## 2. Multi-chain RN proxy registry + USDC/USDT support — Task #8
### Problem
`backend/src/services/payment/requestNetwork/proxyAddresses.ts` and `tokens.ts` currently hardcode BSC USDC plus a handful of token entries. The in-house checkout will fall through to "in-house checkout not available" the moment a buyer wants to pay on Arbitrum/Polygon/Ethereum, or wants USDT instead of USDC on the same chain.
### Goal
Verified-from-chain registry of:
- RN's `ERC20FeeProxy` address per supported chain.
- USDC + USDT contract address + decimals per chain.
Plus an admin "supported networks" UI that:
- Lists each chain + token combo with its current status (verified-on-chain / probe failed / disabled).
- Shows which chains a given seller has whitelisted (depends on per-seller `acceptedChains` config; out of scope here — see `Request Network Integration Constraints.md` §2).
### Hard-known facts
- RN published their canonical `ERC20FeeProxy` for BSC + Arbitrum as `0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9` (CREATE2 deterministic). Same address on Ethereum mainnet, Polygon, Base **per the deterministic deployment claim** — needs verifying.
- BSC USDC has 18 decimals (Binance-Peg). Mainnet/Arb/Polygon USDC have 6.
- USDT on Ethereum requires `approve(0)` before a non-zero re-approve. Other chains' USDT don't.
### Scope
1. Probe script `backend/scripts/probe-rn-chains.ts` that walks every chain in `supported-chains.json`, calls a known view fn on the candidate proxy address, and confirms it's a real RN proxy (not just bytes). Emits a report.
2. Promote `tokens.ts` to load from a JSON file + override layer for admin-managed entries. Keep the canonical defaults committed.
3. Backend route `GET /api/admin/rn/networks` returning the registry plus probe status.
4. Frontend admin page `/dashboard/admin/networks` rendering the table.
5. `buildInHouseCheckoutBlock` consults the chain registry; returns `reason='unsupported_chain:<chainId>'` cleanly.
6. Add the USDT-mainnet `approve(0)` quirk to the frontend approve step. When detected, the approve flow does `approve(spender, 0)``approve(spender, amount)`.
### Non-goals
- Letting a seller pick which chain a given buyer can use (separate PRD, §2 in constraints doc).
- Cross-chain bridging.
### Acceptance criteria
1. Probe script run on dev confirms RN proxy address on at least BSC, Arbitrum, Polygon, Ethereum, Base. Differences are documented.
2. Token registry has entries for USDC + USDT on those 5 chains, with correct decimals.
3. In-house checkout supports USDT on BSC end-to-end (a paid probe).
4. USDT-mainnet `approve(0)` reset is handled in the UI when needed.
5. Admin networks page renders the registry with a per-row "probe again" button.
---
## 3. Confirmation-counting + admin threshold UI — Task #9
### Problem
The Transaction Safety Provider already reads `TRANSACTION_SAFETY_MIN_CONFIRMATIONS` from env (default 12). That number is global, baked into env, only changeable by re-deploy. We want it tunable per-chain at runtime by an admin, with a clear UI showing each in-flight payment's current confirmation depth against the threshold.
### Goal
1. Persist per-chain confirmation thresholds in a `ConfigKV` collection (or extend an existing settings model) so admin can adjust without redeploy.
2. The `TransactionSafetyProvider`'s confirmation check reads the runtime threshold first, falls back to env.
3. Frontend admin UI to view + edit per-chain thresholds, and a "payments awaiting confirmation" table that shows `confirmations / threshold` updated live.
### Scope
1. New collection / extension to existing `Setting` model: `{ key: 'confirmation_threshold:<chainId>', value: <int>, updatedBy, updatedAt }`.
2. Public-to-admin endpoint `GET /api/admin/settings/confirmation-thresholds` and `PATCH /api/admin/settings/confirmation-thresholds/:chainId`.
3. Wire `transactionSafetyProvider` to read from this store; cache for 30s to avoid Mongo hammering.
4. Frontend admin page `/dashboard/admin/confirmation-thresholds`:
- Table of chains, current threshold, recommended default (e.g. 12 for BSC).
- Edit-in-place with a confirm dialog.
- Audit-log style "changed by X on Y at Z".
5. Frontend admin page `/dashboard/admin/payments/awaiting-confirmation`:
- Lists payments with `escrowState !== 'funded'` and `metadata.transactionSafety.lastCheck.status === 'pending'`.
- For each: tx hash (linked to explorer), current confirmations (poll-driven), threshold, ETA.
### Non-goals
- Per-asset thresholds (only per-chain).
- Per-seller overrides.
### Acceptance criteria
1. Admin can lower BSC's threshold from 12 to 3 on the live dev stack without a redeploy and a new webhook fires the safety gate with the new value within 30s.
2. Awaiting-confirmation table updates live as new blocks arrive (poll every 12s on BSC).
3. Audit log records every threshold change with admin user, before/after, timestamp.
---
## 4. Optional AML screening (seller-paid) — Task #10
### Problem
The Transaction Safety Provider has an `evaluateAmlPlaceholder()` stub that currently returns `status: skipped`. We want a real AML pass that the seller can *opt into* per-offer, with the seller covering the per-check API cost.
### Goal
1. Pick a provider (Chainalysis Address Screening, TRM Labs, Elliptic — open question). Default recommendation: Chainalysis Address Screening (cheapest, simplest API).
2. Per-offer setting: `requireAmlCheck: true|false` plus `amlCheckPricePaidBy: 'seller'`.
3. When AML required, the in-house checkout webhook hits the provider with the buyer's source address. Result feeds into Transaction Safety Provider as a real `aml_screening` check.
4. Seller's account is debited for the per-check cost from their Amanat balance (or the payment is partially withheld for the cost).
### Hard-known facts
- AML providers charge per-check (USD 0.100.50 typical). Some charge a flat monthly minimum.
- Chainalysis returns categories like `sanctions`, `darknet_marketplace`, `mixer`. Provider doesn't return PII.
- Most providers have rate limits (~50 rps).
### Open questions
1. **Provider choice.** Need a 1-page comparison: per-check cost, response latency, supported chains, sanctions-coverage scope.
2. **Failure mode.** If the AML API is down, do we pass-through (let the payment complete) or fail-closed (block)? Recommended: fail-closed only when seller explicitly opted in *and* enabled "block-on-provider-failure". Otherwise warn + log.
3. **Cost accounting.** Per-check cost is small; do we round up to nearest cent, batch by day, or pass-through exact?
### Scope
1. Add `requireAmlCheck` + `amlBlockOnFailure` fields to the `Offer` schema (or `SellerOffer`).
2. New `backend/src/services/payment/safety/amlProvider.ts` interface + `chainalysisProvider.ts` impl. Behind env flag `TRANSACTION_SAFETY_AML_PROVIDER=chainalysis`.
3. Transaction Safety Provider's `aml_screening` check now real, with `metadata.amlResult` persisted on the Payment record for audit.
4. Cost accounting: deduct per-check cost from seller's escrow on payment completion; surface this as a line item on the payment-details view.
5. Frontend offer-edit UI: a toggle "Require AML on incoming payments (cost: $X per payment, paid by you)".
6. Frontend admin UI for global AML provider configuration (provider, API key, per-chain enabled/disabled).
### Non-goals
- Buyer-side AML (we screen the buyer's *source* address, not the seller's identity).
- Custom AML rules / scoring beyond the provider's verdict.
### Acceptance criteria
1. A seller can opt into AML on a specific offer. Toggle persists.
2. An incoming payment to that offer triggers a real Chainalysis API call; the result is stored on the Payment record.
3. Verdict `sanctions` blocks the escrow gate; verdict `clean` lets it through.
4. The seller's settled amount is reduced by the AML check cost; a corresponding ledger entry is created.
5. Admin can rotate the Chainalysis API key without redeploy.
6. If the provider is down and `amlBlockOnFailure=true`, the payment stays in pending; a `provider_unavailable` reason surfaces in the admin dashboard.
---
## 5. Trezor support for admin signing — Task #11
### Problem
Today, admin actions that require signing (escrow release, refund, sweep of derived destinations once Task #7 ships) run from a hot-key in the backend env (`ADMIN_PRIVATE_KEY` or similar). That key is a single-point-of-compromise for all custodial funds.
### Goal
Replace the hot-key flow with a Trezor-mediated browser flow:
1. Admin connects a Trezor via WebUSB in the admin dashboard.
2. Admin approves an action in the UI; the unsigned transaction is built backend-side, sent to the browser, signed by the Trezor, broadcast from the browser.
3. The backend never has the private key. The Trezor seed never touches a network.
### Hard-known facts
- `@trezor/connect-web` is the maintained library for Trezor in browser. EIP-1193-compatible adapter exists.
- Trezor supports EVM signing for any chain; chain ID is part of the tx.
- WebUSB is Chromium-only. Firefox users need the Trezor Bridge native helper.
### Open questions
1. **Multi-admin.** If two admins both have a Trezor configured, do they both need to sign (m-of-n), or any one of them? Default: any one of them; m-of-n is out of scope here.
2. **Trezor model.** Trezor One vs Model T have different signing UX. We target both; the lib abstracts it.
3. **Fallback.** What if Trezor is unavailable when an urgent release is needed? Default: a "break-glass" hot-key path that admin can flip on for a 1-hour window, alarms blast Telegram.
### Scope
1. New module `frontend/src/web3/trezor/trezorConnector.ts` wrapping `@trezor/connect-web`.
2. Admin actions (release/refund/sweep) get a "Sign with Trezor" button that:
- Hits backend `POST /api/admin/actions/build-tx` returning unsigned tx bytes.
- Sends to Trezor for signing.
- Submits signed tx via wagmi `sendTransaction`.
- Calls `POST /api/admin/actions/confirm-tx` with the tx hash.
3. Backend supports both `confirmReleaseTx` flow (existing) and the new build-tx pattern.
4. Admin settings page to "register Trezor": stores the Trezor's address(es) so backend can reject signatures from unauthorized devices.
5. Audit log on every Trezor-signed action.
### Non-goals
- Multi-sig contracts (Safe etc.) — separate decision.
- Buyer-side Trezor (buyer already uses their own wallet via wagmi `injected()`).
- Mobile Trezor flow (desktop only for v1).
### Acceptance criteria
1. Admin can register a Trezor address; subsequent admin actions show "sign with Trezor" CTA.
2. End-to-end release of escrow: build → Trezor approves → tx broadcast → backend confirms.
3. If Trezor is unregistered or admin tries to sign with a different device, the backend rejects the confirm step.
4. Audit log entries include admin user, Trezor address, tx hash, action, before/after escrow state.
5. Break-glass hot-key path requires an explicit admin toggle, expires after 1h, fires a Telegram alarm.
---
## Shared dependencies / order-of-operations
- Task #8 (multichain) and Task #9 (confirmations) are independent and can land in parallel.
- Task #7 (ephemeral wallets) depends on Task #11 (Trezor) only for the sweep step — the address-generation half can ship first, sweep can land later with hot-key, then migrate to Trezor when #11 is done.
- Task #10 (AML) depends on nothing from the other four. It plugs into the existing Transaction Safety Provider.
- Task #11 (Trezor) is self-contained.
Tasks were sized for one experienced contributor to take any single one end-to-end without needing the others to land first. The integration glue (UI placement, navigation, telemetry) is left for the maintainer.

View File

@@ -208,6 +208,7 @@ These are documented in their respective sections but worth highlighting:
> - Opening a dispute does **not pause** the escrow until admin intervention. See [[Dispute Flow]] + [[Escrow Flow]]. > - Opening a dispute does **not pause** the escrow until admin intervention. See [[Dispute Flow]] + [[Escrow Flow]].
> - Several development env values committed as public — see [[Environment Variables]] for rotation list. > - Several development env values committed as public — see [[Environment Variables]] for rotation list.
> - Single-host deployment; horizontal scaling requires Redis adapter for Socket.IO — see [[Real-time Layer]] §8. > - Single-host deployment; horizontal scaling requires Redis adapter for Socket.IO — see [[Real-time Layer]] §8.
> - Request Network webhooks currently land on the main app. Roadmap: Cloudflare Worker durable ingress + replay, with backend Transaction Safety Provider checks before escrow is credited. See [[Request Network Integration Constraints]].
--- ---

View File

@@ -1,6 +1,6 @@
# Taskmaster Dashboard # Taskmaster Dashboard
Generated from `.taskmaster/tasks/tasks.json` at 2026-05-24T07:15:25.199Z. Generated from `.taskmaster/tasks/tasks.json` at 2026-05-28T11:49:27.076Z.
Taskmaster remains the canonical source of truth. Re-run: Taskmaster remains the canonical source of truth. Re-run:
@@ -10,9 +10,9 @@ node scripts/export-taskmaster-to-obsidian.mjs
## Status Summary ## Status Summary
- done: 28 - done: 44
- in-progress: 3 - in-progress: 2
- pending: 14 - pending: 8
## Task Index ## Task Index
@@ -43,26 +43,35 @@ node scripts/export-taskmaster-to-obsidian.mjs
| [[Tasks/task-3-10|3.10]] | Update release/refund APIs and marketplace release paths | done | high | 3.8, 3.9 | | [[Tasks/task-3-10|3.10]] | Update release/refund APIs and marketplace release paths | done | high | 3.8, 3.9 |
| [[Tasks/task-3-11|3.11]] | Add comprehensive observability, runbooks, and incident controls | done | high | 3.6, 3.8, 3.9, 3.10 | | [[Tasks/task-3-11|3.11]] | Add comprehensive observability, runbooks, and incident controls | done | high | 3.6, 3.8, 3.9, 3.10 |
| [[Tasks/task-3-12|3.12]] | Add end-to-end integration, migration, and rollback test suites | done | high | 3.6, 3.10, 3.11 | | [[Tasks/task-3-12|3.12]] | Add end-to-end integration, migration, and rollback test suites | done | high | 3.6, 3.10, 3.11 |
| [[Tasks/task-4|4]] | Define backend security and refactor strategy from latest audit | in-progress | high | None | | [[Tasks/task-3-13|3.13]] | Add durable RN webhook ingress and transaction safety | pending | high | None |
| [[Tasks/task-4|4]] | Define backend security and refactor strategy from latest audit | done | high | None |
| [[Tasks/task-4-1|4.1]] | Assign security ownership and launch decision criteria | done | high | None | | [[Tasks/task-4-1|4.1]] | Assign security ownership and launch decision criteria | done | high | None |
| [[Tasks/task-4-2|4.2]] | Produce threat model for escrow platform | done | high | 1 | | [[Tasks/task-4-2|4.2]] | Produce threat model for escrow platform | done | high | 1 |
| [[Tasks/task-4-3|4.3]] | Specify funds ledger and escrow state machine | pending | high | 2 | | [[Tasks/task-4-3|4.3]] | Specify funds ledger and escrow state machine | done | high | 2 |
| [[Tasks/task-4-4|4.4]] | Create authorization matrix for REST and Socket.IO | pending | high | 2 | | [[Tasks/task-4-4|4.4]] | Create authorization matrix for REST and Socket.IO | done | high | 2 |
| [[Tasks/task-4-5|4.5]] | Decide session, passkey, and admin step-up architecture | pending | high | 2 | | [[Tasks/task-4-5|4.5]] | Decide session, passkey, and admin step-up architecture | done | high | 2 |
| [[Tasks/task-4-6|4.6]] | Specify webhook security and provider adapter contracts | pending | high | 3 | | [[Tasks/task-4-6|4.6]] | Specify webhook security and provider adapter contracts | done | high | 3 |
| [[Tasks/task-4-7|4.7]] | Define secure build and supply-chain policy | done | medium | 1 | | [[Tasks/task-4-7|4.7]] | Define secure build and supply-chain policy | done | medium | 1 |
| [[Tasks/task-4-8|4.8]] | Make backend-core stack decision | pending | medium | 2, 3, 4, 5, 6, 7 | | [[Tasks/task-4-8|4.8]] | Make backend-core stack decision | done | medium | 2, 3, 4, 5, 6, 7 |
| [[Tasks/task-4-9|4.9]] | Create migration and operational runbooks | pending | medium | 8 | | [[Tasks/task-4-9|4.9]] | Create migration and operational runbooks | done | medium | 8 |
| [[Tasks/task-5|5]] | Deliver Telegram-native app, bot, and wallet experience | in-progress | high | None | | [[Tasks/task-5|5]] | Deliver Telegram-native app, bot, and wallet experience | in-progress | high | None |
| [[Tasks/task-5-1|5.1]] | Define Telegram product surface and flow map | in-progress | high | None | | [[Tasks/task-5-1|5.1]] | Define Telegram product surface and flow map | done | high | None |
| [[Tasks/task-5-2|5.2]] | Build Telegram identity linking and session model | pending | high | 1 | | [[Tasks/task-5-2|5.2]] | Build Telegram identity linking and session model | done | high | 1 |
| [[Tasks/task-5-3|5.3]] | Implement bot command and notification foundation | pending | high | 1, 2 | | [[Tasks/task-5-3|5.3]] | Implement bot command and notification foundation | done | high | 1, 2 |
| [[Tasks/task-5-4|5.4]] | Build Telegram Mini App shell for marketplace workflows | pending | high | 1, 2 | | [[Tasks/task-5-4|5.4]] | Build Telegram Mini App shell for marketplace workflows | in-progress | high | 1, 2 |
| [[Tasks/task-5-5|5.5]] | Add Telegram payment and wallet strategy | pending | high | 2, 4 | | [[Tasks/task-5-5|5.5]] | Add Telegram payment and wallet strategy | done | high | 2, 4 |
| [[Tasks/task-5-6|5.6]] | Expose escrow, delivery, dispute, and release actions safely | pending | high | 4, 5 | | [[Tasks/task-5-6|5.6]] | Expose escrow, delivery, dispute, and release actions safely | pending | high | 4, 5 |
| [[Tasks/task-5-7|5.7]] | Add admin and support surface for Telegram-originated cases | pending | high | 2, 3, 5 | | [[Tasks/task-5-7|5.7]] | Add admin and support surface for Telegram-originated cases | pending | high | 2, 3, 5 |
| [[Tasks/task-5-8|5.8]] | Add security, compliance, and abuse controls for Telegram | pending | high | 2, 3, 5, 6 | | [[Tasks/task-5-8|5.8]] | Add security, compliance, and abuse controls for Telegram | done | high | 2, 3, 5, 6 |
| [[Tasks/task-5-9|5.9]] | Prepare QA, rollout, analytics, and launch operations | pending | high | 3, 4, 5, 6, 7, 8 | | [[Tasks/task-5-9|5.9]] | Prepare QA, rollout, analytics, and launch operations | done | high | 3, 4, 5, 6, 7, 8 |
| [[Tasks/task-5-10|5.10]] | Implement Telegram as first-class authentication provider | done | high | 2, 8 |
| [[Tasks/task-6|6]] | Request Network in-house checkout (Rabby-supporting) | done | high | None |
| [[Tasks/task-6-1|6.1]] | Deploy confirmation repair before next paid probe | done | high | None |
| [[Tasks/task-7|7]] | Per-(buyer, sellerOffer) ephemeral RN destination wallets | pending | high | None |
| [[Tasks/task-8|8]] | Multichain RN proxy registry + USDC/USDT support | pending | high | None |
| [[Tasks/task-9|9]] | Per-chain confirmation thresholds + admin UI | pending | medium | None |
| [[Tasks/task-10|10]] | Optional AML screening on incoming payments (seller-paid) | pending | medium | None |
| [[Tasks/task-11|11]] | Trezor signing for admin actions (release/refund/sweep) | pending | high | None |
## Obsidian Tasks Query ## Obsidian Tasks Query

View File

@@ -5,7 +5,7 @@ priority: "medium"
depends_on: [] depends_on: []
parent_id: "1" parent_id: "1"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 1.1 - Fix Security Architecture email/password sequence # 1.1 - Fix Security Architecture email/password sequence

View File

@@ -5,7 +5,7 @@ priority: "medium"
depends_on: [] depends_on: []
parent_id: "1" parent_id: "1"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 1.2 - Fix authentication login and refresh diagrams # 1.2 - Fix authentication login and refresh diagrams

View File

@@ -5,7 +5,7 @@ priority: "medium"
depends_on: [] depends_on: []
parent_id: "1" parent_id: "1"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 1.3 - Fix chat, delivery, dispute, OAuth, purchase request, referral, registration, and seller-offer diagrams # 1.3 - Fix chat, delivery, dispute, OAuth, purchase request, referral, registration, and seller-offer diagrams

View File

@@ -5,7 +5,7 @@ priority: "medium"
depends_on: [] depends_on: []
parent_id: "" parent_id: ""
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 1 - Stabilize Mermaid diagram rendering across documentation vault # 1 - Stabilize Mermaid diagram rendering across documentation vault

View File

@@ -0,0 +1,35 @@
---
taskmaster_id: "10"
status: "pending"
priority: "medium"
depends_on: []
parent_id: ""
source: "taskmaster"
generated_at: "2026-05-28T11:49:27.076Z"
---
# 10 - Optional AML screening on incoming payments (seller-paid)
- [ ] 10 - Optional AML screening on incoming payments (seller-paid) #taskmaster #priority/medium #status/pending 🔼 🆔 tm-10
## Metadata
| Field | Value |
| --- | --- |
| Taskmaster ID | 10 |
| Status | pending |
| Priority | medium |
| Dependencies | None |
| Parent | None |
## Description
Turn the existing aml_screening placeholder in TransactionSafetyProvider into a real Chainalysis (or equivalent) Address Screening call that the seller opts into per-offer and pays the per-check cost for.
## Details
See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §4. Default provider recommendation: Chainalysis Address Screening (cheapest, simplest). Files: new backend/src/services/payment/safety/amlProvider.ts interface + chainalysisProvider.ts impl behind env TRANSACTION_SAFETY_AML_PROVIDER=chainalysis with API_KEY in KMS; transactionSafetyProvider's evaluateAmlPlaceholder() becomes real, persists raw provider response on Payment.metadata.amlResult; Offer schema add requireAmlCheck + amlBlockOnFailure booleans; offer-edit UI toggle 'Require AML on incoming payments ($X per payment, paid by you)'; admin global config UI for provider selection + API key rotation + per-chain enabled flag; cost accounting: deduct per-check cost from seller's escrow on completion as a separate ledger line item, surfaced on payment-details. Open questions before code: pick provider (Chainalysis vs TRM vs Elliptic — need 1-page comparison of cost/latency/coverage); failure mode (fail-closed only when seller opted in AND amlBlockOnFailure=true, else warn/log); cost batching cadence. Acceptance: seller toggles AML on an offer; incoming payment triggers a real Chainalysis call; sanctions verdict blocks the safety gate; clean verdict passes; seller's settled amount reduced by check cost; admin can rotate API key without redeploy; provider-down + amlBlockOnFailure=true keeps payment pending with provider_unavailable reason. Dependencies: none. This is task #10 in the PRD.
## Verification
_No verification strategy._

View File

@@ -0,0 +1,35 @@
---
taskmaster_id: "11"
status: "pending"
priority: "high"
depends_on: []
parent_id: ""
source: "taskmaster"
generated_at: "2026-05-28T11:49:27.076Z"
---
# 11 - Trezor signing for admin actions (release/refund/sweep)
- [ ] 11 - Trezor signing for admin actions (release/refund/sweep) #taskmaster #priority/high #status/pending ⏫ 🆔 tm-11
## Metadata
| Field | Value |
| --- | --- |
| Taskmaster ID | 11 |
| Status | pending |
| Priority | high |
| Dependencies | None |
| Parent | None |
## Description
Replace the hot-key admin signing flow with a WebUSB-based Trezor flow so the backend never holds a private key. All admin-side txes are built backend, signed via Trezor in the browser, broadcast from the browser.
## Details
See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §5. Lib: @trezor/connect-web (WebUSB; Chromium-only — Firefox users need Trezor Bridge native helper). Files: new frontend/src/web3/trezor/trezorConnector.ts wrapping @trezor/connect-web; existing admin actions (release/refund/sweep when #7 lands) get a 'Sign with Trezor' button that flows: POST /api/admin/actions/build-tx → returns unsigned tx bytes → send to Trezor → sign → wagmi sendTransaction broadcasts → POST /api/admin/actions/confirm-tx with hash; admin settings page to register Trezor address(es) (backend rejects signatures from unauthorized devices); audit log on every Trezor-signed action; break-glass hot-key path requires explicit admin toggle, expires after 1h, fires Telegram alarm. Open questions: m-of-n multi-admin signing — default single-signer for v1; Trezor One vs Model T — lib abstracts; fallback when Trezor unavailable — break-glass with alarm. Acceptance: admin registers Trezor address; release flow uses Trezor end-to-end; backend rejects signatures from unregistered devices; audit log captures admin user + Trezor addr + tx hash + before/after escrow state; break-glass works and alarms. Non-goals: mobile Trezor flow, buyer-side Trezor (buyer uses wagmi injected). Dependencies: task #7 (ephemeral wallets) for the sweep step — but task #11 can ship the release/refund flows first. This is task #11 in the PRD.
## Verification
_No verification strategy._

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: [] depends_on: []
parent_id: "2" parent_id: "2"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 2.1 - Secure unauthenticated endpoints and owner enforcement # 2.1 - Secure unauthenticated endpoints and owner enforcement

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["1"] depends_on: ["1"]
parent_id: "2" parent_id: "2"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 2.2 - Re-enable and scope rate limiting # 2.2 - Re-enable and scope rate limiting

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["1"] depends_on: ["1"]
parent_id: "2" parent_id: "2"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 2.3 - Replace stubbed passkey/WebAuthn flow # 2.3 - Replace stubbed passkey/WebAuthn flow

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["1"] depends_on: ["1"]
parent_id: "2" parent_id: "2"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 2.4 - Strengthen DePay/Web3 payment verification # 2.4 - Strengthen DePay/Web3 payment verification

View File

@@ -5,7 +5,7 @@ priority: "medium"
depends_on: ["1"] depends_on: ["1"]
parent_id: "2" parent_id: "2"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 2.5 - Lock Socket.IO room joins to authenticated context # 2.5 - Lock Socket.IO room joins to authenticated context

View File

@@ -5,7 +5,7 @@ priority: "medium"
depends_on: ["1", "4"] depends_on: ["1", "4"]
parent_id: "2" parent_id: "2"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 2.6 - Enforce dispute hold before payout and release operations # 2.6 - Enforce dispute hold before payout and release operations

View File

@@ -5,7 +5,7 @@ priority: "medium"
depends_on: ["1", "2", "3", "4", "5", "6"] depends_on: ["1", "2", "3", "4", "5", "6"]
parent_id: "2" parent_id: "2"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 2.7 - Align documentation, API references, and runtime enums # 2.7 - Align documentation, API references, and runtime enums

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: [] depends_on: []
parent_id: "" parent_id: ""
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 2 - Implement platform audit remediation plan # 2 - Implement platform audit remediation plan

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: [] depends_on: []
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.1 - Define provider-neutral payment contracts and adapter # 3.1 - Define provider-neutral payment contracts and adapter

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3.8", "3.9"] depends_on: ["3.8", "3.9"]
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.10 - Update release/refund APIs and marketplace release paths # 3.10 - Update release/refund APIs and marketplace release paths

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3.6", "3.8", "3.9", "3.10"] depends_on: ["3.6", "3.8", "3.9", "3.10"]
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.11 - Add comprehensive observability, runbooks, and incident controls # 3.11 - Add comprehensive observability, runbooks, and incident controls

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3.6", "3.10", "3.11"] depends_on: ["3.6", "3.10", "3.11"]
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.12 - Add end-to-end integration, migration, and rollback test suites # 3.12 - Add end-to-end integration, migration, and rollback test suites

View File

@@ -0,0 +1,35 @@
---
taskmaster_id: "3.13"
status: "pending"
priority: "high"
depends_on: []
parent_id: "3"
source: "taskmaster"
generated_at: "2026-05-28T11:49:27.076Z"
---
# 3.13 - Add durable RN webhook ingress and transaction safety
- [ ] 3.13 - Add durable RN webhook ingress and transaction safety #taskmaster #priority/high #status/pending ⏫ 🆔 tm-3-13
## Metadata
| Field | Value |
| --- | --- |
| Taskmaster ID | 3.13 |
| Status | pending |
| Priority | high |
| Dependencies | None |
| Parent | 3 - Migrate payment architecture toward Request Network and internal funds management |
## Description
Roadmap follow-up from the 2026-05-28 dev payment probe: Request Network delivered the webhook but Amanat returned 404. Add Cloudflare Worker durable webhook ingress with storage/replay and keep backend Transaction Safety Provider checks as the trust boundary before marking escrow funded.
## Details
_No details._
## Verification
_No verification strategy._

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3.1"] depends_on: ["3.1"]
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.2 - Implement provider configuration, feature flags, and safe rollback # 3.2 - Implement provider configuration, feature flags, and safe rollback

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3.1"] depends_on: ["3.1"]
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.3 - Create internal funds and payment ledger model # 3.3 - Create internal funds and payment ledger model

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3.3"] depends_on: ["3.3"]
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.4 - Build migration and indexing plan for existing SHKeeper records # 3.4 - Build migration and indexing plan for existing SHKeeper records

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3.2"] depends_on: ["3.2"]
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.5 - Implement Request Network pay-in intent and secure payment pages # 3.5 - Implement Request Network pay-in intent and secure payment pages

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3.2"] depends_on: ["3.2"]
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.6 - Implement signed Request Network webhook intake # 3.6 - Implement signed Request Network webhook intake

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3.5", "3.6"] depends_on: ["3.5", "3.6"]
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.7 - Implement reconciliation and repair jobs # 3.7 - Implement reconciliation and repair jobs

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3.5"] depends_on: ["3.5"]
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.8 - Replace checkout and payment UI with provider-neutral flows # 3.8 - Replace checkout and payment UI with provider-neutral flows

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3.3", "3.7"] depends_on: ["3.3", "3.7"]
parent_id: "3" parent_id: "3"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3.9 - Add payout/release and refund orchestration using ledger gates # 3.9 - Add payout/release and refund orchestration using ledger gates

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["2"] depends_on: ["2"]
parent_id: "" parent_id: ""
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 3 - Migrate payment architecture toward Request Network and internal funds management # 3 - Migrate payment architecture toward Request Network and internal funds management

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: [] depends_on: []
parent_id: "4" parent_id: "4"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 4.1 - Assign security ownership and launch decision criteria # 4.1 - Assign security ownership and launch decision criteria

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["1"] depends_on: ["1"]
parent_id: "4" parent_id: "4"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 4.2 - Produce threat model for escrow platform # 4.2 - Produce threat model for escrow platform

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["2"] depends_on: ["2"]
parent_id: "4" parent_id: "4"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:26:29.052Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 4.3 - Specify funds ledger and escrow state machine # 4.3 - Specify funds ledger and escrow state machine
@@ -28,8 +28,6 @@ Define canonical money movement and legal state transitions before refactor or p
## Details ## Details
Completed. Produced `09 - Audits/Funds Ledger and Escrow State Machine Specification.md` (states, transitions, invariants, and migration guidance for canonical funds/escrow transitions).
Create specs for FundsAccount, LedgerEntry, FundsBalance, gross paid, provider fees, platform fees, held, disputed, releasable, released, refunded, idempotency keys, reconciliation behavior, purchase request states, payment states, escrow/funds states, dispute states, valid transitions, forbidden transitions, and release/refund/admin override preconditions. Create specs for FundsAccount, LedgerEntry, FundsBalance, gross paid, provider fees, platform fees, held, disputed, releasable, released, refunded, idempotency keys, reconciliation behavior, purchase request states, payment states, escrow/funds states, dispute states, valid transitions, forbidden transitions, and release/refund/admin override preconditions.
## Verification ## Verification

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["2"] depends_on: ["2"]
parent_id: "4" parent_id: "4"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:26:29.052Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 4.4 - Create authorization matrix for REST and Socket.IO # 4.4 - Create authorization matrix for REST and Socket.IO
@@ -28,8 +28,6 @@ Map every endpoint and realtime event to access level, ownership checks, state p
## Details ## Details
Completed. Produced `09 - Audits/Authorization Matrix - REST and Socket.IO.md` and `09 - Audits/Realtime Authorization Spec.md`.
Include public/authenticated/owner/buyer/seller/admin/support/service-role classifications. Socket.IO rooms must be server-derived from authenticated identity, not client-supplied user IDs. Include public/authenticated/owner/buyer/seller/admin/support/service-role classifications. Socket.IO rooms must be server-derived from authenticated identity, not client-supplied user IDs.
## Verification ## Verification

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["2"] depends_on: ["2"]
parent_id: "4" parent_id: "4"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:26:29.052Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 4.5 - Decide session, passkey, and admin step-up architecture # 4.5 - Decide session, passkey, and admin step-up architecture
@@ -28,8 +28,6 @@ Choose browser session model and high-risk admin authentication requirements.
## Details ## Details
Completed. Produced `09 - Audits/Session and Authentication Architecture Decision.md`.
Decide localStorage versus httpOnly cookies, access/refresh token lifetimes, CSRF strategy, refresh rotation, WebAuthn requirements, OAuth requirements, device/session revocation, and whether payouts/role changes require step-up authentication or two-person approval. Decide localStorage versus httpOnly cookies, access/refresh token lifetimes, CSRF strategy, refresh rotation, WebAuthn requirements, OAuth requirements, device/session revocation, and whether payouts/role changes require step-up authentication or two-person approval.
## Verification ## Verification

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["3"] depends_on: ["3"]
parent_id: "4" parent_id: "4"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:26:29.052Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 4.6 - Specify webhook security and provider adapter contracts # 4.6 - Specify webhook security and provider adapter contracts
@@ -28,8 +28,6 @@ Define provider-neutral payment interface and signed webhook processing rules.
## Details ## Details
Completed. Produced `09 - Audits/Webhook Security Spec.md` and `09 - Audits/Payment Provider Adapter Spec.md`.
Document createPayInIntent, getPayInStatus, handleProviderWebhook, createHostedPaymentLink, createReleaseInstruction, createRefundInstruction, getPayoutStatus, searchProviderPayments, raw-body signature verification, replay prevention, delivery ID idempotency, duplicate/unknown event behavior, retry semantics, dead-letter/replay storage, and alert thresholds. Document createPayInIntent, getPayInStatus, handleProviderWebhook, createHostedPaymentLink, createReleaseInstruction, createRefundInstruction, getPayoutStatus, searchProviderPayments, raw-body signature verification, replay prevention, delivery ID idempotency, duplicate/unknown event behavior, retry semantics, dead-letter/replay storage, and alert thresholds.
## Verification ## Verification

View File

@@ -5,7 +5,7 @@ priority: "medium"
depends_on: ["1"] depends_on: ["1"]
parent_id: "4" parent_id: "4"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 4.7 - Define secure build and supply-chain policy # 4.7 - Define secure build and supply-chain policy

View File

@@ -5,7 +5,7 @@ priority: "medium"
depends_on: ["2", "3", "4", "5", "6", "7"] depends_on: ["2", "3", "4", "5", "6", "7"]
parent_id: "4" parent_id: "4"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:26:29.052Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 4.8 - Make backend-core stack decision # 4.8 - Make backend-core stack decision
@@ -28,8 +28,6 @@ Choose whether the security-critical backend core remains TypeScript or moves to
## Details ## Details
Completed. Produced `09 - Audits/Backend Core Stack Decision Record - 2026-05-24.md`.
Evaluate team capability, two-year maintainability, operational footprint, rewrite cost, dual-stack complexity, auditability, supply-chain exposure, and which modules belong in a payment/auth/escrow core versus the existing marketplace/chat API. Evaluate team capability, two-year maintainability, operational footprint, rewrite cost, dual-stack complexity, auditability, supply-chain exposure, and which modules belong in a payment/auth/escrow core versus the existing marketplace/chat API.
## Verification ## Verification

View File

@@ -5,7 +5,7 @@ priority: "medium"
depends_on: ["8"] depends_on: ["8"]
parent_id: "4" parent_id: "4"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:26:29.052Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 4.9 - Create migration and operational runbooks # 4.9 - Create migration and operational runbooks
@@ -28,8 +28,6 @@ Document rollout, rollback, and incident response for the selected backend/funds
## Details ## Details
Completed. Produced `08 - Operations/Backend Funds Migration and Operational Runbooks.md`.
Include SHKeeper legacy read path, provider feature flag, ledger backfill, validation report before enforcement, rollback criteria, webhook cutoff, manual reconciliation, failed webhook, duplicate/missing payment, stuck release, disputed release attempt, compromised admin, leaked API key, provider outage, chain/RPC outage, suspicious payment proof, and npm/package compromise. Include SHKeeper legacy read path, provider feature flag, ledger backfill, validation report before enforcement, rollback criteria, webhook cutoff, manual reconciliation, failed webhook, duplicate/missing payment, stuck release, disputed release attempt, compromised admin, leaked API key, provider outage, chain/RPC outage, suspicious payment proof, and npm/package compromise.
## Verification ## Verification

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: [] depends_on: []
parent_id: "" parent_id: ""
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:26:29.052Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 4 - Define backend security and refactor strategy from latest audit # 4 - Define backend security and refactor strategy from latest audit

View File

@@ -1,23 +1,23 @@
--- ---
taskmaster_id: "5.1" taskmaster_id: "5.1"
status: "in-progress" status: "done"
priority: "high" priority: "high"
depends_on: [] depends_on: []
parent_id: "5" parent_id: "5"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 5.1 - Define Telegram product surface and flow map # 5.1 - Define Telegram product surface and flow map
- [ ] 5.1 - Define Telegram product surface and flow map #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5-1 - [x] 5.1 - Define Telegram product surface and flow map #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-1
## Metadata ## Metadata
| Field | Value | | Field | Value |
| --- | --- | | --- | --- |
| Taskmaster ID | 5.1 | | Taskmaster ID | 5.1 |
| Status | in-progress | | Status | done |
| Priority | high | | Priority | high |
| Dependencies | None | | Dependencies | None |
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |

View File

@@ -2,16 +2,15 @@
taskmaster_id: "5.10" taskmaster_id: "5.10"
status: "done" status: "done"
priority: "high" priority: "high"
depends_on: ["5.2", "5.8"] depends_on: ["2", "8"]
parent_id: "5" parent_id: "5"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T09:18:26.638Z" generated_at: "2026-05-28T11:49:27.076Z"
completed_at: "2026-05-24"
--- ---
# 5.10 - Implement Telegram as first-class authentication provider # 5.10 - Implement Telegram as first-class authentication provider
- [x] 5.10 - Implement Telegram as first-class authentication provider #taskmaster #priority/high #status/done ⏫ 🆔 tm-5.10 - [x] 5.10 - Implement Telegram as first-class authentication provider #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-10 ⛔ tm-2 ⛔ tm-8
## Metadata ## Metadata
@@ -20,24 +19,19 @@ completed_at: "2026-05-24"
| Taskmaster ID | 5.10 | | Taskmaster ID | 5.10 |
| Status | done | | Status | done |
| Priority | high | | Priority | high |
| Dependencies | 5.2, 5.8 | | Dependencies | 2, 8 |
| Parent | 5 | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
## Description ## Description
Add `POST /api/auth/telegram` and frontend login flow so users can authenticate with Amanat using only Telegram identity, without email or password. Add a POST /auth/telegram endpoint and frontend login flow so users can authenticate with Amanat using only their Telegram identity — no email or password required.
## Details ## Details
Backend verifies Telegram Mini App `initData` and Telegram Login Widget payloads, checks/reuses `TelegramLink`, auto-provisions Telegram-only users with nullable email, `authProvider: "telegram"`, and `telegramVerified: true`, and returns the normal JWT/refresh-token pair plus `isNewUser`. Source PRD: .taskmaster/docs/prd-telegram-phone-auth.md. Backend: create POST /auth/telegram that accepts Mini App initData or Telegram Login Widget payload, verifies the signature (reuse verifyMiniAppInitData; add verifyTelegramLoginWidget for the widget path), looks up TelegramLink by telegramUserId, and either authenticates the linked user or auto-provisions a new Amanat account (authProvider: telegram, telegramVerified: true, nullable email via sparse unique index). Returns JWT + refreshToken + isNewUser flag. Apply existing replay protection and rate limits. User model: make email nullable (sparse index), add authProvider and telegramVerified fields. Frontend: auto-detect Telegram Mini App context and skip login page; POST initData to /auth/telegram; show lightweight onboarding overlay for new users (optional email, language, currency). Add 'Continue with Telegram' button on web login page alongside Google OAuth. Security: blocked Telegram accounts return 403 regardless of re-linking attempts; high-risk action step-up policy is unchanged; never expose raw phone number.
Frontend auto-authenticates Telegram Mini App launches from raw signed `initData`, adds a Telegram login action, and shows a lightweight onboarding dialog for new Telegram users.
## Verification ## Verification
- Backend typecheck passed. Verify: new Telegram user auto-provisions and receives JWT; returning user authenticates via both initData and Login Widget; replayed initData is rejected; stale auth_date is rejected; blocked account returns 403; existing email-password users are unaffected; email remains optional (not required) for Telegram-authed users; isNewUser flag triggers onboarding overlay; high-risk actions still require step-up confirmation.
- Backend targeted Jest passed: `__tests__/telegram-auth.test.ts`, `__tests__/telegram-service.test.ts`.
- Frontend targeted Jest passed: `__tests__/auth/telegram-auth-action.test.ts`, `__tests__/sections/telegram/telegram-mini-app-shell.test.tsx`.
- Full frontend typecheck still has unrelated pre-existing payment UI errors outside this task.
See [[Task 5.10 Telegram First-Class Authentication]] for the audit report. Implemented verification: backend typecheck; backend targeted Jest __tests__/telegram-auth.test.ts and __tests__/telegram-service.test.ts; frontend targeted Jest __tests__/auth/telegram-auth-action.test.ts and __tests__/sections/telegram/telegram-mini-app-shell.test.tsx. Full frontend typecheck still has unrelated pre-existing payment icon/payload errors outside Task 5.10.

View File

@@ -1,23 +1,23 @@
--- ---
taskmaster_id: "5.2" taskmaster_id: "5.2"
status: "pending" status: "done"
priority: "high" priority: "high"
depends_on: ["1"] depends_on: ["1"]
parent_id: "5" parent_id: "5"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 5.2 - Build Telegram identity linking and session model # 5.2 - Build Telegram identity linking and session model
- [ ] 5.2 - Build Telegram identity linking and session model #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-2 ⛔ tm-1 - [x] 5.2 - Build Telegram identity linking and session model #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-2 ⛔ tm-1
## Metadata ## Metadata
| Field | Value | | Field | Value |
| --- | --- | | --- | --- |
| Taskmaster ID | 5.2 | | Taskmaster ID | 5.2 |
| Status | pending | | Status | done |
| Priority | high | | Priority | high |
| Dependencies | 1 | | Dependencies | 1 |
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |

View File

@@ -1,23 +1,23 @@
--- ---
taskmaster_id: "5.3" taskmaster_id: "5.3"
status: "pending" status: "done"
priority: "high" priority: "high"
depends_on: ["1", "2"] depends_on: ["1", "2"]
parent_id: "5" parent_id: "5"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 5.3 - Implement bot command and notification foundation # 5.3 - Implement bot command and notification foundation
- [ ] 5.3 - Implement bot command and notification foundation #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-3 ⛔ tm-1 ⛔ tm-2 - [x] 5.3 - Implement bot command and notification foundation #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-3 ⛔ tm-1 ⛔ tm-2
## Metadata ## Metadata
| Field | Value | | Field | Value |
| --- | --- | | --- | --- |
| Taskmaster ID | 5.3 | | Taskmaster ID | 5.3 |
| Status | pending | | Status | done |
| Priority | high | | Priority | high |
| Dependencies | 1, 2 | | Dependencies | 1, 2 |
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |

View File

@@ -1,23 +1,23 @@
--- ---
taskmaster_id: "5.4" taskmaster_id: "5.4"
status: "pending" status: "in-progress"
priority: "high" priority: "high"
depends_on: ["1", "2"] depends_on: ["1", "2"]
parent_id: "5" parent_id: "5"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 5.4 - Build Telegram Mini App shell for marketplace workflows # 5.4 - Build Telegram Mini App shell for marketplace workflows
- [ ] 5.4 - Build Telegram Mini App shell for marketplace workflows #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-4 ⛔ tm-1 ⛔ tm-2 - [ ] 5.4 - Build Telegram Mini App shell for marketplace workflows #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5-4 ⛔ tm-1 ⛔ tm-2
## Metadata ## Metadata
| Field | Value | | Field | Value |
| --- | --- | | --- | --- |
| Taskmaster ID | 5.4 | | Taskmaster ID | 5.4 |
| Status | pending | | Status | in-progress |
| Priority | high | | Priority | high |
| Dependencies | 1, 2 | | Dependencies | 1, 2 |
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |

View File

@@ -1,23 +1,23 @@
--- ---
taskmaster_id: "5.5" taskmaster_id: "5.5"
status: "pending" status: "done"
priority: "high" priority: "high"
depends_on: ["2", "4"] depends_on: ["2", "4"]
parent_id: "5" parent_id: "5"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 5.5 - Add Telegram payment and wallet strategy # 5.5 - Add Telegram payment and wallet strategy
- [ ] 5.5 - Add Telegram payment and wallet strategy #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-5 ⛔ tm-2 ⛔ tm-4 - [x] 5.5 - Add Telegram payment and wallet strategy #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-5 ⛔ tm-2 ⛔ tm-4
## Metadata ## Metadata
| Field | Value | | Field | Value |
| --- | --- | | --- | --- |
| Taskmaster ID | 5.5 | | Taskmaster ID | 5.5 |
| Status | pending | | Status | done |
| Priority | high | | Priority | high |
| Dependencies | 2, 4 | | Dependencies | 2, 4 |
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["4", "5"] depends_on: ["4", "5"]
parent_id: "5" parent_id: "5"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 5.6 - Expose escrow, delivery, dispute, and release actions safely # 5.6 - Expose escrow, delivery, dispute, and release actions safely

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: ["2", "3", "5"] depends_on: ["2", "3", "5"]
parent_id: "5" parent_id: "5"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 5.7 - Add admin and support surface for Telegram-originated cases # 5.7 - Add admin and support surface for Telegram-originated cases

View File

@@ -1,23 +1,23 @@
--- ---
taskmaster_id: "5.8" taskmaster_id: "5.8"
status: "pending" status: "done"
priority: "high" priority: "high"
depends_on: ["2", "3", "5", "6"] depends_on: ["2", "3", "5", "6"]
parent_id: "5" parent_id: "5"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 5.8 - Add security, compliance, and abuse controls for Telegram # 5.8 - Add security, compliance, and abuse controls for Telegram
- [ ] 5.8 - Add security, compliance, and abuse controls for Telegram #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5 ⛔ tm-6 - [x] 5.8 - Add security, compliance, and abuse controls for Telegram #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5 ⛔ tm-6
## Metadata ## Metadata
| Field | Value | | Field | Value |
| --- | --- | | --- | --- |
| Taskmaster ID | 5.8 | | Taskmaster ID | 5.8 |
| Status | pending | | Status | done |
| Priority | high | | Priority | high |
| Dependencies | 2, 3, 5, 6 | | Dependencies | 2, 3, 5, 6 |
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |

View File

@@ -1,23 +1,23 @@
--- ---
taskmaster_id: "5.9" taskmaster_id: "5.9"
status: "pending" status: "done"
priority: "high" priority: "high"
depends_on: ["3", "4", "5", "6", "7", "8"] depends_on: ["3", "4", "5", "6", "7", "8"]
parent_id: "5" parent_id: "5"
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 5.9 - Prepare QA, rollout, analytics, and launch operations # 5.9 - Prepare QA, rollout, analytics, and launch operations
- [ ] 5.9 - Prepare QA, rollout, analytics, and launch operations #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-9 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7 ⛔ tm-8 - [x] 5.9 - Prepare QA, rollout, analytics, and launch operations #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-9 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7 ⛔ tm-8
## Metadata ## Metadata
| Field | Value | | Field | Value |
| --- | --- | | --- | --- |
| Taskmaster ID | 5.9 | | Taskmaster ID | 5.9 |
| Status | pending | | Status | done |
| Priority | high | | Priority | high |
| Dependencies | 3, 4, 5, 6, 7, 8 | | Dependencies | 3, 4, 5, 6, 7, 8 |
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |

View File

@@ -5,7 +5,7 @@ priority: "high"
depends_on: [] depends_on: []
parent_id: "" parent_id: ""
source: "taskmaster" source: "taskmaster"
generated_at: "2026-05-24T07:15:25.199Z" generated_at: "2026-05-28T11:49:27.076Z"
--- ---
# 5 - Deliver Telegram-native app, bot, and wallet experience # 5 - Deliver Telegram-native app, bot, and wallet experience

View File

@@ -0,0 +1,35 @@
---
taskmaster_id: "6.1"
status: "done"
priority: "high"
depends_on: []
parent_id: "6"
source: "taskmaster"
generated_at: "2026-05-28T11:49:27.076Z"
---
# 6.1 - Deploy confirmation repair before next paid probe
- [x] 6.1 - Deploy confirmation repair before next paid probe #taskmaster #priority/high #status/done ⏫ 🆔 tm-6-1
## Metadata
| Field | Value |
| --- | --- |
| Taskmaster ID | 6.1 |
| Status | done |
| Priority | high |
| Dependencies | None |
| Parent | 6 - Request Network in-house checkout (Rabby-supporting) |
## Description
2026-05-28 dev BSC transaction succeeded and RN delivered four webhooks, but Amanat returned 404 due Request Network reference-correlation mismatch. Before another paid payment test, deploy the backend correlation fix, callback polling fix, signed-webhook smoke test, and Transaction Safety Provider gate; then repeat the probe and inspect safety decision state.
## Details
_No details._
## Verification
_No verification strategy._

View File

@@ -0,0 +1,35 @@
---
taskmaster_id: "6"
status: "done"
priority: "high"
depends_on: []
parent_id: ""
source: "taskmaster"
generated_at: "2026-05-28T11:49:27.076Z"
---
# 6 - Request Network in-house checkout (Rabby-supporting)
- [x] 6 - Request Network in-house checkout (Rabby-supporting) #taskmaster #priority/high #status/done ⏫ 🆔 tm-6
## Metadata
| Field | Value |
| --- | --- |
| Taskmaster ID | 6 |
| Status | done |
| Priority | high |
| Dependencies | None |
| Parent | None |
## Description
Replace the redirect to pay.request.network with an Amanat-rendered checkout page that submits the same on-chain calls as RN's hosted UI, so RN's webhook fires unchanged but buyers stay on amn.gg and Rabby works.
## Details
See PRD: nick-doc/.taskmaster/docs/prd-request-network-in-house-checkout.md (summary at nick-doc/PRD - Request Network In-House Checkout.md). Status: draft, pending review with second developer. Approach: replicate the two on-chain calls (approve + RN_FEE_PROXY.transferFromWithReferenceAndFee) using wagmi v2 with existing injected()/metaMask() connectors (Rabby works via EIP-6963). Hard-known: proxy 0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9, selector 0xc219a14d, paymentRef = last8Bytes(keccak256(requestId+salt+dest)), feeAmount=0, feeAddress=0x...dEaD. Backend: extend POST /payment/request-network/intents response with inHouseCheckout object (destination, tokenAddress, decimals, chainId, proxyAddress, paymentReference, feeAmount, feeAddress, amountWei). Frontend: new page /checkout/request-network/:paymentId with state machine reusing manual-payment.tsx layout chrome, hosted-page link kept as escape hatch. Implementation gated on a $0.50 cold probe on dev BSC to confirm RN's webhook fires for an externally-built tx. Out of scope: per-seller multi-chain config (§2), ephemeral wallets (§3), full RN removal (§4), gasless. Open questions in PRD §10.
## Verification
_No verification strategy._

View File

@@ -0,0 +1,35 @@
---
taskmaster_id: "7"
status: "pending"
priority: "high"
depends_on: []
parent_id: ""
source: "taskmaster"
generated_at: "2026-05-28T11:49:27.076Z"
---
# 7 - Per-(buyer, sellerOffer) ephemeral RN destination wallets
- [ ] 7 - Per-(buyer, sellerOffer) ephemeral RN destination wallets #taskmaster #priority/high #status/pending ⏫ 🆔 tm-7
## Metadata
| Field | Value |
| --- | --- |
| Taskmaster ID | 7 |
| Status | pending |
| Priority | high |
| Dependencies | None |
| Parent | None |
## Description
Replace the single shared Amanat destination wallet with a per-(buyerId, sellerOfferId) HD-derived address sent to Request Network on intent creation, plus sweep-on-approval and an admin UI.
## Details
See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §1. Files: new backend/src/services/payment/wallets/derivedDestinations.ts (getDestinationFor(buyerId, sellerOfferId) → {address, derivationPath, chainId}); Payment schema add metadata.derivedDestination; requestNetworkPayInService.ts override destinationId before POST /v2/secure-payments (we confirmed RN accepts different destinations per intent); new sweep cron + admin manual-trigger endpoint gated on Transaction Safety Provider; admin UI at /dashboard/admin/derived-destinations with address, balance, last sweep tx (BscScan link), ownership status. Open questions to settle first: HD vs disposable EOAs vs smart-forwarder (recommended HD); sweep cadence (recommended immediate); granularity (recommended per-(buyer, seller), not per-payment); re-use vs rotate after sweep. KMS-rooted seed; backend never holds raw private keys; signing via KMS API (Task #11 Trezor flow is the longer-term replacement). Acceptance: two payments from one buyer to two sellers land on two different addresses; RN webhook fires for both; sweep is idempotent; master seed never leaves KMS.
## Verification
_No verification strategy._

View File

@@ -0,0 +1,35 @@
---
taskmaster_id: "8"
status: "pending"
priority: "high"
depends_on: []
parent_id: ""
source: "taskmaster"
generated_at: "2026-05-28T11:49:27.076Z"
---
# 8 - Multichain RN proxy registry + USDC/USDT support
- [ ] 8 - Multichain RN proxy registry + USDC/USDT support #taskmaster #priority/high #status/pending ⏫ 🆔 tm-8
## Metadata
| Field | Value |
| --- | --- |
| Taskmaster ID | 8 |
| Status | pending |
| Priority | high |
| Dependencies | None |
| Parent | None |
## Description
Probe and persist RN ERC20FeeProxy addresses on BSC/Arb/ETH/Polygon/Base, add USDC + USDT token entries with correct decimals per chain, and surface an admin networks page. Include the USDT-mainnet approve(0) reset quirk in the frontend approve step.
## Details
See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §2. Tasks: new backend/scripts/probe-rn-chains.ts that walks each chain in supported-chains.json and verifies the canonical 0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9 proxy is the real RN proxy via a known view fn (CREATE2 is deterministic, but verify); promote backend/src/services/payment/requestNetwork/tokens.ts to load from JSON + admin override; add USDT entries on all 5 chains (BSC USDT 18-dec quirk, mainnet/Arb/Polygon/Base USDT 6-dec); buildInHouseCheckoutBlock returns reason='unsupported_chain:<id>' for unknowns; new admin route GET /api/admin/rn/networks + frontend page /dashboard/admin/networks rendering the registry with per-row 'probe again'. Frontend approve flow: if buyer is on Ethereum mainnet AND token is USDT AND current allowance > 0, do approve(spender, 0) first then approve(spender, amount). Acceptance: probe succeeds on at least BSC/Arb/Polygon/ETH/Base; one paid probe on BSC USDT end-to-end; mainnet USDT approve(0) reset works; admin page reflects registry. Dependencies: none — runs in parallel with #9. This is task #8 in the PRD.
## Verification
_No verification strategy._

View File

@@ -0,0 +1,35 @@
---
taskmaster_id: "9"
status: "pending"
priority: "medium"
depends_on: []
parent_id: ""
source: "taskmaster"
generated_at: "2026-05-28T11:49:27.076Z"
---
# 9 - Per-chain confirmation thresholds + admin UI
- [ ] 9 - Per-chain confirmation thresholds + admin UI #taskmaster #priority/medium #status/pending 🔼 🆔 tm-9
## Metadata
| Field | Value |
| --- | --- |
| Taskmaster ID | 9 |
| Status | pending |
| Priority | medium |
| Dependencies | None |
| Parent | None |
## Description
Make TransactionSafetyProvider's confirmation threshold tunable at runtime per chain via admin UI, with an awaiting-confirmation payments view that shows live confirmations vs threshold.
## Details
See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §3. Today TRANSACTION_SAFETY_MIN_CONFIRMATIONS is a global env var, default 12, baked in until redeploy. Move to runtime config: new Setting docs keyed 'confirmation_threshold:<chainId>' or extend existing model; cache reads in transactionSafetyProvider.ts for 30s; GET/PATCH /api/admin/settings/confirmation-thresholds (auth: admin); new admin page /dashboard/admin/confirmation-thresholds (table: chain, current, recommended default, edit-in-place with confirm dialog, audit log of changes); new admin page /dashboard/admin/payments/awaiting-confirmation (payments where escrowState !== 'funded' AND metadata.transactionSafety.lastCheck.status === 'pending'; for each show tx hash linked to explorer, current confirmations via 12s poll on BSC, threshold, ETA). Acceptance: admin lowers BSC threshold from 12 to 3 on dev, next webhook honors new value within 30s; awaiting-confirmation table updates live; audit log records every change. Non-goals: per-asset, per-seller thresholds. Dependencies: none. This is task #9 in the PRD.
## Verification
_No verification strategy._

View File

@@ -1,6 +1,6 @@
# Taskmaster Tasks # Taskmaster Tasks
Generated from `.taskmaster/tasks/tasks.json` at 2026-05-24T07:15:25.199Z. Generated from `.taskmaster/tasks/tasks.json` at 2026-05-28T11:49:27.076Z.
These lines use the Obsidian Tasks emoji format: These lines use the Obsidian Tasks emoji format:
@@ -35,23 +35,32 @@ These lines use the Obsidian Tasks emoji format:
- [x] 3.10 - Update release/refund APIs and marketplace release paths #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-10 ⛔ tm-3-8 ⛔ tm-3-9 - [x] 3.10 - Update release/refund APIs and marketplace release paths #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-10 ⛔ tm-3-8 ⛔ tm-3-9
- [x] 3.11 - Add comprehensive observability, runbooks, and incident controls #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-11 ⛔ tm-3-6 ⛔ tm-3-8 ⛔ tm-3-9 ⛔ tm-3-10 - [x] 3.11 - Add comprehensive observability, runbooks, and incident controls #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-11 ⛔ tm-3-6 ⛔ tm-3-8 ⛔ tm-3-9 ⛔ tm-3-10
- [x] 3.12 - Add end-to-end integration, migration, and rollback test suites #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-12 ⛔ tm-3-6 ⛔ tm-3-10 ⛔ tm-3-11 - [x] 3.12 - Add end-to-end integration, migration, and rollback test suites #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-12 ⛔ tm-3-6 ⛔ tm-3-10 ⛔ tm-3-11
- [ ] 4 - Define backend security and refactor strategy from latest audit #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-4 - [ ] 3.13 - Add durable RN webhook ingress and transaction safety #taskmaster #priority/high #status/pending ⏫ 🆔 tm-3-13
- [x] 4 - Define backend security and refactor strategy from latest audit #taskmaster #priority/high #status/done ⏫ 🆔 tm-4
- [x] 4.1 - Assign security ownership and launch decision criteria #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-1 - [x] 4.1 - Assign security ownership and launch decision criteria #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-1
- [x] 4.2 - Produce threat model for escrow platform #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-2 ⛔ tm-1 - [x] 4.2 - Produce threat model for escrow platform #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-2 ⛔ tm-1
- [ ] 4.3 - Specify funds ledger and escrow state machine #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-3 ⛔ tm-2 - [x] 4.3 - Specify funds ledger and escrow state machine #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-3 ⛔ tm-2
- [ ] 4.4 - Create authorization matrix for REST and Socket.IO #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-4 ⛔ tm-2 - [x] 4.4 - Create authorization matrix for REST and Socket.IO #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-4 ⛔ tm-2
- [ ] 4.5 - Decide session, passkey, and admin step-up architecture #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-5 ⛔ tm-2 - [x] 4.5 - Decide session, passkey, and admin step-up architecture #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-5 ⛔ tm-2
- [ ] 4.6 - Specify webhook security and provider adapter contracts #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-6 ⛔ tm-3 - [x] 4.6 - Specify webhook security and provider adapter contracts #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-6 ⛔ tm-3
- [x] 4.7 - Define secure build and supply-chain policy #taskmaster #priority/medium #status/done 🔼 🆔 tm-4-7 ⛔ tm-1 - [x] 4.7 - Define secure build and supply-chain policy #taskmaster #priority/medium #status/done 🔼 🆔 tm-4-7 ⛔ tm-1
- [ ] 4.8 - Make backend-core stack decision #taskmaster #priority/medium #status/pending 🔼 🆔 tm-4-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7 - [x] 4.8 - Make backend-core stack decision #taskmaster #priority/medium #status/done 🔼 🆔 tm-4-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7
- [ ] 4.9 - Create migration and operational runbooks #taskmaster #priority/medium #status/pending 🔼 🆔 tm-4-9 ⛔ tm-8 - [x] 4.9 - Create migration and operational runbooks #taskmaster #priority/medium #status/done 🔼 🆔 tm-4-9 ⛔ tm-8
- [ ] 5 - Deliver Telegram-native app, bot, and wallet experience #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5 - [ ] 5 - Deliver Telegram-native app, bot, and wallet experience #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5
- [ ] 5.1 - Define Telegram product surface and flow map #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5-1 - [x] 5.1 - Define Telegram product surface and flow map #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-1
- [ ] 5.2 - Build Telegram identity linking and session model #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-2 ⛔ tm-1 - [x] 5.2 - Build Telegram identity linking and session model #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-2 ⛔ tm-1
- [ ] 5.3 - Implement bot command and notification foundation #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-3 ⛔ tm-1 ⛔ tm-2 - [x] 5.3 - Implement bot command and notification foundation #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-3 ⛔ tm-1 ⛔ tm-2
- [ ] 5.4 - Build Telegram Mini App shell for marketplace workflows #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-4 ⛔ tm-1 ⛔ tm-2 - [ ] 5.4 - Build Telegram Mini App shell for marketplace workflows #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5-4 ⛔ tm-1 ⛔ tm-2
- [ ] 5.5 - Add Telegram payment and wallet strategy #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-5 ⛔ tm-2 ⛔ tm-4 - [x] 5.5 - Add Telegram payment and wallet strategy #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-5 ⛔ tm-2 ⛔ tm-4
- [ ] 5.6 - Expose escrow, delivery, dispute, and release actions safely #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-6 ⛔ tm-4 ⛔ tm-5 - [ ] 5.6 - Expose escrow, delivery, dispute, and release actions safely #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-6 ⛔ tm-4 ⛔ tm-5
- [ ] 5.7 - Add admin and support surface for Telegram-originated cases #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-7 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5 - [ ] 5.7 - Add admin and support surface for Telegram-originated cases #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-7 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5
- [ ] 5.8 - Add security, compliance, and abuse controls for Telegram #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5 ⛔ tm-6 - [x] 5.8 - Add security, compliance, and abuse controls for Telegram #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5 ⛔ tm-6
- [ ] 5.9 - Prepare QA, rollout, analytics, and launch operations #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-9 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7 ⛔ tm-8 - [x] 5.9 - Prepare QA, rollout, analytics, and launch operations #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-9 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7 ⛔ tm-8
- [x] 5.10 - Implement Telegram as first-class authentication provider #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-10 ⛔ tm-2 ⛔ tm-8
- [x] 6 - Request Network in-house checkout (Rabby-supporting) #taskmaster #priority/high #status/done ⏫ 🆔 tm-6
- [x] 6.1 - Deploy confirmation repair before next paid probe #taskmaster #priority/high #status/done ⏫ 🆔 tm-6-1
- [ ] 7 - Per-(buyer, sellerOffer) ephemeral RN destination wallets #taskmaster #priority/high #status/pending ⏫ 🆔 tm-7
- [ ] 8 - Multichain RN proxy registry + USDC/USDT support #taskmaster #priority/high #status/pending ⏫ 🆔 tm-8
- [ ] 9 - Per-chain confirmation thresholds + admin UI #taskmaster #priority/medium #status/pending 🔼 🆔 tm-9
- [ ] 10 - Optional AML screening on incoming payments (seller-paid) #taskmaster #priority/medium #status/pending 🔼 🆔 tm-10
- [ ] 11 - Trezor signing for admin actions (release/refund/sweep) #taskmaster #priority/high #status/pending ⏫ 🆔 tm-11