import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { useTradeReputation } from '@/hooks/useTradeAttestations'; import { useBatchTrustScores } from '@/hooks/useBatchTrustScores'; import { cn } from '@/lib/utils'; import { Handshake } from 'lucide-react'; function Stat({ label, value, accent }: { label: string; value: number; accent?: boolean }) { return (

{value}

{label}

); } /** * Marketplace reputation for a profile, derived from mutually-signed trade * attestations (kind 31871, see NIP.md → Trade Attestations). * * "Verified" is the strong signal: the seller AND the counterparty both signed * an attestation for the same listing. Renders nothing when there are no trades. */ export function TradeReputationCard({ pubkey, className }: { pubkey: string; className?: string }) { const { data } = useTradeReputation(pubkey); const verifiedWith = data?.verifiedWith ?? []; // Trust-weight each mutually-confirmed trade by the counterparty's web-of-trust // score, so a ring of fresh accounts can't inflate reputation. const { data: scores } = useBatchTrustScores(verifiedWith.map((v) => v.pubkey)); const total = (data?.sales ?? 0) + (data?.purchases ?? 0); if (!data || total === 0) return null; const people = data.verifiedCounterparties; // Cap each counterparty's contribution at 3 so one partner — or a colluding // pair confirming each other over and over — can't inflate the score. const weighted = verifiedWith.reduce( (sum, v) => sum + Math.min(v.count, 3) * ((scores?.get(v.pubkey) ?? 0) / 100), 0, ); const trustLabel = weighted >= 5 ? 'Highly trusted trader' : weighted >= 1 ? 'Building reputation' : 'New trader'; // The classic fake-reputation pattern: several "trades", all with one account. const singlePartnerWarning = data.verified >= 3 && people <= 1; return ( Trades

{data.verified > 0 ? `${data.verified} mutually-confirmed ${data.verified === 1 ? 'trade' : 'trades'} with ${people} ${people === 1 ? 'person' : 'people'}` : 'Awaiting mutual confirmation'}

{singlePartnerWarning && (

⚠ Every confirmation is with the same account. Mutual confirmation is self-reported, so treat this record with care.

)} {data.verified > 0 && (

Trust-weighted {weighted.toFixed(1)} {' · '} {trustLabel}

)}

Self-reported and mutually signed — a signal, not proof of payment.

); }