DEV Community

ABIN SHAJI THOMAS
ABIN SHAJI THOMAS

Posted on

ScamLens: an evidence-linked scam check for India, built on TigerGraph

The problem

A typical Indian scam starts with a message: "Your bank account has been hacked. Pay Rs 35,000 now to this UPI ID or this wallet." The victim has seconds to decide. Most checkers either say "looks fine" or give a score nobody can verify.

ScamLens is an evidence-linked scam check. Paste a suspicious message, wallet address, UPI ID or Telegram handle and you get a Low / Elevated / High risk level where every claim links to evidence you can open. It was built for Hacker House Goa 2026 by team ArcReap.

Three tiers that are never mixed

Tier What it means
Verified The identifier is on a public list: US OFAC sanctions, ScamSniffer's blacklist, GoPlus, Etherscan, TronGrid. A source link is shown.
Reported At least 2 independent reporters flagged it within 90 days.
Suspected One of 18 fixed pattern rules matched, and the exact quote from the text is shown.

The risk level is computed by fixed code, not guessed by an AI. High needs a verified match, or an independent report plus a counted signal. Suspected alone never produces High, so a brand-new scam honestly caps at Elevated until real evidence exists. A Low result always says "this does not mean safe".

Identifiers come only from a strict extractor. A wallet must pass its built-in checksum (EIP-55 for Ethereum-style addresses, Base58Check for TRON and Bitcoin, bech32), so typos and invented addresses are not treated as real. The principle is "AI proposes, code disposes": ScamLens runs with no LLM at runtime.

Where TigerGraph comes in

One identifier alone often looks harmless. Scammers reuse wallets across campaigns, and the same Telegram admin recruits for different scams. In a table, each report is a separate row, so those links stay hidden.

Our graph (ScamLens on TigerGraph Savanna) has Report, Wallet, UPI, TelegramHandle, PhoneNumber and Domain vertices, linked when a report mentions several identifiers together. Four installed GSQL queries do the work:

  1. Q1: start from a UPI ID, follow the wallet it shares with other reports, and reach the Telegram handles tied to that wallet, but only when at least 2 independent reporters back it.
  2. Q2: find wallets that pay already-flagged addresses within 2 hops.
  3. Q3: find Telegram clusters that pay the same wallet.
  4. Q4: a neighbourhood view for the graph panel.

A hub filter (default 25) keeps a busy exchange-style address from linking everything together.

Architecture

Browser -> Next.js (Vercel) -> extractor (checksums) -> verified sources
                                   |                         |
                                   v                         v
                       18 pattern rules            risk engine (fixed code)
                                   |
                                   v
              TigerGraph (links)  <->  Postgres (system of record, labelled fallback)
Enter fullscreen mode Exit fullscreen mode

Postgres on Supabase is the system of record. TigerGraph is the link engine. If the graph is paused or fails, the result says "Graph backend: postgres" instead of pretending the graph ran. A parity script runs the same cases through both and checks they agree: 19 of 19 pass.

What went wrong, and what we learned

Our first migration failed with "Access Denied". Report.reporter_key is on a global vertex type, and our graph-scoped token could not change global schema. A query also refused to compile until that attribute existed. We ran a GSQL global schema change job in the editor, reinstalled the queries, and re-ran our setup script until parity passed. The setup script now checks the schema first and prints a human step instead of attempting global changes.

Savanna also pauses and does not auto-start, so the fallback is not optional. We designed it from the start.

Results

  • 80 synthetic evaluation cases: 0 false positives, 0 false negatives (the early code had 3 and 2).
  • Warning-context detection so a genuine bank warning like "never share your OTP" is not flagged.
  • Ed25519-signed receipts that anyone can verify in the browser at /verify.
  • An "I already paid" plan: call 1930, tell your bank, then cybercrime.gov.in, with a complaint draft built in the browser.
  • No login, and the user's check is never stored.

Honest limits

The Reported tier and the graph links rely on synthetic data labelled "Illustrative demo data" until real independent reports exist. A suspicious wording we have not covered can still get a Low. The eval is synthetic, so it measures rule behaviour, not real-world accuracy.

Stack

Next.js 16, TypeScript, Tailwind CSS 4, TigerGraph Savanna (GSQL), Supabase Postgres, Vercel, zod, viem, Vitest.

Built by team ArcReap at Hacker House Goa 2026 for TigerGraph. Feedback welcome: scamlenspvt@gmail.com or @scamlens on X.

Top comments (0)