-
-
Notifications
You must be signed in to change notification settings - Fork 35
Description
Problem
TxEnvelopeTempo.deserialize does not recognise the spec-compliant fee payer placeholder encoding from Rust/alloy.
The Tempo transaction spec defines the placeholder as Some(Signature::default()), which RLP-encodes to [0x80, 0x80, 0x80] (c3 80 80 80). This is what Rust/alloy produces.
However, deserialize at L347-362 only recognises 0x00 or a valid address as the null sentinel. The zero-tuple falls through to Signature.fromTuple, yielding { r: 0n, s: 0n, yParity: 0 } — a real signature object instead of null.
This causes getSignPayload / serialize to encode field 12 as a 4-byte RLP list instead of the 1-byte 0x00 placeholder, breaking sender recovery and fee payer co-signing for cross-client transactions.
Suggested Fix
In deserialize, after Signature.fromTuple, check for a zero-valued signature and normalise to null:
} else {
const sig = Signature.fromTuple(feePayerSignatureOrSender as never)
// Zero-valued ECDSA signature is cryptographically impossible —
// this is the spec-compliant placeholder from Rust/alloy.
if (sig.r === 0n && sig.s === 0n) {
transaction.feePayerSignature = null
} else {
transaction.feePayerSignature = sig
}
}Spec Reference
- Fee Payer Signature Details
- Transaction Flow: "User sets
fee_payer_signatureto placeholder (Some(Signature::default()))" - Wire format:
fee_payer_signature→0x80 if None, RLP list [v, r, s] if Some
Workaround
mppx has a workaround in wevm/mppx#104 that normalises post-deserialize.