Skip to content

youvandra/WalletLens

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

73 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WalletLens

On-chain wallet intelligence for agents. An A2MCP Agentic Service Provider on OKX.AI, running on X Layer.

WalletLens turns any X Layer wallet address into a decision-grade behavioral profile: an archetype with a confidence score, activity breakdown, token portfolio and net worth, behavioral scores, and risk signals — every result carrying an evidence block so an agent can weigh, trust, and justify what it does next.

Human layer (optional). Ask for roast: true and you also get a shareable "Wrapped" slideshow an agent can hand back to its user.

Live https://txwrap.my.id
MCP endpoint https://txwrap.my.id/mcp
Agent ID 4938 (X Layer, chain 196)
Price 0.05 USDT0 per tool call · 20 free calls/IP/day

Why an agent needs this

An autonomous agent working on-chain constantly runs into an address it knows nothing about. WalletLens is the primitive that answers:

"Who is this wallet, and should I act on it?"

As structured data the agent can compose — not a web page it has to scrape.

Crucially, every profile ships archetypeConfidence and an evidence block (how many transactions were analyzed, the window, an explicit caveat). Decisions get made on data the agent can reason about, not a black box.


Quick start

For agents

Point any MCP client at the endpoint. initialize and tools/list are free, so discovery always works:

curl -s -X POST https://txwrap.my.id/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Screen a counterparty before transacting with it:

curl -s -X POST https://txwrap.my.id/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{
    "jsonrpc": "2.0", "id": 2, "method": "tools/call",
    "params": {
      "name": "screen_wallet",
      "arguments": { "address": "0x69c236e021f5775b0d0328ded5eac708e3b869df" }
    }
  }'
{
  "address": "0x69c236e021f5775b0d0328ded5eac708e3b869df",
  "summary": "Risk medium — recommendation: caution. dormant: no activity for 121 days. Based on 250 of 3552345 txs.",
  "risk": "medium",
  "recommendation": "caution",
  "riskFlags": ["dormant"],
  "reasons": ["dormant: no activity for 121 days"],
  "blocklist": { "selfBlocklisted": false, "flaggedCounterparties": [] },
  "signalReasons": { "dormant": "no activity for 121 days" },
  "confidence": 0.85,
  "evidence": {
    "analyzedTx": 250,
    "totalTx": 3552345,
    "window": "most recent transactions",
    "caveat": "Derived from recent on-chain activity only, not full history."
  }
}

For humans

Open https://txwrap.my.id, paste an address, or click "see a sample wrap" to tour the slideshow with no wallet needed.


MCP tools

Tool Input Returns
profile_wallet address, roast? Full profile: archetype (+confidence), activity breakdown, portfolio, scores, signals, top counterparty, evidence. With roast: true, adds a human summary + slideshow URL.
classify_wallet address Cheap check: archetype, confidence, rarity tier, active signals, evidence.
screen_wallet address Risk screen: coarse risk level, a proceed/caution/avoid recommendation with per-flag numeric reasons, all 14 signals, a blocklist check (self + counterparties), evidence.
compare_wallets addresses[2..5] Side-by-side profiles, scores, and signals for ranking.
find_sybils addresses[3..20] Coordination screen: clusters wallets by shared counterparties, shared funder, and correlated timing, with a per-pair score.
screen_wallets addresses[2..20] Bulk light screen in one call: per-wallet risk, recommendation, flags, archetype, momentum. Made for vetting an allowlist cheaply; follow up on flagged wallets with screen_wallet.
check_approvals address The drainer check: decodes recent approve() calldata and reports each spender + allowance, flagging unlimited allowances and blocklisted spenders.
diff_wallet address Monitoring: first call saves a baseline, every later call reports what changed — archetype/momentum flips, signals gained/lost, new txns, net-worth moves.
expand_risk address Guilt-by-association: light-screens the wallet's top counterparties (both directions) and returns an aggregate neighborhood verdict. Verified token contracts excluded.
get_quota Free. Remaining free calls today + current x402 pricing. Never counts against the quota.
get_population Free. Aggregate of every wallet WalletLens has profiled: archetype + score distributions — the exact population behind the percentile field.

Profile shape

profile_wallet returns the full WalletMetrics object:

