docs: ship in-house RN checkout, scope 5 follow-up tasks (#7-11)
In-house Request Network checkout went fully end-to-end on dev today. A real 0.01 USDC payment flowed through wallet connect -> approve -> ERC20FeeProxy.transferFromWithReferenceAndFee -> RN webhook -> TransactionSafetyProvider -> Payment.status=completed -> page success state. Tx 0x494c77a29161b5100d8e0b1ac675f1822955d0bb3633ecdbfafb886f84f2f320. Docs: - New PRD: Wallet, Multichain, Confirmations, AML, Trezor (5 follow-ups, each sized for an independent contributor) - Updated PRD: Request Network In-House Checkout (phases 0..3 done, phase 4 partial, phases 5-6 not started) - Updated handoff: deployed versions, what is working end-to-end, follow-up tasks index Taskmaster: 5 new top-level tasks (#7..#11) covering ephemeral destination wallets, multichain proxy registry + USDC/USDT, runtime confirmation thresholds, optional seller-paid AML screening, and Trezor signing for admin actions. Tasks are scoped fine-grained so each is independent enough for kimi to pick up. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
280
.taskmaster/docs/prd-request-network-in-house-checkout.md
Normal file
280
.taskmaster/docs/prd-request-network-in-house-checkout.md
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
# PRD: Request Network In-House Checkout
|
||||||
|
|
||||||
|
**Status:** Draft — updated after 2026-05-28 dev webhook probe
|
||||||
|
**Date:** 2026-05-27
|
||||||
|
**Related:** `01 - Architecture/Request Network Integration Constraints.md` §1; `PRD - Request Network Migration and Funds Management.md`
|
||||||
|
**Owner:** Backend payments + Frontend
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Problem
|
||||||
|
|
||||||
|
Buyers paying through Request Network (RN) are redirected from Amanat to RN's hosted page at `pay.request.network/?token=…`. That page has three concrete problems:
|
||||||
|
|
||||||
|
1. **Rabby is not supported.** A meaningful portion of our user base pays from Rabby. The hosted page does not detect it (no EIP-6963 enumeration, hard-coded MetaMask/WalletConnect/Coinbase). For those users, checkout fails before a transaction is even attempted.
|
||||||
|
2. **The page is brand-divergent.** Buyers leave the Amanat domain mid-flow, which is a trust and conversion cost we can avoid.
|
||||||
|
3. **The page relies on RN's choice of infrastructure.** Observed in our own probe: their UI wraps the payment in Safe smart accounts + ERC-4337 + a Pimlico paymaster, hitting public BSC RPCs that already rate-limited us once ("RPC endpoint returned too many errors"). We have no control to fix that.
|
||||||
|
|
||||||
|
The core RN protocol is sound. The hosted UI on top of it is the problem.
|
||||||
|
|
||||||
|
### 2026-05-28 reality update
|
||||||
|
|
||||||
|
The first dev BSC probe did not fail because RN stayed silent. It failed because Amanat dropped the provider callback:
|
||||||
|
|
||||||
|
- Test transaction: `0x3a23febd9abd43d7e0851c1ea86c4ceaf08c11098852cb0425fa074e9c88350b`.
|
||||||
|
- On-chain result: successful BSC USDC transfer to Amanat's configured destination wallet.
|
||||||
|
- RN webhook result: RN called `POST /api/payment/request-network/webhook` on `dev.amn.gg` four times from `34.34.233.192`.
|
||||||
|
- Backend result: nginx/backend returned `404` because the handler did not correlate all Request Network identifiers stored on the `Payment` record.
|
||||||
|
- Frontend result: the callback page stayed on the processing state and later hit `429` from 3-second polling.
|
||||||
|
|
||||||
|
The pre-implementation gate therefore changes from "prove RN calls us" to "deploy and smoke-test the webhook correlation repair, callback polling repair, and transaction-safety gate before another paid probe".
|
||||||
|
|
||||||
|
## 2. Goal
|
||||||
|
|
||||||
|
Replace the redirect to RN's hosted page with an Amanat-rendered checkout that:
|
||||||
|
|
||||||
|
- Connects any EVM wallet (Rabby, MetaMask, OKX, Trust, WalletConnect — anything wagmi's `injected()` connector enumerates).
|
||||||
|
- Builds and submits the exact same on-chain calls RN's hosted page makes, so RN's existing webhook fires unchanged.
|
||||||
|
- Stays on `dev.amn.gg` (or prod equivalent) for the entire flow.
|
||||||
|
- Falls back gracefully to the hosted page for buyers who explicitly request it.
|
||||||
|
|
||||||
|
Settlement, webhook handling, and the backend `Payment` lifecycle do not change. Only the buyer-facing checkout surface changes.
|
||||||
|
|
||||||
|
Webhook delivery alone is not a sufficient trust signal. Amanat must run a **Transaction Safety Provider** gate before marking escrow funded. The initial provider checks: transaction hash present, configured confirmation depth, transfer recipient/token/amount match on-chain evidence, and future AML/sanctions provider approval.
|
||||||
|
|
||||||
|
## 3. Non-goals
|
||||||
|
|
||||||
|
- Per-seller multi-chain configuration (covered in `Request Network Integration Constraints.md` §2 — separate PRD).
|
||||||
|
- Per-`(buyer, merchant)` ephemeral wallets / wallet abstraction layer (§3 — separate PRD).
|
||||||
|
- Replacing RN entirely with our own chain watcher (§4 — depends on this PRD's outcome).
|
||||||
|
- Gasless / sponsored transactions for the buyer. Buyer pays own gas via their EOA. We can revisit paymaster integration in a follow-up.
|
||||||
|
|
||||||
|
## 4. Background: what RN's protocol actually requires
|
||||||
|
|
||||||
|
Cold-inspected from a real `$12` BSC payment on RN's hosted page:
|
||||||
|
|
||||||
|
| Item | Value |
|
||||||
|
|---|---|
|
||||||
|
| Proxy contract (BSC, and same address on most EVMs via deterministic CREATE2) | `0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9` |
|
||||||
|
| Function | `transferFromWithReferenceAndFee(address token, address to, uint256 amount, bytes reference, uint256 feeAmount, address feeAddress)` |
|
||||||
|
| Selector | `0xc219a14d` |
|
||||||
|
| Emitted event | `TransferWithReferenceAndFee(token, to, amount, reference, feeAmount, feeAddress)` |
|
||||||
|
| `paymentReference` derivation | `last8Bytes(keccak256(lowercase(requestId + salt + destinationAddress)))` |
|
||||||
|
| Fee config seen on RN's UI | `feeAmount = 0`, `feeAddress = 0x…dEaD` |
|
||||||
|
|
||||||
|
RN's webhook listens for `TransferWithReferenceAndFee`. If we emit it ourselves with the correct `paymentReference`, the webhook fires. The hosted UI is a UI-only convenience — not a settlement requirement.
|
||||||
|
|
||||||
|
## 5. Proposed flow (buyer perspective)
|
||||||
|
|
||||||
|
1. Buyer clicks "Pay with Request Network" on the request page.
|
||||||
|
2. Frontend calls existing `POST /payment/request-network/intents` (unchanged endpoint, expanded response — see §6).
|
||||||
|
3. Frontend navigates to new in-house page: `/checkout/request-network/:paymentId`.
|
||||||
|
4. Page shows: amount, token, chain, recipient (truncated, copyable), countdown timer.
|
||||||
|
5. "Connect wallet" — wagmi `injected()` + `metaMask()` (already configured). Rabby works automatically via EIP-6963.
|
||||||
|
6. Once connected, page checks the buyer's wallet is on the correct chain. If not, prompts `switchChain` (wagmi).
|
||||||
|
7. Page also checks current allowance. If `allowance(buyer, RN_PROXY) >= amount`, skip approve.
|
||||||
|
8. Buyer signs **transaction 1: `USDC.approve(RN_PROXY, amount)`**. UI shows "Approving…" → "Approved".
|
||||||
|
9. Buyer signs **transaction 2: `RN_PROXY.transferFromWithReferenceAndFee(token, dest, amount, ref, 0, 0x…dEaD)`**. UI shows "Submitting payment…" → "Confirmed on-chain".
|
||||||
|
10. Page waits for backend `payment-confirmed` socket event (already emitted on RN webhook → `Payment.status='paid'`). Shows success state.
|
||||||
|
11. Redirect to existing payment-success route.
|
||||||
|
|
||||||
|
Escape hatches surfaced as secondary links on the page:
|
||||||
|
|
||||||
|
- **"Continue on Request Network's hosted page"** → falls through to `securePaymentUrl` (unchanged behavior).
|
||||||
|
- **"Copy payment details"** → exposes destination, amount, token, chain, paymentReference for manual entry into any wallet.
|
||||||
|
|
||||||
|
## 6. Backend changes
|
||||||
|
|
||||||
|
### 6.1 Intent response payload
|
||||||
|
|
||||||
|
Expand `PayInIntentResult` for RN. Today it returns `paymentUrl`, `paymentId`, `providerPaymentId`, `amount`, `config.networks`, `config.allowedTokens`, `raw`. Add:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
inHouseCheckout: {
|
||||||
|
destination: '0x05E280d7f3cA954f37afA8B1E4d2a51D167c573e',
|
||||||
|
tokenAddress: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',
|
||||||
|
tokenSymbol: 'USDC',
|
||||||
|
decimals: 18, // BSC USDC quirk; varies per token+chain
|
||||||
|
chainId: 56,
|
||||||
|
proxyAddress: '0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9',
|
||||||
|
paymentReference: '0xa826e248f5de5463', // 8-byte hex, computed from RN's requestId + salt
|
||||||
|
feeAmount: '0',
|
||||||
|
feeAddress: '0x000000000000000000000000000000000000dEaD',
|
||||||
|
amountWei: '12000000000000000000', // pre-multiplied by decimals, frontend doesn't compute
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 Sources for each field
|
||||||
|
|
||||||
|
| Field | Source |
|
||||||
|
|---|---|
|
||||||
|
| `destination`, `tokenAddress`, `chainId` | Parse `REQUEST_NETWORK_MERCHANT_REFERENCE` env (`address@eip155:chainId#ref:tokenAddr`). Today done once at startup; extract into a helper. |
|
||||||
|
| `decimals` | Token registry lookup. Hardcode the few we care about (USDC/USDT × BSC/ETH/Arb/Polygon) in a constant map; fall back to on-chain `decimals()` if missing. |
|
||||||
|
| `proxyAddress` | Constant per chain. Use canonical `0x0DfbEe14…0aC9` for all EVMs unless RN deploys a non-canonical address (open question — see §10). |
|
||||||
|
| `paymentReference` | Computed from RN's `/v2/secure-payments` response. `salt` is in their `raw` payload. Use `keccak256` + slice-to-8-bytes. |
|
||||||
|
| `feeAmount`, `feeAddress` | Constants matching what RN's hosted UI submits. Verify via cold inspection on each new chain we enable. |
|
||||||
|
| `amountWei` | `BigInt(amount) * 10n ** BigInt(decimals)`. Done backend-side to avoid frontend rounding bugs. |
|
||||||
|
|
||||||
|
### 6.3 Files touched
|
||||||
|
|
||||||
|
- `backend/src/services/payment/requestNetwork/contract.ts` — extend `PayInIntentResult` (or a new `inHouseCheckout` sub-object).
|
||||||
|
- `backend/src/services/payment/requestNetwork/requestNetworkPayInService.ts` — populate the new fields.
|
||||||
|
- `backend/src/services/payment/requestNetwork/merchantReference.ts` (new) — parser for the `address@chain#ref:token` format. Currently this is implicit in env lookups; promote to a named helper.
|
||||||
|
- `backend/src/services/payment/requestNetwork/tokens.ts` (new) — `{ chainId, tokenAddr } → { symbol, decimals }` lookup.
|
||||||
|
- `backend/src/services/payment/requestNetwork/paymentReference.ts` (new) — `computePaymentReference(requestId, salt, destination)`.
|
||||||
|
- Unit tests for each new helper.
|
||||||
|
|
||||||
|
### 6.4 Webhook handler
|
||||||
|
|
||||||
|
The route remains `/api/payment/request-network/webhook`, but the handler must be hardened before more paid probes:
|
||||||
|
|
||||||
|
- Correlate against every RN identifier we persist: `providerPaymentId`, `metadata.requestNetworkRequestId`, `metadata.requestNetworkPaymentReference`, and nested `metadata.requestNetworkData` ids/references.
|
||||||
|
- Reject unsigned or test-header callbacks unless explicit test mode is enabled.
|
||||||
|
- Store raw webhook evidence on the `Payment` record for support/replay.
|
||||||
|
- Call the Transaction Safety Provider before marking `Payment.status='completed'` / `escrowState='funded'`.
|
||||||
|
- Return a successful pending response when safety is not yet satisfied, so the delivery is not lost but escrow is not credited.
|
||||||
|
|
||||||
|
## 7. Frontend changes
|
||||||
|
|
||||||
|
### 7.1 New page
|
||||||
|
|
||||||
|
`frontend/src/pages/checkout/request-network/[paymentId].tsx` (or whatever the router convention is).
|
||||||
|
|
||||||
|
State machine (one component, reducer or zustand):
|
||||||
|
|
||||||
|
```
|
||||||
|
idle
|
||||||
|
→ connecting (wallet not connected)
|
||||||
|
→ wrong-chain (connected, chain mismatch)
|
||||||
|
→ ready (correct chain, allowance unknown)
|
||||||
|
→ checking-allowance
|
||||||
|
→ needs-approve → approving → approve-confirming → ready-to-pay
|
||||||
|
→ ready-to-pay
|
||||||
|
→ paying → pay-confirming → confirmed
|
||||||
|
→ error (with retry)
|
||||||
|
→ expired (timer ran out)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 Reusable parts from SHKeeper
|
||||||
|
|
||||||
|
`frontend/src/web3/components/manual-payment.tsx` already implements: address-with-QR, copy-to-clipboard, countdown timer, localStorage persistence per request, socket-driven status update. Reuse the layout chrome. The wallet-interaction half is new.
|
||||||
|
|
||||||
|
### 7.3 Wagmi calls
|
||||||
|
|
||||||
|
Two contracts. The ERC-20 ABI is already in viem/wagmi. RN proxy ABI is a single function — define it inline.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const RN_PROXY_ABI = [{
|
||||||
|
inputs: [
|
||||||
|
{ name: 'tokenAddress', type: 'address' },
|
||||||
|
{ name: 'to', type: 'address' },
|
||||||
|
{ name: 'amount', type: 'uint256' },
|
||||||
|
{ name: 'paymentReference', type: 'bytes' },
|
||||||
|
{ name: 'feeAmount', type: 'uint256' },
|
||||||
|
{ name: 'feeAddress', type: 'address' },
|
||||||
|
],
|
||||||
|
name: 'transferFromWithReferenceAndFee',
|
||||||
|
outputs: [], stateMutability: 'nonpayable', type: 'function',
|
||||||
|
}] as const;
|
||||||
|
```
|
||||||
|
|
||||||
|
Hooks used:
|
||||||
|
|
||||||
|
- `useAccount`, `useChainId`, `useSwitchChain`
|
||||||
|
- `useReadContract` for `allowance`
|
||||||
|
- `useWriteContract` + `useWaitForTransactionReceipt` for approve and proxy call
|
||||||
|
|
||||||
|
### 7.4 Routing change
|
||||||
|
|
||||||
|
Today, `createRequestNetworkIntent` consumers do `window.location = response.paymentUrl`. Replace with `router.push('/checkout/request-network/' + response.paymentId)`. Keep `response.paymentUrl` available so the in-house page can render the escape-hatch link.
|
||||||
|
|
||||||
|
### 7.5 Files touched
|
||||||
|
|
||||||
|
- `frontend/src/pages/checkout/request-network/[paymentId].tsx` — new page.
|
||||||
|
- `frontend/src/web3/components/rn-in-house-checkout.tsx` — new component holding the state machine.
|
||||||
|
- `frontend/src/web3/contracts/rn-fee-proxy.ts` — ABI + address-per-chain constants.
|
||||||
|
- `frontend/src/sections/request/components/buyer-steps/…` — change the existing RN button handler from `window.location` to `router.push`.
|
||||||
|
- Tests/Storybook for the new component.
|
||||||
|
|
||||||
|
## 8. Acceptance criteria
|
||||||
|
|
||||||
|
1. A buyer using **Rabby** can complete an RN payment end-to-end on `dev.amn.gg` without leaving the domain.
|
||||||
|
2. The two on-chain transactions emit a `TransferWithReferenceAndFee` event with the same `paymentReference` RN's hosted page would have produced.
|
||||||
|
3. RN's existing webhook fires on the event and the `Payment` doc transitions to `completed` / `escrowState='funded'` after safety approval.
|
||||||
|
4. If buyer connects on the wrong chain, they see a one-click "Switch network" CTA.
|
||||||
|
5. If buyer already has sufficient allowance, the approve step is skipped.
|
||||||
|
6. If the buyer abandons the page, returning to it restores their state from localStorage and resumes from the correct step.
|
||||||
|
7. "Continue on Request Network's hosted page" link is visible on the in-house page and works exactly like today's redirect.
|
||||||
|
8. Page handles tx failure (user reject, insufficient gas, RPC error) with a clear retry path that does not corrupt the `Payment` doc.
|
||||||
|
9. Existing non-RN payment flows (SHKeeper, others) are untouched.
|
||||||
|
|
||||||
|
## 9. Out of scope (explicit non-decisions)
|
||||||
|
|
||||||
|
- Multi-chain at checkout (BSC + Arb + ETH together) — needs the per-seller `acceptedChains` config; separate PRD.
|
||||||
|
- WalletConnect integration — currently disabled in `web3/config.ts` for SSR reasons; not regressed but not added either.
|
||||||
|
- Migration plan to remove RN entirely — kept as `§4` open option in the architecture doc.
|
||||||
|
- Mobile Mini App rendering of the checkout (different surface — handled in Task 5.4).
|
||||||
|
|
||||||
|
## 10. Open questions for review
|
||||||
|
|
||||||
|
These are the items we should discuss with the second developer before starting implementation.
|
||||||
|
|
||||||
|
1. **Proxy address universality.** Is `0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9` the RN ERC20FeeProxy address on **every** chain we plan to support (BSC, Arb, ETH mainnet, Polygon, Base)? We confirmed BSC + Arbitrum from RN's payments-subgraph repo. The other chains need explicit confirmation — preferably an on-chain probe per chain.
|
||||||
|
2. **API pricing for hosted-UI vs API-only.** RN's pricing model may assume hosted-UI usage. If we use them as a notification primitive only, are we still in their pricing terms? Worth a direct question to RN account management.
|
||||||
|
3. **Approval UX.** RN's hosted UI uses `approve(spender, MAX_UINT256)` for gas efficiency. Some Amanat users have voiced concern in past audits about unbounded approvals. Options:
|
||||||
|
- Mirror RN: `MAX_UINT256` (best UX, repeat payments don't need re-approve).
|
||||||
|
- Exact-amount: `approve(spender, amount)`. Slightly worse UX (every payment requires an approve), better security posture.
|
||||||
|
- Recommend: exact-amount by default, opt-in "remember this approval" for power users. Discuss.
|
||||||
|
4. **Tokens with non-standard ERC-20 behavior.** USDT on Ethereum mainnet famously requires `approve(0)` before changing a non-zero allowance. We need to handle this if we add USDT-ETH later. Not relevant on day one (BSC config is USDC), but worth flagging now.
|
||||||
|
5. **Cancel and timeout semantics.** Today the `Payment` doc transitions on the webhook. If the buyer signs the approve but bails on the proxy call, the doc sits in `pending` forever. Options:
|
||||||
|
- 30-minute TTL on the `pending` doc (existing partial unique index would let a re-attempt succeed).
|
||||||
|
- "Cancel intent" button on the in-house page that calls a new backend endpoint to mark the doc `cancelled`.
|
||||||
|
- Both. Discuss.
|
||||||
|
6. **Manual reconciliation.** If a buyer pays the correct amount to the correct destination but bypasses the proxy (e.g., raw `transfer`), no event fires and no webhook arrives. They'll think they paid but our system won't know. Today RN's hosted UI prevents this; our in-house UI inherits the same risk only if we add a "raw transfer" escape hatch — which we won't. But: should we proactively detect orphan transfers (chain watcher) and surface them in support? Out of scope for v1.
|
||||||
|
7. **Feature flag and rollout.** Ship behind a flag and A/B against the current redirect for one week of dev usage? Or hard-cut once acceptance criteria pass? Recommend A/B for at least one full release cycle.
|
||||||
|
8. **Telemetry.** What events do we instrument so we can prove the in-house page outperforms the redirect on conversion? Suggested: `rn_checkout_opened`, `rn_wallet_connected`, `rn_approve_signed`, `rn_pay_signed`, `rn_pay_confirmed`, `rn_pay_failed{reason}`, `rn_escape_to_hosted_clicked`.
|
||||||
|
|
||||||
|
## 11. Risks
|
||||||
|
|
||||||
|
- **Webhook handling failure.** RN delivered the 2026-05-28 dev webhook, but Amanat returned `404`. A deployed correlation fix and smoke test are now the load-bearing gate before another paid probe.
|
||||||
|
- **Webhook durability.** The main app is too unstable to be the only callback landing zone. Put a Cloudflare Worker in front of Request Network webhooks to durably store raw delivery evidence, forward to the backend, and replay after outages.
|
||||||
|
- **False-positive payment credit.** A signed provider event must not be enough to fund escrow. Transaction Safety Provider gates completion on on-chain evidence, confirmation depth, transfer matching, and future AML/sanctions checks.
|
||||||
|
- **Chain-specific divergences.** RN may have deployed non-canonical proxy contracts on some chains. We mitigate by hard-coding per-chain proxy addresses and treating "unknown chain → fall back to hosted page" as the safe default.
|
||||||
|
- **Wallet support drift.** EIP-6963 is mature but not universal. We rely on wagmi's `injected()` connector enumeration; if a wallet doesn't implement EIP-6963, it falls into the generic `window.ethereum` slot. Acceptable.
|
||||||
|
- **Buyer signs approve, then we change ABI before they sign the proxy call.** Not really a risk if both txs are in the same session, but worth a smoke test on a long-lived session.
|
||||||
|
|
||||||
|
## 12. Implementation phases
|
||||||
|
|
||||||
|
Roughly two weeks of checkout work, now gated on confirmation reliability repair.
|
||||||
|
|
||||||
|
| Phase | Work | Gate |
|
||||||
|
|---|---|---|
|
||||||
|
| 0 — Probe | Fire one real dev BSC payment and inspect nginx/backend logs | Completed: RN webhook reached nginx/backend; app returned `404` |
|
||||||
|
| 0A — Confirmation repair | Deploy correlation fix, callback polling fix, signed-webhook smoke test, and Transaction Safety Provider | Unsigned/test callbacks rejected unless explicitly enabled; real webhook can find the `Payment` |
|
||||||
|
| 1 — Backend | Expand intent response with `inHouseCheckout` fields; add helpers and tests | Existing RN smoke test still passes; new unit tests pass |
|
||||||
|
| 2 — Frontend skeleton | New page + state machine + wallet-connect; no on-chain calls yet, mocked confirmations | Local clickthrough on `dev.amn.gg` with Rabby connected |
|
||||||
|
| 3 — On-chain wiring | Real `approve` + `transferFromWithReferenceAndFee` calls; allowance check; chain-switch | One real end-to-end payment on dev BSC, webhook fires, `Payment.status='completed'`, safety approved |
|
||||||
|
| 4 — Hardening | Error handling, timer, persistence, telemetry, escape-hatch link | Acceptance criteria 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: <https://github.com/RequestNetwork/requestNetwork/blob/master/packages/advanced-logic/specs/payment-network-erc20-fee-proxy-contract-0.1.0.md>
|
||||||
|
- Arbitrum proxy deployment: <https://github.com/RequestNetwork/payments-subgraph/blob/main/subgraph.arbitrum-one.yaml>
|
||||||
|
- Architecture constraints doc: `01 - Architecture/Request Network Integration Constraints.md`
|
||||||
|
- Previous RN work: `PRD - Request Network Migration and Funds Management.md`
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"master": {
|
"master": {
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": 1,
|
||||||
"title": "Stabilize Mermaid diagram rendering across documentation vault",
|
"title": "Stabilize Mermaid diagram rendering across documentation vault",
|
||||||
"description": "Correct Mermaid syntax/rendering issues across the documentation vault and validate all Mermaid blocks.",
|
"description": "Correct Mermaid syntax/rendering issues across the documentation vault and validate all Mermaid blocks.",
|
||||||
"details": "Source PRD: .taskmaster/docs/prd-mermaid-diagram-rendering-stabilization.md. Scope covered 57 Mermaid blocks and 11 failing blocks. The source PRD records that all targeted files now pass mmdc parse validation and the full vault sweep passes.",
|
"details": "Source PRD: .taskmaster/docs/prd-mermaid-diagram-rendering-stabilization.md. Scope covered 57 Mermaid blocks and 11 failing blocks. The source PRD records that all targeted files now pass mmdc parse validation and the full vault sweep passes.",
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "2",
|
"id": 2,
|
||||||
"title": "Implement platform audit remediation plan",
|
"title": "Implement platform audit remediation plan",
|
||||||
"description": "Address the code-backed security and consistency issues identified in the 2026-05-24 platform audit remediation PRD.",
|
"description": "Address the code-backed security and consistency issues identified in the 2026-05-24 platform audit remediation PRD.",
|
||||||
"details": "Source PRD: .taskmaster/docs/prd-platform-audit-remediation-plan-2026-05-24.md. Target backend hardening first, then documentation/runtime alignment. Delivery order suggested by PRD: security/auth, rate limiting, passkeys, Web3 verification, socket hardening, dispute hold controls, docs/API alignment.",
|
"details": "Source PRD: .taskmaster/docs/prd-platform-audit-remediation-plan-2026-05-24.md. Target backend hardening first, then documentation/runtime alignment. Delivery order suggested by PRD: security/auth, rate limiting, passkeys, Web3 verification, socket hardening, dispute hold controls, docs/API alignment.",
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "3",
|
"id": 3,
|
||||||
"title": "Migrate payment architecture toward Request Network and internal funds management",
|
"title": "Migrate payment architecture toward Request Network and internal funds management",
|
||||||
"description": "Plan and implement provider-neutral payment flows, Request Network pay-in support, funds ledger, webhook reconciliation, release/refund orchestration, UI migration, and SHKeeper decommissioning.",
|
"description": "Plan and implement provider-neutral payment flows, Request Network pay-in support, funds ledger, webhook reconciliation, release/refund orchestration, UI migration, and SHKeeper decommissioning.",
|
||||||
"details": "Source PRD: .taskmaster/docs/prd-request-network-migration-and-funds-management.md. The PRD recommends phased migration behind a provider adapter, Secure Payment Pages first, platform-controlled escrow/payee destination, and a first-class internal funds ledger before release/refund enforcement.\n\nPost-completion update: Task 3 now includes a CI-safe focused verification command for the provider-neutral payment migration plus optional Trezor safekeeping. Trezor safekeeping is optional by default via TREZOR_SAFEKEEPING_REQUIRED=false and only gates release/refund confirmation when explicitly enabled. Vault references: 04 - Flows/Trezor Safekeeping Flow.md, 03 - API Reference/Trezor API.md, and 08 - Operations/Payment and Trezor Verification Report.md.",
|
"details": "Source PRD: .taskmaster/docs/prd-request-network-migration-and-funds-management.md. The PRD recommends phased migration behind a provider adapter, Secure Payment Pages first, platform-controlled escrow/payee destination, and a first-class internal funds ledger before release/refund enforcement.\n\nPost-completion update: Task 3 now includes a CI-safe focused verification command for the provider-neutral payment migration plus optional Trezor safekeeping. Trezor safekeeping is optional by default via TREZOR_SAFEKEEPING_REQUIRED=false and only gates release/refund confirmation when explicitly enabled. Vault references: 04 - Flows/Trezor Safekeeping Flow.md, 03 - API Reference/Trezor API.md, and 08 - Operations/Payment and Trezor Verification Report.md.",
|
||||||
@@ -326,12 +326,22 @@
|
|||||||
"parentTaskId": 3,
|
"parentTaskId": 3,
|
||||||
"parentId": "undefined",
|
"parentId": "undefined",
|
||||||
"updatedAt": "2026-05-24T06:51:00.615Z"
|
"updatedAt": "2026-05-24T06:51:00.615Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 13,
|
||||||
|
"title": "Add durable RN webhook ingress and transaction safety",
|
||||||
|
"description": "Roadmap follow-up from the 2026-05-28 dev payment probe: Request Network delivered the webhook but Amanat returned 404. Add Cloudflare Worker durable webhook ingress with storage/replay and keep backend Transaction Safety Provider checks as the trust boundary before marking escrow funded.",
|
||||||
|
"details": "",
|
||||||
|
"status": "pending",
|
||||||
|
"dependencies": [],
|
||||||
|
"parentTaskId": 3,
|
||||||
|
"parentId": "undefined"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"updatedAt": "2026-05-24T07:04:01.906Z"
|
"updatedAt": "2026-05-24T07:04:01.906Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "4",
|
"id": 4,
|
||||||
"title": "Define backend security and refactor strategy from latest audit",
|
"title": "Define backend security and refactor strategy from latest audit",
|
||||||
"description": "Convert the backend stack security/refactor assessment into concrete architecture decisions, documentation deliverables, and developer handoff criteria.",
|
"description": "Convert the backend stack security/refactor assessment into concrete architecture decisions, documentation deliverables, and developer handoff criteria.",
|
||||||
"details": "Source audit: .taskmaster/docs/audit-backend-stack-security-and-refactor-assessment-2026-05-24.md. This task is advisory/architecture-focused and should run in parallel with immediate hardening. It should produce the decision artifacts needed before any backend-core rewrite or provider migration is started.",
|
"details": "Source audit: .taskmaster/docs/audit-backend-stack-security-and-refactor-assessment-2026-05-24.md. This task is advisory/architecture-focused and should run in parallel with immediate hardening. It should produce the decision artifacts needed before any backend-core rewrite or provider migration is started.",
|
||||||
@@ -473,7 +483,7 @@
|
|||||||
"updatedAt": "2026-05-24T07:23:44.643Z"
|
"updatedAt": "2026-05-24T07:23:44.643Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "5",
|
"id": 5,
|
||||||
"title": "Deliver Telegram-native app, bot, and wallet experience",
|
"title": "Deliver Telegram-native app, bot, and wallet experience",
|
||||||
"description": "Create a Telegram bot plus Mini App surface so users can complete Amanat buyer, seller, escrow, chat, dispute, payment, release/refund, and support workflows from inside Telegram.",
|
"description": "Create a Telegram bot plus Mini App surface so users can complete Amanat buyer, seller, escrow, chat, dispute, payment, release/refund, and support workflows from inside Telegram.",
|
||||||
"details": "Source PRD: .taskmaster/docs/prd-telegram-native-app-bot-wallet.md. Keep this as a separate delivery track from security remediation and Request Network migration. Identity, bot navigation, Mini App shell, and notifications can start behind flags; wallet/payment crediting and release/refund actions must use canonical backend authorization, provider adapter, funds ledger, escrow state machine, idempotency, and dispute holds.",
|
"details": "Source PRD: .taskmaster/docs/prd-telegram-native-app-bot-wallet.md. Keep this as a separate delivery track from security remediation and Request Network migration. Identity, bot navigation, Mini App shell, and notifications can start behind flags; wallet/payment crediting and release/refund actions must use canonical backend authorization, provider adapter, funds ledger, escrow state machine, idempotency, and dispute holds.",
|
||||||
@@ -635,16 +645,98 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"updatedAt": "2026-05-24T13:46:14.458Z"
|
"updatedAt": "2026-05-24T13:46:14.458Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"title": "Request Network in-house checkout (Rabby-supporting)",
|
||||||
|
"description": "Replace the redirect to pay.request.network with an Amanat-rendered checkout page that submits the same on-chain calls as RN's hosted UI, so RN's webhook fires unchanged but buyers stay on amn.gg and Rabby works.",
|
||||||
|
"details": "See PRD: nick-doc/.taskmaster/docs/prd-request-network-in-house-checkout.md (summary at nick-doc/PRD - Request Network In-House Checkout.md). Status: draft, pending review with second developer. Approach: replicate the two on-chain calls (approve + RN_FEE_PROXY.transferFromWithReferenceAndFee) using wagmi v2 with existing injected()/metaMask() connectors (Rabby works via EIP-6963). Hard-known: proxy 0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9, selector 0xc219a14d, paymentRef = last8Bytes(keccak256(requestId+salt+dest)), feeAmount=0, feeAddress=0x...dEaD. Backend: extend POST /payment/request-network/intents response with inHouseCheckout object (destination, tokenAddress, decimals, chainId, proxyAddress, paymentReference, feeAmount, feeAddress, amountWei). Frontend: new page /checkout/request-network/:paymentId with state machine reusing manual-payment.tsx layout chrome, hosted-page link kept as escape hatch. Implementation gated on a $0.50 cold probe on dev BSC to confirm RN's webhook fires for an externally-built tx. Out of scope: per-seller multi-chain config (§2), ephemeral wallets (§3), full RN removal (§4), gasless. Open questions in PRD §10.",
|
||||||
|
"testStrategy": "",
|
||||||
|
"status": "done",
|
||||||
|
"dependencies": [],
|
||||||
|
"priority": "high",
|
||||||
|
"subtasks": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"title": "Deploy confirmation repair before next paid probe",
|
||||||
|
"description": "2026-05-28 dev BSC transaction succeeded and RN delivered four webhooks, but Amanat returned 404 due Request Network reference-correlation mismatch. Before another paid payment test, deploy the backend correlation fix, callback polling fix, signed-webhook smoke test, and Transaction Safety Provider gate; then repeat the probe and inspect safety decision state.",
|
||||||
|
"details": "",
|
||||||
|
"status": "done",
|
||||||
|
"dependencies": [],
|
||||||
|
"parentTaskId": 6,
|
||||||
|
"updatedAt": "2026-05-28T07:34:40.368Z",
|
||||||
|
"parentId": "undefined"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updatedAt": "2026-05-28T07:34:40.368Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"title": "Per-(buyer, sellerOffer) ephemeral RN destination wallets",
|
||||||
|
"description": "Replace the single shared Amanat destination wallet with a per-(buyerId, sellerOfferId) HD-derived address sent to Request Network on intent creation, plus sweep-on-approval and an admin UI.",
|
||||||
|
"details": "See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §1. Files: new backend/src/services/payment/wallets/derivedDestinations.ts (getDestinationFor(buyerId, sellerOfferId) → {address, derivationPath, chainId}); Payment schema add metadata.derivedDestination; requestNetworkPayInService.ts override destinationId before POST /v2/secure-payments (we confirmed RN accepts different destinations per intent); new sweep cron + admin manual-trigger endpoint gated on Transaction Safety Provider; admin UI at /dashboard/admin/derived-destinations with address, balance, last sweep tx (BscScan link), ownership status. Open questions to settle first: HD vs disposable EOAs vs smart-forwarder (recommended HD); sweep cadence (recommended immediate); granularity (recommended per-(buyer, seller), not per-payment); re-use vs rotate after sweep. KMS-rooted seed; backend never holds raw private keys; signing via KMS API (Task #11 Trezor flow is the longer-term replacement). Acceptance: two payments from one buyer to two sellers land on two different addresses; RN webhook fires for both; sweep is idempotent; master seed never leaves KMS.",
|
||||||
|
"testStrategy": "",
|
||||||
|
"status": "pending",
|
||||||
|
"dependencies": [],
|
||||||
|
"priority": "high",
|
||||||
|
"subtasks": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"title": "Multichain RN proxy registry + USDC/USDT support",
|
||||||
|
"description": "Probe and persist RN ERC20FeeProxy addresses on BSC/Arb/ETH/Polygon/Base, add USDC + USDT token entries with correct decimals per chain, and surface an admin networks page. Include the USDT-mainnet approve(0) reset quirk in the frontend approve step.",
|
||||||
|
"details": "See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §2. Tasks: new backend/scripts/probe-rn-chains.ts that walks each chain in supported-chains.json and verifies the canonical 0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9 proxy is the real RN proxy via a known view fn (CREATE2 is deterministic, but verify); promote backend/src/services/payment/requestNetwork/tokens.ts to load from JSON + admin override; add USDT entries on all 5 chains (BSC USDT 18-dec quirk, mainnet/Arb/Polygon/Base USDT 6-dec); buildInHouseCheckoutBlock returns reason='unsupported_chain:<id>' for unknowns; new admin route GET /api/admin/rn/networks + frontend page /dashboard/admin/networks rendering the registry with per-row 'probe again'. Frontend approve flow: if buyer is on Ethereum mainnet AND token is USDT AND current allowance > 0, do approve(spender, 0) first then approve(spender, amount). Acceptance: probe succeeds on at least BSC/Arb/Polygon/ETH/Base; one paid probe on BSC USDT end-to-end; mainnet USDT approve(0) reset works; admin page reflects registry. Dependencies: none — runs in parallel with #9. This is task #8 in the PRD.",
|
||||||
|
"testStrategy": "",
|
||||||
|
"status": "pending",
|
||||||
|
"dependencies": [],
|
||||||
|
"priority": "high",
|
||||||
|
"subtasks": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"title": "Per-chain confirmation thresholds + admin UI",
|
||||||
|
"description": "Make TransactionSafetyProvider's confirmation threshold tunable at runtime per chain via admin UI, with an awaiting-confirmation payments view that shows live confirmations vs threshold.",
|
||||||
|
"details": "See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §3. Today TRANSACTION_SAFETY_MIN_CONFIRMATIONS is a global env var, default 12, baked in until redeploy. Move to runtime config: new Setting docs keyed 'confirmation_threshold:<chainId>' or extend existing model; cache reads in transactionSafetyProvider.ts for 30s; GET/PATCH /api/admin/settings/confirmation-thresholds (auth: admin); new admin page /dashboard/admin/confirmation-thresholds (table: chain, current, recommended default, edit-in-place with confirm dialog, audit log of changes); new admin page /dashboard/admin/payments/awaiting-confirmation (payments where escrowState !== 'funded' AND metadata.transactionSafety.lastCheck.status === 'pending'; for each show tx hash linked to explorer, current confirmations via 12s poll on BSC, threshold, ETA). Acceptance: admin lowers BSC threshold from 12 to 3 on dev, next webhook honors new value within 30s; awaiting-confirmation table updates live; audit log records every change. Non-goals: per-asset, per-seller thresholds. Dependencies: none. This is task #9 in the PRD.",
|
||||||
|
"testStrategy": "",
|
||||||
|
"status": "pending",
|
||||||
|
"dependencies": [],
|
||||||
|
"priority": "medium",
|
||||||
|
"subtasks": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 10,
|
||||||
|
"title": "Optional AML screening on incoming payments (seller-paid)",
|
||||||
|
"description": "Turn the existing aml_screening placeholder in TransactionSafetyProvider into a real Chainalysis (or equivalent) Address Screening call that the seller opts into per-offer and pays the per-check cost for.",
|
||||||
|
"details": "See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §4. Default provider recommendation: Chainalysis Address Screening (cheapest, simplest). Files: new backend/src/services/payment/safety/amlProvider.ts interface + chainalysisProvider.ts impl behind env TRANSACTION_SAFETY_AML_PROVIDER=chainalysis with API_KEY in KMS; transactionSafetyProvider's evaluateAmlPlaceholder() becomes real, persists raw provider response on Payment.metadata.amlResult; Offer schema add requireAmlCheck + amlBlockOnFailure booleans; offer-edit UI toggle 'Require AML on incoming payments ($X per payment, paid by you)'; admin global config UI for provider selection + API key rotation + per-chain enabled flag; cost accounting: deduct per-check cost from seller's escrow on completion as a separate ledger line item, surfaced on payment-details. Open questions before code: pick provider (Chainalysis vs TRM vs Elliptic — need 1-page comparison of cost/latency/coverage); failure mode (fail-closed only when seller opted in AND amlBlockOnFailure=true, else warn/log); cost batching cadence. Acceptance: seller toggles AML on an offer; incoming payment triggers a real Chainalysis call; sanctions verdict blocks the safety gate; clean verdict passes; seller's settled amount reduced by check cost; admin can rotate API key without redeploy; provider-down + amlBlockOnFailure=true keeps payment pending with provider_unavailable reason. Dependencies: none. This is task #10 in the PRD.",
|
||||||
|
"testStrategy": "",
|
||||||
|
"status": "pending",
|
||||||
|
"dependencies": [],
|
||||||
|
"priority": "medium",
|
||||||
|
"subtasks": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 11,
|
||||||
|
"title": "Trezor signing for admin actions (release/refund/sweep)",
|
||||||
|
"description": "Replace the hot-key admin signing flow with a WebUSB-based Trezor flow so the backend never holds a private key. All admin-side txes are built backend, signed via Trezor in the browser, broadcast from the browser.",
|
||||||
|
"details": "See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §5. Lib: @trezor/connect-web (WebUSB; Chromium-only — Firefox users need Trezor Bridge native helper). Files: new frontend/src/web3/trezor/trezorConnector.ts wrapping @trezor/connect-web; existing admin actions (release/refund/sweep when #7 lands) get a 'Sign with Trezor' button that flows: POST /api/admin/actions/build-tx → returns unsigned tx bytes → send to Trezor → sign → wagmi sendTransaction broadcasts → POST /api/admin/actions/confirm-tx with hash; admin settings page to register Trezor address(es) (backend rejects signatures from unauthorized devices); audit log on every Trezor-signed action; break-glass hot-key path requires explicit admin toggle, expires after 1h, fires Telegram alarm. Open questions: m-of-n multi-admin signing — default single-signer for v1; Trezor One vs Model T — lib abstracts; fallback when Trezor unavailable — break-glass with alarm. Acceptance: admin registers Trezor address; release flow uses Trezor end-to-end; backend rejects signatures from unregistered devices; audit log captures admin user + Trezor addr + tx hash + before/after escrow state; break-glass works and alarms. Non-goals: mobile Trezor flow, buyer-side Trezor (buyer uses wagmi injected). Dependencies: task #7 (ephemeral wallets) for the sweep step — but task #11 can ship the release/refund flows first. This is task #11 in the PRD.",
|
||||||
|
"testStrategy": "",
|
||||||
|
"status": "pending",
|
||||||
|
"dependencies": [],
|
||||||
|
"priority": "high",
|
||||||
|
"subtasks": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"lastModified": "2026-05-24T13:46:14.458Z",
|
"lastModified": "2026-05-28T07:34:40.369Z",
|
||||||
"taskCount": 5,
|
"taskCount": 6,
|
||||||
"completedCount": 4,
|
"completedCount": 5,
|
||||||
"tags": [
|
"tags": [
|
||||||
"master"
|
"master"
|
||||||
]
|
],
|
||||||
|
"created": "2026-05-28T11:47:32.273Z",
|
||||||
|
"description": "Tasks for master context",
|
||||||
|
"updated": "2026-05-28T11:48:22.144Z"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
# Request Network Integration — Constraints and Design Implications
|
# Request Network Integration — Constraints and Design Implications
|
||||||
|
|
||||||
**Date:** 2026-05-27
|
**Date:** 2026-05-27
|
||||||
**Status:** Active concerns; mitigations partially designed, partially blocked on RN clarifications
|
**Status:** Active concerns; 2026-05-28 probe confirmed RN webhook delivery but exposed Amanat confirmation handling gaps
|
||||||
**Owners:** Backend payments (Amanat), product
|
**Owners:** Backend payments (Amanat), product
|
||||||
|
|
||||||
This document captures four payment-flow issues that surfaced while integrating Request Network (RN) into the Amanat escrow stack. Each one is either a show-stopper or a non-trivial architectural constraint. Listed in priority order.
|
This document captures payment-flow issues that surfaced while integrating Request Network (RN) into the Amanat escrow stack. Each one is either a show-stopper or a non-trivial architectural constraint. Listed in priority order.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -24,8 +24,8 @@ So the new flow becomes:
|
|||||||
2. **We render our own checkout screen** that:
|
2. **We render our own checkout screen** that:
|
||||||
- Shows the buyer the wallet address to pay to (the destination resolved from the merchant reference / chain / token).
|
- Shows the buyer the wallet address to pay to (the destination resolved from the merchant reference / chain / token).
|
||||||
- Lets the buyer connect *any* wallet — Rabby, MetaMask, OKX, Phantom-bridged, WalletConnect.
|
- Lets the buyer connect *any* wallet — Rabby, MetaMask, OKX, Phantom-bridged, WalletConnect.
|
||||||
- Builds the transfer transaction client-side (standard ERC-20 transfer) and asks the wallet to sign.
|
- Builds the two RN-compatible transactions client-side: token `approve(proxy, amount)`, then `transferFromWithReferenceAndFee(...)` on RN's ERC20FeeProxy.
|
||||||
3. RN's webhook (`/v2/request/{id}`-style polling fallback) tells us when the payment lands.
|
3. RN's webhook tells us when the proxy event lands; Request Network search/status APIs remain the polling fallback.
|
||||||
|
|
||||||
### Why this is acceptable
|
### Why this is acceptable
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ So the new flow becomes:
|
|||||||
|
|
||||||
### Open
|
### Open
|
||||||
|
|
||||||
- Need to confirm RN actually settles a payment that arrives from a *transaction we built*, not from their hosted page. Their pricing/fees may be tied to going through their UI. **Test required** before committing to this path.
|
- Need to confirm RN settles a payment that arrives from a *proxy transaction we built*, not from their hosted page. The 2026-05-28 probe confirms RN webhook delivery to Amanat, but the app returned `404`; repeat the probe only after the confirmation repair is deployed.
|
||||||
- Need a fallback for the buyer who insists on the RN hosted UI (some users will already have the link copied). Keep `securePaymentUrl` exposed as a "advanced / pay with RN" link.
|
- Need a fallback for the buyer who insists on the RN hosted UI (some users will already have the link copied). Keep `securePaymentUrl` exposed as a "advanced / pay with RN" link.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -143,15 +143,36 @@ Until #5 is confirmed, the rest is just paper architecture.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 5. Webhook durability and transaction safety are P0 before more paid probes
|
||||||
|
|
||||||
|
### What the 2026-05-28 probe proved
|
||||||
|
|
||||||
|
The dev test transaction `0x3a23febd9abd43d7e0851c1ea86c4ceaf08c11098852cb0425fa074e9c88350b` succeeded on BSC. RN then called `POST /api/payment/request-network/webhook` on `dev.amn.gg` four times from `34.34.233.192`. Amanat returned `404` because backend correlation looked up the wrong reference shape; the `Payment` record held RN request/payment-reference values that the handler did not search.
|
||||||
|
|
||||||
|
### Design implication
|
||||||
|
|
||||||
|
Do not treat the main Express app as the only webhook landing zone, and do not treat a signed provider callback as enough to credit escrow.
|
||||||
|
|
||||||
|
### Required mitigation
|
||||||
|
|
||||||
|
1. **Correlation repair:** lookup Request Network payments by every persisted reference shape, including `providerPaymentId`, top-level RN request id/payment reference, and nested raw RN data.
|
||||||
|
2. **Callback repair:** payment callback polling must unwrap the backend response shape, clear polling after terminal states, and avoid a 3-second loop that self-rate-limits.
|
||||||
|
3. **Transaction Safety Provider:** completion must pass configured safety checks: transaction hash present, minimum confirmations, token/recipient/amount transfer match, and future AML/sanctions provider approval.
|
||||||
|
4. **Durable ingress:** put a Cloudflare Worker in front of RN webhooks. The Worker stores raw delivery evidence durably, forwards to the backend, and supports replay. It is not the trust oracle; the backend still verifies, deduplicates, and applies safety/ledger transitions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Cross-cutting next actions
|
## Cross-cutting next actions
|
||||||
|
|
||||||
| # | Action | Blocker / Owner |
|
| # | Action | Blocker / Owner |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 1 | Test: payment via wallet-built transfer triggers RN webhook | Backend payments |
|
| 1 | Deploy confirmation repair and repeat the dev payment probe | Backend payments |
|
||||||
| 2 | Test: `/v2/secure-payments` accepts a per-request destination wallet | Backend payments |
|
| 2 | Test: `/v2/secure-payments` accepts a per-request destination wallet | Backend payments |
|
||||||
| 3 | Confirm RN doesn't auto-bridge when buyer pays on the destination chain natively | Backend payments |
|
| 3 | Confirm RN doesn't auto-bridge when buyer pays on the destination chain natively | Backend payments |
|
||||||
| 4 | Get RN's webhook P99 latency + delivery guarantees in writing | Product / RN account manager |
|
| 4 | Get RN's webhook P99 latency + delivery guarantees in writing | Product / RN account manager |
|
||||||
| 5 | Spec the wallet-abstraction layer (HD derivation + sweep job + key policy) | Backend, before going live |
|
| 5 | Spec the wallet-abstraction layer (HD derivation + sweep job + key policy) | Backend, before going live |
|
||||||
| 6 | Spec the seller-side accepted-chains config | Backend + frontend |
|
| 6 | Spec the seller-side accepted-chains config | Backend + frontend |
|
||||||
|
| 7 | Add Cloudflare Worker durable webhook ingress to the roadmap | Backend / platform |
|
||||||
|
| 8 | Add AML/sanctions adapter behind Transaction Safety Provider | Compliance / backend |
|
||||||
|
|
||||||
Actions 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.
|
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.
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ Records every monetary movement in the marketplace: buyer pay-ins, seller payout
|
|||||||
| `metadata.requestNetworkPaymentReference` | String | no | — | — | — | Request Network payment reference. |
|
| `metadata.requestNetworkPaymentReference` | String | no | — | — | — | Request Network payment reference. |
|
||||||
| `metadata.requestNetworkSecurePaymentUrl` | String | no | — | — | — | Request Network secure payment URL. |
|
| `metadata.requestNetworkSecurePaymentUrl` | String | no | — | — | — | Request Network secure payment URL. |
|
||||||
| `metadata.requestNetworkData` | Mixed | no | — | — | — | Raw Request Network payload. |
|
| `metadata.requestNetworkData` | Mixed | no | — | — | — | Raw Request Network payload. |
|
||||||
|
| `metadata.transactionSafety` | Mixed | no | — | — | — | Last Transaction Safety Provider decision, checks, evidence, and blocker reason. |
|
||||||
| `metadata.lastWebhookAt` | Date | no | — | — | — | Last webhook timestamp. |
|
| `metadata.lastWebhookAt` | Date | no | — | — | — | Last webhook timestamp. |
|
||||||
| `metadata.webhookPayload` | Mixed | no | — | — | — | Last webhook body. |
|
| `metadata.webhookPayload` | Mixed | no | — | — | — | Last webhook body. |
|
||||||
| `metadata.createdVia` | String | no | — | — | — | Origin marker. |
|
| `metadata.createdVia` | String | no | — | — | — | Origin marker. |
|
||||||
|
|||||||
@@ -113,6 +113,12 @@ SHKeeper is the crypto payment gateway. See [[Payment Flow]] and [[SHKeeper Inte
|
|||||||
| `PAYMENT_PROVIDER_MODE` | backend | optional | `live` | `dry-run` | Provider mode: `live`, `dry-run`, or `read-only` |
|
| `PAYMENT_PROVIDER_MODE` | backend | optional | `live` | `dry-run` | Provider mode: `live`, `dry-run`, or `read-only` |
|
||||||
| `REQUEST_NETWORK_ENABLED` | backend | optional | `false` | `true` | Adds `request.network` to enabled providers when no explicit list is set |
|
| `REQUEST_NETWORK_ENABLED` | backend | optional | `false` | `true` | Adds `request.network` to enabled providers when no explicit list is set |
|
||||||
| `PAYMENT_REQUEST_NETWORK_COHORT_PERCENT` | backend | optional | `0` | `10` | Percent of new checkout cohort eligible for Request Network |
|
| `PAYMENT_REQUEST_NETWORK_COHORT_PERCENT` | backend | optional | `0` | `10` | Percent of new checkout cohort eligible for Request Network |
|
||||||
|
| `REQUEST_NETWORK_ALLOW_TEST_WEBHOOKS` | backend | optional | `false` | `false` | Allows `x-request-network-test` webhook bypass only in explicit test mode. Keep false in dev/prod unless running a controlled smoke test. |
|
||||||
|
| `TRANSACTION_SAFETY_ENABLED` | backend | optional | `true` | `true` | Enables the Transaction Safety Provider gate before Request Network pay-ins are marked completed. |
|
||||||
|
| `TRANSACTION_SAFETY_REQUIRE_TX_HASH` | backend | optional | `true` | `true` | Blocks completion when provider evidence does not include a transaction hash. |
|
||||||
|
| `TRANSACTION_SAFETY_REQUIRE_TRANSFER_MATCH` | backend | optional | `true` | `true` | Requires on-chain token/recipient/amount evidence to match the expected payment. |
|
||||||
|
| `TRANSACTION_SAFETY_MIN_CONFIRMATIONS` | backend | optional | `12` | `12` | Minimum chain confirmations required by the Transaction Safety Provider. |
|
||||||
|
| `TRANSACTION_SAFETY_AML_PROVIDER` | backend | optional | `none` | `none` | AML/sanctions provider adapter name. Non-`none` values should block until implemented/configured. |
|
||||||
| `PAYMENT_LEDGER_ENFORCEMENT` | backend | optional | `false` | `true` | Enforce ledger gates for release/refund |
|
| `PAYMENT_LEDGER_ENFORCEMENT` | backend | optional | `false` | `true` | Enforce ledger gates for release/refund |
|
||||||
| `PAYMENT_RECONCILIATION_ENABLED` | backend | optional | `false` | `true` | Enable scheduled provider reconciliation jobs |
|
| `PAYMENT_RECONCILIATION_ENABLED` | backend | optional | `false` | `true` | Enable scheduled provider reconciliation jobs |
|
||||||
| `TREZOR_SAFEKEEPING_REQUIRED` | backend | optional | `false` | `true` | Optional hardware-signature gate for release/refund confirmation. Only the literal value `true` enforces Trezor proof. |
|
| `TREZOR_SAFEKEEPING_REQUIRED` | backend | optional | `false` | `true` | Optional hardware-signature gate for release/refund confirmation. Only the literal value `true` enforces Trezor proof. |
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# Handoff: Request Network In-House Checkout — 2026-05-28
|
||||||
|
|
||||||
|
Status: **fully end-to-end working on dev.amn.gg as of 2.6.38 backend / 2.6.41 frontend**. A 0.01 USDC payment (tx `0x494c77a2…`) flowed: page render → wallet connect (Rabby/injected) → approve → `transferFromWithReferenceAndFee` → RN webhook → backend marks completed → page flips to "پرداخت تأیید شد ✓" → continue → `/dashboard/payment/<id>`.
|
||||||
|
|
||||||
|
## What's live
|
||||||
|
|
||||||
|
- **Backend 2.6.38** — `/api/payment/request-network/intents` returns an `inHouseCheckout` block (destination, tokenAddress, decimals, chainId, proxyAddress, paymentReference 8-byte hex, feeAmount, feeAddress, amountWei). `GET /api/payment/request-network/:paymentId/checkout` rehydrates the block for an existing Payment record (lazy-enriches legacy records that pre-date 2.6.34 by calling RN's `GET /v2/request/:id`). Public `GET /api/version` for the version badge. `PaymentCoordinator.updatePurchaseRequestStatus` guards both `template-checkout-` and `template-tc-` prefixes (plus regex fallback for any non-ObjectId) — earlier the `template-tc-` blindspot crashed webhook processing on template-checkout payments and stranded escrow.
|
||||||
|
- **Frontend 2.6.41** — `/checkout/request-network/[paymentId]` page with wagmi state machine: connect → switch-chain → check-allowance → approve → pay → wait-for-webhook. Destination + payment-reference + approve-tx + pay-tx hashes are copyable and click through to BscScan. Once a pay tx is in flight the page no longer reverts to "approve" even though the proxy call consumed the allowance. A 10-second `GET /api/payment/:id` poll runs as a fallback when the socket misses `payment-update`. Success-state continue button handles synthetic purchaseRequestId prefixes (`template-checkout-`, `template-tc-`) by routing to `/dashboard/payment/<id>` instead of the 404-prone `/dashboard/request/<syntheticId>`. WagmiProvider is now rendered unconditionally + the checkout page also self-wraps in its own WagmiProvider for defensive isolation.
|
||||||
|
|
||||||
|
Verify which versions are running by hovering the version chip at bottom-left of any page on dev.amn.gg, or `curl https://dev.amn.gg/api/version`.
|
||||||
|
|
||||||
|
## Where things stand
|
||||||
|
|
||||||
|
A real 0.01 USDC payment ran clean through the in-house path on 2026-05-28. Webhook delivery is durable enough for dev usage; durability for prod is Phase 5 (Cloudflare Worker ingress, not started). Five follow-up tasks were scoped immediately after — see `PRD - Wallet, Multichain, Confirmations, AML, Trezor.md` and Taskmaster `#7..#11`.
|
||||||
|
|
||||||
|
## Known issues / open work
|
||||||
|
|
||||||
|
- **TypeScript-error CI false-success**: pipelines #40 and #41 reported ✅ green in Woodpecker while `yarn build` was actually failing at the TS step and no image was pushed. Memory entry: `woodpecker_silent_build_fail.md`. **Always verify** `dev-<version>` exists in `git.manko.yoga` before trusting CI green. The wagmi `chainId` field requires `as any` because of its literal-union type — keep that pattern when adding new wagmi calls.
|
||||||
|
- **Existing/legacy Payment records** (created before backend 2.6.34) don't have RN's request details cached. The GET endpoint lazy-enriches them via `GET /v2/request/:requestId` on first visit, then persists. If RN's API is down at that moment, falls back to the hosted-page link.
|
||||||
|
- **Mongo access is denied** to the auto-mode classifier on dev — debugging payment records currently requires either the user's mongo creds or relying on the 409 `debug` block surfaced through the frontend.
|
||||||
|
- **Wagmi provider isolation (2.6.39)**: The checkout page wraps itself in its own `WagmiProvider`. The root `Web3Provider` also renders `WagmiProvider` unconditionally as of 2.6.38. The doubling is intentional defensiveness — if one provider has an issue, the other still serves the checkout flow. Can be simplified later if both prove stable.
|
||||||
|
- **PRD Phase 5 — Cloudflare Worker durable webhook ingress** — not started. Taskmaster `3.13`. Current dev relies on `dev.amn.gg` being up at the moment RN's webhook fires. For prod, RN webhooks need to land in a durable Cloudflare Worker that buffers + replays into the backend.
|
||||||
|
|
||||||
|
## Files changed (recent)
|
||||||
|
|
||||||
|
Backend (`/Users/manwe/CascadeProjects/escrow/backend`):
|
||||||
|
- `src/services/payment/requestNetwork/contract.ts` — spreads full RN response into `raw`
|
||||||
|
- `src/services/payment/requestNetwork/inHouseCheckout.ts` — block builder, reads `paymentReference` from `rnRaw.requestDetails.paymentReference`
|
||||||
|
- `src/services/payment/requestNetwork/merchantReference.ts`, `tokens.ts`, `proxyAddresses.ts`, `paymentReference.ts` — helpers
|
||||||
|
- `src/services/payment/requestNetwork/requestNetworkPayInService.ts` — calls `GET /v2/request` after intent creation
|
||||||
|
- `src/services/payment/requestNetwork/requestNetworkRoutes.ts` — `GET /:paymentId/checkout` + lazy enrichment + debug response
|
||||||
|
- `src/services/payment/requestNetwork/networkClient.ts` — already had `getRequestStatus`
|
||||||
|
- `src/app.ts` — `GET /api/version`, exempt from rate limit
|
||||||
|
- `__tests__/rn-in-house-checkout.test.ts` — 12 unit tests, all green
|
||||||
|
|
||||||
|
Frontend (`/Users/manwe/CascadeProjects/escrow/frontend`):
|
||||||
|
- `src/web3/contracts/rn-fee-proxy.ts` — RN proxy + ERC20 ABIs
|
||||||
|
- `src/web3/context/wagmi-provider.tsx` — removed the mount-gate that caused `WagmiProviderNotFoundError`
|
||||||
|
- `src/web3/components/provider-payment.tsx` — `router.push` to in-house page + sessionStorage stash
|
||||||
|
- `src/sections/payment/checkout/types.ts` + `rn-in-house-checkout-view.tsx` — state machine, local WagmiProvider wrap
|
||||||
|
- `src/app/checkout/request-network/[paymentId]/page.tsx` — app router entry
|
||||||
|
- `src/components/version-logger.tsx` — version chip + tooltip showing backend version
|
||||||
|
|
||||||
|
## Memory entries added
|
||||||
|
|
||||||
|
- `MEMORY.md` index updated with:
|
||||||
|
- `arcane_dev_stack.md` (env/project IDs, two-step deploy note)
|
||||||
|
- `woodpecker_silent_build_fail.md` (CI green ≠ image pushed)
|
||||||
|
- and existing `rn_webhook_event_field.md`, `backend_rate_limits.md`, `telegram_notify_no_parse_mode.md`, `devEscrow_nginx_after_redeploy.md`, `parallel_agents_on_escrow.md`
|
||||||
|
|
||||||
|
## Open PRD questions still to decide
|
||||||
|
|
||||||
|
From `PRD - Request Network In-House Checkout.md` §10:
|
||||||
|
- Proxy address universality across chains (currently BSC + Arb confirmed; Task #8 will probe Polygon/ETH/Base)
|
||||||
|
- API pricing for hosted-UI-less usage (need RN account-mgmt question)
|
||||||
|
- Approval UX — exact-amount vs MAX_UINT256 (current: exact-amount)
|
||||||
|
- Cancel / timeout semantics for abandoned intents
|
||||||
|
- Telemetry events for in-house vs hosted A/B
|
||||||
|
|
||||||
|
## Follow-up tasks (Taskmaster + PRD)
|
||||||
|
|
||||||
|
Five follow-ups scoped for kimi to pick up independently. Full spec in `PRD - Wallet, Multichain, Confirmations, AML, Trezor.md`. Quick index:
|
||||||
|
|
||||||
|
| # | Task | Priority | Depends on |
|
||||||
|
|---|---------------------------------------------------------------|----------|------------|
|
||||||
|
| 7 | Per-(buyer, sellerOffer) ephemeral RN destination wallets | high | (sweep step soft-depends on #11) |
|
||||||
|
| 8 | Multichain RN proxy registry + USDC/USDT support | high | — |
|
||||||
|
| 9 | Per-chain confirmation thresholds + admin UI | medium | — |
|
||||||
|
| 10 | Optional AML screening on incoming payments (seller-paid) | medium | — |
|
||||||
|
| 11 | Trezor signing for admin actions (release/refund/sweep) | high | — |
|
||||||
@@ -260,6 +260,20 @@ If user data may have leaked, treat as sev 1 and follow your data-breach disclos
|
|||||||
|
|
||||||
Use when Request Network payments are failing, stalled, or out of sync with local payment state.
|
Use when Request Network payments are failing, stalled, or out of sync with local payment state.
|
||||||
|
|
||||||
|
**First triage:**
|
||||||
|
|
||||||
|
1. Check whether RN reached nginx:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep '/api/payment/request-network/webhook' /opt/backend/nginx/logs/access.log | tail -50
|
||||||
|
```
|
||||||
|
|
||||||
|
2. If RN deliveries returned `404`, treat it as a backend correlation/config bug. Do not run another paid probe until the correlation fix is deployed and smoke-tested.
|
||||||
|
|
||||||
|
3. If deliveries returned `202` or `200` but the payment is still pending, inspect `metadata.transactionSafety` on the `Payment` document. A safety-pending payment is captured but not credited; look for missing tx hash, insufficient confirmations, transfer mismatch, or AML provider blockers.
|
||||||
|
|
||||||
|
4. If Cloudflare Worker durable ingress is enabled, replay from the Worker delivery id/time window after backend repair instead of asking the buyer to pay again.
|
||||||
|
|
||||||
**Immediate rollback (minutes):**
|
**Immediate rollback (minutes):**
|
||||||
|
|
||||||
1. Stop routing new intents to Request Network by setting:
|
1. Stop routing new intents to Request Network by setting:
|
||||||
|
|||||||
@@ -181,6 +181,8 @@ Today these are read manually from logs / Sentry. As Prometheus is added, encode
|
|||||||
|--------|-------|---------|-------|
|
|--------|-------|---------|-------|
|
||||||
| Payment success rate | `db.payments.aggregate([{$group:{_id:"$status",n:{$sum:1}}}])` | > 95 % completed of 24h-old payments | < 90 % |
|
| Payment success rate | `db.payments.aggregate([{$group:{_id:"$status",n:{$sum:1}}}])` | > 95 % completed of 24h-old payments | < 90 % |
|
||||||
| Webhook signature failures | log `Webhook verification failed` | 0 | > 0 |
|
| Webhook signature failures | log `Webhook verification failed` | 0 | > 0 |
|
||||||
|
| Request Network webhook 4xx | nginx access log `/api/payment/request-network/webhook` | 0 | any real provider delivery returning 4xx |
|
||||||
|
| Request Network safety-pending payments | `db.payments.find({"metadata.transactionSafety.status":"pending"})` | explained/short-lived | pending > 10 min without operator note |
|
||||||
| SHKeeper API errors (5xx) | log + Sentry | 0 | > 5/min sustained |
|
| SHKeeper API errors (5xx) | log + Sentry | 0 | > 5/min sustained |
|
||||||
| Payouts stuck in `pending` > 30 min | `db.payments.find({type:'payout',status:'pending',createdAt:{$lt:ISODate(30 min ago)}})` | empty | non-empty |
|
| Payouts stuck in `pending` > 30 min | `db.payments.find({type:'payout',status:'pending',createdAt:{$lt:ISODate(30 min ago)}})` | empty | non-empty |
|
||||||
| Missing `transactionHash` after `completed` | the same query that drives `fix-transaction-hashes.js` | empty | non-empty |
|
| Missing `transactionHash` after `completed` | the same query that drives `fix-transaction-hashes.js` | empty | non-empty |
|
||||||
|
|||||||
127
PRD - Request Network In-House Checkout.md
Normal file
127
PRD - Request Network In-House Checkout.md
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# PRD: Request Network In-House Checkout
|
||||||
|
|
||||||
|
> Source spec: `.taskmaster/docs/prd-request-network-in-house-checkout.md`
|
||||||
|
> Status: **Draft — updated after 2026-05-28 dev webhook probe**
|
||||||
|
> Related: `01 - Architecture/Request Network Integration Constraints.md` §1
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
Buyers paying through Request Network are redirected to `pay.request.network/?token=…`. That page doesn't support **Rabby** (a meaningful slice of our user base), takes the buyer off `amn.gg` mid-flow, and wraps the payment in Safe + ERC-4337 + Pimlico paymaster + public BSC RPC — a stack we already saw rate-limit in real use.
|
||||||
|
|
||||||
|
The RN *protocol* is fine. Their *UI* is the problem.
|
||||||
|
|
||||||
|
## 2026-05-28 reality update
|
||||||
|
|
||||||
|
The dev BSC probe changed the risk model:
|
||||||
|
|
||||||
|
- Test transaction: `0x3a23febd9abd43d7e0851c1ea86c4ceaf08c11098852cb0425fa074e9c88350b`.
|
||||||
|
- On-chain result: successful BSC USDC transfer to Amanat's configured destination wallet.
|
||||||
|
- RN webhook result: RN did call `POST /api/payment/request-network/webhook` on `dev.amn.gg` four times from `34.34.233.192`.
|
||||||
|
- Application result: backend returned `404` because the handler only correlated one local provider id shape and missed the RN request/payment-reference fields stored on the `Payment` record.
|
||||||
|
- Frontend result: callback stayed on "processing payment" and the 3-second polling loop later hit `429`.
|
||||||
|
|
||||||
|
So the original "webhook silence" risk is no longer the observed failure. RN delivered the webhook; Amanat dropped it. Before another paid probe, dev must run the correlation fix and the callback polling fix, then pass the Request Network webhook smoke test.
|
||||||
|
|
||||||
|
## Core idea
|
||||||
|
|
||||||
|
RN's webhook detects payments by listening for a single on-chain event — `TransferWithReferenceAndFee` — emitted by their `ERC20FeeProxy` contract. We confirmed this by cold-inspecting an actual `$12` payment on their hosted page: under the Safe/4337 wrapper, the real work is two calls — `approve(proxy, amount)` and `transferFromWithReferenceAndFee(...)`.
|
||||||
|
|
||||||
|
If we make those same two calls from our own UI, RN's webhook fires. The hosted page is decorative.
|
||||||
|
|
||||||
|
However, webhook delivery alone is not enough to credit escrow. The backend now needs a **Transaction Safety Provider** gate between "provider says paid" and "Amanat marks funded". That provider approves only after configured checks pass: transaction hash present, chain confirmations deep enough, transfer recipient/token/amount matched on-chain, and any external AML/sanctions provider response is acceptable.
|
||||||
|
|
||||||
|
## What we replace
|
||||||
|
|
||||||
|
| Today | Proposed |
|
||||||
|
|---|---|
|
||||||
|
| Click "Pay with RN" → `window.location = securePaymentUrl` | Click "Pay with RN" → `/checkout/request-network/:paymentId` (Amanat-rendered) |
|
||||||
|
| RN's wallet picker (no Rabby) | wagmi `injected()` + `metaMask()` — Rabby works via EIP-6963 |
|
||||||
|
| Safe + 4337 + paymaster | Buyer's EOA, two direct txs, buyer pays own gas |
|
||||||
|
| Public BSC RPC | Whatever the buyer's wallet uses (under their control) |
|
||||||
|
|
||||||
|
## What does NOT change
|
||||||
|
|
||||||
|
- Backend webhook route stays the same, but the handler must correlate every RN reference shape (`providerPaymentId`, request id, payment reference, nested raw data) and pass the Transaction Safety Provider before marking a payment funded.
|
||||||
|
- `Payment` lifecycle is unchanged.
|
||||||
|
- Settlement, refunds, dispute paths are unchanged.
|
||||||
|
- Non-RN payment providers (SHKeeper, etc.) are unaffected.
|
||||||
|
- Buyer can still opt out: hosted-page link stays available as an escape hatch.
|
||||||
|
|
||||||
|
## Hard-known protocol facts (from inspection)
|
||||||
|
|
||||||
|
| Item | Value |
|
||||||
|
|---|---|
|
||||||
|
| RN ERC20FeeProxy (BSC + Arb, likely all EVMs) | `0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9` |
|
||||||
|
| Function | `transferFromWithReferenceAndFee(token, to, amount, ref, feeAmount, feeAddress)` |
|
||||||
|
| Selector | `0xc219a14d` |
|
||||||
|
| `paymentReference` derivation | `last8Bytes(keccak256(requestId + salt + destination))` |
|
||||||
|
| Fee config currently used | `feeAmount = 0`, `feeAddress = 0x…dEaD` |
|
||||||
|
|
||||||
|
## Backend deliverables (sketch)
|
||||||
|
|
||||||
|
Extend `POST /payment/request-network/intents` response with an `inHouseCheckout` object containing: `destination`, `tokenAddress`, `decimals`, `chainId`, `proxyAddress`, `paymentReference`, `feeAmount`, `feeAddress`, `amountWei`. Full field sourcing in the spec.
|
||||||
|
|
||||||
|
## Frontend deliverables (sketch)
|
||||||
|
|
||||||
|
New page `/checkout/request-network/:paymentId` with a wagmi-driven state machine: connect → switch-chain → check-allowance → approve → pay → wait-for-webhook → done. Reuses layout chrome from `web3/components/manual-payment.tsx` (SHKeeper). Escape-hatch link to the hosted page stays visible.
|
||||||
|
|
||||||
|
## Acceptance criteria (short list)
|
||||||
|
|
||||||
|
1. A Rabby user completes an RN payment without leaving `amn.gg`.
|
||||||
|
2. RN's webhook fires from a transaction built and submitted by our UI.
|
||||||
|
3. The `Payment` doc transitions to `completed` / `escrowState='funded'` exactly as it does today, but only after safety checks pass.
|
||||||
|
4. Wrong-chain → one-click switch. Sufficient allowance → approve step skipped. Abandoned page → resumable.
|
||||||
|
5. Hosted-page link still works and is documented as the fallback.
|
||||||
|
|
||||||
|
Full list in the spec.
|
||||||
|
|
||||||
|
## Open questions for the review
|
||||||
|
|
||||||
|
1. Is the proxy address identical on every chain we plan to support, or only some?
|
||||||
|
2. RN's pricing — are we still in their terms if we never use their hosted UI?
|
||||||
|
3. `approve(MAX_UINT256)` (RN's pattern, best UX) vs exact-amount approve (better security)?
|
||||||
|
4. Cancel / timeout semantics for abandoned intents — TTL, explicit cancel endpoint, or both?
|
||||||
|
5. Feature flag + A/B in dev for one cycle before prod, or hard-cut once acceptance passes?
|
||||||
|
|
||||||
|
## Risks
|
||||||
|
|
||||||
|
- **Webhook handling failure.** RN did deliver the 2026-05-28 dev webhook, but Amanat returned `404`. A deployed correlation fix and smoke test are now the gate before any more paid probes.
|
||||||
|
- **Webhook durability.** The main app is too unstable to be the only webhook landing zone. Roadmap item: put a Cloudflare Worker in front of RN webhooks, store raw delivery metadata durably, then forward/replay into the backend.
|
||||||
|
- **False-positive payment credit.** A signed webhook must not be enough to credit escrow. Transaction Safety Provider gates payment completion on on-chain transfer verification, confirmation depth, and future AML/sanctions checks.
|
||||||
|
- Chain-specific proxy address divergence (mitigation: per-chain constants, fall back to hosted page for unknown chains).
|
||||||
|
|
||||||
|
## Implementation phases
|
||||||
|
|
||||||
|
| # | Phase | Gate |
|
||||||
|
|---|---|---|
|
||||||
|
| 0 | Probe — real dev BSC payment | ✅ Completed: RN webhook reached nginx/backend, but app returned `404` |
|
||||||
|
| 0A | Confirmation repair — deploy correlation fix, callback polling fix, and Transaction Safety Provider | ✅ Completed: smoke test passes; unsigned/test webhooks rejected |
|
||||||
|
| 1 | Backend: expand intent payload + helpers | ✅ Completed (2.6.32 → 2.6.38) |
|
||||||
|
| 2 | Frontend: page skeleton + wallet connect | ✅ Completed (2.6.30 → 2.6.41) |
|
||||||
|
| 3 | On-chain wiring (approve + proxy call) | ✅ Completed: real 0.01 USDC payment on dev BSC 2026-05-28 (tx `0x494c77a2…`), Payment.status=completed, safety approved |
|
||||||
|
| 4 | Hardening: errors, timer, persistence, telemetry, escape hatch | 🟡 Partial — copy/BscScan links, pay-button trap, 10s status poll, template-tc routing fix shipped 2.6.41. Timer + persistence + telemetry left. |
|
||||||
|
| 5 | Durable ingress — Cloudflare Worker receives RN webhooks, stores delivery record, forwards to backend, exposes replay | ⏳ Not started (Taskmaster `3.13`) |
|
||||||
|
| 6 | Rollout: flag + A/B | ⏳ Not started |
|
||||||
|
|
||||||
|
Five follow-up workstreams scoped 2026-05-28 in `PRD - Wallet, Multichain, Confirmations, AML, Trezor.md` (Taskmaster `#7…#11`) cover ephemeral destination wallets, multichain proxy registry, runtime confirmation thresholds, optional AML screening, and Trezor signing for admin actions.
|
||||||
|
|
||||||
|
## Durable webhook ingress roadmap
|
||||||
|
|
||||||
|
Add a small Cloudflare Worker as the public Request Network webhook target:
|
||||||
|
|
||||||
|
1. Receive RN webhook with raw body, headers, request id, delivery id, source IP, timestamp.
|
||||||
|
2. Verify RN signature at the edge if secret handling/raw-body verification is compatible; otherwise store first and let backend perform canonical verification.
|
||||||
|
3. Write an immutable delivery record to durable storage (Cloudflare Queues + D1/R2/KV, final choice TBD).
|
||||||
|
4. Forward to the primary backend and optionally a secondary backend endpoint.
|
||||||
|
5. Return `2xx` only after durable enqueue/store succeeds.
|
||||||
|
6. Provide operator replay by delivery id or time window.
|
||||||
|
|
||||||
|
The Worker is an ingress and evidence buffer, not the trust oracle. The backend still owns signature verification, idempotency, Transaction Safety Provider checks, ledger updates, and marketplace state transitions.
|
||||||
|
|
||||||
|
## See also
|
||||||
|
|
||||||
|
- `.taskmaster/docs/prd-request-network-in-house-checkout.md` — full spec with field sources, file lists, state-machine details, telemetry events.
|
||||||
|
- `01 - Architecture/Request Network Integration Constraints.md` — §1 (this PRD addresses), §2/§3/§4 are explicitly out of scope here.
|
||||||
|
- `PRD - Request Network Migration and Funds Management.md` — the broader RN context.
|
||||||
@@ -13,6 +13,8 @@ Request Network is request/payment-reference based. The platform creates a Reque
|
|||||||
|
|
||||||
Primary recommendation: run a phased migration behind a provider adapter. Introduce Request Network for new pay-ins first using Secure Payment Pages, keep SHKeeper read-only for existing payments, then add funds ledger, release/refund gates, and Request Network payout flows.
|
Primary recommendation: run a phased migration behind a provider adapter. Introduce Request Network for new pay-ins first using Secure Payment Pages, keep SHKeeper read-only for existing payments, then add funds ledger, release/refund gates, and Request Network payout flows.
|
||||||
|
|
||||||
|
2026-05-28 update: the first dev BSC payment probe confirmed Request Network did deliver webhooks to `dev.amn.gg`, but Amanat returned `404` because local correlation did not search all RN reference fields. The migration roadmap now needs two P0 additions before wider RN testing: a Transaction Safety Provider gate before escrow funding, and durable webhook ingress (Cloudflare Worker) so backend instability does not lose callback evidence.
|
||||||
|
|
||||||
## Source Findings
|
## Source Findings
|
||||||
|
|
||||||
Current code:
|
Current code:
|
||||||
@@ -219,6 +221,36 @@ Risk Assessment:
|
|||||||
- Mitigation: raw-body middleware scoped to webhook route, event fixture tests, dead-letter queue/table, operator replay endpoint.
|
- Mitigation: raw-body middleware scoped to webhook route, event fixture tests, dead-letter queue/table, operator replay endpoint.
|
||||||
- Rollback: pause webhook processor and rely on manual/admin reconciliation for Request Network records.
|
- Rollback: pause webhook processor and rely on manual/admin reconciliation for Request Network records.
|
||||||
|
|
||||||
|
## PRD 4A - Transaction Safety Provider and Durable Webhook Ingress
|
||||||
|
|
||||||
|
Priority: P0
|
||||||
|
|
||||||
|
Goal: prevent false-positive payment credit and prevent webhook loss when the main app is unstable.
|
||||||
|
|
||||||
|
Scope:
|
||||||
|
|
||||||
|
- Add a Transaction Safety Provider invoked by Request Network webhook and reconciliation paths before marking pay-ins completed.
|
||||||
|
- Require configurable checks: transaction hash present, minimum confirmations, on-chain transfer recipient/token/amount match, and AML/sanctions provider approval when configured.
|
||||||
|
- Store `metadata.transactionSafety`, last webhook payload, and safety-blocker reason for support/replay.
|
||||||
|
- Add a Cloudflare Worker as the public Request Network webhook target.
|
||||||
|
- Worker stores raw body, headers, delivery id, request id/payment reference, source IP, and timestamp in durable storage before forwarding to the backend.
|
||||||
|
- Provide replay by delivery id/time window/payment reference.
|
||||||
|
|
||||||
|
Acceptance Criteria:
|
||||||
|
|
||||||
|
- A signed RN webhook cannot set `Payment.status='completed'` unless safety checks approve.
|
||||||
|
- If tx hash is missing, webhook evidence is retained and the payment remains pending/safety-blocked rather than lost.
|
||||||
|
- Reconciliation uses the same safety gate as webhook processing.
|
||||||
|
- Unsigned/test callbacks are rejected unless explicit test mode is enabled.
|
||||||
|
- Backend outage still leaves a durable webhook record that an operator can replay.
|
||||||
|
|
||||||
|
Risk Assessment:
|
||||||
|
|
||||||
|
- Impact: Very High. This controls when escrow is credited.
|
||||||
|
- Likelihood: High. The 2026-05-28 probe already produced a dropped webhook.
|
||||||
|
- Main risks: accidentally blocking legitimate payments while tx hash/source evidence is missing, or accidentally trusting the Worker as the payment authority.
|
||||||
|
- Mitigation: safety decisions are explicit (`approved`, `pending`, `rejected`, `skipped`), backend remains the trust boundary, and operators can replay stored deliveries after fixes deploy.
|
||||||
|
|
||||||
## PRD 5 - Release, Refund, and Payout Orchestration
|
## PRD 5 - Release, Refund, and Payout Orchestration
|
||||||
|
|
||||||
Priority: P1
|
Priority: P1
|
||||||
@@ -313,11 +345,13 @@ Risk Assessment:
|
|||||||
2. Add funds ledger models/services and dry-run backfill report.
|
2. Add funds ledger models/services and dry-run backfill report.
|
||||||
3. Implement Request Network secure pay-in flow behind feature flag.
|
3. Implement Request Network secure pay-in flow behind feature flag.
|
||||||
4. Implement signed webhook receiver and reconciliation job.
|
4. Implement signed webhook receiver and reconciliation job.
|
||||||
5. Enable Request Network for limited new checkout cohort.
|
5. Add Transaction Safety Provider to webhook and reconciliation completion paths.
|
||||||
6. Add release/refund orchestration using ledger gates.
|
6. Add durable Request Network webhook ingress, preferably Cloudflare Worker + queue/storage + replay.
|
||||||
7. Migrate admin/frontend views.
|
7. Enable Request Network for limited new checkout cohort.
|
||||||
8. Backfill legacy records.
|
8. Add release/refund orchestration using ledger gates.
|
||||||
9. Decommission SHKeeper once no active records depend on it.
|
9. Migrate admin/frontend views.
|
||||||
|
10. Backfill legacy records.
|
||||||
|
11. Decommission SHKeeper once no active records depend on it.
|
||||||
|
|
||||||
## Open Decisions
|
## Open Decisions
|
||||||
|
|
||||||
@@ -326,8 +360,9 @@ Risk Assessment:
|
|||||||
- Which chains/currencies are required for launch: BSC USDT parity with today, or Request Network supported stablecoin routes first?
|
- Which chains/currencies are required for launch: BSC USDT parity with today, or Request Network supported stablecoin routes first?
|
||||||
- Should platform fee be paid by buyer, seller, or absorbed by Amanat?
|
- Should platform fee be paid by buyer, seller, or absorbed by Amanat?
|
||||||
- Does Amanat need crypto-to-fiat/offramp later, which adds KYC/payment detail requirements?
|
- Does Amanat need crypto-to-fiat/offramp later, which adds KYC/payment detail requirements?
|
||||||
|
- Which AML/sanctions provider should back the first Transaction Safety Provider implementation?
|
||||||
|
- Which Cloudflare durable primitive should store webhook evidence: Queues plus D1, R2 raw payloads, or another append-only store?
|
||||||
|
|
||||||
## Recommendation
|
## Recommendation
|
||||||
|
|
||||||
Start with Secure Payment Pages and a platform escrow/payee destination controlled by Amanat. This best matches the current escrow mental model while reducing frontend transaction-building risk. Do not route pay-ins directly to sellers until dispute handling, refund logic, and service fee economics are fully redesigned.
|
Start with Secure Payment Pages and a platform escrow/payee destination controlled by Amanat. This best matches the current escrow mental model while reducing frontend transaction-building risk. Do not route pay-ins directly to sellers until dispute handling, refund logic, and service fee economics are fully redesigned.
|
||||||
|
|
||||||
|
|||||||
225
PRD - Wallet, Multichain, Confirmations, AML, Trezor.md
Normal file
225
PRD - Wallet, Multichain, Confirmations, AML, Trezor.md
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
# PRD: Wallet, Multichain, Confirmations, AML, Trezor
|
||||||
|
|
||||||
|
> Status: **Draft — 2026-05-28**
|
||||||
|
> Author: nick + claude (after in-house RN checkout shipped on dev 2.6.38/2.6.41)
|
||||||
|
> Owner: backend (payments) + frontend (admin UI + checkout)
|
||||||
|
> Related: `PRD - Request Network In-House Checkout.md`, `01 - Architecture/Request Network Integration Constraints.md`
|
||||||
|
|
||||||
|
Five follow-ups to the in-house Request Network checkout. They are sized so a single contributor can pick up any one of them in isolation. Each is its own Taskmaster top-level task — see `#7…#11`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Per-(buyer, seller) ephemeral destination wallets — Task #7
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
Today the in-house checkout sends *all* RN-routed payments to one Amanat-controlled wallet (env: `REQUEST_NETWORK_MERCHANT_REFERENCE`). That wallet is shared across every buyer, every seller, every offer. It's both an audit nightmare (no buyer↔settlement linkage at the wallet level) and a single point of compromise.
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
For each `(buyerId, sellerOfferId)` (or `(buyerId, sellerId)` — see open questions), generate a fresh on-chain destination address, persist it on the `Payment` record, and tell Request Network to expect funds on that address. RN's webhook flows unchanged.
|
||||||
|
|
||||||
|
### Hard-known facts (from RN docs we've cold-inspected so far)
|
||||||
|
- The "destination" in RN is the `destinationId` inside the merchant reference: `<address>@eip155:<chainId>#<contractId>:<tokenAddress>`. RN doesn't bind this to an Amanat-level identity; it's just where the funds end up.
|
||||||
|
- Each `POST /v2/secure-payments` request *can* pass a different `destinationId`. RN doesn't reject divergent destinations across requests from the same client.
|
||||||
|
- `paymentReference` is derived per request (`last8Bytes(keccak256(requestId+salt+destination))`), so different destinations naturally produce different on-chain refs. The webhook listener keys on the ref + tx hash.
|
||||||
|
|
||||||
|
### Open questions to settle before code
|
||||||
|
1. **Key custody model.** Options:
|
||||||
|
- **Deterministic HD wallet** rooted at one Amanat master seed; derive per-`(buyer, seller)` path (e.g. `m/44'/60'/0'/<buyerIdx>/<sellerIdx>`). Keys live in the backend, single seed in KMS/HSM. Sweep is one tx per derived addr.
|
||||||
|
- **One-shot disposable EOAs**, encrypted and stored in Mongo (or KMS), keyed by `(buyer, seller)`. Sweep then forget.
|
||||||
|
- **Smart contract per offer** that auto-forwards to the master wallet on receive. Avoids holding keys at all, but costs gas + an extra hop.
|
||||||
|
- Recommended starting point: HD wallet, with sweep-on-confirmation. Cheapest, most auditable.
|
||||||
|
2. **Sweep strategy.** Sweep immediately on webhook confirmation, or batch sweep cron'd nightly? Trade gas vs. exposure window. Default: sweep immediately under Transaction Safety Provider approval.
|
||||||
|
3. **Granularity.** Per `(buyer, seller)`, per `(buyer, seller, offer)`, or per single payment? Per-offer gives clean audit lineage; per-payment is overkill (extra derivations); per-`(buyer, seller)` is reusable across multi-step deals.
|
||||||
|
4. **Re-use vs. expire.** If a derived address has funds in it after sweep, do we still re-use for the same pair's next payment, or rotate? Re-use = simpler, slight privacy hit.
|
||||||
|
|
||||||
|
### Scope
|
||||||
|
1. New module `backend/src/services/payment/wallets/derivedDestinations.ts` with `getDestinationFor(buyerId, sellerOfferId)` returning `{ address, derivationPath, chainId }`.
|
||||||
|
2. Migration on `Payment` schema to add `metadata.derivedDestination` (address + derivation path snapshot).
|
||||||
|
3. RN intent creation calls `getDestinationFor(...)` and overrides the destination half of `REQUEST_NETWORK_MERCHANT_REFERENCE`.
|
||||||
|
4. Sweep job (cron + manual-trigger admin endpoint) under Transaction Safety Provider gate.
|
||||||
|
5. Admin UI (table) to view derived destinations, their balances, sweep status, and last sweep tx.
|
||||||
|
|
||||||
|
### Non-goals
|
||||||
|
- Multi-chain destinations (covered in Task #8).
|
||||||
|
- Buyer-side ephemeral keys (covered in `Request Network Integration Constraints.md` §3, separate PRD).
|
||||||
|
- Hardware-wallet-signed sweeps (covered in Task #11).
|
||||||
|
|
||||||
|
### Acceptance criteria
|
||||||
|
1. Two payments from the same buyer to two different sellers land on two different addresses on-chain.
|
||||||
|
2. RN's webhook fires correctly for both, regardless of the destination divergence.
|
||||||
|
3. Sweep runs idempotently — re-running it on an already-swept address is a no-op.
|
||||||
|
4. Admin UI shows the address, its balance, last sweep tx (link to BscScan), and current ownership status.
|
||||||
|
5. Master seed never leaves the KMS/secret store. Backend reads derivation paths only; signs sweep txes via KMS API.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Multi-chain RN proxy registry + USDC/USDT support — Task #8
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
`backend/src/services/payment/requestNetwork/proxyAddresses.ts` and `tokens.ts` currently hardcode BSC USDC plus a handful of token entries. The in-house checkout will fall through to "in-house checkout not available" the moment a buyer wants to pay on Arbitrum/Polygon/Ethereum, or wants USDT instead of USDC on the same chain.
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
Verified-from-chain registry of:
|
||||||
|
- RN's `ERC20FeeProxy` address per supported chain.
|
||||||
|
- USDC + USDT contract address + decimals per chain.
|
||||||
|
|
||||||
|
Plus an admin "supported networks" UI that:
|
||||||
|
- Lists each chain + token combo with its current status (verified-on-chain / probe failed / disabled).
|
||||||
|
- Shows which chains a given seller has whitelisted (depends on per-seller `acceptedChains` config; out of scope here — see `Request Network Integration Constraints.md` §2).
|
||||||
|
|
||||||
|
### Hard-known facts
|
||||||
|
- RN published their canonical `ERC20FeeProxy` for BSC + Arbitrum as `0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9` (CREATE2 deterministic). Same address on Ethereum mainnet, Polygon, Base **per the deterministic deployment claim** — needs verifying.
|
||||||
|
- BSC USDC has 18 decimals (Binance-Peg). Mainnet/Arb/Polygon USDC have 6.
|
||||||
|
- USDT on Ethereum requires `approve(0)` before a non-zero re-approve. Other chains' USDT don't.
|
||||||
|
|
||||||
|
### Scope
|
||||||
|
1. Probe script `backend/scripts/probe-rn-chains.ts` that walks every chain in `supported-chains.json`, calls a known view fn on the candidate proxy address, and confirms it's a real RN proxy (not just bytes). Emits a report.
|
||||||
|
2. Promote `tokens.ts` to load from a JSON file + override layer for admin-managed entries. Keep the canonical defaults committed.
|
||||||
|
3. Backend route `GET /api/admin/rn/networks` returning the registry plus probe status.
|
||||||
|
4. Frontend admin page `/dashboard/admin/networks` rendering the table.
|
||||||
|
5. `buildInHouseCheckoutBlock` consults the chain registry; returns `reason='unsupported_chain:<chainId>'` cleanly.
|
||||||
|
6. Add the USDT-mainnet `approve(0)` quirk to the frontend approve step. When detected, the approve flow does `approve(spender, 0)` → `approve(spender, amount)`.
|
||||||
|
|
||||||
|
### Non-goals
|
||||||
|
- Letting a seller pick which chain a given buyer can use (separate PRD, §2 in constraints doc).
|
||||||
|
- Cross-chain bridging.
|
||||||
|
|
||||||
|
### Acceptance criteria
|
||||||
|
1. Probe script run on dev confirms RN proxy address on at least BSC, Arbitrum, Polygon, Ethereum, Base. Differences are documented.
|
||||||
|
2. Token registry has entries for USDC + USDT on those 5 chains, with correct decimals.
|
||||||
|
3. In-house checkout supports USDT on BSC end-to-end (a paid probe).
|
||||||
|
4. USDT-mainnet `approve(0)` reset is handled in the UI when needed.
|
||||||
|
5. Admin networks page renders the registry with a per-row "probe again" button.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Confirmation-counting + admin threshold UI — Task #9
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
The Transaction Safety Provider already reads `TRANSACTION_SAFETY_MIN_CONFIRMATIONS` from env (default 12). That number is global, baked into env, only changeable by re-deploy. We want it tunable per-chain at runtime by an admin, with a clear UI showing each in-flight payment's current confirmation depth against the threshold.
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
1. Persist per-chain confirmation thresholds in a `ConfigKV` collection (or extend an existing settings model) so admin can adjust without redeploy.
|
||||||
|
2. The `TransactionSafetyProvider`'s confirmation check reads the runtime threshold first, falls back to env.
|
||||||
|
3. Frontend admin UI to view + edit per-chain thresholds, and a "payments awaiting confirmation" table that shows `confirmations / threshold` updated live.
|
||||||
|
|
||||||
|
### Scope
|
||||||
|
1. New collection / extension to existing `Setting` model: `{ key: 'confirmation_threshold:<chainId>', value: <int>, updatedBy, updatedAt }`.
|
||||||
|
2. Public-to-admin endpoint `GET /api/admin/settings/confirmation-thresholds` and `PATCH /api/admin/settings/confirmation-thresholds/:chainId`.
|
||||||
|
3. Wire `transactionSafetyProvider` to read from this store; cache for 30s to avoid Mongo hammering.
|
||||||
|
4. Frontend admin page `/dashboard/admin/confirmation-thresholds`:
|
||||||
|
- Table of chains, current threshold, recommended default (e.g. 12 for BSC).
|
||||||
|
- Edit-in-place with a confirm dialog.
|
||||||
|
- Audit-log style "changed by X on Y at Z".
|
||||||
|
5. Frontend admin page `/dashboard/admin/payments/awaiting-confirmation`:
|
||||||
|
- Lists payments with `escrowState !== 'funded'` and `metadata.transactionSafety.lastCheck.status === 'pending'`.
|
||||||
|
- For each: tx hash (linked to explorer), current confirmations (poll-driven), threshold, ETA.
|
||||||
|
|
||||||
|
### Non-goals
|
||||||
|
- Per-asset thresholds (only per-chain).
|
||||||
|
- Per-seller overrides.
|
||||||
|
|
||||||
|
### Acceptance criteria
|
||||||
|
1. Admin can lower BSC's threshold from 12 to 3 on the live dev stack without a redeploy and a new webhook fires the safety gate with the new value within 30s.
|
||||||
|
2. Awaiting-confirmation table updates live as new blocks arrive (poll every 12s on BSC).
|
||||||
|
3. Audit log records every threshold change with admin user, before/after, timestamp.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Optional AML screening (seller-paid) — Task #10
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
The Transaction Safety Provider has an `evaluateAmlPlaceholder()` stub that currently returns `status: skipped`. We want a real AML pass that the seller can *opt into* per-offer, with the seller covering the per-check API cost.
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
1. Pick a provider (Chainalysis Address Screening, TRM Labs, Elliptic — open question). Default recommendation: Chainalysis Address Screening (cheapest, simplest API).
|
||||||
|
2. Per-offer setting: `requireAmlCheck: true|false` plus `amlCheckPricePaidBy: 'seller'`.
|
||||||
|
3. When AML required, the in-house checkout webhook hits the provider with the buyer's source address. Result feeds into Transaction Safety Provider as a real `aml_screening` check.
|
||||||
|
4. Seller's account is debited for the per-check cost from their Amanat balance (or the payment is partially withheld for the cost).
|
||||||
|
|
||||||
|
### Hard-known facts
|
||||||
|
- AML providers charge per-check (USD 0.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.
|
||||||
@@ -208,6 +208,7 @@ These are documented in their respective sections but worth highlighting:
|
|||||||
> - Opening a dispute does **not pause** the escrow until admin intervention. See [[Dispute Flow]] + [[Escrow Flow]].
|
> - Opening a dispute does **not pause** the escrow until admin intervention. See [[Dispute Flow]] + [[Escrow Flow]].
|
||||||
> - Several development env values committed as public — see [[Environment Variables]] for rotation list.
|
> - Several development env values committed as public — see [[Environment Variables]] for rotation list.
|
||||||
> - Single-host deployment; horizontal scaling requires Redis adapter for Socket.IO — see [[Real-time Layer]] §8.
|
> - Single-host deployment; horizontal scaling requires Redis adapter for Socket.IO — see [[Real-time Layer]] §8.
|
||||||
|
> - Request Network webhooks currently land on the main app. Roadmap: Cloudflare Worker durable ingress + replay, with backend Transaction Safety Provider checks before escrow is credited. See [[Request Network Integration Constraints]].
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Taskmaster Dashboard
|
# Taskmaster Dashboard
|
||||||
|
|
||||||
Generated from `.taskmaster/tasks/tasks.json` at 2026-05-24T07:15:25.199Z.
|
Generated from `.taskmaster/tasks/tasks.json` at 2026-05-28T11:49:27.076Z.
|
||||||
|
|
||||||
Taskmaster remains the canonical source of truth. Re-run:
|
Taskmaster remains the canonical source of truth. Re-run:
|
||||||
|
|
||||||
@@ -10,9 +10,9 @@ node scripts/export-taskmaster-to-obsidian.mjs
|
|||||||
|
|
||||||
## Status Summary
|
## Status Summary
|
||||||
|
|
||||||
- done: 28
|
- done: 44
|
||||||
- in-progress: 3
|
- in-progress: 2
|
||||||
- pending: 14
|
- pending: 8
|
||||||
|
|
||||||
## Task Index
|
## Task Index
|
||||||
|
|
||||||
@@ -43,26 +43,35 @@ node scripts/export-taskmaster-to-obsidian.mjs
|
|||||||
| [[Tasks/task-3-10|3.10]] | Update release/refund APIs and marketplace release paths | done | high | 3.8, 3.9 |
|
| [[Tasks/task-3-10|3.10]] | Update release/refund APIs and marketplace release paths | done | high | 3.8, 3.9 |
|
||||||
| [[Tasks/task-3-11|3.11]] | Add comprehensive observability, runbooks, and incident controls | done | high | 3.6, 3.8, 3.9, 3.10 |
|
| [[Tasks/task-3-11|3.11]] | Add comprehensive observability, runbooks, and incident controls | done | high | 3.6, 3.8, 3.9, 3.10 |
|
||||||
| [[Tasks/task-3-12|3.12]] | Add end-to-end integration, migration, and rollback test suites | done | high | 3.6, 3.10, 3.11 |
|
| [[Tasks/task-3-12|3.12]] | Add end-to-end integration, migration, and rollback test suites | done | high | 3.6, 3.10, 3.11 |
|
||||||
| [[Tasks/task-4|4]] | Define backend security and refactor strategy from latest audit | in-progress | high | None |
|
| [[Tasks/task-3-13|3.13]] | Add durable RN webhook ingress and transaction safety | pending | high | None |
|
||||||
|
| [[Tasks/task-4|4]] | Define backend security and refactor strategy from latest audit | done | high | None |
|
||||||
| [[Tasks/task-4-1|4.1]] | Assign security ownership and launch decision criteria | done | high | None |
|
| [[Tasks/task-4-1|4.1]] | Assign security ownership and launch decision criteria | done | high | None |
|
||||||
| [[Tasks/task-4-2|4.2]] | Produce threat model for escrow platform | done | high | 1 |
|
| [[Tasks/task-4-2|4.2]] | Produce threat model for escrow platform | done | high | 1 |
|
||||||
| [[Tasks/task-4-3|4.3]] | Specify funds ledger and escrow state machine | pending | high | 2 |
|
| [[Tasks/task-4-3|4.3]] | Specify funds ledger and escrow state machine | done | high | 2 |
|
||||||
| [[Tasks/task-4-4|4.4]] | Create authorization matrix for REST and Socket.IO | pending | high | 2 |
|
| [[Tasks/task-4-4|4.4]] | Create authorization matrix for REST and Socket.IO | done | high | 2 |
|
||||||
| [[Tasks/task-4-5|4.5]] | Decide session, passkey, and admin step-up architecture | pending | high | 2 |
|
| [[Tasks/task-4-5|4.5]] | Decide session, passkey, and admin step-up architecture | done | high | 2 |
|
||||||
| [[Tasks/task-4-6|4.6]] | Specify webhook security and provider adapter contracts | pending | high | 3 |
|
| [[Tasks/task-4-6|4.6]] | Specify webhook security and provider adapter contracts | done | high | 3 |
|
||||||
| [[Tasks/task-4-7|4.7]] | Define secure build and supply-chain policy | done | medium | 1 |
|
| [[Tasks/task-4-7|4.7]] | Define secure build and supply-chain policy | done | medium | 1 |
|
||||||
| [[Tasks/task-4-8|4.8]] | Make backend-core stack decision | pending | medium | 2, 3, 4, 5, 6, 7 |
|
| [[Tasks/task-4-8|4.8]] | Make backend-core stack decision | done | medium | 2, 3, 4, 5, 6, 7 |
|
||||||
| [[Tasks/task-4-9|4.9]] | Create migration and operational runbooks | pending | medium | 8 |
|
| [[Tasks/task-4-9|4.9]] | Create migration and operational runbooks | done | medium | 8 |
|
||||||
| [[Tasks/task-5|5]] | Deliver Telegram-native app, bot, and wallet experience | in-progress | high | None |
|
| [[Tasks/task-5|5]] | Deliver Telegram-native app, bot, and wallet experience | in-progress | high | None |
|
||||||
| [[Tasks/task-5-1|5.1]] | Define Telegram product surface and flow map | in-progress | high | None |
|
| [[Tasks/task-5-1|5.1]] | Define Telegram product surface and flow map | done | high | None |
|
||||||
| [[Tasks/task-5-2|5.2]] | Build Telegram identity linking and session model | pending | high | 1 |
|
| [[Tasks/task-5-2|5.2]] | Build Telegram identity linking and session model | done | high | 1 |
|
||||||
| [[Tasks/task-5-3|5.3]] | Implement bot command and notification foundation | pending | high | 1, 2 |
|
| [[Tasks/task-5-3|5.3]] | Implement bot command and notification foundation | done | high | 1, 2 |
|
||||||
| [[Tasks/task-5-4|5.4]] | Build Telegram Mini App shell for marketplace workflows | pending | high | 1, 2 |
|
| [[Tasks/task-5-4|5.4]] | Build Telegram Mini App shell for marketplace workflows | in-progress | high | 1, 2 |
|
||||||
| [[Tasks/task-5-5|5.5]] | Add Telegram payment and wallet strategy | pending | high | 2, 4 |
|
| [[Tasks/task-5-5|5.5]] | Add Telegram payment and wallet strategy | done | high | 2, 4 |
|
||||||
| [[Tasks/task-5-6|5.6]] | Expose escrow, delivery, dispute, and release actions safely | pending | high | 4, 5 |
|
| [[Tasks/task-5-6|5.6]] | Expose escrow, delivery, dispute, and release actions safely | pending | high | 4, 5 |
|
||||||
| [[Tasks/task-5-7|5.7]] | Add admin and support surface for Telegram-originated cases | pending | high | 2, 3, 5 |
|
| [[Tasks/task-5-7|5.7]] | Add admin and support surface for Telegram-originated cases | pending | high | 2, 3, 5 |
|
||||||
| [[Tasks/task-5-8|5.8]] | Add security, compliance, and abuse controls for Telegram | pending | high | 2, 3, 5, 6 |
|
| [[Tasks/task-5-8|5.8]] | Add security, compliance, and abuse controls for Telegram | done | high | 2, 3, 5, 6 |
|
||||||
| [[Tasks/task-5-9|5.9]] | Prepare QA, rollout, analytics, and launch operations | pending | high | 3, 4, 5, 6, 7, 8 |
|
| [[Tasks/task-5-9|5.9]] | Prepare QA, rollout, analytics, and launch operations | done | high | 3, 4, 5, 6, 7, 8 |
|
||||||
|
| [[Tasks/task-5-10|5.10]] | Implement Telegram as first-class authentication provider | done | high | 2, 8 |
|
||||||
|
| [[Tasks/task-6|6]] | Request Network in-house checkout (Rabby-supporting) | done | high | None |
|
||||||
|
| [[Tasks/task-6-1|6.1]] | Deploy confirmation repair before next paid probe | done | high | None |
|
||||||
|
| [[Tasks/task-7|7]] | Per-(buyer, sellerOffer) ephemeral RN destination wallets | pending | high | None |
|
||||||
|
| [[Tasks/task-8|8]] | Multichain RN proxy registry + USDC/USDT support | pending | high | None |
|
||||||
|
| [[Tasks/task-9|9]] | Per-chain confirmation thresholds + admin UI | pending | medium | None |
|
||||||
|
| [[Tasks/task-10|10]] | Optional AML screening on incoming payments (seller-paid) | pending | medium | None |
|
||||||
|
| [[Tasks/task-11|11]] | Trezor signing for admin actions (release/refund/sweep) | pending | high | None |
|
||||||
|
|
||||||
## Obsidian Tasks Query
|
## Obsidian Tasks Query
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "medium"
|
|||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: "1"
|
parent_id: "1"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 1.1 - Fix Security Architecture email/password sequence
|
# 1.1 - Fix Security Architecture email/password sequence
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "medium"
|
|||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: "1"
|
parent_id: "1"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 1.2 - Fix authentication login and refresh diagrams
|
# 1.2 - Fix authentication login and refresh diagrams
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "medium"
|
|||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: "1"
|
parent_id: "1"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 1.3 - Fix chat, delivery, dispute, OAuth, purchase request, referral, registration, and seller-offer diagrams
|
# 1.3 - Fix chat, delivery, dispute, OAuth, purchase request, referral, registration, and seller-offer diagrams
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "medium"
|
|||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: ""
|
parent_id: ""
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 1 - Stabilize Mermaid diagram rendering across documentation vault
|
# 1 - Stabilize Mermaid diagram rendering across documentation vault
|
||||||
|
|||||||
35
Taskmaster/Tasks/task-10.md
Normal file
35
Taskmaster/Tasks/task-10.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
taskmaster_id: "10"
|
||||||
|
status: "pending"
|
||||||
|
priority: "medium"
|
||||||
|
depends_on: []
|
||||||
|
parent_id: ""
|
||||||
|
source: "taskmaster"
|
||||||
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 10 - Optional AML screening on incoming payments (seller-paid)
|
||||||
|
|
||||||
|
- [ ] 10 - Optional AML screening on incoming payments (seller-paid) #taskmaster #priority/medium #status/pending 🔼 🆔 tm-10
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| Taskmaster ID | 10 |
|
||||||
|
| Status | pending |
|
||||||
|
| Priority | medium |
|
||||||
|
| Dependencies | None |
|
||||||
|
| Parent | None |
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Turn the existing aml_screening placeholder in TransactionSafetyProvider into a real Chainalysis (or equivalent) Address Screening call that the seller opts into per-offer and pays the per-check cost for.
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §4. Default provider recommendation: Chainalysis Address Screening (cheapest, simplest). Files: new backend/src/services/payment/safety/amlProvider.ts interface + chainalysisProvider.ts impl behind env TRANSACTION_SAFETY_AML_PROVIDER=chainalysis with API_KEY in KMS; transactionSafetyProvider's evaluateAmlPlaceholder() becomes real, persists raw provider response on Payment.metadata.amlResult; Offer schema add requireAmlCheck + amlBlockOnFailure booleans; offer-edit UI toggle 'Require AML on incoming payments ($X per payment, paid by you)'; admin global config UI for provider selection + API key rotation + per-chain enabled flag; cost accounting: deduct per-check cost from seller's escrow on completion as a separate ledger line item, surfaced on payment-details. Open questions before code: pick provider (Chainalysis vs TRM vs Elliptic — need 1-page comparison of cost/latency/coverage); failure mode (fail-closed only when seller opted in AND amlBlockOnFailure=true, else warn/log); cost batching cadence. Acceptance: seller toggles AML on an offer; incoming payment triggers a real Chainalysis call; sanctions verdict blocks the safety gate; clean verdict passes; seller's settled amount reduced by check cost; admin can rotate API key without redeploy; provider-down + amlBlockOnFailure=true keeps payment pending with provider_unavailable reason. Dependencies: none. This is task #10 in the PRD.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
_No verification strategy._
|
||||||
35
Taskmaster/Tasks/task-11.md
Normal file
35
Taskmaster/Tasks/task-11.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
taskmaster_id: "11"
|
||||||
|
status: "pending"
|
||||||
|
priority: "high"
|
||||||
|
depends_on: []
|
||||||
|
parent_id: ""
|
||||||
|
source: "taskmaster"
|
||||||
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 11 - Trezor signing for admin actions (release/refund/sweep)
|
||||||
|
|
||||||
|
- [ ] 11 - Trezor signing for admin actions (release/refund/sweep) #taskmaster #priority/high #status/pending ⏫ 🆔 tm-11
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| Taskmaster ID | 11 |
|
||||||
|
| Status | pending |
|
||||||
|
| Priority | high |
|
||||||
|
| Dependencies | None |
|
||||||
|
| Parent | None |
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Replace the hot-key admin signing flow with a WebUSB-based Trezor flow so the backend never holds a private key. All admin-side txes are built backend, signed via Trezor in the browser, broadcast from the browser.
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §5. Lib: @trezor/connect-web (WebUSB; Chromium-only — Firefox users need Trezor Bridge native helper). Files: new frontend/src/web3/trezor/trezorConnector.ts wrapping @trezor/connect-web; existing admin actions (release/refund/sweep when #7 lands) get a 'Sign with Trezor' button that flows: POST /api/admin/actions/build-tx → returns unsigned tx bytes → send to Trezor → sign → wagmi sendTransaction broadcasts → POST /api/admin/actions/confirm-tx with hash; admin settings page to register Trezor address(es) (backend rejects signatures from unauthorized devices); audit log on every Trezor-signed action; break-glass hot-key path requires explicit admin toggle, expires after 1h, fires Telegram alarm. Open questions: m-of-n multi-admin signing — default single-signer for v1; Trezor One vs Model T — lib abstracts; fallback when Trezor unavailable — break-glass with alarm. Acceptance: admin registers Trezor address; release flow uses Trezor end-to-end; backend rejects signatures from unregistered devices; audit log captures admin user + Trezor addr + tx hash + before/after escrow state; break-glass works and alarms. Non-goals: mobile Trezor flow, buyer-side Trezor (buyer uses wagmi injected). Dependencies: task #7 (ephemeral wallets) for the sweep step — but task #11 can ship the release/refund flows first. This is task #11 in the PRD.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
_No verification strategy._
|
||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: "2"
|
parent_id: "2"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 2.1 - Secure unauthenticated endpoints and owner enforcement
|
# 2.1 - Secure unauthenticated endpoints and owner enforcement
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["1"]
|
depends_on: ["1"]
|
||||||
parent_id: "2"
|
parent_id: "2"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 2.2 - Re-enable and scope rate limiting
|
# 2.2 - Re-enable and scope rate limiting
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["1"]
|
depends_on: ["1"]
|
||||||
parent_id: "2"
|
parent_id: "2"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 2.3 - Replace stubbed passkey/WebAuthn flow
|
# 2.3 - Replace stubbed passkey/WebAuthn flow
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["1"]
|
depends_on: ["1"]
|
||||||
parent_id: "2"
|
parent_id: "2"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 2.4 - Strengthen DePay/Web3 payment verification
|
# 2.4 - Strengthen DePay/Web3 payment verification
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "medium"
|
|||||||
depends_on: ["1"]
|
depends_on: ["1"]
|
||||||
parent_id: "2"
|
parent_id: "2"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 2.5 - Lock Socket.IO room joins to authenticated context
|
# 2.5 - Lock Socket.IO room joins to authenticated context
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "medium"
|
|||||||
depends_on: ["1", "4"]
|
depends_on: ["1", "4"]
|
||||||
parent_id: "2"
|
parent_id: "2"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 2.6 - Enforce dispute hold before payout and release operations
|
# 2.6 - Enforce dispute hold before payout and release operations
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "medium"
|
|||||||
depends_on: ["1", "2", "3", "4", "5", "6"]
|
depends_on: ["1", "2", "3", "4", "5", "6"]
|
||||||
parent_id: "2"
|
parent_id: "2"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 2.7 - Align documentation, API references, and runtime enums
|
# 2.7 - Align documentation, API references, and runtime enums
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: ""
|
parent_id: ""
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 2 - Implement platform audit remediation plan
|
# 2 - Implement platform audit remediation plan
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.1 - Define provider-neutral payment contracts and adapter
|
# 3.1 - Define provider-neutral payment contracts and adapter
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3.8", "3.9"]
|
depends_on: ["3.8", "3.9"]
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.10 - Update release/refund APIs and marketplace release paths
|
# 3.10 - Update release/refund APIs and marketplace release paths
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3.6", "3.8", "3.9", "3.10"]
|
depends_on: ["3.6", "3.8", "3.9", "3.10"]
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.11 - Add comprehensive observability, runbooks, and incident controls
|
# 3.11 - Add comprehensive observability, runbooks, and incident controls
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3.6", "3.10", "3.11"]
|
depends_on: ["3.6", "3.10", "3.11"]
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.12 - Add end-to-end integration, migration, and rollback test suites
|
# 3.12 - Add end-to-end integration, migration, and rollback test suites
|
||||||
|
|||||||
35
Taskmaster/Tasks/task-3-13.md
Normal file
35
Taskmaster/Tasks/task-3-13.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
taskmaster_id: "3.13"
|
||||||
|
status: "pending"
|
||||||
|
priority: "high"
|
||||||
|
depends_on: []
|
||||||
|
parent_id: "3"
|
||||||
|
source: "taskmaster"
|
||||||
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 3.13 - Add durable RN webhook ingress and transaction safety
|
||||||
|
|
||||||
|
- [ ] 3.13 - Add durable RN webhook ingress and transaction safety #taskmaster #priority/high #status/pending ⏫ 🆔 tm-3-13
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| Taskmaster ID | 3.13 |
|
||||||
|
| Status | pending |
|
||||||
|
| Priority | high |
|
||||||
|
| Dependencies | None |
|
||||||
|
| Parent | 3 - Migrate payment architecture toward Request Network and internal funds management |
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Roadmap follow-up from the 2026-05-28 dev payment probe: Request Network delivered the webhook but Amanat returned 404. Add Cloudflare Worker durable webhook ingress with storage/replay and keep backend Transaction Safety Provider checks as the trust boundary before marking escrow funded.
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
_No details._
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
_No verification strategy._
|
||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3.1"]
|
depends_on: ["3.1"]
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.2 - Implement provider configuration, feature flags, and safe rollback
|
# 3.2 - Implement provider configuration, feature flags, and safe rollback
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3.1"]
|
depends_on: ["3.1"]
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.3 - Create internal funds and payment ledger model
|
# 3.3 - Create internal funds and payment ledger model
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3.3"]
|
depends_on: ["3.3"]
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.4 - Build migration and indexing plan for existing SHKeeper records
|
# 3.4 - Build migration and indexing plan for existing SHKeeper records
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3.2"]
|
depends_on: ["3.2"]
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.5 - Implement Request Network pay-in intent and secure payment pages
|
# 3.5 - Implement Request Network pay-in intent and secure payment pages
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3.2"]
|
depends_on: ["3.2"]
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.6 - Implement signed Request Network webhook intake
|
# 3.6 - Implement signed Request Network webhook intake
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3.5", "3.6"]
|
depends_on: ["3.5", "3.6"]
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.7 - Implement reconciliation and repair jobs
|
# 3.7 - Implement reconciliation and repair jobs
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3.5"]
|
depends_on: ["3.5"]
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.8 - Replace checkout and payment UI with provider-neutral flows
|
# 3.8 - Replace checkout and payment UI with provider-neutral flows
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3.3", "3.7"]
|
depends_on: ["3.3", "3.7"]
|
||||||
parent_id: "3"
|
parent_id: "3"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3.9 - Add payout/release and refund orchestration using ledger gates
|
# 3.9 - Add payout/release and refund orchestration using ledger gates
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["2"]
|
depends_on: ["2"]
|
||||||
parent_id: ""
|
parent_id: ""
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 3 - Migrate payment architecture toward Request Network and internal funds management
|
# 3 - Migrate payment architecture toward Request Network and internal funds management
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.1 - Assign security ownership and launch decision criteria
|
# 4.1 - Assign security ownership and launch decision criteria
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["1"]
|
depends_on: ["1"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.2 - Produce threat model for escrow platform
|
# 4.2 - Produce threat model for escrow platform
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["2"]
|
depends_on: ["2"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:26:29.052Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.3 - Specify funds ledger and escrow state machine
|
# 4.3 - Specify funds ledger and escrow state machine
|
||||||
@@ -28,8 +28,6 @@ Define canonical money movement and legal state transitions before refactor or p
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
Completed. Produced `09 - Audits/Funds Ledger and Escrow State Machine Specification.md` (states, transitions, invariants, and migration guidance for canonical funds/escrow transitions).
|
|
||||||
|
|
||||||
Create specs for FundsAccount, LedgerEntry, FundsBalance, gross paid, provider fees, platform fees, held, disputed, releasable, released, refunded, idempotency keys, reconciliation behavior, purchase request states, payment states, escrow/funds states, dispute states, valid transitions, forbidden transitions, and release/refund/admin override preconditions.
|
Create specs for FundsAccount, LedgerEntry, FundsBalance, gross paid, provider fees, platform fees, held, disputed, releasable, released, refunded, idempotency keys, reconciliation behavior, purchase request states, payment states, escrow/funds states, dispute states, valid transitions, forbidden transitions, and release/refund/admin override preconditions.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["2"]
|
depends_on: ["2"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:26:29.052Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.4 - Create authorization matrix for REST and Socket.IO
|
# 4.4 - Create authorization matrix for REST and Socket.IO
|
||||||
@@ -28,8 +28,6 @@ Map every endpoint and realtime event to access level, ownership checks, state p
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
Completed. Produced `09 - Audits/Authorization Matrix - REST and Socket.IO.md` and `09 - Audits/Realtime Authorization Spec.md`.
|
|
||||||
|
|
||||||
Include public/authenticated/owner/buyer/seller/admin/support/service-role classifications. Socket.IO rooms must be server-derived from authenticated identity, not client-supplied user IDs.
|
Include public/authenticated/owner/buyer/seller/admin/support/service-role classifications. Socket.IO rooms must be server-derived from authenticated identity, not client-supplied user IDs.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["2"]
|
depends_on: ["2"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:26:29.052Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.5 - Decide session, passkey, and admin step-up architecture
|
# 4.5 - Decide session, passkey, and admin step-up architecture
|
||||||
@@ -28,8 +28,6 @@ Choose browser session model and high-risk admin authentication requirements.
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
Completed. Produced `09 - Audits/Session and Authentication Architecture Decision.md`.
|
|
||||||
|
|
||||||
Decide localStorage versus httpOnly cookies, access/refresh token lifetimes, CSRF strategy, refresh rotation, WebAuthn requirements, OAuth requirements, device/session revocation, and whether payouts/role changes require step-up authentication or two-person approval.
|
Decide localStorage versus httpOnly cookies, access/refresh token lifetimes, CSRF strategy, refresh rotation, WebAuthn requirements, OAuth requirements, device/session revocation, and whether payouts/role changes require step-up authentication or two-person approval.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["3"]
|
depends_on: ["3"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:26:29.052Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.6 - Specify webhook security and provider adapter contracts
|
# 4.6 - Specify webhook security and provider adapter contracts
|
||||||
@@ -28,8 +28,6 @@ Define provider-neutral payment interface and signed webhook processing rules.
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
Completed. Produced `09 - Audits/Webhook Security Spec.md` and `09 - Audits/Payment Provider Adapter Spec.md`.
|
|
||||||
|
|
||||||
Document createPayInIntent, getPayInStatus, handleProviderWebhook, createHostedPaymentLink, createReleaseInstruction, createRefundInstruction, getPayoutStatus, searchProviderPayments, raw-body signature verification, replay prevention, delivery ID idempotency, duplicate/unknown event behavior, retry semantics, dead-letter/replay storage, and alert thresholds.
|
Document createPayInIntent, getPayInStatus, handleProviderWebhook, createHostedPaymentLink, createReleaseInstruction, createRefundInstruction, getPayoutStatus, searchProviderPayments, raw-body signature verification, replay prevention, delivery ID idempotency, duplicate/unknown event behavior, retry semantics, dead-letter/replay storage, and alert thresholds.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "medium"
|
|||||||
depends_on: ["1"]
|
depends_on: ["1"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.7 - Define secure build and supply-chain policy
|
# 4.7 - Define secure build and supply-chain policy
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "medium"
|
|||||||
depends_on: ["2", "3", "4", "5", "6", "7"]
|
depends_on: ["2", "3", "4", "5", "6", "7"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:26:29.052Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.8 - Make backend-core stack decision
|
# 4.8 - Make backend-core stack decision
|
||||||
@@ -28,8 +28,6 @@ Choose whether the security-critical backend core remains TypeScript or moves to
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
Completed. Produced `09 - Audits/Backend Core Stack Decision Record - 2026-05-24.md`.
|
|
||||||
|
|
||||||
Evaluate team capability, two-year maintainability, operational footprint, rewrite cost, dual-stack complexity, auditability, supply-chain exposure, and which modules belong in a payment/auth/escrow core versus the existing marketplace/chat API.
|
Evaluate team capability, two-year maintainability, operational footprint, rewrite cost, dual-stack complexity, auditability, supply-chain exposure, and which modules belong in a payment/auth/escrow core versus the existing marketplace/chat API.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "medium"
|
|||||||
depends_on: ["8"]
|
depends_on: ["8"]
|
||||||
parent_id: "4"
|
parent_id: "4"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:26:29.052Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4.9 - Create migration and operational runbooks
|
# 4.9 - Create migration and operational runbooks
|
||||||
@@ -28,8 +28,6 @@ Document rollout, rollback, and incident response for the selected backend/funds
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
Completed. Produced `08 - Operations/Backend Funds Migration and Operational Runbooks.md`.
|
|
||||||
|
|
||||||
Include SHKeeper legacy read path, provider feature flag, ledger backfill, validation report before enforcement, rollback criteria, webhook cutoff, manual reconciliation, failed webhook, duplicate/missing payment, stuck release, disputed release attempt, compromised admin, leaked API key, provider outage, chain/RPC outage, suspicious payment proof, and npm/package compromise.
|
Include SHKeeper legacy read path, provider feature flag, ledger backfill, validation report before enforcement, rollback criteria, webhook cutoff, manual reconciliation, failed webhook, duplicate/missing payment, stuck release, disputed release attempt, compromised admin, leaked API key, provider outage, chain/RPC outage, suspicious payment proof, and npm/package compromise.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: ""
|
parent_id: ""
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:26:29.052Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 4 - Define backend security and refactor strategy from latest audit
|
# 4 - Define backend security and refactor strategy from latest audit
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "5.1"
|
taskmaster_id: "5.1"
|
||||||
status: "in-progress"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: "5"
|
parent_id: "5"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5.1 - Define Telegram product surface and flow map
|
# 5.1 - Define Telegram product surface and flow map
|
||||||
|
|
||||||
- [ ] 5.1 - Define Telegram product surface and flow map #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5-1
|
- [x] 5.1 - Define Telegram product surface and flow map #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-1
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 5.1 |
|
| Taskmaster ID | 5.1 |
|
||||||
| Status | in-progress |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | None |
|
| Dependencies | None |
|
||||||
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
||||||
|
|||||||
@@ -2,16 +2,15 @@
|
|||||||
taskmaster_id: "5.10"
|
taskmaster_id: "5.10"
|
||||||
status: "done"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: ["5.2", "5.8"]
|
depends_on: ["2", "8"]
|
||||||
parent_id: "5"
|
parent_id: "5"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T09:18:26.638Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
completed_at: "2026-05-24"
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5.10 - Implement Telegram as first-class authentication provider
|
# 5.10 - Implement Telegram as first-class authentication provider
|
||||||
|
|
||||||
- [x] 5.10 - Implement Telegram as first-class authentication provider #taskmaster #priority/high #status/done ⏫ 🆔 tm-5.10
|
- [x] 5.10 - Implement Telegram as first-class authentication provider #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-10 ⛔ tm-2 ⛔ tm-8
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
@@ -20,24 +19,19 @@ completed_at: "2026-05-24"
|
|||||||
| Taskmaster ID | 5.10 |
|
| Taskmaster ID | 5.10 |
|
||||||
| Status | done |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | 5.2, 5.8 |
|
| Dependencies | 2, 8 |
|
||||||
| Parent | 5 |
|
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
Add `POST /api/auth/telegram` and frontend login flow so users can authenticate with Amanat using only Telegram identity, without email or password.
|
Add a POST /auth/telegram endpoint and frontend login flow so users can authenticate with Amanat using only their Telegram identity — no email or password required.
|
||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
Backend verifies Telegram Mini App `initData` and Telegram Login Widget payloads, checks/reuses `TelegramLink`, auto-provisions Telegram-only users with nullable email, `authProvider: "telegram"`, and `telegramVerified: true`, and returns the normal JWT/refresh-token pair plus `isNewUser`.
|
Source PRD: .taskmaster/docs/prd-telegram-phone-auth.md. Backend: create POST /auth/telegram that accepts Mini App initData or Telegram Login Widget payload, verifies the signature (reuse verifyMiniAppInitData; add verifyTelegramLoginWidget for the widget path), looks up TelegramLink by telegramUserId, and either authenticates the linked user or auto-provisions a new Amanat account (authProvider: telegram, telegramVerified: true, nullable email via sparse unique index). Returns JWT + refreshToken + isNewUser flag. Apply existing replay protection and rate limits. User model: make email nullable (sparse index), add authProvider and telegramVerified fields. Frontend: auto-detect Telegram Mini App context and skip login page; POST initData to /auth/telegram; show lightweight onboarding overlay for new users (optional email, language, currency). Add 'Continue with Telegram' button on web login page alongside Google OAuth. Security: blocked Telegram accounts return 403 regardless of re-linking attempts; high-risk action step-up policy is unchanged; never expose raw phone number.
|
||||||
|
|
||||||
Frontend auto-authenticates Telegram Mini App launches from raw signed `initData`, adds a Telegram login action, and shows a lightweight onboarding dialog for new Telegram users.
|
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
- Backend typecheck passed.
|
Verify: new Telegram user auto-provisions and receives JWT; returning user authenticates via both initData and Login Widget; replayed initData is rejected; stale auth_date is rejected; blocked account returns 403; existing email-password users are unaffected; email remains optional (not required) for Telegram-authed users; isNewUser flag triggers onboarding overlay; high-risk actions still require step-up confirmation.
|
||||||
- Backend targeted Jest passed: `__tests__/telegram-auth.test.ts`, `__tests__/telegram-service.test.ts`.
|
|
||||||
- Frontend targeted Jest passed: `__tests__/auth/telegram-auth-action.test.ts`, `__tests__/sections/telegram/telegram-mini-app-shell.test.tsx`.
|
|
||||||
- Full frontend typecheck still has unrelated pre-existing payment UI errors outside this task.
|
|
||||||
|
|
||||||
See [[Task 5.10 Telegram First-Class Authentication]] for the audit report.
|
Implemented verification: backend typecheck; backend targeted Jest __tests__/telegram-auth.test.ts and __tests__/telegram-service.test.ts; frontend targeted Jest __tests__/auth/telegram-auth-action.test.ts and __tests__/sections/telegram/telegram-mini-app-shell.test.tsx. Full frontend typecheck still has unrelated pre-existing payment icon/payload errors outside Task 5.10.
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "5.2"
|
taskmaster_id: "5.2"
|
||||||
status: "pending"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: ["1"]
|
depends_on: ["1"]
|
||||||
parent_id: "5"
|
parent_id: "5"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5.2 - Build Telegram identity linking and session model
|
# 5.2 - Build Telegram identity linking and session model
|
||||||
|
|
||||||
- [ ] 5.2 - Build Telegram identity linking and session model #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-2 ⛔ tm-1
|
- [x] 5.2 - Build Telegram identity linking and session model #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-2 ⛔ tm-1
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 5.2 |
|
| Taskmaster ID | 5.2 |
|
||||||
| Status | pending |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | 1 |
|
| Dependencies | 1 |
|
||||||
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "5.3"
|
taskmaster_id: "5.3"
|
||||||
status: "pending"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: ["1", "2"]
|
depends_on: ["1", "2"]
|
||||||
parent_id: "5"
|
parent_id: "5"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5.3 - Implement bot command and notification foundation
|
# 5.3 - Implement bot command and notification foundation
|
||||||
|
|
||||||
- [ ] 5.3 - Implement bot command and notification foundation #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-3 ⛔ tm-1 ⛔ tm-2
|
- [x] 5.3 - Implement bot command and notification foundation #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-3 ⛔ tm-1 ⛔ tm-2
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 5.3 |
|
| Taskmaster ID | 5.3 |
|
||||||
| Status | pending |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | 1, 2 |
|
| Dependencies | 1, 2 |
|
||||||
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "5.4"
|
taskmaster_id: "5.4"
|
||||||
status: "pending"
|
status: "in-progress"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: ["1", "2"]
|
depends_on: ["1", "2"]
|
||||||
parent_id: "5"
|
parent_id: "5"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5.4 - Build Telegram Mini App shell for marketplace workflows
|
# 5.4 - Build Telegram Mini App shell for marketplace workflows
|
||||||
|
|
||||||
- [ ] 5.4 - Build Telegram Mini App shell for marketplace workflows #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-4 ⛔ tm-1 ⛔ tm-2
|
- [ ] 5.4 - Build Telegram Mini App shell for marketplace workflows #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5-4 ⛔ tm-1 ⛔ tm-2
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 5.4 |
|
| Taskmaster ID | 5.4 |
|
||||||
| Status | pending |
|
| Status | in-progress |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | 1, 2 |
|
| Dependencies | 1, 2 |
|
||||||
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "5.5"
|
taskmaster_id: "5.5"
|
||||||
status: "pending"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: ["2", "4"]
|
depends_on: ["2", "4"]
|
||||||
parent_id: "5"
|
parent_id: "5"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5.5 - Add Telegram payment and wallet strategy
|
# 5.5 - Add Telegram payment and wallet strategy
|
||||||
|
|
||||||
- [ ] 5.5 - Add Telegram payment and wallet strategy #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-5 ⛔ tm-2 ⛔ tm-4
|
- [x] 5.5 - Add Telegram payment and wallet strategy #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-5 ⛔ tm-2 ⛔ tm-4
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 5.5 |
|
| Taskmaster ID | 5.5 |
|
||||||
| Status | pending |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | 2, 4 |
|
| Dependencies | 2, 4 |
|
||||||
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["4", "5"]
|
depends_on: ["4", "5"]
|
||||||
parent_id: "5"
|
parent_id: "5"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5.6 - Expose escrow, delivery, dispute, and release actions safely
|
# 5.6 - Expose escrow, delivery, dispute, and release actions safely
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: ["2", "3", "5"]
|
depends_on: ["2", "3", "5"]
|
||||||
parent_id: "5"
|
parent_id: "5"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5.7 - Add admin and support surface for Telegram-originated cases
|
# 5.7 - Add admin and support surface for Telegram-originated cases
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "5.8"
|
taskmaster_id: "5.8"
|
||||||
status: "pending"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: ["2", "3", "5", "6"]
|
depends_on: ["2", "3", "5", "6"]
|
||||||
parent_id: "5"
|
parent_id: "5"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5.8 - Add security, compliance, and abuse controls for Telegram
|
# 5.8 - Add security, compliance, and abuse controls for Telegram
|
||||||
|
|
||||||
- [ ] 5.8 - Add security, compliance, and abuse controls for Telegram #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5 ⛔ tm-6
|
- [x] 5.8 - Add security, compliance, and abuse controls for Telegram #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5 ⛔ tm-6
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 5.8 |
|
| Taskmaster ID | 5.8 |
|
||||||
| Status | pending |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | 2, 3, 5, 6 |
|
| Dependencies | 2, 3, 5, 6 |
|
||||||
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
---
|
---
|
||||||
taskmaster_id: "5.9"
|
taskmaster_id: "5.9"
|
||||||
status: "pending"
|
status: "done"
|
||||||
priority: "high"
|
priority: "high"
|
||||||
depends_on: ["3", "4", "5", "6", "7", "8"]
|
depends_on: ["3", "4", "5", "6", "7", "8"]
|
||||||
parent_id: "5"
|
parent_id: "5"
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5.9 - Prepare QA, rollout, analytics, and launch operations
|
# 5.9 - Prepare QA, rollout, analytics, and launch operations
|
||||||
|
|
||||||
- [ ] 5.9 - Prepare QA, rollout, analytics, and launch operations #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-9 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7 ⛔ tm-8
|
- [x] 5.9 - Prepare QA, rollout, analytics, and launch operations #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-9 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7 ⛔ tm-8
|
||||||
|
|
||||||
## Metadata
|
## Metadata
|
||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Taskmaster ID | 5.9 |
|
| Taskmaster ID | 5.9 |
|
||||||
| Status | pending |
|
| Status | done |
|
||||||
| Priority | high |
|
| Priority | high |
|
||||||
| Dependencies | 3, 4, 5, 6, 7, 8 |
|
| Dependencies | 3, 4, 5, 6, 7, 8 |
|
||||||
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
| Parent | 5 - Deliver Telegram-native app, bot, and wallet experience |
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ priority: "high"
|
|||||||
depends_on: []
|
depends_on: []
|
||||||
parent_id: ""
|
parent_id: ""
|
||||||
source: "taskmaster"
|
source: "taskmaster"
|
||||||
generated_at: "2026-05-24T07:15:25.199Z"
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5 - Deliver Telegram-native app, bot, and wallet experience
|
# 5 - Deliver Telegram-native app, bot, and wallet experience
|
||||||
|
|||||||
35
Taskmaster/Tasks/task-6-1.md
Normal file
35
Taskmaster/Tasks/task-6-1.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
taskmaster_id: "6.1"
|
||||||
|
status: "done"
|
||||||
|
priority: "high"
|
||||||
|
depends_on: []
|
||||||
|
parent_id: "6"
|
||||||
|
source: "taskmaster"
|
||||||
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 6.1 - Deploy confirmation repair before next paid probe
|
||||||
|
|
||||||
|
- [x] 6.1 - Deploy confirmation repair before next paid probe #taskmaster #priority/high #status/done ⏫ 🆔 tm-6-1
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| Taskmaster ID | 6.1 |
|
||||||
|
| Status | done |
|
||||||
|
| Priority | high |
|
||||||
|
| Dependencies | None |
|
||||||
|
| Parent | 6 - Request Network in-house checkout (Rabby-supporting) |
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
2026-05-28 dev BSC transaction succeeded and RN delivered four webhooks, but Amanat returned 404 due Request Network reference-correlation mismatch. Before another paid payment test, deploy the backend correlation fix, callback polling fix, signed-webhook smoke test, and Transaction Safety Provider gate; then repeat the probe and inspect safety decision state.
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
_No details._
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
_No verification strategy._
|
||||||
35
Taskmaster/Tasks/task-6.md
Normal file
35
Taskmaster/Tasks/task-6.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
taskmaster_id: "6"
|
||||||
|
status: "done"
|
||||||
|
priority: "high"
|
||||||
|
depends_on: []
|
||||||
|
parent_id: ""
|
||||||
|
source: "taskmaster"
|
||||||
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 6 - Request Network in-house checkout (Rabby-supporting)
|
||||||
|
|
||||||
|
- [x] 6 - Request Network in-house checkout (Rabby-supporting) #taskmaster #priority/high #status/done ⏫ 🆔 tm-6
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| Taskmaster ID | 6 |
|
||||||
|
| Status | done |
|
||||||
|
| Priority | high |
|
||||||
|
| Dependencies | None |
|
||||||
|
| Parent | None |
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Replace the redirect to pay.request.network with an Amanat-rendered checkout page that submits the same on-chain calls as RN's hosted UI, so RN's webhook fires unchanged but buyers stay on amn.gg and Rabby works.
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
See PRD: nick-doc/.taskmaster/docs/prd-request-network-in-house-checkout.md (summary at nick-doc/PRD - Request Network In-House Checkout.md). Status: draft, pending review with second developer. Approach: replicate the two on-chain calls (approve + RN_FEE_PROXY.transferFromWithReferenceAndFee) using wagmi v2 with existing injected()/metaMask() connectors (Rabby works via EIP-6963). Hard-known: proxy 0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9, selector 0xc219a14d, paymentRef = last8Bytes(keccak256(requestId+salt+dest)), feeAmount=0, feeAddress=0x...dEaD. Backend: extend POST /payment/request-network/intents response with inHouseCheckout object (destination, tokenAddress, decimals, chainId, proxyAddress, paymentReference, feeAmount, feeAddress, amountWei). Frontend: new page /checkout/request-network/:paymentId with state machine reusing manual-payment.tsx layout chrome, hosted-page link kept as escape hatch. Implementation gated on a $0.50 cold probe on dev BSC to confirm RN's webhook fires for an externally-built tx. Out of scope: per-seller multi-chain config (§2), ephemeral wallets (§3), full RN removal (§4), gasless. Open questions in PRD §10.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
_No verification strategy._
|
||||||
35
Taskmaster/Tasks/task-7.md
Normal file
35
Taskmaster/Tasks/task-7.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
taskmaster_id: "7"
|
||||||
|
status: "pending"
|
||||||
|
priority: "high"
|
||||||
|
depends_on: []
|
||||||
|
parent_id: ""
|
||||||
|
source: "taskmaster"
|
||||||
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 7 - Per-(buyer, sellerOffer) ephemeral RN destination wallets
|
||||||
|
|
||||||
|
- [ ] 7 - Per-(buyer, sellerOffer) ephemeral RN destination wallets #taskmaster #priority/high #status/pending ⏫ 🆔 tm-7
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| Taskmaster ID | 7 |
|
||||||
|
| Status | pending |
|
||||||
|
| Priority | high |
|
||||||
|
| Dependencies | None |
|
||||||
|
| Parent | None |
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Replace the single shared Amanat destination wallet with a per-(buyerId, sellerOfferId) HD-derived address sent to Request Network on intent creation, plus sweep-on-approval and an admin UI.
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §1. Files: new backend/src/services/payment/wallets/derivedDestinations.ts (getDestinationFor(buyerId, sellerOfferId) → {address, derivationPath, chainId}); Payment schema add metadata.derivedDestination; requestNetworkPayInService.ts override destinationId before POST /v2/secure-payments (we confirmed RN accepts different destinations per intent); new sweep cron + admin manual-trigger endpoint gated on Transaction Safety Provider; admin UI at /dashboard/admin/derived-destinations with address, balance, last sweep tx (BscScan link), ownership status. Open questions to settle first: HD vs disposable EOAs vs smart-forwarder (recommended HD); sweep cadence (recommended immediate); granularity (recommended per-(buyer, seller), not per-payment); re-use vs rotate after sweep. KMS-rooted seed; backend never holds raw private keys; signing via KMS API (Task #11 Trezor flow is the longer-term replacement). Acceptance: two payments from one buyer to two sellers land on two different addresses; RN webhook fires for both; sweep is idempotent; master seed never leaves KMS.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
_No verification strategy._
|
||||||
35
Taskmaster/Tasks/task-8.md
Normal file
35
Taskmaster/Tasks/task-8.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
taskmaster_id: "8"
|
||||||
|
status: "pending"
|
||||||
|
priority: "high"
|
||||||
|
depends_on: []
|
||||||
|
parent_id: ""
|
||||||
|
source: "taskmaster"
|
||||||
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 8 - Multichain RN proxy registry + USDC/USDT support
|
||||||
|
|
||||||
|
- [ ] 8 - Multichain RN proxy registry + USDC/USDT support #taskmaster #priority/high #status/pending ⏫ 🆔 tm-8
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| Taskmaster ID | 8 |
|
||||||
|
| Status | pending |
|
||||||
|
| Priority | high |
|
||||||
|
| Dependencies | None |
|
||||||
|
| Parent | None |
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Probe and persist RN ERC20FeeProxy addresses on BSC/Arb/ETH/Polygon/Base, add USDC + USDT token entries with correct decimals per chain, and surface an admin networks page. Include the USDT-mainnet approve(0) reset quirk in the frontend approve step.
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §2. Tasks: new backend/scripts/probe-rn-chains.ts that walks each chain in supported-chains.json and verifies the canonical 0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9 proxy is the real RN proxy via a known view fn (CREATE2 is deterministic, but verify); promote backend/src/services/payment/requestNetwork/tokens.ts to load from JSON + admin override; add USDT entries on all 5 chains (BSC USDT 18-dec quirk, mainnet/Arb/Polygon/Base USDT 6-dec); buildInHouseCheckoutBlock returns reason='unsupported_chain:<id>' for unknowns; new admin route GET /api/admin/rn/networks + frontend page /dashboard/admin/networks rendering the registry with per-row 'probe again'. Frontend approve flow: if buyer is on Ethereum mainnet AND token is USDT AND current allowance > 0, do approve(spender, 0) first then approve(spender, amount). Acceptance: probe succeeds on at least BSC/Arb/Polygon/ETH/Base; one paid probe on BSC USDT end-to-end; mainnet USDT approve(0) reset works; admin page reflects registry. Dependencies: none — runs in parallel with #9. This is task #8 in the PRD.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
_No verification strategy._
|
||||||
35
Taskmaster/Tasks/task-9.md
Normal file
35
Taskmaster/Tasks/task-9.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
taskmaster_id: "9"
|
||||||
|
status: "pending"
|
||||||
|
priority: "medium"
|
||||||
|
depends_on: []
|
||||||
|
parent_id: ""
|
||||||
|
source: "taskmaster"
|
||||||
|
generated_at: "2026-05-28T11:49:27.076Z"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 9 - Per-chain confirmation thresholds + admin UI
|
||||||
|
|
||||||
|
- [ ] 9 - Per-chain confirmation thresholds + admin UI #taskmaster #priority/medium #status/pending 🔼 🆔 tm-9
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| Taskmaster ID | 9 |
|
||||||
|
| Status | pending |
|
||||||
|
| Priority | medium |
|
||||||
|
| Dependencies | None |
|
||||||
|
| Parent | None |
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Make TransactionSafetyProvider's confirmation threshold tunable at runtime per chain via admin UI, with an awaiting-confirmation payments view that shows live confirmations vs threshold.
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
See PRD - Wallet, Multichain, Confirmations, AML, Trezor.md §3. Today TRANSACTION_SAFETY_MIN_CONFIRMATIONS is a global env var, default 12, baked in until redeploy. Move to runtime config: new Setting docs keyed 'confirmation_threshold:<chainId>' or extend existing model; cache reads in transactionSafetyProvider.ts for 30s; GET/PATCH /api/admin/settings/confirmation-thresholds (auth: admin); new admin page /dashboard/admin/confirmation-thresholds (table: chain, current, recommended default, edit-in-place with confirm dialog, audit log of changes); new admin page /dashboard/admin/payments/awaiting-confirmation (payments where escrowState !== 'funded' AND metadata.transactionSafety.lastCheck.status === 'pending'; for each show tx hash linked to explorer, current confirmations via 12s poll on BSC, threshold, ETA). Acceptance: admin lowers BSC threshold from 12 to 3 on dev, next webhook honors new value within 30s; awaiting-confirmation table updates live; audit log records every change. Non-goals: per-asset, per-seller thresholds. Dependencies: none. This is task #9 in the PRD.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
_No verification strategy._
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Taskmaster Tasks
|
# Taskmaster Tasks
|
||||||
|
|
||||||
Generated from `.taskmaster/tasks/tasks.json` at 2026-05-24T07:15:25.199Z.
|
Generated from `.taskmaster/tasks/tasks.json` at 2026-05-28T11:49:27.076Z.
|
||||||
|
|
||||||
These lines use the Obsidian Tasks emoji format:
|
These lines use the Obsidian Tasks emoji format:
|
||||||
|
|
||||||
@@ -35,23 +35,32 @@ These lines use the Obsidian Tasks emoji format:
|
|||||||
- [x] 3.10 - Update release/refund APIs and marketplace release paths #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-10 ⛔ tm-3-8 ⛔ tm-3-9
|
- [x] 3.10 - Update release/refund APIs and marketplace release paths #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-10 ⛔ tm-3-8 ⛔ tm-3-9
|
||||||
- [x] 3.11 - Add comprehensive observability, runbooks, and incident controls #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-11 ⛔ tm-3-6 ⛔ tm-3-8 ⛔ tm-3-9 ⛔ tm-3-10
|
- [x] 3.11 - Add comprehensive observability, runbooks, and incident controls #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-11 ⛔ tm-3-6 ⛔ tm-3-8 ⛔ tm-3-9 ⛔ tm-3-10
|
||||||
- [x] 3.12 - Add end-to-end integration, migration, and rollback test suites #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-12 ⛔ tm-3-6 ⛔ tm-3-10 ⛔ tm-3-11
|
- [x] 3.12 - Add end-to-end integration, migration, and rollback test suites #taskmaster #priority/high #status/done ⏫ 🆔 tm-3-12 ⛔ tm-3-6 ⛔ tm-3-10 ⛔ tm-3-11
|
||||||
- [ ] 4 - Define backend security and refactor strategy from latest audit #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-4
|
- [ ] 3.13 - Add durable RN webhook ingress and transaction safety #taskmaster #priority/high #status/pending ⏫ 🆔 tm-3-13
|
||||||
|
- [x] 4 - Define backend security and refactor strategy from latest audit #taskmaster #priority/high #status/done ⏫ 🆔 tm-4
|
||||||
- [x] 4.1 - Assign security ownership and launch decision criteria #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-1
|
- [x] 4.1 - Assign security ownership and launch decision criteria #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-1
|
||||||
- [x] 4.2 - Produce threat model for escrow platform #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-2 ⛔ tm-1
|
- [x] 4.2 - Produce threat model for escrow platform #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-2 ⛔ tm-1
|
||||||
- [ ] 4.3 - Specify funds ledger and escrow state machine #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-3 ⛔ tm-2
|
- [x] 4.3 - Specify funds ledger and escrow state machine #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-3 ⛔ tm-2
|
||||||
- [ ] 4.4 - Create authorization matrix for REST and Socket.IO #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-4 ⛔ tm-2
|
- [x] 4.4 - Create authorization matrix for REST and Socket.IO #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-4 ⛔ tm-2
|
||||||
- [ ] 4.5 - Decide session, passkey, and admin step-up architecture #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-5 ⛔ tm-2
|
- [x] 4.5 - Decide session, passkey, and admin step-up architecture #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-5 ⛔ tm-2
|
||||||
- [ ] 4.6 - Specify webhook security and provider adapter contracts #taskmaster #priority/high #status/pending ⏫ 🆔 tm-4-6 ⛔ tm-3
|
- [x] 4.6 - Specify webhook security and provider adapter contracts #taskmaster #priority/high #status/done ⏫ 🆔 tm-4-6 ⛔ tm-3
|
||||||
- [x] 4.7 - Define secure build and supply-chain policy #taskmaster #priority/medium #status/done 🔼 🆔 tm-4-7 ⛔ tm-1
|
- [x] 4.7 - Define secure build and supply-chain policy #taskmaster #priority/medium #status/done 🔼 🆔 tm-4-7 ⛔ tm-1
|
||||||
- [ ] 4.8 - Make backend-core stack decision #taskmaster #priority/medium #status/pending 🔼 🆔 tm-4-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7
|
- [x] 4.8 - Make backend-core stack decision #taskmaster #priority/medium #status/done 🔼 🆔 tm-4-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7
|
||||||
- [ ] 4.9 - Create migration and operational runbooks #taskmaster #priority/medium #status/pending 🔼 🆔 tm-4-9 ⛔ tm-8
|
- [x] 4.9 - Create migration and operational runbooks #taskmaster #priority/medium #status/done 🔼 🆔 tm-4-9 ⛔ tm-8
|
||||||
- [ ] 5 - Deliver Telegram-native app, bot, and wallet experience #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5
|
- [ ] 5 - Deliver Telegram-native app, bot, and wallet experience #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5
|
||||||
- [ ] 5.1 - Define Telegram product surface and flow map #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5-1
|
- [x] 5.1 - Define Telegram product surface and flow map #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-1
|
||||||
- [ ] 5.2 - Build Telegram identity linking and session model #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-2 ⛔ tm-1
|
- [x] 5.2 - Build Telegram identity linking and session model #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-2 ⛔ tm-1
|
||||||
- [ ] 5.3 - Implement bot command and notification foundation #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-3 ⛔ tm-1 ⛔ tm-2
|
- [x] 5.3 - Implement bot command and notification foundation #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-3 ⛔ tm-1 ⛔ tm-2
|
||||||
- [ ] 5.4 - Build Telegram Mini App shell for marketplace workflows #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-4 ⛔ tm-1 ⛔ tm-2
|
- [ ] 5.4 - Build Telegram Mini App shell for marketplace workflows #taskmaster #priority/high #status/in-progress ⏫ 🆔 tm-5-4 ⛔ tm-1 ⛔ tm-2
|
||||||
- [ ] 5.5 - Add Telegram payment and wallet strategy #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-5 ⛔ tm-2 ⛔ tm-4
|
- [x] 5.5 - Add Telegram payment and wallet strategy #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-5 ⛔ tm-2 ⛔ tm-4
|
||||||
- [ ] 5.6 - Expose escrow, delivery, dispute, and release actions safely #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-6 ⛔ tm-4 ⛔ tm-5
|
- [ ] 5.6 - Expose escrow, delivery, dispute, and release actions safely #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-6 ⛔ tm-4 ⛔ tm-5
|
||||||
- [ ] 5.7 - Add admin and support surface for Telegram-originated cases #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-7 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5
|
- [ ] 5.7 - Add admin and support surface for Telegram-originated cases #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-7 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5
|
||||||
- [ ] 5.8 - Add security, compliance, and abuse controls for Telegram #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5 ⛔ tm-6
|
- [x] 5.8 - Add security, compliance, and abuse controls for Telegram #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-8 ⛔ tm-2 ⛔ tm-3 ⛔ tm-5 ⛔ tm-6
|
||||||
- [ ] 5.9 - Prepare QA, rollout, analytics, and launch operations #taskmaster #priority/high #status/pending ⏫ 🆔 tm-5-9 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7 ⛔ tm-8
|
- [x] 5.9 - Prepare QA, rollout, analytics, and launch operations #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-9 ⛔ tm-3 ⛔ tm-4 ⛔ tm-5 ⛔ tm-6 ⛔ tm-7 ⛔ tm-8
|
||||||
|
- [x] 5.10 - Implement Telegram as first-class authentication provider #taskmaster #priority/high #status/done ⏫ 🆔 tm-5-10 ⛔ tm-2 ⛔ tm-8
|
||||||
|
- [x] 6 - Request Network in-house checkout (Rabby-supporting) #taskmaster #priority/high #status/done ⏫ 🆔 tm-6
|
||||||
|
- [x] 6.1 - Deploy confirmation repair before next paid probe #taskmaster #priority/high #status/done ⏫ 🆔 tm-6-1
|
||||||
|
- [ ] 7 - Per-(buyer, sellerOffer) ephemeral RN destination wallets #taskmaster #priority/high #status/pending ⏫ 🆔 tm-7
|
||||||
|
- [ ] 8 - Multichain RN proxy registry + USDC/USDT support #taskmaster #priority/high #status/pending ⏫ 🆔 tm-8
|
||||||
|
- [ ] 9 - Per-chain confirmation thresholds + admin UI #taskmaster #priority/medium #status/pending 🔼 🆔 tm-9
|
||||||
|
- [ ] 10 - Optional AML screening on incoming payments (seller-paid) #taskmaster #priority/medium #status/pending 🔼 🆔 tm-10
|
||||||
|
- [ ] 11 - Trezor signing for admin actions (release/refund/sweep) #taskmaster #priority/high #status/pending ⏫ 🆔 tm-11
|
||||||
|
|||||||
Reference in New Issue
Block a user