Crypto wallet screening is much more than "look up the address on a list and block it if you find it". For the 0.5 BTC a real user just deposited at a real exchange, you need to run seven distinct steps in the background — from normalization through cluster lookup, hop-distance analysis, score aggregation, the final decision, and the audit log that proves it all happened. This guide walks operations teams through those seven steps in a way they can actually deploy: real failure modes at each step, scalability traps to avoid, and reasonable SLA targets.
This article is the operational companion to our blockchain AML pillar guide; the conceptual framework lives there, the implementation lives here.
Step 1: Address normalization
Before you call any screening API, validate and normalize the incoming address. This prevents both garbage-in-garbage-out at the provider and cache misses caused by different representations of the same address.
Per-chain rules:
- Bitcoin: Validate checksum for Bech32 (bc1...), Legacy P2PKH (1...), P2SH (3...), and Bech32m taproot (bc1p...) formats. Use BIP-173/BIP-350 for Bech32/taproot. Reject mixed-case input.
- EVM (Ethereum, BNB Chain, Polygon, Arbitrum, Optimism, Base): 42 characters,
0xprefix, EIP-55 mixed-case checksum validation. Lowercase-only inputs are risky — many systems accept them but the checksum guard is gone. - Solana: 32-byte ed25519 public key, base58 encoded. Verify curve-point validity.
- TRON: Base58Check, "T" prefix. The hex prefix (0x41) difference catches people out.
Practical tip: Use your normalized address as the cache key before sending it to the provider. If the same user re-deposits to the same address, a 24-hour cache hit cuts both provider cost and latency dramatically.
Step 2: Cluster lookup
Send the normalized address to your data provider's cluster lookup endpoint. A single API call is enough; typical latency is 50-150 ms.
Expected response shape (example):
{
"address": "bc1q...",
"cluster_id": "cluster_a8f3b2",
"cluster_name": "Binance hot wallet 14",
"cluster_type": "exchange",
"cluster_size": 4827193,
"risk_categories": [],
"direct_match": false,
"last_updated": "2026-05-22T08:14:00Z"
}
Read cluster_type early (exchange, custody, mining_pool, defi_pool, mixer, darknet_market, unknown) — this single field unlocks fast-path automation:
exchangeorcustody: Known tier-1 exchange or institutional custody → low risk, fast clear. Maintain your own allow-list for tier-2/3 exchanges; do not blanket-trust everything labeled "exchange".mining_pool: Generally clean outflow, but calibrate separately (some pools function as de-facto mixers).mixerordarknet_market: 0-hop direct match → auto-decline.unknownordefi_pool: Move to the next steps.
Step 3: Risk-signal categorization
If the provider response shows non-empty risk_categories, you have a direct match (direct_match: true). Evaluate the eight standard categories in priority order:
| Priority | Category | Typical decision (direct match) |
|---|---|---|
| 1 | CSAM | Auto-decline + SAR + custody freeze |
| 2 | Sanctions (OFAC, UN, EU, UK) | Auto-decline + SAR + competent-authority notification |
| 3 | Ransomware | Auto-decline + SAR |
| 4 | Stolen funds (major hack drainings) | Auto-decline + SAR |
| 5 | Darknet market | Manual review (high) or decline (per policy) |
| 6 | Mixer / tumbler | Manual review (high) |
| 7 | Scam / fraud | Manual review |
| 8 | Gambling (unlicensed) | Per policy — manual review or monitor |
When multiple categories appear simultaneously, the highest-priority decision applies. Log all categories, not just the highest one — you need to prove what you saw during an examination.
Step 4: Hop-distance trace
If there is no direct match, or the cluster is unknown, this is where the real work happens. Trace the source graph (forward trace from origin) of incoming funds and the destination graph (reverse trace from terminus) of outgoing funds, to 5-10 hop depth.
A practical configuration:
- Depth: 5 hops minimum for deposit-side screening; 8-10 hops for forward analysis. Going deeper dilutes signal (the industry calls this the "noise floor").
- Time horizon: 12 months back is typical — older history is mostly a false-positive source.
- Min transaction value: Filter dust (sub-$1 transactions). This is a known attack vector: bad actors send 0.01 USD "dirty" to a clean wallet trying to taint it.
A provider response typically looks like:
{
"exposure": [
{
"category": "mixer",
"label": "Tornado Cash",
"exposure_pct": 4.2,
"exposure_value_usd": 421,
"min_hop": 2,
"transactions_count": 3,
"first_seen": "2026-05-20T14:11:00Z"
},
{
"category": "darknet_market",
"label": "Hydra (historical)",
"exposure_pct": 0.8,
"exposure_value_usd": 80,
"min_hop": 6,
"transactions_count": 1,
"first_seen": "2024-11-03T09:22:00Z"
}
]
}
Step 5: Score aggregation
The exposure data above needs to be collapsed into a single decision-grade score. A simple, robust formula:
score = Σ ( base_weight[category] × hop_decay(min_hop) × exposure_pct )
Typical weight table:
| Category | base_weight |
|---|---|
| Sanctions | 100 |
| CSAM | 100 |
| Ransomware | 95 |
| Stolen funds | 85 |
| Darknet market | 75 |
| Mixer | 65 |
| Scam / fraud | 50 |
| Gambling | 30 |
For hop_decay, the simple 1 / hop is reasonable: 0 hops = 1.0, 1 = 0.5, 2 = 0.33, 3 = 0.25, 5 = 0.20. More sophisticated calibrations use exponential decay (e^(-k×hop)).
For the example above: (65 × 0.33 × 4.2) + (75 × 0.17 × 0.8) ≈ 90 + 10 = 100. Borderline — but that is what threshold policy is for.
Step 6: Decision thresholds
Map the aggregate score into three bands:
- 0-30: auto_clear — credit deposit immediately.
- 31-70: manual_review — hold deposit, queue for analyst. SLA: 4-24 hours (institution-dependent).
- 71-100: auto_decline — reject or hold the deposit, follow regulator guidance. File a SAR.
These thresholds must be a written, versioned policy. A policy change must not retroactively re-decide past cases — the log should record which decision_threshold_version ran. When a regulator asks "why this decision?", you need to point at the policy in force at that time.
Thresholds can also be dynamic by customer risk profile: stricter for institutional, looser for retail; tighter bands for high-value transactions (e.g. >$50k). Document those nuances explicitly in the policy.
Step 7: Decision execution and audit log
Three things happen simultaneously when the decision returns:
- System action — credit the user, queue for review, or refund.
- Audit log write — to immutable append-only storage. Full schema is in our blockchain AML pillar guide.
- Notification — to the analyst team if manual review; to both user and the MLRO (or equivalent) if auto-decline.
The critical property of the audit log is immutability: once written, it cannot be deleted or modified. Use S3 Object Lock, Azure Blob Storage immutability policy, or any WORM (Write Once, Read Many) configuration. A hash chain or similar integrity check is a useful additional defense.
Retention: typical EU AMLD6/MiCA practice is 10 years; US BSA is 5 years for most records. Pick the longest applicable to your jurisdictions.
Bonus: post-trade re-screening
The initial (pre-trade) screen only reflects the label database at that moment. If the provider publishes a new Lazarus Group cluster 6 hours later, the depositing wallet that looked clean this morning may now be high risk. Mature operators run post-trade re-screening:
- Re-screen at confirmation completion (6 BTC, 12-32 ETH confirmations).
- Re-screen again 24 hours later (covers provider labeling lag).
- If the result changes, apply the new decision — including retroactive balance freeze if your customer terms allow.
Re-screen logs should hang off the original screening_id as re_screen_history[]; that lets you reconstruct decision evolution for a given transaction holistically.
Common mistakes and how to avoid them
Mistake 1: Not storing the raw provider response. Many teams log only the score and discard the raw payload. Six months later, "what did the provider return for this address?" gets a different answer (labels updated). Persist the raw JSON to immutable storage.
Mistake 2: Hardcoding decision thresholds. Thresholds should be read from a database table or config file, and versioned. Developer-driven changes = audit trail rot.
Mistake 3: Not monitoring the manual-review queue. Manual-review rate is a KPI: under 5% means thresholds are too loose; over 25% means too tight (analyst burnout). 10-15% is a healthy band.
Mistake 4: Not revising the allow-list. Known exchange clusters change over time; if a tier-1 exchange exit-scams (Mt. Gox, FTX), your allow-list does not help you. Quarterly allow-list review is mandatory.
Frequently Asked Questions
How fast should a wallet screening API call return?
For pre-trade decisions (cluster lookup + fast signal evaluation), p99 < 500 ms is reasonable. For full hop trace, p99 < 2 seconds. Providers slower than that degrade user experience — a depositing user should not see a spinning wheel. High-volume operators should demand SLA commitments from providers; SOC 2 reports usually disclose them.
What should my cache strategy be?
For the same address, 24-hour in-memory cache plus 7-day persistent cache is a reasonable start. But careful: a wallet's label can change at any moment. Tune TTLs by label category — 1-hour TTL for sanctions and CSAM, 7-30 days for exchange/custody.
How do I correlate the same user across different chains and wallets?
Cross-chain bridge tracking plus KYC-side user identity work together. Wallet-to-user mapping (deposit_address_assigned_to_user_id) is on your side; cross-chain cluster mapping is on the provider's side. Layering them produces "this user's all-chain risk profile". See our DEX and DeFi AML framework for the cross-chain dimension.
What should an analyst review during manual review?
At minimum: (1) the raw provider response (label rationale, attribution source), (2) hop-trace graph visualization, (3) the customer's prior screening decisions (sample size matters), (4) the user's KYC profile and risk score, (5) transaction volume and size, (6) any source-of-funds documentation requested from the customer. After deciding, the notes field is mandatory — what was seen, why this decision.
What do I do when a false positive happens?
Two things: (a) send feedback to the provider on that specific decision — reputable providers use this to refine cluster attribution, (b) record your own local override (add to allow-list or downgrade score), and gate the override on a senior approver. Overrides should not accumulate silently — quarterly review rolls them into general policy.
How Legichain helps
Legichain's blockchain AML API wraps these seven steps into a single REST endpoint: POST /v1/wallet/screen returns the normalize-cluster-classify-hop trace-score aggregation-decision response at <500 ms p99. Threshold policy is managed and versioned from the dashboard and auto-bound to logs; the manual review queue lands in the admin console; immutable audit logs land in your AWS S3 Object Lock or Azure WORM blob storage of choice. International exchanges integrating Travel Rule under FATF or EU TFR can run wallet screening and Travel Rule transmission as a single transaction lifecycle.
Next steps
- Blockchain AML complete guide (pillar) — architecture and conceptual framework
- Mixer, tumbler and darknet AML signals — technical anatomy of the labels you saw in these steps
- Crypto exchange wallet screening: pre-trade vs post-trade — exchange-specific use case
