Skip to content

Conversation

@andrestielau
Copy link
Contributor

This pull request introduces an embedded ERC-7730 function selector registry for Ethereum transaction parsing in the visualsign-ethereum crate. It adds a build-time code generation pipeline that parses JSON registry specs and produces a static Rust map for function selector lookups, enabling the decoding of Ethereum transaction calldata into labeled fields using the ERC-7730 registry. The PR also adds new provider and registry modules, and includes initial ERC-20 and ERC-4626 registry specs.

Build system and dependency updates:

  • Added new dependencies for code generation and registry parsing, including visualsign-erc7730-adapter, phf, once_cell, and related build dependencies in Cargo.toml.
  • Added .gitattributes entries to mark registry JSON files as generated, improving repository hygiene.

Registry and code generation:

  • Introduced a build.rs script that parses all JSON registry specs under static/eip7730/registry, deduplicates function selectors, and generates Rust code for a static selector-to-format map using phf.
  • Added two initial ERC-7730 JSON registry specs for ERC-20 tokens and ERC-4626 vaults, providing field-level metadata for common DeFi contract functions. [1] [2]

Core library changes:

  • Added new provider and registry modules to the crate, and exposed them in the crate root. [1] [2]
  • Implemented registry.rs to provide a decode_calldata function, mapping calldata selectors to labeled fields using the generated registry, and included comprehensive tests for registry correctness and decoding behavior.
  • Added provider/eip7730.rs with functions to decode raw Ethereum transactions (RLP bytes) into SignablePayloadFields or SignablePayloads using the embedded registry.

@andrestielau andrestielau self-assigned this Aug 14, 2025
Copy link
Contributor

@prasanna-anchorage prasanna-anchorage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this was a different PR about tracing the source file

@@ -0,0 +1,65 @@
{
"$schema": "../specs/erc7730-v1.schema.json",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how are we pulling these files? can we make it more traceable to the source repo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cloned the repo and copied the files, but I can try a better approach

- Added new expected output and input files for EIP-7730 transactions.
- Improved test structure by creating a helper function for fixture paths.
- Removed redundant code in the decoding function to streamline processing.
- Ensured consistency in dependency declarations in Cargo.toml.
- Renamed Eip7730Visualizer to Eip7730TxVisualizer for clarity.
- Updated visualize_tx_commands to create a list layout of decoded fields instead of a single text field.
- Enhanced decode_calldata to extract values based on field paths and create appropriate SignablePayloadFields.
- Introduced helper functions for extracting values from calldata and creating typed fields.
- Removed outdated test fixtures for ledgerquest_mint and paraswap_simpleBuy.
- Added new test fixture for paraswap_simpleSwap.
- Updated tests to reflect changes in the visualizer output structure.
- Implemented a build script to generate the registry from JSON definitions.
Comment on lines +28 to +31
static INIT: Once = Once::new();
// Top-level map: chain_id (Some or None for chain-agnostic) -> address -> visualizer
static mut COMMAND_REGISTRY_PTR: *mut HashMap<Option<u64>, HashMap<Address, DynVisualizer>> =
std::ptr::null_mut();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is better to use OnceLock and RefMut?

@@ -0,0 +1,291 @@
use alloy_primitives::keccak256;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really hard to read the code, maybe we could use qoute and syn?

Comment on lines +47 to +68
pub fn normalize_selector(key: &str) -> Option<String> {
let k = key.trim();
// Already a 4-byte selector
if k.len() == 10 && k.starts_with("0x") && k.chars().skip(2).all(|c| c.is_ascii_hexdigit()) {
return Some(k.to_ascii_lowercase());
}
// Function signature form: name(args)
if let (Some(_l), Some(r)) = (k.find('('), k.rfind(')')) {
if r > 0 {
let sig = &k[..=r]; // include ')'
// Remove any internal whitespace to be safe
let cleaned: String = sig.chars().filter(|c| !c.is_whitespace()).collect();
let digest = keccak256(cleaned.as_bytes());
let selector = &digest.as_slice()[..4];
return Some(format!(
"0x{:02x}{:02x}{:02x}{:02x}",
selector[0], selector[1], selector[2], selector[3]
));
}
}
None
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe there is an alloy utility for that

@@ -0,0 +1,36 @@
use crate::registry::{CommandVisualizer, VisualizerContext, decode_calldata};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be have/use a single error type throughout the codebase

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.

4 participants