{
  "address": "0x…",
  "archetype": "The 2AM Degen",     // one of 11 rule-based archetypes
  "archetypeConfidence": 0.85,      // heuristic, capped at 0.95 — never certainty
  "rarity": "S-Tier",               // rank from your own standout score
  "percentile": {                   // omitted until the sample is large enough
    "standoutScore": 91, "topPercent": 5, "sampleSize": 420,
    "basis": "wallets profiled by WalletLens (not the full X Layer population)"
  },

  "totalTx": 847,
  "tokenSymbol": "OKB",
  "balanceEth": "12.4821",          // native balance, token units
  "netWorthUsd": "2465.32",         // native + ERC-20 holdings
  "gasBurnedEth": "3.2140",
  "swapCount": 213,

  "activityBreakdown": {            // classified by 4-byte method selector
    "swap": 213, "approve": 47, "transfer": 89, "native": 61, "other": 90
  },
  "portfolio": {
    "tokenCount": 7, "totalValueUsd": 1841.22, "stablecoinValueUsd": 614.43,
    "nftCount": 4, "topHoldings": [{ "symbol": "USDT", "amount": "614.05", "valueUsd": 614.43 }]
  },
  "tokenActivity": { "transferCount": 96, "uniqueTokens": 11, "inbound": 41, "outbound": 55, "topToken": "USDT" },
  "crossChain": { "total": 9, "deposits": 5, "withdrawals": 4 },
  "internalTxCount": 132,

  "defiScore": 78, "airdropScore": 82, "degenScore": 91, "whaleometer": 67,
  "diamondHandsDays": 14, "uniqueProtocols": 19,
  "peakHour": 2, "activityStreak": 23,
  "trajectory": { "tx7d": 12, "tx30d": 48, "prev7d": 7, "momentum": "heating" },
  "topFrenemy": "0x8f3a…7f80", "topFrenemyLabel": "0x8f3a…7f80",
  "topCounterparties": [           // top-5 outgoing, labeled when verified
    { "address": "0x74b7…6d22", "label": "USDC", "txCount": 41 }
  ],
  "topSenders": [                  // inbound mirror: who funds this wallet
    { "address": "0x8f3a…7f80", "label": "0x8f3a…7f80", "txCount": 17 }
  ],

  "summary": "The 2AM Degen (confidence 0.85, S-Tier), momentum heating, …",
  "signals": { "nightOwl": true, "approvalHeavy": true, "likelyBot": false, /**/ },
  "signalReasons": {               // the numbers behind every fired signal
    "nightOwl": "38% of 250 analyzed txs between 00:00-06:00 UTC",
    "approvalHeavy": "47 approvals in 250 analyzed txs"
  },
  "evidence": { "analyzedTx": 250, "totalTx": 847, "window": "", "caveat": "" }
}

Signals

Every tool result also carries a deterministic one-sentence summary an agent can relay verbatim (no AI call involved), and every fired signal comes with a signalReasons entry holding the actual numbers behind it — so a decision can be justified, not just made.

Attested results. screen_wallet, expand_risk, and check_approvals responses carry an attestation: an EIP-191 signature over the keccak256 of the canonical result, recoverable to a published signer address (GET /attestation/info). An agent can hand the result + attestation to a third party — another agent, or an OKX.AI dispute evaluator — who verifies it via POST /attestation/verify or plain ecrecover. Due diligence becomes portable proof, not a private API response. The signing key is an identity key only; it never holds funds.

A connecting agent is oriented automatically: the MCP initialize response carries server-level instructions — a which-tool-for-what guide, how to read results (summary / evidence / attestation), and the free-vs-paid cost model — so a client feeds the model a usage guide before its first call. Per-tool descriptions cover the specifics.

The full spec of how every number is produced ships as a free MCP resource: read txwrap://methodology (resources/read) for the exact thresholds and formulas behind every score, signal, archetype, and verdict — citable by any agent that needs to defend a decision made on our data.

Fourteen boolean flags, each derived only from what X Layer actually exposes:

Signal Means
nightOwl >30% of transactions between 00:00–06:00 UTC
approvalHeavy Approval-dominated activity — possible allowance risk
likelyBot Bot-like timing and volume
dustPattern Many tiny-value transactions
highSwapActivity Swap-dominated activity
newWallet First transaction under 30 days ago
dormant No activity for over 90 days
whale Large native balance or net worth
diversifiedPortfolio Holds 5+ ERC-20 tokens
stablecoinHeavy Over half of portfolio value in stablecoins
crossChainUser Has bridged via X Layer ↔ TradeZone
nftCollector Holds 3+ NFTs
contractHeavy More internal (contract) txns than external ones
reciprocalFlow Repeated two-way ping-pong with the same counterparties — wash-trading / fake-volume tell

