From 0060b1691271b06356b85feb1f68e55bd0ff89e8 Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Thu, 28 May 2026 15:50:24 +0400 Subject: [PATCH] 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 --- .../prd-request-network-in-house-checkout.md | 280 ++++++++++++++++++ .taskmaster/tasks/tasks.json | 110 ++++++- ...Request Network Integration Constraints.md | 33 ++- 02 - Data Models/Payment.md | 1 + 07 - Development/Environment Variables.md | 6 + ...etwork Confirmation Repair - 2026-05-28.md | 212 +++++++++++++ ... Network In-House Checkout - 2026-05-28.md | 70 +++++ 08 - Operations/Incident Response.md | 14 + 08 - Operations/Monitoring.md | 2 + PRD - Request Network In-House Checkout.md | 127 ++++++++ ... Network Migration and Funds Management.md | 47 ++- ... Multichain, Confirmations, AML, Trezor.md | 225 ++++++++++++++ README.md | 1 + Taskmaster/README.md | 45 +-- Taskmaster/Tasks/task-1-1.md | 2 +- Taskmaster/Tasks/task-1-2.md | 2 +- Taskmaster/Tasks/task-1-3.md | 2 +- Taskmaster/Tasks/task-1.md | 2 +- Taskmaster/Tasks/task-10.md | 35 +++ Taskmaster/Tasks/task-11.md | 35 +++ Taskmaster/Tasks/task-2-1.md | 2 +- Taskmaster/Tasks/task-2-2.md | 2 +- Taskmaster/Tasks/task-2-3.md | 2 +- Taskmaster/Tasks/task-2-4.md | 2 +- Taskmaster/Tasks/task-2-5.md | 2 +- Taskmaster/Tasks/task-2-6.md | 2 +- Taskmaster/Tasks/task-2-7.md | 2 +- Taskmaster/Tasks/task-2.md | 2 +- Taskmaster/Tasks/task-3-1.md | 2 +- Taskmaster/Tasks/task-3-10.md | 2 +- Taskmaster/Tasks/task-3-11.md | 2 +- Taskmaster/Tasks/task-3-12.md | 2 +- Taskmaster/Tasks/task-3-13.md | 35 +++ Taskmaster/Tasks/task-3-2.md | 2 +- Taskmaster/Tasks/task-3-3.md | 2 +- Taskmaster/Tasks/task-3-4.md | 2 +- Taskmaster/Tasks/task-3-5.md | 2 +- Taskmaster/Tasks/task-3-6.md | 2 +- Taskmaster/Tasks/task-3-7.md | 2 +- Taskmaster/Tasks/task-3-8.md | 2 +- Taskmaster/Tasks/task-3-9.md | 2 +- Taskmaster/Tasks/task-3.md | 2 +- Taskmaster/Tasks/task-4-1.md | 2 +- Taskmaster/Tasks/task-4-2.md | 2 +- Taskmaster/Tasks/task-4-3.md | 4 +- Taskmaster/Tasks/task-4-4.md | 4 +- Taskmaster/Tasks/task-4-5.md | 4 +- Taskmaster/Tasks/task-4-6.md | 4 +- Taskmaster/Tasks/task-4-7.md | 2 +- Taskmaster/Tasks/task-4-8.md | 4 +- Taskmaster/Tasks/task-4-9.md | 4 +- Taskmaster/Tasks/task-4.md | 2 +- Taskmaster/Tasks/task-5-1.md | 8 +- Taskmaster/Tasks/task-5-10.md | 24 +- Taskmaster/Tasks/task-5-2.md | 8 +- Taskmaster/Tasks/task-5-3.md | 8 +- Taskmaster/Tasks/task-5-4.md | 8 +- Taskmaster/Tasks/task-5-5.md | 8 +- Taskmaster/Tasks/task-5-6.md | 2 +- Taskmaster/Tasks/task-5-7.md | 2 +- Taskmaster/Tasks/task-5-8.md | 8 +- Taskmaster/Tasks/task-5-9.md | 8 +- Taskmaster/Tasks/task-5.md | 2 +- Taskmaster/Tasks/task-6-1.md | 35 +++ Taskmaster/Tasks/task-6.md | 35 +++ Taskmaster/Tasks/task-7.md | 35 +++ Taskmaster/Tasks/task-8.md | 35 +++ Taskmaster/Tasks/task-9.md | 35 +++ Taskmaster/tasks.md | 39 ++- 69 files changed, 1513 insertions(+), 147 deletions(-) create mode 100644 .taskmaster/docs/prd-request-network-in-house-checkout.md create mode 100644 08 - Operations/Handoff - Request Network Confirmation Repair - 2026-05-28.md create mode 100644 08 - Operations/Handoff - Request Network In-House Checkout - 2026-05-28.md create mode 100644 PRD - Request Network In-House Checkout.md create mode 100644 PRD - Wallet, Multichain, Confirmations, AML, Trezor.md create mode 100644 Taskmaster/Tasks/task-10.md create mode 100644 Taskmaster/Tasks/task-11.md create mode 100644 Taskmaster/Tasks/task-3-13.md create mode 100644 Taskmaster/Tasks/task-6-1.md create mode 100644 Taskmaster/Tasks/task-6.md create mode 100644 Taskmaster/Tasks/task-7.md create mode 100644 Taskmaster/Tasks/task-8.md create mode 100644 Taskmaster/Tasks/task-9.md diff --git a/.taskmaster/docs/prd-request-network-in-house-checkout.md b/.taskmaster/docs/prd-request-network-in-house-checkout.md new file mode 100644 index 0000000..520ee22 --- /dev/null +++ b/.taskmaster/docs/prd-request-network-in-house-checkout.md @@ -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 1–9 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: +- Arbitrum proxy deployment: +- Architecture constraints doc: `01 - Architecture/Request Network Integration Constraints.md` +- Previous RN work: `PRD - Request Network Migration and Funds Management.md` diff --git a/.taskmaster/tasks/tasks.json b/.taskmaster/tasks/tasks.json index 2e6edc1..880738a 100644 --- a/.taskmaster/tasks/tasks.json +++ b/.taskmaster/tasks/tasks.json @@ -2,7 +2,7 @@ "master": { "tasks": [ { - "id": "1", + "id": 1, "title": "Stabilize Mermaid diagram rendering across documentation vault", "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.", @@ -47,7 +47,7 @@ ] }, { - "id": "2", + "id": 2, "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.", "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", "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.", @@ -326,12 +326,22 @@ "parentTaskId": 3, "parentId": "undefined", "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" }, { - "id": "4", + "id": 4, "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.", "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" }, { - "id": "5", + "id": 5, "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.", "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" + }, + { + "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:' 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:' 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": { "version": "1.0.0", - "lastModified": "2026-05-24T13:46:14.458Z", - "taskCount": 5, - "completedCount": 4, + "lastModified": "2026-05-28T07:34:40.369Z", + "taskCount": 6, + "completedCount": 5, "tags": [ "master" - ] + ], + "created": "2026-05-28T11:47:32.273Z", + "description": "Tasks for master context", + "updated": "2026-05-28T11:48:22.144Z" } } } \ No newline at end of file diff --git a/01 - Architecture/Request Network Integration Constraints.md b/01 - Architecture/Request Network Integration Constraints.md index 426b189..0da0066 100644 --- a/01 - Architecture/Request Network Integration Constraints.md +++ b/01 - Architecture/Request Network Integration Constraints.md @@ -1,10 +1,10 @@ # Request Network Integration — Constraints and Design Implications **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 -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: - 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. - - Builds the transfer transaction client-side (standard ERC-20 transfer) and asks the wallet to sign. -3. RN's webhook (`/v2/request/{id}`-style polling fallback) tells us when the payment lands. + - Builds the two RN-compatible transactions client-side: token `approve(proxy, amount)`, then `transferFromWithReferenceAndFee(...)` on RN's ERC20FeeProxy. +3. RN's webhook tells us when the proxy event lands; Request Network search/status APIs remain the polling fallback. ### Why this is acceptable @@ -34,7 +34,7 @@ So the new flow becomes: ### 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. --- @@ -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 | # | 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 | | 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 | | 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 | +| 7 | Add Cloudflare Worker durable webhook ingress to the roadmap | Backend / platform | +| 8 | Add AML/sanctions adapter behind Transaction Safety Provider | Compliance / backend | Actions 1–4 are *information-gathering* and should run in parallel before any more architectural commitment to RN. Actions 5–6 are blocked on 1–3 confirming RN can actually support this shape. diff --git a/02 - Data Models/Payment.md b/02 - Data Models/Payment.md index 334e9fb..239aede 100644 --- a/02 - Data Models/Payment.md +++ b/02 - Data Models/Payment.md @@ -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.requestNetworkSecurePaymentUrl` | String | no | — | — | — | Request Network secure payment URL. | | `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.webhookPayload` | Mixed | no | — | — | — | Last webhook body. | | `metadata.createdVia` | String | no | — | — | — | Origin marker. | diff --git a/07 - Development/Environment Variables.md b/07 - Development/Environment Variables.md index 70948bd..9dcb5d7 100644 --- a/07 - Development/Environment Variables.md +++ b/07 - Development/Environment Variables.md @@ -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` | | `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 | +| `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_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. | diff --git a/08 - Operations/Handoff - Request Network Confirmation Repair - 2026-05-28.md b/08 - Operations/Handoff - Request Network Confirmation Repair - 2026-05-28.md new file mode 100644 index 0000000..72a9849 --- /dev/null +++ b/08 - Operations/Handoff - Request Network Confirmation Repair - 2026-05-28.md @@ -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. + diff --git a/08 - Operations/Handoff - Request Network In-House Checkout - 2026-05-28.md b/08 - Operations/Handoff - Request Network In-House Checkout - 2026-05-28.md new file mode 100644 index 0000000..b3d2297 --- /dev/null +++ b/08 - Operations/Handoff - Request Network In-House Checkout - 2026-05-28.md @@ -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/`. + +## 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/` instead of the 404-prone `/dashboard/request/`. 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-` 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 | — | diff --git a/08 - Operations/Incident Response.md b/08 - Operations/Incident Response.md index 2e47174..62826fa 100644 --- a/08 - Operations/Incident Response.md +++ b/08 - Operations/Incident Response.md @@ -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. +**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):** 1. Stop routing new intents to Request Network by setting: diff --git a/08 - Operations/Monitoring.md b/08 - Operations/Monitoring.md index 5373018..16cc5fd 100644 --- a/08 - Operations/Monitoring.md +++ b/08 - Operations/Monitoring.md @@ -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 % | | 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 | | 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 | diff --git a/PRD - Request Network In-House Checkout.md b/PRD - Request Network In-House Checkout.md new file mode 100644 index 0000000..9c70bd2 --- /dev/null +++ b/PRD - Request Network In-House Checkout.md @@ -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. diff --git a/PRD - Request Network Migration and Funds Management.md b/PRD - Request Network Migration and Funds Management.md index 508a612..877ac31 100644 --- a/PRD - Request Network Migration and Funds Management.md +++ b/PRD - Request Network Migration and Funds Management.md @@ -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. +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 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. - 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 Priority: P1 @@ -313,11 +345,13 @@ Risk Assessment: 2. Add funds ledger models/services and dry-run backfill report. 3. Implement Request Network secure pay-in flow behind feature flag. 4. Implement signed webhook receiver and reconciliation job. -5. Enable Request Network for limited new checkout cohort. -6. Add release/refund orchestration using ledger gates. -7. Migrate admin/frontend views. -8. Backfill legacy records. -9. Decommission SHKeeper once no active records depend on it. +5. Add Transaction Safety Provider to webhook and reconciliation completion paths. +6. Add durable Request Network webhook ingress, preferably Cloudflare Worker + queue/storage + replay. +7. Enable Request Network for limited new checkout cohort. +8. Add release/refund orchestration using ledger gates. +9. Migrate admin/frontend views. +10. Backfill legacy records. +11. Decommission SHKeeper once no active records depend on it. ## 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? - 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? +- 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 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. - diff --git a/PRD - Wallet, Multichain, Confirmations, AML, Trezor.md b/PRD - Wallet, Multichain, Confirmations, AML, Trezor.md new file mode 100644 index 0000000..0bcff36 --- /dev/null +++ b/PRD - Wallet, Multichain, Confirmations, AML, Trezor.md @@ -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: `
@eip155:#:`. 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'//`). 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:'` 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:', value: , 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.10–0.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. diff --git a/README.md b/README.md index 07f7543..cbe2277 100644 --- a/README.md +++ b/README.md @@ -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]]. > - 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. +> - 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]]. --- diff --git a/Taskmaster/README.md b/Taskmaster/README.md index a52a458..d88e64e 100644 --- a/Taskmaster/README.md +++ b/Taskmaster/README.md @@ -1,6 +1,6 @@ # 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: @@ -10,9 +10,9 @@ node scripts/export-taskmaster-to-obsidian.mjs ## Status Summary -- done: 28 -- in-progress: 3 -- pending: 14 +- done: 44 +- in-progress: 2 +- pending: 8 ## 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-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-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-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-4|4.4]] | Create authorization matrix for REST and Socket.IO | pending | high | 2 | -| [[Tasks/task-4-5|4.5]] | Decide session, passkey, and admin step-up architecture | pending | high | 2 | -| [[Tasks/task-4-6|4.6]] | Specify webhook security and provider adapter contracts | pending | high | 3 | +| [[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 | done | 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 | done | high | 3 | | [[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-9|4.9]] | Create migration and operational runbooks | pending | medium | 8 | +| [[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 | done | medium | 8 | | [[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-2|5.2]] | Build Telegram identity linking and session model | pending | high | 1 | -| [[Tasks/task-5-3|5.3]] | Implement bot command and notification foundation | pending | high | 1, 2 | -| [[Tasks/task-5-4|5.4]] | Build Telegram Mini App shell for marketplace workflows | pending | high | 1, 2 | -| [[Tasks/task-5-5|5.5]] | Add Telegram payment and wallet strategy | pending | high | 2, 4 | +| [[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 | done | high | 1 | +| [[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 | in-progress | high | 1, 2 | +| [[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-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-9|5.9]] | Prepare QA, rollout, analytics, and launch operations | pending | high | 3, 4, 5, 6, 7, 8 | +| [[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 | 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 diff --git a/Taskmaster/Tasks/task-1-1.md b/Taskmaster/Tasks/task-1-1.md index fae2d00..c9cfb45 100644 --- a/Taskmaster/Tasks/task-1-1.md +++ b/Taskmaster/Tasks/task-1-1.md @@ -5,7 +5,7 @@ priority: "medium" depends_on: [] parent_id: "1" 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 diff --git a/Taskmaster/Tasks/task-1-2.md b/Taskmaster/Tasks/task-1-2.md index 9a103d6..e115a08 100644 --- a/Taskmaster/Tasks/task-1-2.md +++ b/Taskmaster/Tasks/task-1-2.md @@ -5,7 +5,7 @@ priority: "medium" depends_on: [] parent_id: "1" 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 diff --git a/Taskmaster/Tasks/task-1-3.md b/Taskmaster/Tasks/task-1-3.md index 580af3b..9c9a90c 100644 --- a/Taskmaster/Tasks/task-1-3.md +++ b/Taskmaster/Tasks/task-1-3.md @@ -5,7 +5,7 @@ priority: "medium" depends_on: [] parent_id: "1" 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 diff --git a/Taskmaster/Tasks/task-1.md b/Taskmaster/Tasks/task-1.md index a4150bd..3faa530 100644 --- a/Taskmaster/Tasks/task-1.md +++ b/Taskmaster/Tasks/task-1.md @@ -5,7 +5,7 @@ priority: "medium" depends_on: [] parent_id: "" 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 diff --git a/Taskmaster/Tasks/task-10.md b/Taskmaster/Tasks/task-10.md new file mode 100644 index 0000000..114c630 --- /dev/null +++ b/Taskmaster/Tasks/task-10.md @@ -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._ diff --git a/Taskmaster/Tasks/task-11.md b/Taskmaster/Tasks/task-11.md new file mode 100644 index 0000000..d4064b4 --- /dev/null +++ b/Taskmaster/Tasks/task-11.md @@ -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._ diff --git a/Taskmaster/Tasks/task-2-1.md b/Taskmaster/Tasks/task-2-1.md index 1235256..1fd9ac0 100644 --- a/Taskmaster/Tasks/task-2-1.md +++ b/Taskmaster/Tasks/task-2-1.md @@ -5,7 +5,7 @@ priority: "high" depends_on: [] parent_id: "2" 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 diff --git a/Taskmaster/Tasks/task-2-2.md b/Taskmaster/Tasks/task-2-2.md index 7e6ff0d..8cbf2fc 100644 --- a/Taskmaster/Tasks/task-2-2.md +++ b/Taskmaster/Tasks/task-2-2.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["1"] parent_id: "2" 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 diff --git a/Taskmaster/Tasks/task-2-3.md b/Taskmaster/Tasks/task-2-3.md index f4dc7b0..5d6f0c4 100644 --- a/Taskmaster/Tasks/task-2-3.md +++ b/Taskmaster/Tasks/task-2-3.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["1"] parent_id: "2" 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 diff --git a/Taskmaster/Tasks/task-2-4.md b/Taskmaster/Tasks/task-2-4.md index a1b291c..09af1b9 100644 --- a/Taskmaster/Tasks/task-2-4.md +++ b/Taskmaster/Tasks/task-2-4.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["1"] parent_id: "2" 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 diff --git a/Taskmaster/Tasks/task-2-5.md b/Taskmaster/Tasks/task-2-5.md index edf5880..6fc65ee 100644 --- a/Taskmaster/Tasks/task-2-5.md +++ b/Taskmaster/Tasks/task-2-5.md @@ -5,7 +5,7 @@ priority: "medium" depends_on: ["1"] parent_id: "2" 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 diff --git a/Taskmaster/Tasks/task-2-6.md b/Taskmaster/Tasks/task-2-6.md index aa71129..857f825 100644 --- a/Taskmaster/Tasks/task-2-6.md +++ b/Taskmaster/Tasks/task-2-6.md @@ -5,7 +5,7 @@ priority: "medium" depends_on: ["1", "4"] parent_id: "2" 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 diff --git a/Taskmaster/Tasks/task-2-7.md b/Taskmaster/Tasks/task-2-7.md index 29bdef5..d67ad26 100644 --- a/Taskmaster/Tasks/task-2-7.md +++ b/Taskmaster/Tasks/task-2-7.md @@ -5,7 +5,7 @@ priority: "medium" depends_on: ["1", "2", "3", "4", "5", "6"] parent_id: "2" 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 diff --git a/Taskmaster/Tasks/task-2.md b/Taskmaster/Tasks/task-2.md index 63f0f09..e5b21cf 100644 --- a/Taskmaster/Tasks/task-2.md +++ b/Taskmaster/Tasks/task-2.md @@ -5,7 +5,7 @@ priority: "high" depends_on: [] parent_id: "" source: "taskmaster" -generated_at: "2026-05-24T07:15:25.199Z" +generated_at: "2026-05-28T11:49:27.076Z" --- # 2 - Implement platform audit remediation plan diff --git a/Taskmaster/Tasks/task-3-1.md b/Taskmaster/Tasks/task-3-1.md index 69dd0b2..e4f8049 100644 --- a/Taskmaster/Tasks/task-3-1.md +++ b/Taskmaster/Tasks/task-3-1.md @@ -5,7 +5,7 @@ priority: "high" depends_on: [] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3-10.md b/Taskmaster/Tasks/task-3-10.md index 56005e0..d398ca8 100644 --- a/Taskmaster/Tasks/task-3-10.md +++ b/Taskmaster/Tasks/task-3-10.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3.8", "3.9"] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3-11.md b/Taskmaster/Tasks/task-3-11.md index 762997d..a8542c8 100644 --- a/Taskmaster/Tasks/task-3-11.md +++ b/Taskmaster/Tasks/task-3-11.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3.6", "3.8", "3.9", "3.10"] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3-12.md b/Taskmaster/Tasks/task-3-12.md index 4bb0886..96c2017 100644 --- a/Taskmaster/Tasks/task-3-12.md +++ b/Taskmaster/Tasks/task-3-12.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3.6", "3.10", "3.11"] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3-13.md b/Taskmaster/Tasks/task-3-13.md new file mode 100644 index 0000000..6c77d1e --- /dev/null +++ b/Taskmaster/Tasks/task-3-13.md @@ -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._ diff --git a/Taskmaster/Tasks/task-3-2.md b/Taskmaster/Tasks/task-3-2.md index 1ef21d4..6409611 100644 --- a/Taskmaster/Tasks/task-3-2.md +++ b/Taskmaster/Tasks/task-3-2.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3.1"] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3-3.md b/Taskmaster/Tasks/task-3-3.md index d078885..251c613 100644 --- a/Taskmaster/Tasks/task-3-3.md +++ b/Taskmaster/Tasks/task-3-3.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3.1"] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3-4.md b/Taskmaster/Tasks/task-3-4.md index e9a4d33..7606496 100644 --- a/Taskmaster/Tasks/task-3-4.md +++ b/Taskmaster/Tasks/task-3-4.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3.3"] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3-5.md b/Taskmaster/Tasks/task-3-5.md index 9bc9349..b21e508 100644 --- a/Taskmaster/Tasks/task-3-5.md +++ b/Taskmaster/Tasks/task-3-5.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3.2"] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3-6.md b/Taskmaster/Tasks/task-3-6.md index 2f66e3c..1f4cfaa 100644 --- a/Taskmaster/Tasks/task-3-6.md +++ b/Taskmaster/Tasks/task-3-6.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3.2"] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3-7.md b/Taskmaster/Tasks/task-3-7.md index 1dd3d20..59feb77 100644 --- a/Taskmaster/Tasks/task-3-7.md +++ b/Taskmaster/Tasks/task-3-7.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3.5", "3.6"] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3-8.md b/Taskmaster/Tasks/task-3-8.md index d871d03..e7a8863 100644 --- a/Taskmaster/Tasks/task-3-8.md +++ b/Taskmaster/Tasks/task-3-8.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3.5"] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3-9.md b/Taskmaster/Tasks/task-3-9.md index 8680b5d..2041baf 100644 --- a/Taskmaster/Tasks/task-3-9.md +++ b/Taskmaster/Tasks/task-3-9.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3.3", "3.7"] parent_id: "3" 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 diff --git a/Taskmaster/Tasks/task-3.md b/Taskmaster/Tasks/task-3.md index 7915ffc..16bae6b 100644 --- a/Taskmaster/Tasks/task-3.md +++ b/Taskmaster/Tasks/task-3.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["2"] parent_id: "" 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 diff --git a/Taskmaster/Tasks/task-4-1.md b/Taskmaster/Tasks/task-4-1.md index 6cf8cd1..fcd01d0 100644 --- a/Taskmaster/Tasks/task-4-1.md +++ b/Taskmaster/Tasks/task-4-1.md @@ -5,7 +5,7 @@ priority: "high" depends_on: [] parent_id: "4" 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 diff --git a/Taskmaster/Tasks/task-4-2.md b/Taskmaster/Tasks/task-4-2.md index 06f2783..dfc84e0 100644 --- a/Taskmaster/Tasks/task-4-2.md +++ b/Taskmaster/Tasks/task-4-2.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["1"] parent_id: "4" 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 diff --git a/Taskmaster/Tasks/task-4-3.md b/Taskmaster/Tasks/task-4-3.md index bb0fe7e..b832d82 100644 --- a/Taskmaster/Tasks/task-4-3.md +++ b/Taskmaster/Tasks/task-4-3.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["2"] parent_id: "4" 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 @@ -28,8 +28,6 @@ Define canonical money movement and legal state transitions before refactor or p ## 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. ## Verification diff --git a/Taskmaster/Tasks/task-4-4.md b/Taskmaster/Tasks/task-4-4.md index c2b5e48..626ad49 100644 --- a/Taskmaster/Tasks/task-4-4.md +++ b/Taskmaster/Tasks/task-4-4.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["2"] parent_id: "4" 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 @@ -28,8 +28,6 @@ Map every endpoint and realtime event to access level, ownership checks, state p ## 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. ## Verification diff --git a/Taskmaster/Tasks/task-4-5.md b/Taskmaster/Tasks/task-4-5.md index c55397b..e18ef4a 100644 --- a/Taskmaster/Tasks/task-4-5.md +++ b/Taskmaster/Tasks/task-4-5.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["2"] parent_id: "4" 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 @@ -28,8 +28,6 @@ Choose browser session model and high-risk admin authentication requirements. ## 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. ## Verification diff --git a/Taskmaster/Tasks/task-4-6.md b/Taskmaster/Tasks/task-4-6.md index ec93da4..1072db7 100644 --- a/Taskmaster/Tasks/task-4-6.md +++ b/Taskmaster/Tasks/task-4-6.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["3"] parent_id: "4" 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 @@ -28,8 +28,6 @@ Define provider-neutral payment interface and signed webhook processing rules. ## 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. ## Verification diff --git a/Taskmaster/Tasks/task-4-7.md b/Taskmaster/Tasks/task-4-7.md index e7a6936..6cb74fa 100644 --- a/Taskmaster/Tasks/task-4-7.md +++ b/Taskmaster/Tasks/task-4-7.md @@ -5,7 +5,7 @@ priority: "medium" depends_on: ["1"] parent_id: "4" 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 diff --git a/Taskmaster/Tasks/task-4-8.md b/Taskmaster/Tasks/task-4-8.md index 948e31c..013127b 100644 --- a/Taskmaster/Tasks/task-4-8.md +++ b/Taskmaster/Tasks/task-4-8.md @@ -5,7 +5,7 @@ priority: "medium" depends_on: ["2", "3", "4", "5", "6", "7"] parent_id: "4" 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 @@ -28,8 +28,6 @@ Choose whether the security-critical backend core remains TypeScript or moves to ## 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. ## Verification diff --git a/Taskmaster/Tasks/task-4-9.md b/Taskmaster/Tasks/task-4-9.md index 4b08e1d..598cdfa 100644 --- a/Taskmaster/Tasks/task-4-9.md +++ b/Taskmaster/Tasks/task-4-9.md @@ -5,7 +5,7 @@ priority: "medium" depends_on: ["8"] parent_id: "4" 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 @@ -28,8 +28,6 @@ Document rollout, rollback, and incident response for the selected backend/funds ## 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. ## Verification diff --git a/Taskmaster/Tasks/task-4.md b/Taskmaster/Tasks/task-4.md index 32d60b7..61ad6db 100644 --- a/Taskmaster/Tasks/task-4.md +++ b/Taskmaster/Tasks/task-4.md @@ -5,7 +5,7 @@ priority: "high" depends_on: [] parent_id: "" 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 diff --git a/Taskmaster/Tasks/task-5-1.md b/Taskmaster/Tasks/task-5-1.md index 4c4b770..de31c94 100644 --- a/Taskmaster/Tasks/task-5-1.md +++ b/Taskmaster/Tasks/task-5-1.md @@ -1,23 +1,23 @@ --- taskmaster_id: "5.1" -status: "in-progress" +status: "done" priority: "high" depends_on: [] parent_id: "5" 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 #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 | Field | Value | | --- | --- | | Taskmaster ID | 5.1 | -| Status | in-progress | +| Status | done | | Priority | high | | Dependencies | None | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | diff --git a/Taskmaster/Tasks/task-5-10.md b/Taskmaster/Tasks/task-5-10.md index 3773159..00d84f9 100644 --- a/Taskmaster/Tasks/task-5-10.md +++ b/Taskmaster/Tasks/task-5-10.md @@ -2,16 +2,15 @@ taskmaster_id: "5.10" status: "done" priority: "high" -depends_on: ["5.2", "5.8"] +depends_on: ["2", "8"] parent_id: "5" source: "taskmaster" -generated_at: "2026-05-24T09:18:26.638Z" -completed_at: "2026-05-24" +generated_at: "2026-05-28T11:49:27.076Z" --- # 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 @@ -20,24 +19,19 @@ completed_at: "2026-05-24" | Taskmaster ID | 5.10 | | Status | done | | Priority | high | -| Dependencies | 5.2, 5.8 | -| Parent | 5 | +| Dependencies | 2, 8 | +| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | ## 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 -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`. - -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. +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. ## Verification -- Backend typecheck passed. -- 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. +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. -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. diff --git a/Taskmaster/Tasks/task-5-2.md b/Taskmaster/Tasks/task-5-2.md index 0dcaeab..61eb60d 100644 --- a/Taskmaster/Tasks/task-5-2.md +++ b/Taskmaster/Tasks/task-5-2.md @@ -1,23 +1,23 @@ --- taskmaster_id: "5.2" -status: "pending" +status: "done" priority: "high" depends_on: ["1"] parent_id: "5" 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 #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 | Field | Value | | --- | --- | | Taskmaster ID | 5.2 | -| Status | pending | +| Status | done | | Priority | high | | Dependencies | 1 | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | diff --git a/Taskmaster/Tasks/task-5-3.md b/Taskmaster/Tasks/task-5-3.md index d2d03ad..60fe0b3 100644 --- a/Taskmaster/Tasks/task-5-3.md +++ b/Taskmaster/Tasks/task-5-3.md @@ -1,23 +1,23 @@ --- taskmaster_id: "5.3" -status: "pending" +status: "done" priority: "high" depends_on: ["1", "2"] parent_id: "5" 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 #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 | Field | Value | | --- | --- | | Taskmaster ID | 5.3 | -| Status | pending | +| Status | done | | Priority | high | | Dependencies | 1, 2 | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | diff --git a/Taskmaster/Tasks/task-5-4.md b/Taskmaster/Tasks/task-5-4.md index 84106b3..5cbfe96 100644 --- a/Taskmaster/Tasks/task-5-4.md +++ b/Taskmaster/Tasks/task-5-4.md @@ -1,23 +1,23 @@ --- taskmaster_id: "5.4" -status: "pending" +status: "in-progress" priority: "high" depends_on: ["1", "2"] parent_id: "5" 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 #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 | Field | Value | | --- | --- | | Taskmaster ID | 5.4 | -| Status | pending | +| Status | in-progress | | Priority | high | | Dependencies | 1, 2 | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | diff --git a/Taskmaster/Tasks/task-5-5.md b/Taskmaster/Tasks/task-5-5.md index 49ab206..e2c5e6e 100644 --- a/Taskmaster/Tasks/task-5-5.md +++ b/Taskmaster/Tasks/task-5-5.md @@ -1,23 +1,23 @@ --- taskmaster_id: "5.5" -status: "pending" +status: "done" priority: "high" depends_on: ["2", "4"] parent_id: "5" 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 #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 | Field | Value | | --- | --- | | Taskmaster ID | 5.5 | -| Status | pending | +| Status | done | | Priority | high | | Dependencies | 2, 4 | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | diff --git a/Taskmaster/Tasks/task-5-6.md b/Taskmaster/Tasks/task-5-6.md index 18ccbb3..04102e1 100644 --- a/Taskmaster/Tasks/task-5-6.md +++ b/Taskmaster/Tasks/task-5-6.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["4", "5"] parent_id: "5" 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 diff --git a/Taskmaster/Tasks/task-5-7.md b/Taskmaster/Tasks/task-5-7.md index aeac626..b6f4c5d 100644 --- a/Taskmaster/Tasks/task-5-7.md +++ b/Taskmaster/Tasks/task-5-7.md @@ -5,7 +5,7 @@ priority: "high" depends_on: ["2", "3", "5"] parent_id: "5" 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 diff --git a/Taskmaster/Tasks/task-5-8.md b/Taskmaster/Tasks/task-5-8.md index f707f83..b118a0b 100644 --- a/Taskmaster/Tasks/task-5-8.md +++ b/Taskmaster/Tasks/task-5-8.md @@ -1,23 +1,23 @@ --- taskmaster_id: "5.8" -status: "pending" +status: "done" priority: "high" depends_on: ["2", "3", "5", "6"] parent_id: "5" 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 #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 | Field | Value | | --- | --- | | Taskmaster ID | 5.8 | -| Status | pending | +| Status | done | | Priority | high | | Dependencies | 2, 3, 5, 6 | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | diff --git a/Taskmaster/Tasks/task-5-9.md b/Taskmaster/Tasks/task-5-9.md index 96f316b..b47dffe 100644 --- a/Taskmaster/Tasks/task-5-9.md +++ b/Taskmaster/Tasks/task-5-9.md @@ -1,23 +1,23 @@ --- taskmaster_id: "5.9" -status: "pending" +status: "done" priority: "high" depends_on: ["3", "4", "5", "6", "7", "8"] parent_id: "5" 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 #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 | Field | Value | | --- | --- | | Taskmaster ID | 5.9 | -| Status | pending | +| Status | done | | Priority | high | | Dependencies | 3, 4, 5, 6, 7, 8 | | Parent | 5 - Deliver Telegram-native app, bot, and wallet experience | diff --git a/Taskmaster/Tasks/task-5.md b/Taskmaster/Tasks/task-5.md index 0e9b00f..c0eab9c 100644 --- a/Taskmaster/Tasks/task-5.md +++ b/Taskmaster/Tasks/task-5.md @@ -5,7 +5,7 @@ priority: "high" depends_on: [] parent_id: "" 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 diff --git a/Taskmaster/Tasks/task-6-1.md b/Taskmaster/Tasks/task-6-1.md new file mode 100644 index 0000000..c5ca80a --- /dev/null +++ b/Taskmaster/Tasks/task-6-1.md @@ -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._ diff --git a/Taskmaster/Tasks/task-6.md b/Taskmaster/Tasks/task-6.md new file mode 100644 index 0000000..d42e4ec --- /dev/null +++ b/Taskmaster/Tasks/task-6.md @@ -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._ diff --git a/Taskmaster/Tasks/task-7.md b/Taskmaster/Tasks/task-7.md new file mode 100644 index 0000000..faa4fbb --- /dev/null +++ b/Taskmaster/Tasks/task-7.md @@ -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._ diff --git a/Taskmaster/Tasks/task-8.md b/Taskmaster/Tasks/task-8.md new file mode 100644 index 0000000..962eda9 --- /dev/null +++ b/Taskmaster/Tasks/task-8.md @@ -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:' 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._ diff --git a/Taskmaster/Tasks/task-9.md b/Taskmaster/Tasks/task-9.md new file mode 100644 index 0000000..392ea5d --- /dev/null +++ b/Taskmaster/Tasks/task-9.md @@ -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:' 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._ diff --git a/Taskmaster/tasks.md b/Taskmaster/tasks.md index 78301d7..bad9cd6 100644 --- a/Taskmaster/tasks.md +++ b/Taskmaster/tasks.md @@ -1,6 +1,6 @@ # 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: @@ -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.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 -- [ ] 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.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 -- [ ] 4.4 - Create authorization matrix for REST and Socket.IO #taskmaster #priority/high #status/pending ⏫ 🆔 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 -- [ ] 4.6 - Specify webhook security and provider adapter contracts #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-6 ⛔ tm-3 +- [x] 4.3 - Specify funds ledger and escrow state machine #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-3 ⛔ tm-2 +- [x] 4.4 - Create authorization matrix for REST and Socket.IO #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-4 ⛔ tm-2 +- [x] 4.5 - Decide session, passkey, and admin step-up architecture #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-5 ⛔ tm-2 +- [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 -- [ ] 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 -- [ ] 4.9 - Create migration and operational runbooks #taskmaster #priority/medium #status/pending 🔼 🆔 tm-4-9 ⛔ tm-8 +- [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 +- [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.1 - Define Telegram product surface and flow map #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5-1 -- [ ] 5.2 - Build Telegram identity linking and session model #taskmaster #priority/high #status/pending ⏫ 🆔 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 -- [ ] 5.4 - Build Telegram Mini App shell for marketplace workflows #taskmaster #priority/high #status/pending ⏫ 🆔 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.1 - Define Telegram product surface and flow map #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-1 +- [x] 5.2 - Build Telegram identity linking and session model #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-2 ⛔ tm-1 +- [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/in-progress ⏫ 🆔 tm-5-4 ⛔ tm-1 ⛔ tm-2 +- [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.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 -- [ ] 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.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 +- [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