{"record":{"id":"05178e1dd72cc030","repo":"nautechsystems/nautilus_trader","slug":"contract-address-should-be-set-in-logs-05178e","errorCode":null,"errorMessage":"Contract address should be set in logs","messagePattern":"Contract address should be set in logs","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/mint.rs","lineNumber":96,"sourceCode":"\n    if let Some(data) = &log.data {\n        let data_bytes = data.as_ref();\n\n        // Validate if data contains 4 parameters of 32 bytes each\n        if data_bytes.len() < 4 * 32 {\n            anyhow::bail!(\"Mint event data is too short\");\n        }\n\n        // Decode the data using the MintEventData struct\n        let decoded = match <MintEventData as SolType>::abi_decode(data_bytes) {\n            Ok(decoded) => decoded,\n            Err(e) => anyhow::bail!(\"Failed to decode mint event data: {e}\"),\n        };\n\n        let pool_address = Address::from_slice(\n            log.address\n                .clone()\n                .expect(\"Contract address should be set in logs\")\n                .as_ref(),\n        );\n        let pool_identifier = PoolIdentifier::Address(Ustr::from(&pool_address.to_string()));\n        Ok(MintEvent::new(\n            dex,\n            pool_identifier,\n            extract_block_number(log)?,\n            extract_transaction_hash(log)?,\n            extract_transaction_index(log)?,\n            extract_log_index(log)?,\n            decoded.sender,\n            owner,\n            tick_lower,\n            tick_upper,\n            decoded.amount,\n            decoded.amount0,\n            decoded.amount1,\n        ))","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/mint.rs#L78-L114","documentation":"In `parse_mint_event_hypersync`, the decoded HyperSync log's `address` field is `Option<Address>`; the parser calls `.expect(\"Contract address should be set in logs\")` while converting it to the Uniswap V3 pool address. Every real EVM log carries the emitting contract's address, so a `None` here means the caller constructed a log without an address — a violation of the parser's input contract, hence a panic rather than a graceful error. It indicates malformed/incomplete log data passed to the hypersync parsing path, not a chain or decoding problem.","triggerScenarios":"Calling `parse_mint_event_hypersync` with a `HyperSyncLog` whose `address` field is `None` (or the serde/default constructor left it unset), typically a hand-built log in tests or a deserialization path that did not populate `log.address`.","commonSituations":"Test fixtures for mint events built with `HyperSyncLog::default()` or struct-update syntax omitting `address`; a schema/version change in the hypersync client that makes `address` optional; gluing logs from another data source into the hypersync parser.","solutions":["Populate `log.address` with the emitting pool contract address in the log you pass to `parse_mint_event_hypersync`.","If the log comes from deserialized hypersync data, verify the client/schema maps the log's `address` field correctly and is not dropping it.","In code you control, match on the Option and return a descriptive error instead of relying on the panic.","Check for hypersync-client version changes that altered the log struct's address field optionality."],"exampleFix":"// before\nlet pool_address = Address::from_slice(\n    log.address.clone().expect(\"Contract address should be set in logs\").as_ref(),\n);\n// after\nlet emitter = log.address.clone().ok_or_else(|| anyhow::anyhow!(\"mint log missing contract address\"))?;\nlet pool_address = Address::from_slice(emitter.as_ref());","handlingStrategy":"validation","validationCode":"fn ensure_log_address(log: &HyperSyncLog) -> Result<Address, String> {\n    log.address\n        .as_ref()\n        .map(|a| Address::from_slice(a.as_ref()))\n        .ok_or_else(|| \"hypersync log missing contract address\".to_string())\n}","typeGuard":"fn has_address(log: &HyperSyncLog) -> bool {\n    log.address.is_some()\n}","tryCatchPattern":"// Rust: use Result instead of panic at the call site\nlet pool_address = ensure_log_address(&log)?;","preventionTips":["Build log fixtures through a helper constructor that always sets `address`.","Never construct HyperSyncLog via `Default`; require the emitter explicitly.","Add a test asserting all fixture logs have an address set."],"tags":["panic","rust","hypersync","uniswap-v3","missing-field"],"backgroundTag":"null-argument","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}