From ebb13be7c9ec3514e28bb2e0caf9bd3444fe1013 Mon Sep 17 00:00:00 2001 From: Josue19-08 Date: Thu, 10 Sep 2026 12:27:55 -0600 Subject: [PATCH] Wire 'Report as scam' action in the UI SyncRiskList.reportScam already existed in packages/core but nothing in apps/web called it, so a user recognizing a scam address had no way to add it to the local risk list for future AnalyzeSendIntent checks (or, once P2P lands, to propagate it to peers). Co-Authored-By: Claude Sonnet 5 --- apps/web/src/App.tsx | 26 +++++++++++++++++++++++--- apps/web/src/compositionRoot.ts | 3 ++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index 8f54c0b..8ef877e 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -1,29 +1,46 @@ import { useState } from "react"; -import type { RiskAssessment } from "@custos/core"; +import type { Address, RiskAssessment } from "@custos/core"; import { requiresFriction, requiresHardBlock } from "@custos/core"; -import { analyzeSendIntent } from "./compositionRoot.js"; +import { analyzeSendIntent, syncRiskList } from "./compositionRoot.js"; export function App() { const [address, setAddress] = useState(""); const [amount, setAmount] = useState(""); const [context, setContext] = useState(""); + const [destination, setDestination] = useState
(null); const [assessment, setAssessment] = useState(null); const [busy, setBusy] = useState(false); + const [reporting, setReporting] = useState(false); + const [reported, setReported] = useState(false); async function handleCheck() { setBusy(true); + setReported(false); try { + const checkedDestination: Address = { value: address, network: "tron" }; const result = await analyzeSendIntent.execute({ - destination: { value: address, network: "tron" }, + destination: checkedDestination, amountUsdt: Number(amount) || 0, context: context ? { text: context } : undefined, }); + setDestination(checkedDestination); setAssessment(result); } finally { setBusy(false); } } + async function handleReportScam() { + if (!destination) return; + setReporting(true); + try { + await syncRiskList.reportScam(destination); + setReported(true); + } finally { + setReporting(false); + } + } + return (

Custos

@@ -74,6 +91,9 @@ export function App() { Risk level: {assessment.level}

{assessment.summary}

{requiresHardBlock(assessment.level) &&

This send would be blocked — WDK signing must not proceed.

} + )}
diff --git a/apps/web/src/compositionRoot.ts b/apps/web/src/compositionRoot.ts index f5ed7ad..3ed47f0 100644 --- a/apps/web/src/compositionRoot.ts +++ b/apps/web/src/compositionRoot.ts @@ -1,4 +1,4 @@ -import { AnalyzeSendIntent, RecordUserDecision } from "@custos/core"; +import { AnalyzeSendIntent, RecordUserDecision, SyncRiskList } from "@custos/core"; import { QvacScamDetectionAdapter } from "@custos/adapters-qvac"; import { LocalRiskListAdapter } from "@custos/adapters-p2p"; import { LocalAuditLogAdapter } from "@custos/adapters-storage"; @@ -15,3 +15,4 @@ const auditLog = new LocalAuditLogAdapter(); export const analyzeSendIntent = new AnalyzeSendIntent({ scamDetection, riskList }); export const recordUserDecision = new RecordUserDecision({ auditLog }); +export const syncRiskList = new SyncRiskList({ riskList });