{"record":{"id":"7715509ae7fd3f7f","repo":"nautechsystems/nautilus_trader","slug":"missing-ticklower-in-topic2-when-parsing-burn-even","errorCode":null,"errorMessage":"Missing tickLower in topic2 when parsing burn event","messagePattern":"Missing tickLower in topic2 when parsing burn event","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/burn.rs","lineNumber":66,"sourceCode":"/// # Errors\n///\n/// Returns an error if the log parsing fails or if the event data is invalid.\n///\n/// # Panics\n///\n/// Panics if the contract address is not set in the log.\npub fn parse_burn_event_hypersync(dex: SharedDex, log: &HypersyncLog) -> anyhow::Result<BurnEvent> {\n    validate_event_signature_hash(\"Burn\", BURN_EVENT_SIGNATURE_HASH, log)?;\n\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 burn 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 burn 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!(\"Burn event data is too short\");\n        }","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/burn.rs#L48-L84","documentation":"parse_burn_event_hypersync reads the int24 tickLower from topic2 of a Uniswap V3 Burn log. If the log has fewer than 3 topics (topic2 absent), the match falls to the None arm and bails with 'Missing tickLower in topic2 when parsing burn event'. The Burn event ABI requires (owner, tickLower, tickUpper) as indexed topics, so a missing topic2 means the log is not a well-formed Burn event.","triggerScenarios":"Calling parse_burn_event_hypersync with a HyperSync log whose `topics` array has fewer than 3 entries — e.g. an anonymous or non-standard Burn-like event, a log from a different event type routed by mistake, or a partially indexed log missing indexed parameters.","commonSituations":"Indexing forked Uniswap V3 pools whose Burn event has different indexed-parameter layout; HyperSync queries that filter on the wrong topic0 but return shorter-topic logs; misrouting Mint/Modge-like events with fewer topics into the Burn parser; upstream indexer gaps producing incomplete log objects.","solutions":["Verify the log's topic0 matches the Uniswap V3 Burn signature 0x0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c before calling the parser","Check `log.topics.len() >= 3` in your ingestion pipeline and skip/flag logs with fewer topics rather than passing them to the parser","Re-fetch the log from HyperSync — upstream indexers occasionally return incomplete topic arrays; a fresh query usually restores all 3 topics","If indexing a fork whose Burn event indexes fewer parameters, write a dedicated parser matching that fork's ABI"],"exampleFix":"// before: passing any Burn-topic log straight to the parser\nlet event = parse_burn_event_hypersync(dex, &log)?;\n\n// after: validate topic count first\nconst BURN_TOPIC: &str = \"0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c\";\nif log.topics.len() < 3 {\n    anyhow::bail!(\"burn log has {} topics, expected 3 — skipping malformed log\", log.topics.len());\n}\nif !log.topics[0].to_string().contains(BURN_TOPIC) {\n    anyhow::bail!(\"not a Uniswap V3 Burn event\");\n}\nlet event = parse_burn_event_hypersync(dex, &log)?;","handlingStrategy":"validation","validationCode":"const BURN_TOPIC: &str = \"0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c\";\npub fn can_parse_burn(log: &HypersyncLog) -> bool {\n    let topic_ok = log.topics.first()\n        .and_then(|t| t.as_ref())\n        .map(|t| t.to_string().contains(BURN_TOPIC))\n        .unwrap_or(false);\n    topic_ok && log.topics.len() >= 3\n}","typeGuard":"fn has_burn_topics(log: &HypersyncLog) -> bool {\n    log.topics.len() >= 3\n        && log.topics[1..3].iter().all(|t| t.as_ref().map(|b| b.len() == 32).unwrap_or(false))\n}","tryCatchPattern":"match parse_burn_event_hypersync(dex, &log) {\n    Ok(event) => store(event),\n    Err(e) if e.to_string().contains(\"Missing tick\") => {\n        tracing::warn!(\"burn log missing indexed tick topics — malformed or non-standard log; skipping\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Filter HyperSync queries by the exact Burn topic0 so only well-formed Burn logs reach the parser","Check topics.len() >= 3 before invoking the parser and skip shorter logs","Re-fetch logs with missing topics — indexer gaps are usually transient","For forked pools with different indexed layouts, write a dedicated parser matching that ABI"],"tags":["blockchain","abi-decoding","hypersync","uniswap-v3","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"}