{"record":{"id":"155d44925f33d606","repo":"nautechsystems/nautilus_trader","slug":"signed-transaction-destination-does-not-match-p","errorCode":null,"errorMessage":"Signed transaction destination {} does not match persisted destination {}","messagePattern":"Signed transaction destination (.+?) does not match persisted destination (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/transaction.rs","lineNumber":294,"sourceCode":"    anyhow::ensure!(\n        tx.chain_id == u64::from(intent.chain_id),\n        \"Signed transaction chain ID {} does not match configured chain ID {}\",\n        tx.chain_id,\n        intent.chain_id\n    );\n    anyhow::ensure!(\n        tx.nonce == intent.nonce,\n        \"Signed transaction nonce {} does not match persisted nonce {}\",\n        tx.nonce,\n        intent.nonce\n    );\n    anyhow::ensure!(\n        tx.to == intent.to,\n        \"Signed transaction destination {} does not match persisted destination {}\",\n        tx.to,\n        intent.to\n    );\n    anyhow::ensure!(\n        tx.value == intent.value,\n        \"Signed transaction value does not match persisted value\"\n    );\n    anyhow::ensure!(\n        tx.input == intent.input,\n        \"Signed transaction calldata does not match persisted calldata\"\n    );\n    anyhow::ensure!(\n        tx.gas_limit <= intent.gas_limit,\n        \"Signed transaction gas limit {} exceeds configured ceiling {}\",\n        tx.gas_limit,\n        intent.gas_limit\n    );\n    anyhow::ensure!(\n        tx.max_fee_per_gas <= u128::from(intent.max_fee_per_gas),\n        \"Signed transaction max fee per gas {} wei exceeds configured ceiling {} wei\",\n        tx.max_fee_per_gas,\n        intent.max_fee_per_gas","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/transaction.rs#L276-L312","documentation":"`validate_signed_transaction` requires the signed transaction's `to` address to equal the destination persisted in the intent. A mismatch means the signed bytes call a different contract/address than the one that was approved, which the library treats as tampering or a wrong-payload bug and refuses to broadcast.","triggerScenarios":"`validate_signed_transaction` decodes signed bytes whose `TxKind::Call` destination differs from `intent.to` — e.g. the signer encoded a different target address, or the persisted intent points at a new deployment while old signed bytes target the old address.","commonSituations":"Contract address changed between environments (testnet vs mainnet deployment, proxy upgrade) while old signed blobs were reused, config supplying a different contract address to the signer than to the intent writer, or hand-crafted/replayed bytes from another chain or fork.","solutions":["Re-sign against the exact destination in the persisted intent (`intent.to`) and validate the fresh bytes.","Confirm signer and intent-creation code resolve the contract address from the same configuration source.","Regenerate the signed payload after any contract redeployment or proxy address change; old signatures are invalid.","If bytes are unexpectedly foreign, trace where the raw transaction was produced — it did not come from this system's signer."],"exampleFix":"// before\nlet tx = TransactionRequest::new().to(other_contract_address);\nlet signed = sign(&tx, &wallet);\nvalidate_signed_transaction(&signed, &intent)?; // destination mismatch\n\n// after\nlet tx = TransactionRequest::new().to(intent.to);\nlet signed = sign(&tx, &wallet);\nvalidate_signed_transaction(&signed, &intent)?;","handlingStrategy":"validation","validationCode":"fn destination_matches(raw: &[u8], intent: &SignedTransactionIntent) -> bool {\n    decode_signed_transaction(raw).map(|tx| tx.to == intent.to).unwrap_or(false)\n}","typeGuard":"fn has_expected_destination(d: &DecodedSignedTransaction, i: &SignedTransactionIntent) -> bool {\n    d.to == i.to\n}","tryCatchPattern":"validate_signed_transaction(&raw, &intent).map_err(|e| {\n    if e.to_string().contains(\"destination\") { Error::WrongTarget(e) } else { Error::Validation(e) }\n})?;","preventionTips":["Resolve contract addresses from one shared config consumed by both signer and intent writer.","Regenerate all signed payloads after any contract redeployment or proxy address change.","Pin contract addresses per chain/environment and fail fast at startup if they differ from persisted intents.","Never accept signed bytes from outside the system's own signer without full validation."],"tags":["blockchain","transaction-validation","destination-address","integrity"],"backgroundTag":"checksum-mismatch","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"}