{"record":{"id":"687c14a6256ed3fe","repo":"nautechsystems/nautilus_trader","slug":"signed-transaction-creates-a-contract-instead-of-c","errorCode":null,"errorMessage":"Signed transaction creates a contract instead of calling a destination","messagePattern":"Signed transaction creates a contract instead of calling a destination","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/transaction.rs","lineNumber":217,"sourceCode":") -> anyhow::Result<DecodedSignedTransaction> {\n    let envelope = TxEnvelope::decode_2718_exact(raw_transaction).map_err(|_| {\n        anyhow::anyhow!(\"Persisted signed transaction is not a complete EIP-2718 envelope\")\n    })?;\n    let TxEnvelope::Eip1559(signed) = envelope else {\n        anyhow::bail!(\"Persisted signed transaction is not EIP-1559\");\n    };\n    anyhow::ensure!(\n        signed.signature().normalize_s().is_none(),\n        \"Persisted transaction signature is not EIP-2 normalized\"\n    );\n    let signer = signed\n        .signature()\n        .recover_address_from_prehash(&signed.signature_hash())\n        .context(\"failed to recover persisted transaction signer\")?;\n    let hash = *signed.hash();\n    let tx = signed.tx();\n    let TxKind::Call(to) = tx.to else {\n        anyhow::bail!(\"Signed transaction creates a contract instead of calling a destination\");\n    };\n    anyhow::ensure!(\n        tx.access_list.is_empty(),\n        \"Signed transaction access list is not empty\"\n    );\n\n    Ok(DecodedSignedTransaction {\n        hash,\n        signer,\n        chain_id: tx.chain_id,\n        nonce: tx.nonce,\n        to,\n        value: tx.value,\n        input: tx.input.clone(),\n        gas_limit: tx.gas_limit,\n        max_fee_per_gas: tx.max_fee_per_gas,\n        max_priority_fee_per_gas: tx.max_priority_fee_per_gas,\n    })","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/transaction.rs#L199-L235","documentation":"After decoding the EIP-1559 transaction, the library requires tx.to to be TxKind::Call (a call to an existing address). If the transaction's `to` is TxKind::Create, it is a contract-creation transaction, which this code path does not support — identity and RPC matching checks assume a destination address exists.","triggerScenarios":"decode_signed_transaction encounters a signed EIP-1559 transaction whose `to` field is None/CREATE — i.e. the payload was built without a destination address, deploying bytecode instead of calling a contract.","commonSituations":"Building the transaction request without setting `to` (e.g. an empty or default-built TxRequest) which the signer serializes as contract creation; intentionally deploying a contract and then passing it through the adapter's call-validation path; a field-mapping bug dropping the destination address before signing.","solutions":["Set the `to` destination address on the transaction request before signing so the signed tx is TxKind::Call.","Confirm you are not accidentally feeding a contract-deployment transaction into this call-oriented validation path.","Trace where the transaction request is constructed and log the `to` field prior to signing to catch it being dropped/defaulted.","If contract creation is intended, use a deployment flow instead of decode_signed_transaction/validate_signed_transaction."],"exampleFix":"// before\nlet tx = TxRequest { input: calldata, ..Default::default() }; // to = None -> CREATE\n// after\nlet tx = TxRequest { to: Address::from_str(contract)?, input: calldata, ..Default::default() };","handlingStrategy":"validation","validationCode":"fn is_contract_call(tx: &TxEip1559) -> bool {\n    matches!(tx.to, TxKind::Call(_))\n}\n// reject requests with to = None before signing","typeGuard":"fn destination(tx: &TxEip1559) -> Option<Address> {\n    match tx.to { TxKind::Call(addr) => Some(addr), TxKind::Create => None }\n}","tryCatchPattern":"match decode_signed_transaction(raw) {\n    Err(e) if e.to_string().contains(\"creates a contract\") => /* abort: deployment tx sent through call path */,\n    Err(e) => return Err(e),\n    Ok(decoded) => decoded,\n}","preventionTips":["Always set `to` explicitly when building transaction requests; never rely on defaults","Assert the tx kind is Call in the request-builder before signing","Separate contract-deployment flows from call flows so they never share the validation path","Log the destination address at request-construction time"],"tags":["rust","blockchain","contract-creation","transaction-validation"],"backgroundTag":"unsupported-operation","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"}