{"record":{"id":"bd751f69af535cfa","repo":"nautechsystems/nautilus_trader","slug":"persisted-signed-transaction-is-not-eip-1559","errorCode":null,"errorMessage":"Persisted signed transaction is not EIP-1559","messagePattern":"Persisted signed transaction is not EIP-1559","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/transaction.rs","lineNumber":204,"sourceCode":"    pub chain_id: u64,\n    pub nonce: u64,\n    pub to: Address,\n    pub value: U256,\n    pub input: Bytes,\n    pub gas_limit: u64,\n    pub max_fee_per_gas: u128,\n    pub max_priority_fee_per_gas: u128,\n}\n\n/// Decodes and authenticates one complete signed EIP-1559 transaction.\npub(super) fn decode_signed_transaction(\n    raw_transaction: &[u8],\n) -> 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    );","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/transaction.rs#L186-L222","documentation":"decode_signed_transaction decodes a persisted raw signed transaction and only supports EIP-1559 typed transactions. The bytes first must decode as a complete EIP-2718 typed envelope; if the envelope decodes but is any variant other than Eip1559 (legacy, EIP-2930 access-list, EIP-4844 blob, etc.), this bail fires. The library deliberately narrows to EIP-1559 because downstream identity/fee validation assumes 1559 fields.","triggerScenarios":"Calling decode_signed_transaction (directly or via validate_rpc_transaction_matches_payload, verify_finalized_transaction_identity, validate_signed_transaction) with raw_transaction bytes that are an EIP-2718 envelope of a non-1559 type: a legacy signed tx, an EIP-2930 tx, or an EIP-4844 blob tx.","commonSituations":"Persisting transactions produced by an older signing path or wallet that emits legacy transactions; a chain/wallet upgrade switching the adapter to EIP-2930 or EIP-4844 typed txs; storing the wrong artifact (e.g. a 2930 tx built with an access list) and later replaying it through this decoder.","solutions":["Inspect the first byte of the raw transaction: values other than 0x02 indicate a non-EIP-1559 typed envelope; re-sign or re-persist the transaction as EIP-1559 (type 0x02).","Check how the transaction was produced upstream (signer/wallet config) and force EIP-1559 signing (no access list, no blob fields).","If legacy transactions are legitimate for your chain, decode them with a legacy path instead of routing them into decode_signed_transaction.","Verify you persisted the signed EIP-1559 tx and not a differently-typed artifact (e.g. compare the tx hash/type from the signing step)."],"exampleFix":"// before\nlet envelope = TxEnvelope::decode_2718_exact(raw)?; // may be Eip2930/Eip4844 from signer\n// after\nlet envelope = TxEnvelope::decode_2718_exact(raw)?;\nassert!(matches!(envelope, TxEnvelope::Eip1559(_)), \"signer must produce EIP-1559 (type 0x02) txs\");\ndecode_signed_transaction(raw)?;","handlingStrategy":"validation","validationCode":"fn is_eip1559_envelope(raw: &[u8]) -> bool {\n    TxEnvelope::decode_2718_exact(raw)\n        .map(|e| matches!(e, TxEnvelope::Eip1559(_)))\n        .unwrap_or(false)\n}\n// call decode_signed_transaction only if is_eip1559_envelope(raw)","typeGuard":"fn as_eip1559(envelope: &TxEnvelope) -> Option<&Signed<TxLegacyOr1559Check>> {\n    match envelope { TxEnvelope::Eip1559(s) => Some(s), _ => None }\n}","tryCatchPattern":"match decode_signed_transaction(raw) {\n    Err(e) if e.to_string().contains(\"not EIP-1559\") => /* re-sign as 1559 or route to legacy decoder */,\n    Err(e) => return Err(e),\n    Ok(decoded) => decoded,\n}","preventionTips":["Pin the signer/wallet to EIP-1559 (type 0x02) transaction generation","Check the first envelope byte (0x02 = EIP-1559) before persisting signed transactions","Keep the persisted raw tx and its type metadata together so mismatches are caught at write time","Test the signing path against the decoder in CI"],"tags":["rust","blockchain","eip-1559","transaction-decoding"],"backgroundTag":"invalid-enum-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}