nautechsystems/nautilus_trader · error

Failed to decode swap event data: {e}

Error message

Failed to decode swap event data: {e}

What it means

The same hypersync swap parser failed at the ABI decode stage: the data passed the 160-byte pre-check but <SwapEventData as SolType>::abi_decode rejected it. The inner alloy decoding error is embedded so developers can see the exact word/type mismatch.

Source

Thrown at crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/swap.rs:74

/// Panics if the contract address is not set in the log.
pub fn parse_swap_event_hypersync(dex: SharedDex, log: &HypersyncLog) -> anyhow::Result<SwapEvent> {
    validate_event_signature_hash("SwapEvent", SWAP_EVENT_SIGNATURE_HASH, log)?;

    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();

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

        // Decode the data using the SwapEventData struct
        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 _ = decoded.amount0;
        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,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Print the failing data hex and compare word-by-word against the canonical V3 Swap layout (amount0, amount1, sqrtPriceX96, liquidity, tick)
  2. Confirm the log's topic0 equals the canonical V3 Swap signature hash
  3. Validate the hex payload decodes cleanly (even length, valid hex) before ABI decoding
  4. Regenerate SwapEventData bindings if the target contract is a fork with an altered event
  5. Treat undecodable logs as skip-and-log instead of failing block ingestion

Example fix

// before
let decoded = match <SwapEventData as SolType>::abi_decode(data_bytes) {
    Ok(d) => d,
    Err(e) => anyhow::bail!("Failed to decode swap event data: {e}"),
};
// after
let decoded = match <SwapEventData as SolType>::abi_decode(data_bytes) {
    Ok(d) => d,
    Err(e) => {
        tracing::warn!(%e, "undecodable swap log skipped");
        return Ok(None);
    }
};
Defensive patterns

Strategy: try-catch

Validate before calling

if log.topic0 != SWAP_V3_TOPIC0 || data_bytes.len() < 160 { skip(); }
// additionally validate hex payload:
if data_hex.len() % 2 != 0 { skip(); }

Try / catch

match parse_swap_event_hypersync(&dex, &log) {
    Ok(ev) => handle(ev),
    Err(e) => { tracing::warn!(%e, data = %hex, "undecodable swap log skipped"); Ok(None) }
}

Prevention

When it happens

Trigger: Data is >= 160 bytes but the word layout does not match SwapEventData — extra leading bytes, non-canonical padding, or a fork contract with a modified Swap schema.

Common situations: Decoding logs from a modified Uniswap fork; provider returning hex with wrong encoding (odd-length hex, non-hex chars); decoding events from unrelated contracts that share a partial topic0.

Understand the failure class

Related errors


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