feat(cast): add events command - #16238
Conversation
✅ Changelog foundThe deterministic check will validate the changed entry. |
mattsse
left a comment
There was a problem hiding this comment.
The recursive ABI lookup currently regresses proxy trace identities and is responsible for the remaining main CI failure. Please keep address-local identity metadata separate from the full ABI chain used by cast events.
| .into_iter() | ||
| .zip(addresses.iter().copied()) | ||
| .map(|(chain, address)| { | ||
| let result = if chain.abis.is_empty() { |
There was a problem hiding this comment.
If the proxy's own ABI fetch succeeds but the implementation fetch fails mid-chain, chain.abis is still non-empty here, so this returns Ok indistinguishable from full success. decode_logs in events.rs only warns on Err, so a partially-resolved proxy silently loses all implementation events with no diagnostic.
| .zip(addresses.iter().copied()) | ||
| .map(|(chain, address)| { | ||
| let result = if chain.abis.is_empty() { | ||
| Err(eyre::eyre!("external ABI lookup failed")) |
There was a problem hiding this comment.
This collapses every failure cause (rate limit, bad API key, Cloudflare block, genuinely unverified) into one fixed string. The real EtherscanError is warn!-logged in the fetcher but never makes it into self.contracts, so sh_warn!("Failed to fetch ABI for {address}: {err}") in events.rs can never say anything more specific than "external ABI lookup failed".
| if let Some(decoded) = decoded { | ||
| return decoded; | ||
| } | ||
| if canonical_signature && regular_events.is_some() { |
There was a problem hiding this comment.
regular_events.is_some() only means an event is registered for this key, not that it decoded successfully. If every candidate here fails decode_log but a uniquely-matching anonymous event exists for the same address/topic-count, this returns undecoded before ever reaching the anonymous_events branch below.
| decoder.decode_event_with_address_signature(log.address(), log.data()).await; | ||
| EventOutput::new(log, decoded.name, decoded.params) | ||
| }) | ||
| .buffered(MAX_CONCURRENT_RPC_REQUESTS) |
There was a problem hiding this comment.
SignaturesIdentifier::identify has no in-flight coalescing (checks cache under a read lock, then separately acquires a write lock to fetch), concurrent decode tasks resolving the same unresolved topic0 each issue their own OpenChain HTTP request instead of sharing one lookup.
| } | ||
|
|
||
| /// Fetches all verified ABIs for each address using the configured external sources. | ||
| pub async fn get_abis( |
There was a problem hiding this comment.
This reimplements proxy-chain following (walk proxy/implementation, cycle-guard, accumulate ABIs) that already exists as find_source in crates/common/src/abi.rs, with different depth/cycle handling and no shared fallback logic. A future proxy-detection fix would need to be applied in both places.
Adds
cast eventsto fetch and decode events from a transaction receipt or acast logs-style filter. It supports transaction hashes, addresses, block ranges, topics, and chunked queries, using address-specific explorer ABIs and signature lookup with raw-log fallback.The command provides readable human output and structured JSON while preserving log metadata and ordering. Proxy diagnostics are routed to stderr so stdout remains machine-readable.
Closes #2340.