screen_wallet promotes likelyBot, dustPattern, approvalHeavy, newWallet, dormant, and reciprocalFlow into riskFlags, then maps the count onto a coarse risk level (low / medium / high).

It also runs a blocklist check against a registry of known-malicious addresses (blocklist.ts, seeded with verified entries only, extendable via BLOCKLIST_ADDRESSES). A direct hit on the screened address adds the blocklisted flag and forces risk: high; a hit on any counterparty adds interactedWithBlocklisted. Both are reported under a blocklist object. For allowance-level detail, check_approvals decodes the wallet's recent approve() calldata (via the transaction-fills endpoint) and flags unlimited allowances and blocklisted spenders.


Use cases

Agent Task Tool
Trading / OTC "Before I send funds to 0xABC…, screen it for bot / sybil / dust-farming risk." screen_wallet
Airdrop / protocol "I'm airdropping to these 5 wallets — which look like farmers?" compare_wallets + screen_wallet
Airdrop / anti-sybil "Are these 12 wallets secretly one operator?" find_sybils
Allowlist vetting "Screen these 20 wallets cheaply, flag the risky ones." screen_wallets, then screen_wallet on hits
Security / hygiene "Does this wallet have dangerous open allowances?" check_approvals
Monitoring "Watch this counterparty — tell me when its behavior changes." diff_wallet on a schedule
Deep due diligence "The wallet looks clean — but who is it dealing with?" expand_risk
Budgeting "How many free calls do I have left today?" get_quota (free)
Research / portfolio "What kind of trader is 0xABC…?" profile_wallet
Risk "Rank these 3 addresses by activity and trustworthiness." compare_wallets
Growth / CRM "Classify these wallets into archetypes for our outreach list." classify_wallet
Social / content "Make a shareable Wrapped for my user's wallet." profile_wallet with roast: true

Pricing (x402)

MCP tool calls are metered with x402 v2, paid in USDT0 on X Layer (eip155:196), through OKX's official SDK (@okxweb3/x402-express + OKXFacilitatorClient + ExactEvmScheme).

How it flows:

  1. initialize, tools/list, and the get_quota tool are always free — any client can connect, discover the tools, and budget its spend.
  2. Each IP gets X402_FREE_DAILY (default 20) free tools/call per day. Remaining calls are reported in the X-Free-Calls-Remaining header.
  3. Past the quota the server answers HTTP 402 with a PAYMENT-REQUIRED header.
  4. The payer signs and replays the request. The OKX facilitator settles the transfer on-chain to X402_PAY_TO (syncSettle: true, so the payer gets a final result rather than a pending one).

This server holds no private key and pays no gas — settlement never passes through it. The facilitator reuses the XLAYER_* API credentials.

Decoded PAYMENT-REQUIRED challenge:

{
  "x402Version": 2,
  "resource": { "url": "https://txwrap.my.id/mcp", "mimeType": "application/json" },
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:196",
    "amount": "50000",
    "asset": "0x779ded0c9e1022225f8e0630b35a9b54be713736",
    "payTo": "0x736159a06c89ea5b12ed88be658741edca64324d",
    "maxTimeoutSeconds": 300,
    "extra": { "name": "USD₮0", "version": "1" }
  }]
}

Check live pricing any time: GET /x402/info.

Value note: pricing is per tool call, not per wallet — one screen_wallets call vets up to 20 addresses, and one find_sybils call clusters up to 20.


HTTP endpoints

Method Path Purpose Paid?
POST /mcp MCP server (Streamable HTTP) — the agent surface tools/call only
POST /api/txwrap REST human path: profile + roast + saved slideshow Free
GET /wrap/:address Shareable slideshow, with per-address OG meta Free
GET /og/:address.png Server-rendered 1200×630 share card Free
GET /x402/info Pricing and payment status Free
GET /attestation/info Attestation signer address + scheme Free
POST /attestation/verify Verify a result + attestation pair Free
GET /api/stats Real usage counters: agent tool calls, human wraps, unique addresses Free
GET /health Liveness probe Free

Architecture

                          POST /mcp  (MCP, agents)
                          POST /api/txwrap  (REST, humans)
                                   │
                          ┌────────▼────────┐
                          │  x402.ts        │  freemium gate; 402 past quota
                          └────────┬────────┘
                          ┌────────▼────────┐
                          │  service.ts     │  one pipeline, both surfaces
                          └────────┬────────┘
        ┌──────────────┬───────────┼───────────┬──────────────┐
        ▼              ▼           ▼           ▼              ▼
   fetcher.ts    analyzer.ts   labels.ts  personality.ts  renderer.ts
   (7 X Layer    (metrics,     (method    (AI roast,      (slideshow,
    endpoints,    signals,      + address  optional)       markdown)
    parallel)     confidence)   labels)
                                                            og.ts
                                                       (share card PNG)

