nautechsystems/nautilus_trader · error

Contract address should be set in logs

Error message

Contract address should be set in logs

What it means

parse_swap_event_hypersync requires log.address to be present: it is the pool contract address converted into a PoolIdentifier for the SwapEvent. The parser asserts this with expect(), documented as a panic condition, because a Swap log without an emitting address is considered malformed input that the caller should have filtered.

Source

Thrown at crates/adapters/blockchain/src/exchanges/parsing/pancakeswap_v3/swap.rs:81

    let sender = extract_address_from_topic(log, 1, "sender")?;
    let recipient = extract_address_from_topic(log, 2, "recipient")?;

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

        if data_bytes.len() < 7 * 32 {
            anyhow::bail!("Swap event data is too short");
        }

        let decoded = match <SwapEventData as SolType>::abi_decode(data_bytes) {
            Ok(decoded) => decoded,
            Err(e) => anyhow::bail!("Failed to decode swap event data: {e}"),
        };
        let pool_address = Address::from_slice(
            log.address
                .clone()
                .expect("Contract address should be set in logs")
                .as_ref(),
        );
        let pool_identifier = PoolIdentifier::Address(Ustr::from(&pool_address.to_string()));
        Ok(SwapEvent::new(
            dex,
            pool_identifier,
            extract_block_number(log)?,
            extract_transaction_hash(log)?,
            extract_transaction_index(log)?,
            extract_log_index(log)?,
            sender,
            recipient,
            decoded.amount0,
            decoded.amount1,
            decoded.sqrt_price_x96,
            decoded.liquidity,
            decoded.tick.as_i32(),
        ))

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Include the address field in the Hypersync log query so all rows carry the emitting contract address.
  2. Filter logs with address None upstream (e.g. validate_event_signature_hash-style guard or a pre-check) before parsing.
  3. Convert the expect into an anyhow error return inside the parser for graceful handling.

Example fix

// before
let pool_address = Address::from_slice(
    log.address.clone().expect("Contract address should be set in logs").as_ref(),
);
// after
let raw_address = log.address.as_ref()
    .ok_or_else(|| anyhow::anyhow!("missing contract address in swap log"))?;
let pool_address = Address::from_slice(raw_address.as_ref());
Defensive patterns

Strategy: validation

Validate before calling

if log.address.is_none() {
    log::warn!("skipping swap log without contract address");
    return Ok(());
}
let event = parse_swap_event_hypersync(dex.clone(), &log)?;

Type guard

fn has_address(log: &HypersyncLog) -> bool {
    log.address.is_some()
}

Try / catch

match parse_swap_event_hypersync(dex, &log) {
    Ok(event) => handle(event),
    Err(e) => log::error!("failed to parse swap log: {e:#}"),
}
// Note: missing address panics via expect(); pre-check log.address before calling.

Prevention

When it happens

Trigger: Calling parse_swap_event_hypersync with a HypersyncLog where address is None — Hypersync result rows lacking the address field, or test fixtures constructing logs without address, when topic/data otherwise match the Swap signature.

Common situations: Hypersync queries with projections excluding address; version drift in the Hypersync client/arrow schema dropping the field; handcrafted log fixtures in integration tests.

Related errors


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