nautechsystems/nautilus_trader · error

Missing tickLower in topic2 when parsing burn event

Error message

Missing tickLower in topic2 when parsing burn event

What it means

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.

Source

Thrown at crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/burn.rs:66

/// # Errors
///
/// Returns an error if the log parsing fails or if the event data is invalid.
///
/// # Panics
///
/// Panics if the contract address is not set in the log.
pub fn parse_burn_event_hypersync(dex: SharedDex, log: &HypersyncLog) -> anyhow::Result<BurnEvent> {
    validate_event_signature_hash("Burn", BURN_EVENT_SIGNATURE_HASH, log)?;

    let owner = extract_address_from_topic(log, 1, "owner")?;

    // Extract int24 tickLower from topic2 (stored as a 32-byte padded value)
    let tick_lower = match log.topics.get(2).and_then(|t| t.as_ref()) {
        Some(topic) => {
            let tick_lower_bytes: [u8; 32] = topic.as_ref().try_into()?;
            i32::from_be_bytes(tick_lower_bytes[28..32].try_into()?)
        }
        None => anyhow::bail!("Missing tickLower in topic2 when parsing burn event"),
    };

    // Extract int24 tickUpper from topic3 (stored as a 32-byte padded value)
    let tick_upper = match log.topics.get(3).and_then(|t| t.as_ref()) {
        Some(topic) => {
            let tick_upper_bytes: [u8; 32] = topic.as_ref().try_into()?;
            i32::from_be_bytes(tick_upper_bytes[28..32].try_into()?)
        }
        None => anyhow::bail!("Missing tickUpper in topic3 when parsing burn event"),
    };

    if let Some(data) = &log.data {
        let data_bytes = data.as_ref();

        // Validate if data contains 3 parameters of 32 bytes each
        if data_bytes.len() < 3 * 32 {
            anyhow::bail!("Burn event data is too short");
        }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the log's topic0 matches the Uniswap V3 Burn signature 0x0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c before calling the parser
  2. Check `log.topics.len() >= 3` in your ingestion pipeline and skip/flag logs with fewer topics rather than passing them to the parser
  3. Re-fetch the log from HyperSync — upstream indexers occasionally return incomplete topic arrays; a fresh query usually restores all 3 topics
  4. If indexing a fork whose Burn event indexes fewer parameters, write a dedicated parser matching that fork's ABI

Example fix

// before: passing any Burn-topic log straight to the parser
let event = parse_burn_event_hypersync(dex, &log)?;

// after: validate topic count first
const BURN_TOPIC: &str = "0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c";
if log.topics.len() < 3 {
    anyhow::bail!("burn log has {} topics, expected 3 — skipping malformed log", log.topics.len());
}
if !log.topics[0].to_string().contains(BURN_TOPIC) {
    anyhow::bail!("not a Uniswap V3 Burn event");
}
let event = parse_burn_event_hypersync(dex, &log)?;
Defensive patterns

Strategy: validation

Validate before calling

const BURN_TOPIC: &str = "0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c";
pub fn can_parse_burn(log: &HypersyncLog) -> bool {
    let topic_ok = log.topics.first()
        .and_then(|t| t.as_ref())
        .map(|t| t.to_string().contains(BURN_TOPIC))
        .unwrap_or(false);
    topic_ok && log.topics.len() >= 3
}

Type guard

fn has_burn_topics(log: &HypersyncLog) -> bool {
    log.topics.len() >= 3
        && log.topics[1..3].iter().all(|t| t.as_ref().map(|b| b.len() == 32).unwrap_or(false))
}

Try / catch

match parse_burn_event_hypersync(dex, &log) {
    Ok(event) => store(event),
    Err(e) if e.to_string().contains("Missing tick") => {
        tracing::warn!("burn log missing indexed tick topics — malformed or non-standard log; skipping");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/7715509ae7fd3f7f. Report an issue: GitHub.