Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions src/chain_parsers/visualsign-ethereum/src/abi_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,26 @@ fn decode_solidity_value(ty: &str, data: &[u8], offset: &mut usize) -> String {
} else if ty == "address[]" {
// Dynamic address arrays - offset points to location of array
if *offset + 32 <= data.len() {
let array_offset = U256::from_be_bytes(data[*offset..*offset + 32].try_into().unwrap_or([0; 32]));
let array_offset =
U256::from_be_bytes(data[*offset..*offset + 32].try_into().unwrap_or([0; 32]));
*offset += 32;

// Read array length at the offset
let array_offset_usize = array_offset.try_into().unwrap_or(0usize);
if array_offset_usize + 32 <= data.len() {
let array_len_val = U256::from_be_bytes(data[array_offset_usize..array_offset_usize + 32].try_into().unwrap_or([0; 32]));
let array_len_val = U256::from_be_bytes(
data[array_offset_usize..array_offset_usize + 32]
.try_into()
.unwrap_or([0; 32]),
);
let array_len: usize = array_len_val.try_into().unwrap_or(0);
let mut addresses = Vec::new();

for i in 0..array_len {
let addr_offset_val: usize = (U256::from(array_offset_usize) + U256::from(32) + U256::from(i * 32)).try_into().unwrap_or(0);
let addr_offset_val: usize =
(U256::from(array_offset_usize) + U256::from(32) + U256::from(i * 32))
.try_into()
.unwrap_or(0);
if addr_offset_val + 32 <= data.len() {
let addr_bytes = &data[addr_offset_val + 12..addr_offset_val + 32]; // Take last 20 bytes
addresses.push(format!("0x{}", hex::encode(addr_bytes)));
Expand All @@ -73,7 +81,8 @@ fn decode_solidity_value(ty: &str, data: &[u8], offset: &mut usize) -> String {
} else if ty.ends_with("[]") {
// Other dynamic arrays - just show offset for now
if *offset + 32 <= data.len() {
let array_offset_val = U256::from_be_bytes(data[*offset..*offset + 32].try_into().unwrap_or([0; 32]));
let array_offset_val =
U256::from_be_bytes(data[*offset..*offset + 32].try_into().unwrap_or([0; 32]));
*offset += 32;
return format!("(dynamic array at offset {})", array_offset_val);
}
Expand Down Expand Up @@ -102,9 +111,7 @@ impl AbiDecoder {

/// Finds a function by its 4-byte selector
fn find_function_by_selector(&self, selector: &[u8; 4]) -> Option<&Function> {
self.abi
.functions()
.find(|f| &f.selector() == selector)
self.abi.functions().find(|f| &f.selector() == selector)
}

/// Decodes a function call from calldata
Expand Down
26 changes: 20 additions & 6 deletions src/chain_parsers/visualsign-ethereum/src/abi_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ impl AbiRegistry {
/// const ABI_JSON: &str = include_str!("abi.json");
/// registry.register_abi("MyContract", ABI_JSON)?;
/// ```
pub fn register_abi(&mut self, name: &str, abi_json: &str) -> Result<(), Box<dyn std::error::Error>> {
pub fn register_abi(
&mut self,
name: &str,
abi_json: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let abi = serde_json::from_str::<JsonAbi>(abi_json)?;
Arc::get_mut(&mut self.abis)
.expect("ABI map should be mutable")
Expand Down Expand Up @@ -155,7 +159,9 @@ mod tests {
#[test]
fn test_register_and_retrieve_abi() {
let mut registry = AbiRegistry::new();
registry.register_abi("TestToken", TEST_ABI).expect("Failed to register ABI");
registry
.register_abi("TestToken", TEST_ABI)
.expect("Failed to register ABI");

let abi = registry.get_abi("TestToken");
assert!(abi.is_some());
Expand All @@ -171,7 +177,9 @@ mod tests {
#[test]
fn test_address_mapping() {
let mut registry = AbiRegistry::new();
registry.register_abi("TestToken", TEST_ABI).expect("Failed to register ABI");
registry
.register_abi("TestToken", TEST_ABI)
.expect("Failed to register ABI");

let addr = "0x1234567890123456789012345678901234567890"
.parse::<Address>()
Expand All @@ -196,7 +204,9 @@ mod tests {
#[test]
fn test_different_chains_separate() {
let mut registry = AbiRegistry::new();
registry.register_abi("TestToken", TEST_ABI).expect("Failed to register ABI");
registry
.register_abi("TestToken", TEST_ABI)
.expect("Failed to register ABI");

let addr = "0x1234567890123456789012345678901234567890"
.parse::<Address>()
Expand All @@ -214,8 +224,12 @@ mod tests {
#[test]
fn test_list_abis() {
let mut registry = AbiRegistry::new();
registry.register_abi("TokenA", TEST_ABI).expect("Failed to register");
registry.register_abi("TokenB", TEST_ABI).expect("Failed to register");
registry
.register_abi("TokenA", TEST_ABI)
.expect("Failed to register");
registry
.register_abi("TokenB", TEST_ABI)
.expect("Failed to register");

let abis = registry.list_abis();
assert_eq!(abis.len(), 2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ impl CalldataVisualizer for DynamicAbiVisualizer {
chain_id: u64,
registry: Option<&ContractRegistry>,
) -> Option<SignablePayloadField> {
self.decoder
.visualize(calldata, chain_id, registry)
.ok()
self.decoder.visualize(calldata, chain_id, registry).ok()
}
}

Expand Down
21 changes: 15 additions & 6 deletions src/chain_parsers/visualsign-ethereum/src/embedded_abis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ mod tests {

#[test]
fn test_parse_abi_address_mapping_valid() {
let result = parse_abi_address_mapping("TestToken:0x1234567890123456789012345678901234567890");
let result =
parse_abi_address_mapping("TestToken:0x1234567890123456789012345678901234567890");
assert!(result.is_some());
let (name, _addr) = result.unwrap();
assert_eq!(name, "TestToken");
Expand All @@ -198,7 +199,9 @@ mod tests {
let mut registry = AbiRegistry::new();
register_embedded_abi(&mut registry, "TestToken", TEST_ABI).unwrap();

let address: Address = "0x1234567890123456789012345678901234567890".parse().unwrap();
let address: Address = "0x1234567890123456789012345678901234567890"
.parse()
.unwrap();
map_abi_address(&mut registry, 1, address, "TestToken");

// Verify it was mapped
Expand Down Expand Up @@ -234,8 +237,12 @@ mod tests {
register_embedded_abi(&mut registry, "ExtendedToken", MULTI_ABI).unwrap();

// Map addresses on different chains
let addr1: Address = "0x1111111111111111111111111111111111111111".parse().unwrap();
let addr2: Address = "0x2222222222222222222222222222222222222222".parse().unwrap();
let addr1: Address = "0x1111111111111111111111111111111111111111"
.parse()
.unwrap();
let addr2: Address = "0x2222222222222222222222222222222222222222"
.parse()
.unwrap();

map_abi_address(&mut registry, 1, addr1, "SimpleToken");
map_abi_address(&mut registry, 1, addr2, "ExtendedToken");
Expand All @@ -254,7 +261,9 @@ mod tests {
assert_ne!(abi1_on_mainnet, abi2_on_mainnet);

// Verify unmapped addresses return None
let unmapped: Address = "0x9999999999999999999999999999999999999999".parse().unwrap();
let unmapped: Address = "0x9999999999999999999999999999999999999999"
.parse()
.unwrap();
assert!(registry.get_abi_for_address(1, unmapped).is_none());
}

Expand All @@ -264,7 +273,7 @@ mod tests {
let mapping_strs = vec![
"Token1:0x1111111111111111111111111111111111111111",
"Token2:0x2222222222222222222222222222222222222222",
"InvalidFormat", // Invalid mapping
"InvalidFormat", // Invalid mapping
"Token3:0x3333333333333333333333333333333333333333",
];

Expand Down
9 changes: 7 additions & 2 deletions src/chain_parsers/visualsign-ethereum/src/grpc_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! using optional secp256k1 signatures.

use crate::abi_registry::AbiRegistry;
use crate::embedded_abis::{register_embedded_abi, AbiEmbeddingError};
use crate::embedded_abis::{AbiEmbeddingError, register_embedded_abi};

/// Error type for gRPC ABI operations
#[derive(Debug, thiserror::Error)]
Expand Down Expand Up @@ -133,7 +133,12 @@ mod tests {

let registry = result.unwrap();
// Verify ABI was registered
assert!(registry.list_abis().iter().any(|name| *name == "wallet_provided"));
assert!(
registry
.list_abis()
.iter()
.any(|name| *name == "wallet_provided")
);
}

#[test]
Expand Down
48 changes: 45 additions & 3 deletions src/chain_parsers/visualsign-ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,9 +331,10 @@ fn convert_to_visual_sign_payload(
let chain_id = transaction.chain_id();

// Try to extract AbiRegistry from options
let abi_registry = options.abi_registry.as_ref().and_then(|any_reg| {
any_reg.downcast_ref::<abi_registry::AbiRegistry>()
});
let abi_registry = options
.abi_registry
.as_ref()
.and_then(|any_reg| any_reg.downcast_ref::<abi_registry::AbiRegistry>());

let chain_name = chains::get_chain_name(chain_id);

Expand Down Expand Up @@ -450,6 +451,45 @@ fn convert_to_visual_sign_payload(
input_fields.push(field);
}
}
// Check if this is an Aave V3 Pool contract and visualize it
else if contract_type
== crate::protocols::aave::config::AaveV3PoolContract::short_type_id()
{
if let Some(field) = (protocols::aave::PoolVisualizer::new())
.visualize_pool_operation(input, chain_id_val, Some(registry))
{
input_fields.push(field);
}
}
}

// Check for Aave governance contracts by address
if let Some(to_addr) = transaction.to() {
// Check if this is the AAVE token (delegation)
if let Some(aave_token) =
protocols::aave::config::AaveV3Config::aave_token_address()
{
if to_addr == aave_token {
if let Some(field) = (protocols::aave::AaveTokenVisualizer)
.visualize_governance(input, chain_id_val, Some(registry))
{
input_fields.push(field);
}
}
}

// Check if this is a VotingMachine contract
if let Some(voting_machine) =
protocols::aave::config::AaveV3Config::voting_machine_address(chain_id_val)
{
if to_addr == voting_machine {
if let Some(field) = (protocols::aave::VotingMachineVisualizer)
.visualize_vote(input, chain_id_val, Some(registry))
{
input_fields.push(field);
}
}
}
}
}
}
Expand Down Expand Up @@ -679,6 +719,7 @@ mod tests {
decode_transfers: false,
transaction_name: Some("Custom Transaction Title".to_string()),
metadata: None,
abi_registry: None,
};
let payload = transaction_to_visual_sign(tx, options).unwrap();

Expand Down Expand Up @@ -905,6 +946,7 @@ mod tests {
decode_transfers: true,
transaction_name: Some("Test Transaction".to_string()),
metadata: None,
abi_registry: None,
}
),
Ok(SignablePayload::new(
Expand Down
Loading
Loading