{"record":{"id":"07751cc36850636d","repo":"nautechsystems/nautilus_trader","slug":"signed-transaction-value-does-not-match-persisted","errorCode":null,"errorMessage":"Signed transaction value does not match persisted value","messagePattern":"Signed transaction value does not match persisted value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/transaction.rs","lineNumber":298,"sourceCode":"        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\n    );\n    anyhow::ensure!(\n        tx.max_priority_fee_per_gas <= tx.max_fee_per_gas,\n        \"Signed transaction priority fee per gas {} wei exceeds max fee per gas {} wei\",","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/transaction.rs#L280-L316","documentation":"`validate_signed_transaction` enforces that the signed transaction's ETH `value` is byte-for-byte equal to the value recorded in the persisted intent. Because the intent is the auditable record of the approved transfer, any difference — even a wei — causes rejection of the signed payload before submission.","triggerScenarios":"`validate_signed_transaction` decodes signed bytes whose `tx.value` differs from `intent.value`, e.g. the signer serialized an amount computed with different units (wei vs gwei/ether), rounding, or a different order size than persisted.","commonSituations":"Unit-conversion mistakes (ether/wei float rounding) between amount computation and signing, persisted intent computed from one price/size snapshot while signing used a newer one, or replayed signed bytes from an earlier order.","solutions":["Re-sign with the value copied exactly from `intent.value` as a u128/wei integer — never via floating point — and validate the fresh bytes.","Trace the value pipeline end to end and keep it in integer wei (Decimal/integer types) from order computation through signing.","Regenerate the intent if the approved amount legitimately changed, then re-sign; do not re-sign over a stale intent.","Check test fixtures for hand-written values that drift from the intent used in the assertion."],"exampleFix":"// before\nlet value = U256::from(0.1_f64 * 1e18); // float rounding drift\nlet signed = sign(tx.with_value(value), &wallet);\n\n// after\nlet value = U256::from(intent.value); // exact persisted wei amount\nlet signed = sign(tx.with_value(value), &wallet);\nvalidate_signed_transaction(&signed, &intent)?;","handlingStrategy":"validation","validationCode":"fn value_matches(raw: &[u8], intent: &SignedTransactionIntent) -> bool {\n    decode_signed_transaction(raw).map(|tx| tx.value == intent.value).unwrap_or(false)\n}","typeGuard":"fn carries_exact_value(d: &DecodedSignedTransaction, i: &SignedTransactionIntent) -> bool {\n    d.value == i.value\n}","tryCatchPattern":"match validate_signed_transaction(&raw, &intent) {\n    Ok(()) => Ok(()),\n    Err(e) if e.to_string().contains(\"value\") => Err(Error::AmountMismatch(e)),\n    Err(e) => Err(e.into()),\n}","preventionTips":["Carry amounts as integer wei end to end; avoid f64/ether conversions in the signing path.","Copy `intent.value` verbatim into the transaction — never recompute the amount at sign time.","If an amount changes, recreate the intent and re-sign atomically rather than patching one side.","Unit-test the value pipeline with extreme amounts to catch rounding and overflow early."],"tags":["blockchain","transaction-validation","value-mismatch","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"}