Skip to content

refactor(cast): share transaction helpers and simplify commands - #16636

Draft
DaniPopes wants to merge 29 commits into
masterfrom
refactor/cast-cleanup
Draft

refactor(cast): share transaction helpers and simplify commands#16636
DaniPopes wants to merge 29 commits into
masterfrom
refactor/cast-cleanup

Conversation

@DaniPopes

Copy link
Copy Markdown
Member

This applies the same treatment to crates/cast that #16615 applied to the linter: reduce every command to the business logic it actually needs, without changing what users see. The crate's sources go from 35,262 to 28,146 lines (−20%) while the 488 CLI snapshot test cases under crates/cast/tests/cli/ are untouched and pass unchanged; the only tests removed are unit tests that duplicated a CLI snapshot, restated the implementation, exercised upstream alloy or clap behaviour, or covered a helper that no longer exists.

The recurring duplication was the Tempo transaction pipeline. cast erc20, the TIP-20 precompile commands and the two registerVirtualMaster paths each carried their own copy of cast send's signing, sponsor and fee-token flow; they now delegate to SendTxArgs, and the sponsor-or-fee-token block, sponsor hash computation, disclosure-confirm-then-build sequence, provider construction and hardfork guards live once in crate::tempo, crate::tx and cmd/auth.rs. The cast_send* helpers take a SendOptions struct instead of nine positional arguments, CastTxBuilder state transitions no longer re-list every field, and the safe subcommands pass their clap argument structs through instead of forwarding up to seventeen positionals. On the read side, args.rs collapses the repeated stdin-parse-print and provider-prologue arms, the Optimism/Tempo/default provider dispatch is one macro, and base.rs keeps only the conversions cast to-base uses. Dead code removed outright includes the unused errors module, the VanityMatcher trait hierarchy in favour of a two-field matcher, the always-erroring cast bind flags, and a handful of unreachable branches and single-use wrapper types.

Three small behaviour alignments are intentional and worth a look: cast erc20 writes with --browser now follow cast send's network selection instead of a separate chain-id probe, cast tip20 create shows the ISO-4217 prompt before resolving the signer as cast send does, and registerVirtualMaster resolves the sender's fee token in all modes rather than only in JSON mode. cast bind --help no longer lists the dead flags of a command that has only ever printed a removal error.

The history is one commit per area so any step can be reverted independently. Written with AI assistance (Claude Code).

🤖 Generated with Claude Code

Introduce tempo_provider, attach_sponsor, apply_fee_payment,
print_sponsor_hash and resolve_send_signer so commands stop
re-implementing the same provider setup, fee-token and sponsor logic.
Hoist the keystore-dir resolution and password prompt that were copied
across Import/Remove/DecryptKeystore/ChangePassword and touch-id into
shared helpers, split the New arm into keystore and keypair helpers,
unify the macOS Touch ID enrollment path behind one helper, and inline
the single-use recover_address_* wrappers.

Replace the vanity VanityMatcher trait, seven matcher structs and the
eight-arm dispatch with one Pattern enum, a Matcher and a single
find_vanity, dropping the unused pub API.