Design rules:

  • service.ts is the single pipeline. MCP and REST both call it, so analysis logic exists in exactly one place.
  • The seven X Layer fetches run in parallel, and every supplementary one degrades gracefully — a flaky token-balance endpoint never takes down a profile.
  • The metrics engine is deterministic (math only). The AI layer only writes the roast, and it is optional.

Data sources

All from the X Layer Data API (HMAC-SHA256 signed):

Data Endpoint
Balance, tx count, first/last seen /address/information-evm
Native transaction history /address/transaction-list
ERC-20 holdings + USD values /address/token-balance
NFT (ERC-721) count /address/token-balance
ERC-20 transfer flows /address/token-transaction-list
Internal (contract) transactions /address/internal-transaction-list
Cross-chain X Layer ↔ TradeZone /tz/cross/transaction-list

The API returns balance, amount, and txFee as human-readable decimal strings, not wei. Parse with Number(), never BigInt().


Honesty rules

These are deliberate constraints, not omissions:

  • No fabricated percentiles. rarity is an honest self-referential tier (S…D) from the wallet's own standout score. A percentile ("top X%") is added only once we have profiled enough wallets to mean it (a sample floor), is measured against wallets WalletLens has profiled — explicitly not the full X Layer population — and is floored at 1% (never "top 0%"). Below the floor the field is simply absent.
  • Confidence is capped at 0.95. A recent-activity window can never justify certainty.
  • No guessed protocol names. labels.ts resolves known addresses; anything unknown renders as clean short hex rather than a plausible-looking lie.
  • Evidence travels with every result. analyzedTx vs totalTx, plus an explicit caveat.
  • The fee matches reality. A paid endpoint must actually settle. We declare 0.05 because x402 v2 settlement genuinely works.

Roadmap

Shipped and planned work beyond the current MVP. Grouped by the two axes the product optimizes for — agent decision-value and human virality — plus the reliability that both depend on.

Agent intelligence

  • Bulk screening + billing introspectionshippedscreen_wallets light-screens up to 20 wallets in one call (~2 upstream fetches per wallet instead of ~12), and the free get_quota tool reports remaining free calls + live pricing so an agent can budget before it spends. All tools now carry the MCP readOnlyHint annotation.
  • Decision-grade output v2shipped — every fired signal ships its numeric justification (signalReasons), every profile lists its top-5 labeled counterparties, every tool result opens with a deterministic summary sentence, and screen_wallet returns an actionable proceed/caution/avoid recommendation with per-flag reasons.
  • Protocol & address labelsshipped (tokens)labels.ts is now seeded with verified X Layer token contracts (WOKB, USDT0, USDC, DAI, USDG, xETH/xSOL/xBTC…) from OKX's official token list, so topFrenemy and find_sybils counterparties read real names instead of short hex. DEX routers / bridges stay unlabeled until an equally authoritative source confirms them (honest short-hex fallback holds).
  • find_sybils toolshipped — take 3–20 addresses and flag coordinated clusters (sybil.ts): shared counterparties (Jaccard), shared funding source, and correlated activity timing (cosine), grouped via union-find with a per-pair coordination score. A primitive for airdrop and grant screening.
  • Drainer / blocklist screenfully shippedscreen_wallet checks the address and its counterparties against a known-malicious registry (blocklist.ts, extendable via BLOCKLIST_ADDRESSES), and check_approvals (approvals.ts) decodes recent approve() calldata from the transaction-fills endpoint to flag unlimited allowances and blocklisted spenders — the drainer check that was previously deferred.
  • Wallet trajectoryshipped — every profile carries a trajectory block (tx7d, tx30d, prev7d, and a momentum of heating / cooling / steady / dormant), so an agent sees direction, not just a snapshot. compare_wallets surfaces momentum per wallet.

Reliability

  • Per-address profile cacheshipped — a short-TTL in-memory cache of metrics keyed by address (cache.ts), so compare_wallets and repeat calls don't re-fan-out ~12 upstream requests and trip X Layer throttling. Tunable via PROFILE_CACHE_TTL_MS.

