Attack WebSocket Message

View raw Markdown

This document describes the JSON structure of WebSocket messages delivered to clients when an on-chain attack is detected.

Messages are delivered on two feeds:

  • /ws/attacks — every detected attack, delivered immediately. This is the feed described in the bulk of this document.
  • /ws/confirmed_attacks — a curated, lower-noise stream of attacks that have been post-processed and confirmed as genuine exploits by an LLM pipeline. See Confirmed-attack feed. A single client may subscribe to both feeds at the same time.

Each message is a single JSON object. There are two variants of the payload:

  • Standard attack — the attack does not touch a known protected address.
  • Protected-address attack — the attack touches an address the recipient has registered for protection. The payload carries three extra fields (victim_protocol_id, victim_protocol, victim_label).

Top-level schema

{ "network": "mainnet", "severity": "HIGH", "attack_type": "suspicious_contract_call_with_profit", "transaction_hash": "0x9c8b6f3b6f6a1b2a3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b", "exploit_address": "0x1111111111111111111111111111111111111111", "block_number": 21345678, "block_timestamp": 1731609600, "proc_time": "2026-05-13 09:42:11.503127", "attacker_address": "0x2222222222222222222222222222222222222222", "input": "0xa9059cbb000000000000000000000000abcdef...", "balance_change": 248173.42, "matched_traces": "", "matched_logs": "", "matched_selectors": "", "victim_address": "0x3333333333333333333333333333333333333333", "protocols": { "...see Enriched data below..." }, "victim_protocol_id": 137, "victim_protocol": "Aave V3", "victim_label": "Aave V3 Pool" }

The last three fields (victim_protocol_id, victim_protocol, victim_label) are present only in the protected-address variant. For a standard attack they are absent from the JSON document.

Field reference

FieldTypeDescription / example values
networkstringSource chain. One of mainnet, bsc, arbitrum, polygon, optimism, base, avax, hyperliquid.
severitystring | nullRisk level. Typical values: "HIGH", "MEDIUM", "LOW", "CRITICAL". May be null when severity could not be computed.
attack_typestringType of detection that fired. See Attack types.
transaction_hashstring (0x + 64 hex)The transaction the alert is bound to.
exploit_addressstring (0x + 40 hex)Contract being interacted with (the suspected exploit / target).
block_numberintBlock height containing the transaction.
block_timestampintUnix epoch seconds, e.g. 1731609600.
proc_timestringUTC timestamp of when the alert was generated, e.g. "2026-05-13 09:42:11.503127".
attacker_addressstring (0x + 40 hex)EOA / contract that initiated the suspected attack.
inputstringRaw transaction calldata, e.g. "0xa9059cbb0000...".
balance_changefloat | nullNet USD value moved by the attacker for this transaction, e.g. 248173.42. Can be 0.0 or negative; null when not computed.
matched_tracesstringComma-separated trace identifiers that matched the detection rules. Often "".
matched_logsstringComma-separated log identifiers that matched. Often "".
matched_selectorsstringComma-separated 4-byte selectors that matched, e.g. "0xa9059cbb,0x23b872dd". Often "".
victim_addressstring | nullAddress suffering the largest loss in USD; may be null for attack types without a single identifiable victim.
protocolsobject | nullEnrichment payload — see Enriched data.
victim_protocol_idint (protected-address variant only)Protocol ID of the matched protected address, e.g. 42.
victim_protocolstring (protected-address variant only)Human-readable protocol name, e.g. "Aave V3".
victim_labelstring (protected-address variant only)Label associated with the protected address, e.g. "Aave V3 Pool".

Attack types

Possible values of attack_type for network-wide exploit monitoring (i.e. alerts that are not scoped to a specific protected address), subscribe to the following set of attack_type values:

  • suspicious_contract_call_with_profit
  • highly_complex_transaction_with_profit
  • mev_tx_with_unusual_profit
  • exploit_in_initcode
  • abnormal_token_minting
  • suspicious_large_transfer
  • access_transfer_to_suspicious_address
  • access_transfer_to_suspicious_address_with_profit

Enriched data (protocols)

The protocols field carries enrichment about the victim and the addresses involved in the transaction. Three shapes are possible:

1. null

No enrichment was attached to this alert. The field is emitted as JSON null.

2. Lightweight enrichment

Returned when only victim information is available:

{ "is_full_enrichment": false, "victim_info": { "is_eoa": false, "address": "0x3333333333333333333333333333333333333333", "name": "Aave V3", "symbol": "aUSDC", "tvl": 4123456789.12, "is_coingecko_pool": false, "is_protocol": true, "site_url": "https://aave.com", "protocol_id": 42 } }

3. Full enrichment

Returned for high-impact alerts and contains, in addition to victim_info, the full set of address-level balance changes for the transaction:

{ "is_full_enrichment": true, "hacker_profit": 248173.42, "victim_info": { "is_eoa": false, "address": "0x3333333333333333333333333333333333333333", "name": "Aave V3", "symbol": "aUSDC", "tvl": 4123456789.12, "is_coingecko_pool": false, "is_protocol": true, "site_url": "https://aave.com", "protocol_id": 42 }, "balance_changes": [ { "address": "0x2222222222222222222222222222222222222222", "balance_change_usd": 248173.42, "is_eoa": true }, { "address": "0x3333333333333333333333333333333333333333", "balance_change_usd": -248173.42, "is_eoa": false, "name": "Aave V3", "symbol": "aUSDC", "tvl": 4123456789.12, "site_url": "https://aave.com", "protocol_id": 42, "is_protocol": true }, { "address": "0x4444444444444444444444444444444444444444", "balance_change_usd": -1532.10, "is_eoa": false, "name": "USDC/WETH 0.05%", "symbol": "USDC", "tvl": 123456789.0, "is_coingecko_pool": true, "is_protocol": false }, { "address": "0x5555555555555555555555555555555555555555", "balance_change_usd": -42.0, "is_eoa": false, "name": "Unverified contract", "symbol": null, "tvl": null, "is_protocol": false }, { "address": "", "balance_change_usd": 1, "is_eoa": false, "name": "Uniswap V3", "symbol": null, "tvl": 5000000000.0, "site_url": "https://uniswap.org", "is_protocol": true } ], "raw_token_balances": { "0x2222222222222222222222222222222222222222": { "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "248173420000" }, "0x3333333333333333333333333333333333333333": { "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "-248173420000" } }, "token_prices": { "token_data": { "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": { "price": "1.00", "decimals": "6", "symbol": "USDC" }, "ethereum:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": { "price": "3450.12", "decimals": "18", "symbol": "WETH" } } } }
victim_info fields
FieldTypeExample
is_eoaboolfalse
addressstring"0x3333...3333"
namestring | null"Aave V3", "Unverified contract", or null
symbolstring | null"aUSDC", "USDC", or null
tvlnumber | nullUSD TVL when known; null otherwise.
is_coingecko_poolbooltrue when the address was classified as a CoinGecko-tracked liquidity pool.
is_protocolbooltrue for known protocols.
site_urlstring | nullProtocol site URL, e.g. "https://aave.com".
protocol_idint | nullNumeric protocol id, e.g. 42.
balance_changes[] entry fields

Each entry always includes address, balance_change_usd, and is_eoa. The remaining fields depend on how the address was classified (known protocol, CoinGecko pool, verified contract, or unresolved):

FieldTypeWhen present
addressstringAlways (may be "" for synthetic protocol-summary rows).
balance_change_usdnumberAlways. Negative = loss, positive = gain. Synthetic protocol-summary rows use 1 as a sentinel.
is_eoaboolAlways.
namestring | nullSet unless the address is an EOA. "Unverified contract" for unresolved contracts.
symbolstring | nullToken symbol when known.
tvlnumber | nullProtocol/pool TVL when known.
site_urlstringKnown protocols only.
protocol_idintKnown-protocol matches only.
is_protocolboolNon-EOA entries.
is_coingecko_poolboolSet to true only on CoinGecko pool matches.
raw_token_balances

Maps owner_address → { token_address: signed_amount_as_string }. Amounts are raw on-chain integers (un-decimalled) and may be negative strings.

token_prices.token_data

Maps "{network}:{token_address_lower}" to { price, decimals, symbol }, where price and decimals are strings.

End-to-end example

WebSocket payload for an attack on a tracked protected address with full enrichment:

{ "network": "mainnet", "severity": "HIGH", "attack_type": "suspicious_contract_call_with_profit", "transaction_hash": "0x9c8b6f3b6f6a1b2a3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b", "exploit_address": "0x1111111111111111111111111111111111111111", "block_number": 21345678, "block_timestamp": 1731609600, "proc_time": "2026-05-13 09:42:11.503127", "attacker_address": "0x2222222222222222222222222222222222222222", "input": "0xa9059cbb0000000000000000000000003333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000003b9aca00", "balance_change": 248173.42, "matched_traces": "", "matched_logs": "", "matched_selectors": "0xa9059cbb", "victim_address": "0x3333333333333333333333333333333333333333", "protocols": { "is_full_enrichment": true, "hacker_profit": 248173.42, "victim_info": { "is_eoa": false, "address": "0x3333333333333333333333333333333333333333", "name": "Aave V3", "symbol": "aUSDC", "tvl": 4123456789.12, "is_coingecko_pool": false, "is_protocol": true, "site_url": "https://aave.com", "protocol_id": 42 }, "balance_changes": [ { "address": "0x2222222222222222222222222222222222222222", "balance_change_usd": 248173.42, "is_eoa": true }, { "address": "0x3333333333333333333333333333333333333333", "balance_change_usd": -248173.42, "is_eoa": false, "name": "Aave V3", "symbol": "aUSDC", "tvl": 4123456789.12, "site_url": "https://aave.com", "protocol_id": 42, "is_protocol": true } ], "raw_token_balances": { "0x2222222222222222222222222222222222222222": { "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "248173420000" }, "0x3333333333333333333333333333333333333333": { "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "-248173420000" } }, "token_prices": { "token_data": { "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": { "price": "1.00", "decimals": "6", "symbol": "USDC" } } } }, "victim_protocol_id": 42, "victim_protocol": "Aave V3", "victim_label": "Aave V3 Pool" }

Confirmed-attack feed

Attacks of certain types are additionally post-processed by an LLM pipeline (the /explain-hack command). When that pipeline confirms a transaction is a genuine exploit (as opposed to a false positive such as legitimate MEV / arbitrage or normal protocol activity), the service emits a confirmed attack on a separate feed:

  • Endpoint: /ws/confirmed_attacks (same API-key authentication as /ws/attacks).
  • Subscription: to receive these over Telegram or to filter by them, use the alert type confirmed_attack in your subscription alerts list. This is independent of the underlying detection type, so you can subscribe to the curated confirmed stream without subscribing to the raw attack types.
  • Timing: confirmed attacks arrive after the regular alert (the LLM round-trip takes from a few seconds up to a couple of minutes). Not every attack produces a confirmed attack — false positives are dropped.

Payload

The confirmed-attack payload is a strict superset of the standard attack payload — every field documented above is present with the same name and type, so existing /ws/attacks consumers can parse a confirmed-attack message with their current parser and ignore the extra fields. The confirmed payload adds:

FieldTypeDescription
llm_explanationstringLLM-generated, Telegram-ready report describing the exploit: affected protocol, loss amount, token/price, vulnerability type, a short description, and TX / victim links. Always present.
victim_protocol_idint | nullProtocol ID of the matched protected address, or null.
victim_protocolstring | nullHuman-readable protocol name, or null.
victim_labelstring | nullLabel of the protected address, or null.

Note the difference from the /ws/attacks feed: there, the three victim_protocol_* fields are omitted for standard attacks and only appear in the protected-address variant. On /ws/confirmed_attacks they are always present, defaulting to null when the attack does not touch a protected address — so the confirmed feed has a single, uniform shape. Detect a protected-address confirmed attack with a null check (victim_protocol_id != null) rather than key presence.

The attack_type field retains the underlying detection type (e.g. suspicious_contract_call_with_profit); the confirmed_attack label is used only for subscription/feed routing, not as the value of attack_type.

Be Among The First to Know

In DeFi, a small delay costs millions. Get the threat intelligence to rely on.

@DefimonAlerts

© 2026 Defimon by Decurity

Powered by QuickNode