feat(cast): bring remaining --json outputs into JsonEnvelope#14918
feat(cast): bring remaining --json outputs into JsonEnvelope#14918mablr wants to merge 17 commits into
--json outputs into JsonEnvelope#14918Conversation
Move `print_scalar`, `print_list`, `print_tokens`, and
`print_json_object` from
local helpers in `args.rs` into `foundry_cli::json` so every cmd module
can import them directly instead of inlining the if/else pattern.
Replace all remaining inline `if shell::is_json() { sh_println!(...) }`
patterns across cmd modules:
- `estimate`, `find_block`, `call`, `mktx` → `print_scalar`
- `txpool` (all variants), `rpc`, `vaddr/create` → `print_json_object`
- `keychain list/inspect/doctor` → `print_json_object` /
`print_json_success`
- `erc20 name/symbol/decimals` → `print_scalar`
- `erc20 balance/allowance/total_supply` → `print_json_success` (keep
`format_uint_exp` for plain-mode display)
- `Block` and `Tx` in `args.rs` → parse pre-formatted JSON string and
wrap
- `Selectors` in `args.rs` → new `SelectorInfo` struct, envelope-wraps
array
- `AbiEncodeEvent` in `args.rs` → new `EncodedEvent{topics,data}` struct
- `interface` → wrap ABI array in envelope on stdout path
Document explicitly unsupported commands with inline comments: `send`
(N::ReceiptResponse lacks Serialize), `logs --subscribe` (streaming),
`wallet` (follow-up), `upload-signature` (external API),
`four-byte-calldata` (interactive).
Add CLI tests: `selectors_json_envelope`,
`abi_encode_event_json_envelope`.
mattsse
left a comment
There was a problem hiding this comment.
Requesting changes: these paths can fail or emit invalid JSON for valid --json usages.
P1: cast call --json reparses response as JSON, but Cast::call returns raw hex when no output is decoded. Valid calls can therefore error on serde_json::from_str. Please avoid reparsing arbitrary display output; return structured data from Cast::call, or wrap raw hex as a JSON string/envelope in the command layer.
P1: cast block --json and cast tx --json also assume output is a JSON object. --raw or scalar field paths such as block hash / tx from can return scalar strings, which either fail JSON parsing or are not objects. Please only call print_json_object for object output, and use a scalar JSON envelope/string path for field selections.
P2: cast mktx prints the expiration status line to stdout before later JSON/scalar output, which corrupts --json output. Please move this to stderr/warning output, suppress it under shell::is_json(), or include it inside the JSON payload.
Please add regressions for cast call --json with undecoded/raw output, cast block/tx --json scalar field paths, and cast mktx --json --expires-at ... producing a single valid JSON document.
959137a to
60cfa08
Compare
figtracer
left a comment
There was a problem hiding this comment.
Three focused JSON-output regressions from the local review pass.
- args.rs: use get(pos).cloned() instead of indexing resolve_results to avoid panic in cast selectors --json when --resolve is not set - interface.rs: use sh_status! for "Saved interface at" so it goes to stderr in JSON mode, keeping stdout clean - keychain.rs: move is_json() branch before the is_empty() guard so cast --json keychain list emits [] instead of plain text when empty - vaddr/create.rs: defer JSON/text output until after register() succeeds to avoid emitting two stdout documents when registration fails
There was a problem hiding this comment.
crates/cast/src/cmd/vaddr/create.rs — mined salt is lost on register failure
The non---no-register path now calls register(...).await? before printing the salt/registration_hash/master_id/virtual_addresses block. On master those values were printed first.
Reproduced with no signer (so register errors):
master
STDOUT:
Salt: 0x9bf4…155f
Registration hash: 0x0000…e5fd
Master ID: 0x3a96b610
Virtual addresses:
tag=0x000000000000 0x3A96B610…0000
STDERR:
Error: cast vaddr create requires a signer (...)
PR
STDOUT: (only the "Mining…/Found salt in…" lines)
STDERR:
Error: cast vaddr create requires a signer (...)
The mined salt is now lost on any registration failure — the user has to mine again (which can take minutes). Suggest restoring the prior order: compute the payload once, print it, then call register. That also lets you collapse the duplicated JSON/plain-text blocks between the no_register branch and the register branch (both currently emit the same payload; print_json_success and print_json_object are equivalent inside if shell::is_json()).
crates/cast/src/cmd/keychain.rs — run_list empty case becomes an error
run_list now routes the empty-keys case through sh_err!, which writes to stderr and prefixes Error:. The same situation in run_show still uses sh_println!, so the two siblings disagree.
Reproduced with TEMPO_HOME pointing at a keys.toml containing keys = []:
master: EXIT 0 STDOUT: "No keys found in keys.toml." STDERR: (empty)
PR: EXIT 0 STDOUT: (empty) STDERR: "Error: No keys found in keys.toml."
An empty list is a successful result, not an error. Suggest keeping sh_println! here for parity with run_show (or change both).
crates/cast/src/cmd/interface.rs — --json stdout and --json -o file shapes diverge
cast interface --json to stdout now wraps the parsed ABIs in a JsonEnvelope, but cast interface --json -o <file> still writes the raw concatenated json_abi strings to the file. Same data, two shapes depending on whether -o is set.
Reproduced with a single-ABI input:
stdout (--json) |
file (--json -o) |
|
|---|---|---|
| master | [ { ...abi... } ] |
[ { ...abi... } ] |
| PR | {"schema_version":1,"success":true,"data":[[{...}]],…} |
[ { ...abi... } ] |
If file output is intentionally a raw artifact (not wrapped), please call that out (doc/comment + test); otherwise both destinations should share the envelope shape. Note that for multiple interfaces the file content is also several JSON objects newline-joined, which isn't one valid JSON document.
Description
Towards OSS-239 (almost there after
walletfollow-up)Move
print_scalar,print_list,print_tokens, andprint_json_objectfrom local helpers inargs.rsintofoundry_cli::jsonso every cmd module can import them directly instead of inlining the if/else pattern.Replace all remaining inline
if shell::is_json() { sh_println!(...) }patterns across cmd modules:estimate,find_block,call,mktx→print_scalartxpool(all variants),rpc,vaddr/create→print_json_objectkeychain list/inspect/doctor→print_json_object/print_json_successerc20 name/symbol/decimals→print_scalarerc20 balance/allowance/total_supply→print_json_success(keepformat_uint_expfor plain-mode display)BlockandTxinargs.rs→ parse pre-formatted JSON string and wrapSelectorsinargs.rs→ newSelectorInfostruct, envelope-wraps arrayAbiEncodeEventinargs.rs→ newEncodedEvent{topics,data}structinterface→ wrap ABI array in envelope on stdout pathDocumented explicitly unsupported commands with inline comments:
send(N::ReceiptResponse lacks Serialize),logs --subscribe(streaming),wallet(follow-up),upload-signature(external API),four-byte-calldata(interactive).PR Checklist