Virality

  • Roast on the share cardshipped — the /og/:address.png card now carries a roast line (og.ts). A wrapped wallet gets its real AI roast baked in at wrap time; any other wallet falls back to the deterministic sarcastic title, so the line is always present, no extra AI call.
  • Real population percentilesshippedstats.ts keeps a rolling sample of standout scores; service.ts adds a percentile block (top X%, sample size, explicit basis) to a profile once the sample clears a floor, and withholds it below. Honest by construction — measured against wallets WalletLens has profiled, not all of X Layer.

Recommended order: labels → cache → find_sybils → drainer screen → roast card → trajectory → percentiles.


Development

Prerequisites

Node.js 20+, and OKX API credentials with X Layer Data API access.

Run locally

git clone https://github.com/youvandra/WalletLens.git
cd txwrap/backend
npm install

cp .env.example .env    # then fill it in
npm run dev             # tsx watch, defaults to port 3001

Then point an MCP client at http://localhost:3001/mcp, or open http://localhost:3001 for the slideshow.

Configuration

Variable Required Default Purpose
XLAYER_API_KEY yes OKX API key
XLAYER_SECRET_KEY yes OKX API secret (HMAC signing)
XLAYER_PASSPHRASE yes OKX API passphrase
PORT no 3001 HTTP port
NODE_ENV no development Environment
PROFILE_CACHE_TTL_MS no 120000 Metrics cache TTL (ms); 0 disables
BLOCKLIST_ADDRESSES no Extra known-malicious addresses for screen_wallet, comma-separated
ATTEST_PRIVATE_KEY no ephemeral Stable signer for result attestations; identity only, never holds funds
SUMOPOD_API_KEY no Enables the AI roast layer; without it a deterministic fallback is used
X402_MODE no off off | on — enable the payment gate
X402_PAY_TO when on Address that receives settled USDT0
X402_PRICE_USD no 0.05 Price per tool call, in USD
X402_FREE_DAILY no 20 Free tool calls per IP per day

The same OKX credentials drive both the Data API and the x402 facilitator.

Scripts

npm run dev     # tsx watch
npm run build   # tsc -> dist/
npm start       # node dist/index.js
npm test        # node:test suite (hermetic, no network)
npx tsc --noEmit  # typecheck

Project structure

backend/src/
  index.ts          Express server, routes, MCP + OG mounting
  service.ts        Shared pipeline: fetch -> analyze -> (roast)
  mcp.ts            MCP server, eleven agent tools
  neighborhood.ts   1-hop neighbor picking + circle verdict (expand_risk)
  sybil.ts          Coordination / sybil detection (pure, used by find_sybils)
  risk.ts           Shared risk-verdict mapping (single + bulk screens)
  approvals.ts      ERC-20 approval decoding — the drainer check
  snapshots.ts      Wallet snapshots + diffing (diff_wallet)
  methodology.ts    Citable spec of every formula (txwrap://methodology)
  attest.ts         EIP-191 signed result attestations (portable proof)
  blocklist.ts      Known-malicious address registry (screen_wallet)
  x402.ts           Payment gate (freemium + HTTP 402)
  xlayer-client.ts  X Layer Data API, HMAC-SHA256 auth
  fetcher.ts        Parallel fetches, graceful degradation
  analyzer.ts       Metrics, archetype, signals, confidence, evidence
  labels.ts         Method-selector + address labeling
  price.ts          Live OKB/USD price (cached, never-throw fallback)
  cache.ts          Generic in-memory TTL cache (memoizes wallet metrics)
  personality.ts    AI roast (optional layer)
  renderer.ts       Agent markdown report (roast layer)
  og.ts             1200x630 share card (SVG -> PNG)
  stats.ts          Real usage counters, persisted to disk
  types.ts          Shared types
  *.test.ts         node:test suites (analyzer, labels)
frontend/
  index.html        Alpine.js + Tailwind SPA (no build step)

Tech stack

  • Backend — Node.js, TypeScript, Express 5
  • Agent interface — Model Context Protocol (@modelcontextprotocol/sdk, Streamable HTTP)
  • Payments — x402 v2 via OKX Payment SDK (@okxweb3/x402-express)
  • Data — X Layer Data API (web3.okx.com), HMAC-SHA256 auth
  • AI — Sumopod (deepseek-v4-flash), optional roast layer
  • Frontend — Alpine.js + Tailwind CSS via CDN, neo-brutalist, no build step
  • Share cards — server-rendered SVG → PNG (@resvg/resvg-js)
  • Deploy — VPS behind nginx, TLS via Let's Encrypt, pm2

Submission

Built for the OKX.AI Genesis Hackathon. Deadline: Jul 17, 2026 23:59 UTC.

About

X Layer wallet address into a decision-grade behavioral profile.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors