nautechsystems/nautilus_trader · error

Signed transaction value does not match persisted value

Error message

Signed transaction value does not match persisted value

What it means

`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.

Source

Thrown at crates/adapters/blockchain/src/execution/transaction.rs:298

        intent.chain_id
    );
    anyhow::ensure!(
        tx.nonce == intent.nonce,
        "Signed transaction nonce {} does not match persisted nonce {}",
        tx.nonce,
        intent.nonce
    );
    anyhow::ensure!(
        tx.to == intent.to,
        "Signed transaction destination {} does not match persisted destination {}",
        tx.to,
        intent.to
    );
    anyhow::ensure!(
        tx.value == intent.value,
        "Signed transaction value does not match persisted value"
    );
    anyhow::ensure!(
        tx.input == intent.input,
        "Signed transaction calldata does not match persisted calldata"
    );
    anyhow::ensure!(
        tx.gas_limit <= intent.gas_limit,
        "Signed transaction gas limit {} exceeds configured ceiling {}",
        tx.gas_limit,
        intent.gas_limit
    );
    anyhow::ensure!(
        tx.max_fee_per_gas <= u128::from(intent.max_fee_per_gas),
        "Signed transaction max fee per gas {} wei exceeds configured ceiling {} wei",
        tx.max_fee_per_gas,
        intent.max_fee_per_gas
    );
    anyhow::ensure!(
        tx.max_priority_fee_per_gas <= tx.max_fee_per_gas,
        "Signed transaction priority fee per gas {} wei exceeds max fee per gas {} wei",

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Re-sign with the value copied exactly from `intent.value` as a u128/wei integer — never via floating point — and validate the fresh bytes.
  2. Trace the value pipeline end to end and keep it in integer wei (Decimal/integer types) from order computation through signing.
  3. Regenerate the intent if the approved amount legitimately changed, then re-sign; do not re-sign over a stale intent.
  4. Check test fixtures for hand-written values that drift from the intent used in the assertion.

Example fix

// before
let value = U256::from(0.1_f64 * 1e18); // float rounding drift
let signed = sign(tx.with_value(value), &wallet);

// after
let value = U256::from(intent.value); // exact persisted wei amount
let signed = sign(tx.with_value(value), &wallet);
validate_signed_transaction(&signed, &intent)?;
Defensive patterns

Strategy: validation

Validate before calling

fn value_matches(raw: &[u8], intent: &SignedTransactionIntent) -> bool {
    decode_signed_transaction(raw).map(|tx| tx.value == intent.value).unwrap_or(false)
}

Type guard

fn carries_exact_value(d: &DecodedSignedTransaction, i: &SignedTransactionIntent) -> bool {
    d.value == i.value
}

Try / catch

match validate_signed_transaction(&raw, &intent) {
    Ok(()) => Ok(()),
    Err(e) if e.to_string().contains("value") => Err(Error::AmountMismatch(e)),
    Err(e) => Err(e.into()),
}

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/07751cc36850636d. Report an issue: GitHub.