nautechsystems/nautilus_trader · error

Missing tickUpper in topic3 when parsing mint event

Error message

Missing tickUpper in topic3 when parsing mint event

What it means

Guard in parse_mint_event_hypersync: a Uniswap V3 Mint event log is missing topic3, which must carry the 32-byte padded tickUpper value. The log cannot be a well-formed Mint event, so parsing aborts rather than producing a tick with a fabricated value.

Source

Thrown at crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/mint.rs:76

    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 mint 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 mint event"),
    };

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

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

        // Decode the data using the MintEventData struct
        let decoded = match <MintEventData as SolType>::abi_decode(data_bytes) {
            Ok(decoded) => decoded,
            Err(e) => anyhow::bail!("Failed to decode mint event data: {e}"),
        };

        let pool_address = Address::from_slice(
            log.address

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Request all four topic slots in the Hypersync query field_selection.
  2. Guard with log.topics.len() >= 4 before parsing ticks.
  3. Confirm topic0 matches the canonical Mint event signature.
  4. Add the tickUpper topic (32-byte big-endian padded int24) to test fixtures.

Example fix

// before
LogFieldSelection { topics: vec![0, 1, 2], ..Default::default() }
// after
LogFieldSelection { topics: vec![0, 1, 2, 3], ..Default::default() }
Defensive patterns

Strategy: validation

Validate before calling

fn has_tick_upper(log: &HypersyncLog) -> bool {
    matches!(log.topics.get(3), Some(Some(_)))
}
if !has_tick_upper(&log) { skip(&log); }

Type guard

fn topic3_bytes(log: &HypersyncLog) -> Option<&[u8; 32]> {
    log.topics.get(3).and_then(|t| t.as_ref())
        .and_then(|t| t.as_ref().try_into().ok())
}

Try / catch

match parse_mint_event_hypersync(log, dex) {
    Ok(event) => process(event),
    Err(e) if e.to_string().contains("Missing tickUpper") => {
        log::debug!("log truncated topics: {e}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A Hypersync log with only 3 topics (signature + owner + tickLower) — the query truncated topics or the fixture omitted the last topic.

Common situations: Hypersync field_selection limiting topics to 3 slots, partially-built test logs, or events with only two indexed parameters being misrouted to the Mint parser.

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/abaa43e717c51331. Report an issue: GitHub.