nautechsystems/nautilus_trader · error

Finalized Swap has no calculated trade information

Error message

Finalized Swap has no calculated trade information

What it means

After a finalized on-chain swap is built, the adapter calls `swap.calculate_trade_info` to derive trade details (price, side, quantity) from the pool tokens. This error is thrown when `calculate_trade_info` succeeded but the swap's `trade_info` field is still `None`, meaning the finalized Swap object carries no calculated trade information. It is an internal invariant check: a finalized swap should always yield trade info once calculated.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:4823

        "Verified inclusion header {} does not match receipt hash {}",
        included.block_number,
        included.receipt.block_hash
    );
    let timestamp_ns = block
        .timestamp
        .checked_mul(NANOSECONDS_IN_SECOND)
        .ok_or_else(|| anyhow::anyhow!("Finalized block timestamp overflows nanoseconds"))?;
    let mut swap = event.to_pool_swap(
        plan.pool.chain.clone(),
        plan.instrument_id,
        plan.pool.pool_identifier,
        UnixNanos::from(timestamp_ns),
    );
    swap.calculate_trade_info(&plan.pool.token0, &plan.pool.token1, None)?;
    let trade = swap
        .trade_info
        .as_ref()
        .ok_or_else(|| anyhow::anyhow!("Finalized Swap has no calculated trade information"))?;
    anyhow::ensure!(
        trade.order_side == plan.order.order_side(),
        "Finalized Swap side {} does not match {} order",
        trade.order_side,
        plan.order.order_side()
    );
    let gas_cost = included
        .receipt
        .effective_gas_price
        .checked_mul(U256::from(included.receipt.gas_used))
        .ok_or_else(|| anyhow::anyhow!("Finalized transaction gas commission overflow"))?;
    let commission = Money::from_u256(gas_cost, plan.pool.chain.native_currency())?;
    let trade_digest = keccak256(format!("{}:{}", included.tx_hash, swap.log_index));
    let trade_digest = trade_digest.to_string();
    let trade_id = TradeId::new_checked(&trade_digest[2..38])?;

    if plan
        .order

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the pool token pair (token0/token1) and decimals are correctly registered in the deployment manifest for this pool
  2. Check that the swap direction (token0->token1 or reverse) is one supported by `calculate_trade_info`
  3. Inspect the `Swap` construction code to confirm amounts/limits are set before finalization
  4. Upgrade or patch the blockchain adapter if `calculate_trade_info` has a known gap leaving `trade_info` as None

Example fix

// before
swap.calculate_trade_info(&plan.pool.token0, &plan.pool.token1, None)?;
// after: validate the swap can produce trade info first
if swap.amount_in.is_zero() || swap.amount_out.is_zero() {
    anyhow::bail!("Swap amounts are zero; trade info cannot be calculated");
}
swap.calculate_trade_info(&plan.pool.token0, &plan.pool.token1, None)?;
Defensive patterns

Strategy: try-catch

Validate before calling

// before execution: ensure the swap can yield trade info
if swap.amount_in.is_zero() || swap.amount_out.is_zero() {
    return Err(anyhow::anyhow!("swap amounts are zero; trade info will not be calculated"));
}

Type guard

fn has_trade_info(swap: &Swap) -> bool {
    swap.trade_info.is_some()
}

Try / catch

match swap.calculate_trade_info(&plan.pool.token0, &plan.pool.token1, None) {
    Ok(_) if swap.trade_info.is_some() => { /* proceed */ }
    Ok(_) => log::error!("trade info not populated; check pool token config"),
    Err(e) => log::error!("trade info calculation failed: {e}"),
}

Prevention

When it happens

Trigger: Executing a finalized DEX swap in `BlockchainExecutionClient` where `calculate_trade_info` leaves `swap.trade_info` unset (e.g. a swap variant that cannot compute trade info for the given token pair, missing decimals, or a malformed swap amount) despite `calculate_trade_info` returning `Ok`.

Common situations: Swapping through a pool whose token configuration or swap direction prevents trade-info computation; adapter bugs where a new swap type does not populate `trade_info`; token decimals or pool data fetched on-chain being inconsistent so calculation silently yields nothing.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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