Skip to content

fix: override eth_callMany to apply seismic preprocessing#388

Open
matthias-wright wants to merge 6 commits into
veridise-audit-april-2026from
m/eth-callmany-auth
Open

fix: override eth_callMany to apply seismic preprocessing#388
matthias-wright wants to merge 6 commits into
veridise-audit-april-2026from
m/eth-callmany-auth

Conversation

@matthias-wright
Copy link
Copy Markdown
Contributor

Overwrites the eth_callMany endpoint to apply the same sanitization steps that are applied to eth_call, eth_simulateV1 , and eth_estimateGas`.

Changes:

  • Adds new call_many method on the EthApiOverride trait, taking Vec<Bundle<SeismicCallRequest>>.
  • EthApiExt::call_many runs each call through convert_seismic_call_to_tx_request and signed_read_to_plaintext_tx before delegating to EthCall::call_many, then encrypts per-call value for signed reads.
  • Adds e2e tests.

samlaf and others added 6 commits April 22, 2026 13:36
Signed-read seismic transactions were previously rejected only at mempool
admission. Block producers ingesting txs through non-mempool paths —
builder API, private orderflow, or the EIP-712 `TypedData` variant of
`eth_sendRawTransaction` which bypassed `Decodable2718` — could include a
signed-read tx directly, letting an attacker who intercepted a signed
`eth_call` payload replay it as an actual state-changing transaction.

Consumes seismic-alloy's decoder-level rejection (#104, c1ce533) and
updates this crate accordingly:

* `send_raw_transaction`: the `TypedData` arm now decodes the EIP-712
  payload into a `SeismicTxEnvelope`, re-encodes as RLP, and delegates to
  `EthTransactions::send_raw_transaction(bytes)`. All signed-tx ingress
  now funnels through a single `Decodable2718::typed_decode` pipeline, so
  decode-time invariants (including the new signed-read rejection) apply
  uniformly. Removes the parallel pool-admission pipeline that was the
  bypass.

* For `eth_call`'s Bytes path, a new `recover_raw_seismic_call_tx` helper
  uses seismic-alloy's permissive `decode_2718_permit_seismic_calls` so
  legitimate signed-read payloads are still accepted.

* Removes the now-redundant mempool-level `validate_signed_read_for_write`
  check and its associated error variant.

Depends on seismic-alloy PR #104; the \`rev\` in Cargo.toml is temporary and
should be bumped to the merged-main commit before landing.
@matthias-wright matthias-wright requested a review from cdrappi as a code owner May 7, 2026 12:58
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

Adds eth_callMany support and refactors seismic transaction handling by centralizing freshness validation in the RPC layer.

Phase 1

crates/seismic/rpc/src/eth/ext.rs:56SeismicApi struct derives Debug and contains GetPurposeKeysResponse with the secret key tx_io_sk. Any debug!() or {:?} formatting of this struct would leak the secret key in logs.

crates/seismic/rpc/src/eth/ext.rs:137EthApiExt struct also derives Debug and holds the same GetPurposeKeysResponse. Same secret key exposure risk as above.

crates/seismic/txpool/src/validator.rs:1187-1192 — TODO comment indicates freshness validation (recent_block_hash and expires_at_block checks) now only happens in the RPC layer and can be bypassed via builder API or other non-mempool paths. This breaks consensus-level validation guarantees.

Phase 2

crates/seismic/rpc/src/eth/ext.rs:372SeismicTxEnvelope::decode_712(&typed_data) converts TypedData to envelope, then immediately re-encodes with envelope.encoded_2718().into(). The conversion roundtrip could introduce subtle serialization differences compared to submitting the same transaction as raw bytes.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants