{"record":{"id":"5fa57483c1c8bc6f","repo":"nautechsystems/nautilus_trader","slug":"missing-tickupper-in-topic3-when-parsing-collect-e","errorCode":null,"errorMessage":"Missing tickUpper in topic3 when parsing collect event","messagePattern":"Missing tickUpper in topic3 when parsing collect event","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/collect.rs","lineNumber":78,"sourceCode":"\n    let owner = extract_address_from_topic(log, 1, \"owner\")?;\n\n    // Extract int24 tickLower from topic2 (stored as a 32-byte padded value)\n    let tick_lower = match log.topics.get(2).and_then(|t| t.as_ref()) {\n        Some(topic) => {\n            let tick_lower_bytes: [u8; 32] = topic.as_ref().try_into()?;\n            i32::from_be_bytes(tick_lower_bytes[28..32].try_into()?)\n        }\n        None => anyhow::bail!(\"Missing tickLower in topic2 when parsing collect event\"),\n    };\n\n    // Extract int24 tickUpper from topic3 (stored as a 32-byte padded value)\n    let tick_upper = match log.topics.get(3).and_then(|t| t.as_ref()) {\n        Some(topic) => {\n            let tick_upper_bytes: [u8; 32] = topic.as_ref().try_into()?;\n            i32::from_be_bytes(tick_upper_bytes[28..32].try_into()?)\n        }\n        None => anyhow::bail!(\"Missing tickUpper in topic3 when parsing collect event\"),\n    };\n\n    if let Some(data) = &log.data {\n        let data_bytes = data.as_ref();\n\n        // Validate if data contains 3 parameters of 32 bytes each\n        if data_bytes.len() < 3 * 32 {\n            anyhow::bail!(\"Collect event data is too short\");\n        }\n\n        // Decode the data using the CollectEventData struct\n        let decoded = match <CollectEventData as SolType>::abi_decode(data_bytes) {\n            Ok(decoded) => decoded,\n            Err(e) => anyhow::bail!(\"Failed to decode collect event data: {e}\"),\n        };\n\n        let pool_address = Address::from_slice(\n            log.address","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/collect.rs#L60-L96","documentation":"Raised by parse_collect_event_hypersync when the Collect event log lacks topic3, which holds the indexed tickUpper int24 value. Without tickUpper the position range cannot be reconstructed, so the function bails instead of producing a wrong CollectEvent.","triggerScenarios":"Parsing a log with fewer than 4 topics, a mismatched event (wrong topic0 filter), or a provider response with a null topic3.","commonSituations":"Broad topic filters catching other pool events; malformed or hand-built test logs; ABI/signature drift between the adapter and deployed pool contract.","solutions":["Filter logs by the exact Collect event topic0 signature before parsing","Assert topics.len() >= 4 with all slots present before calling the parser","Re-verify the Collect event signature against the Uniswap V3 pool ABI in use","Inspect the raw log topics to identify the actually delivered event"],"exampleFix":"// before\nlet event = parse_collect_event_hypersync(&dex, &log)?;\n// after\nanyhow::ensure!(log.topics.len() >= 4, \"Collect log missing topics: {:?}\", log.topics);\nlet event = parse_collect_event_hypersync(&dex, &log)?;","handlingStrategy":"validation","validationCode":"fn has_collect_topics(log: &Log) -> bool {\n    log.topics.len() >= 4 && log.topics[3].is_some()\n}\n// require this before parse_collect_event_hypersync","typeGuard":"fn topic_at(log: &Log, i: usize) -> Option<&[u8; 32]> {\n    log.topics.get(i).and_then(|t| t.as_deref())\n}","tryCatchPattern":"match parse_collect_event_hypersync(&dex, &log) {\n    Ok(event) => handle(event),\n    Err(e) if e.to_string().contains(\"Missing tickUpper\") => {\n        tracing::warn!(\"Collect log missing topic3, skipping\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Filter subscriptions by the full Collect signature, not just name","Check topics.len() >= 4 in ingestion pre-conditions","Keep event-signature constants in one shared module to avoid drift","Add fixture tests covering logs with missing topics"],"tags":["blockchain","uniswap-v3","event-parsing","missing-topic"],"backgroundTag":"missing-required-argument","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}