Collapse the Touch ID sidecar unit tests into one table-driven test and
drop clap-only parse tests and tests duplicated by CLI snapshots.
Inline the run_for_command/cleanup/finish result merging into
SessionArgs::run with two compact matches that keep the existing error
precedence, fold run_revoke into the dispatch arm, derive the JSON
revoke reason from one const fn, reuse the tempo-primitives CallScope
conversion for --scope parsing, and drop the tiny status/interrupt
error wrappers. Remove the unit test that only exercised
foundry_common's retire_session_entry.
Store --max-senders as a plain usize since clap always supplies its
default, and read the JSON mode inside the local listing instead of
threading it through as a parameter.
Remove the unused errors module and the unused Base/NumberWithBase
conversions, formatting impls and ToBase trait. Deduplicate the proxy
slot, proof, log formatting, block field and network provider dispatch
paths, turn the genesis hash match into a table, drop the always-false
lane flag from Cast::transaction and collapse the one-liner subcommand
arms in args.rs. Delete unit tests that duplicate doctests or CLI tests.
Reuse foundry_cli::utils::parse_ether_value in CallSpec and drop its
FromStr impl and the unreachable empty-parts branch. Delete unit tests
that only restate the implementation or upstream parsing: the BlockId
FromStr test in opts, the call kind/log field mapping tests in
rpc_trace, and the ForkEndpointIdentity inequality test in debug.
Route provider construction through `crate::tempo::tempo_provider` and
fee payment through `apply_fee_payment`; add `require_hardfork`,
`print_json_or`, `remaining_limit`, `send_keychain_call`, and a `Doctor`
accumulator whose `check`/`attempt` helpers replace the repeated
push-and-finalize blocks. Funnel the six enum-to-string helpers through
`KeyType`, unify the two `--limit` parsers and the two root-sender
guards, merge `run_list`/`run_show`, the two expiry checks, and the two
allowed-calls checks, and drop single-use structs and wrappers. Collapse
the unit tests into table-driven ones and delete those duplicating CLI
coverage.
Move the doctor context setup out of the dispatch arm and resolve --tempo.expires inside the diagnosis run.
Share the creation-code, ABI loading and constructor-args split between
`creation-code`, `constructor-args` and `artifact`; render `interface`
output once and drop the string-typed ABI re-parsing; reduce the removed
`bind` command to a catch-all args struct; bind the provider once in
`tx-pool`; use `print_json_value_or_scalar` in `rpc`; collapse the
`b2e-payload` input enum and its tests; drop the monad-only DA test.
Build log filters directly from topic arrays instead of the partition
and re-sort dance, table-drive the filter tests, inline the one-line
chain resolution in `events` and simplify the human formatter, drop the
unreachable `create2` subcommand bail and its test, and deduplicate the
artifact lookups, tempdir fallback and storage rendering in `storage`.
Move each `cast safe` subcommand's arguments into a clap `Args` struct
in its module and dispatch with `args.run()` instead of destructuring the
enum and forwarding up to seventeen positional parameters. Share the
provider/chain-id preamble via `rpc_provider`, the onchain send options
via `SafeSendOpts`, and the signed delegate submission between add and
remove. Deduplicate the Transaction Service response handling and the
contract/P-256 signature packing, and drop the unit tests that only
duplicate the safe CLI tests.
Destructure the joined timestamps directly and fold the four one-line interpolation tests into one.
Replace the three hand-rolled copies of the `cast send` flow (the erc20
`erc20_send!` macro, `send_tip20_transaction`, and the duplicated
`registerVirtualMaster` submission in `vaddr create` and `tip20 mine`)
with `SendTxArgs::contract_call(..)` plus one shared
`register_virtual_master` in `tip20/mine.rs` that keeps the quiet JSON
hash capture `vaddr create` needs. Callers now pass ABI-encoded `SolCall`
data instead of stringified signatures and arguments.

Also collapse the repeated read arms in `erc20` and `erc4626` behind
small `token_at`/`vault_at` helpers, share `print_amount` and
`policy_type_label`, drop the duplicated `blocked_reason` table, use
`IERC20::Transfer::SIGNATURE_HASH` and `Address::into_word` in
`vaddr watch`, and delete unit tests that only re-checked alloy selector
generation or behaviour already covered by the CLI snapshot tests.
Simplify the scope and recipient splitting in `tempo_policy_args`, fold
the near-identical `parse_selector_bytes_*` and `parse_scope_*` unit
tests into two table-driven tests, and drop a redundant branch in
`cast tempo login`.
Drop the single-use FromIterator impl for Item, collapse the bail arms in
value_to_item and the JSON error-code selection in main.
Move the state-independent fields of `CastTxBuilder` into one inner
struct so state transitions no longer retype every field, share the
receipt formatting tail between the sync/raw/polled sends, drop the
unused `send_raw`, and fold `TxParams::apply` into
`TransactionOpts::apply`.

Add `confirm_and_build` helpers that run the EIP-7702 disclosure
confirmation, build and print the resolved lane, plus tempo helpers for
sponsor attachment, fee-token resolution and the sponsor hash, and use
them from `send`, `mktx`, `batch-send` and `batch-mktx` instead of the
repeated per-mode copies. `batch-send`/`batch-mktx` now share one
call-spec resolver that reads the Etherscan config from the builder.

Remove unit tests duplicated by CLI snapshot tests.
Share the browser-or-wallet sender resolution and the confirm-and-build
step between `estimate`, `access-list` and `call`, and route the
`--json`/raw result printing of `estimate` and `call` through one
helper.

In `run`, move the `--debug-trace-transaction` path out of `prepare`
into its own method, extract the callTracer frame/error-hint handling
shared with `call --debug-trace-call`, and factor the target-index
lookup, block prefix replay and trace-kind selection shared by the
ordinary and Monad executions. The two `eth_getCode` fan-outs now share
one bounded fetcher.

Drop the single-use `AuthDisclosurePreflight` struct, the
`infer_network_from_chain_id` and override wrappers, and unit tests that
duplicate CLI snapshot tests or upstream clap/network behaviour; the
remaining `pin_remote_trace_block` cases are one table-driven test.
Rely on hex decoding to strip the 0x prefix and classify the raw input only on the trace_rawTransaction path that uses it.
Tempo precompile commands delegate to it after the send cleanup.
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

✅ Changelog found

The deterministic check will validate the changed entry.

…efactor/cast-cleanup

# Conflicts:
#	crates/cast/src/cmd/run.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant