{"record":{"id":"b7cd49c7ea23ca8c","repo":"nautechsystems/nautilus_trader","slug":"invalid-currency0-topic-length","errorCode":null,"errorMessage":"Invalid currency0 topic length","messagePattern":"Invalid currency0 topic length","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/exchanges/parsing/uniswap_v4/initialize.rs","lineNumber":111,"sourceCode":"            \"Initialize event missing topics: expected 4, was {}\",\n            topics.len()\n        );\n    }\n\n    // Extract Pool ID from topics[1] - this is the unique identifier for V4 pools\n    let pool_id_bytes = topics[1]\n        .as_ref()\n        .ok_or_else(|| anyhow::anyhow!(\"Missing poolId topic\"))?\n        .as_ref();\n    let pool_identifier = Ustr::from(&hex::encode_prefixed(pool_id_bytes));\n\n    let currency0 = Address::from_slice(\n        topics[2]\n            .as_ref()\n            .ok_or_else(|| anyhow::anyhow!(\"Missing currency0 topic\"))?\n            .as_ref()\n            .get(12..32)\n            .ok_or_else(|| anyhow::anyhow!(\"Invalid currency0 topic length\"))?,\n    );\n\n    let currency1 = Address::from_slice(\n        topics[3]\n            .as_ref()\n            .ok_or_else(|| anyhow::anyhow!(\"Missing currency1 topic\"))?\n            .as_ref()\n            .get(12..32)\n            .ok_or_else(|| anyhow::anyhow!(\"Invalid currency1 topic length\"))?,\n    );\n\n    if let Some(data) = log.data {\n        let data_bytes = data.as_ref();\n\n        // Validate minimum data length (5 fields × 32 bytes = 160 bytes)\n        if data_bytes.len() < 160 {\n            anyhow::bail!(\n                \"Initialize event data too short: expected at least 160 bytes, was {}\",","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/exchanges/parsing/uniswap_v4/initialize.rs#L93-L129","documentation":"parse_initialize_event_hypersync for Uniswap V4 throws this when topics[2] exists but is shorter than 32 bytes, so slicing the low 20 bytes (12..32) that hold the 160-bit currency0 address fails. Ethereum topics are fixed 32-byte words; a shorter value means the payload is malformed. The library checks the slice instead of panicking on an out-of-range index.","triggerScenarios":"Calling parse_initialize_event_hypersync (v4) with a log whose topics[2] contains fewer than 32 bytes — e.g. a provider returning a stripped/truncated topic, a hand-built fixture with a short byte array, or a binary serializer dropping leading zero bytes.","commonSituations":"Custom RPC/indexer clients that trim topics instead of left-padding addresses to 32 bytes; fixtures built from hex strings parsed without padding; forked contracts emitting non-standard topic widths.","solutions":["Ensure topics are represented as fixed 32-byte words; left-pad the currency0 address with zeros before parsing.","Check the log source/provider is not truncating topics (compare against the raw transaction receipt).","Validate topic byte length (>= 32) before calling the parser and reject/short-circuit malformed logs.","Fix test fixtures to use full 32-byte topic values (e.g. 0x000...<20-byte address>)."],"exampleFix":"// before\nlet topic = hex::decode(short_hex)?; // e.g. 20 bytes\n// after\nlet mut topic = [0u8; 32];\ntopic[12..].copy_from_slice(&hex::decode(addr_hex)?); // left-pad to 32 bytes\nlet event = parse_initialize_event_hypersync(&log)?;","handlingStrategy":"validation","validationCode":"fn topic_is_word(t: &Option<FixedBytes<32>>) -> bool {\n    t.as_ref().map(|b| b.len() == 32).unwrap_or(false)\n}\n// require topic_is_word(&log.topics[2]) before parsing","typeGuard":"fn is_full_word_topic(topic: &Option<FixedBytes<32>>) -> bool {\n    topic.as_ref().is_some_and(|t| t.len() == 32)\n}","tryCatchPattern":"match parse_initialize_event_hypersync(&log) {\n    Ok(event) => handle(event),\n    Err(e) if e.to_string().contains(\"Invalid currency0 topic length\") => {\n        tracing::warn!(\"short currency0 topic; skipping log\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Ensure topics are always fixed 32-byte words (left-pad addresses).","Avoid serializers/clients that strip leading zero bytes from topics.","Compare parsed topics against raw receipt data to detect truncation.","Use full-width hex in test fixtures (0x + 64 chars)."],"tags":["blockchain","uniswap-v4","log-parsing","hypersync"],"backgroundTag":"invalid-argument-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}