From 85b352024001e3c5d0ea6f127f32a47f0724f965 Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Wed, 29 May 2024 12:10:00 +0200 Subject: [PATCH] feat: add solidity error decoding (#1130) add solidity error decoding --- Cargo.lock | 1 + Cargo.toml | 3 ++- src/eth_provider/error.rs | 41 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 754817e64..752d796f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8005,6 +8005,7 @@ dependencies = [ "alloy-primitives 0.7.2", "alloy-rlp", "alloy-signer-wallet", + "alloy-sol-types", "alphanet-instructions", "anyhow", "arbitrary", diff --git a/Cargo.toml b/Cargo.toml index efe9972ae..b75a20f2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,8 +57,9 @@ starknet-crypto = { version = "0.6.1", default-features = false } starknet_api = { version = "0.7.0-dev.0", default-features = false } # Ethereum dependencies -alloy-primitives = "0.7.2" +alloy-primitives = { version = "0.7.2", default-features = false } alloy-rlp = { version = "0.3.4", default-features = false } +alloy-sol-types = { version = "0.7.2", default-features = false } alphanet-instructions = { git = "https://github.com/paradigmxyz/alphanet.git", rev = "a7f66d6", default-features = false } ethers = { version = "2.0.9", default-features = false } ethers-solc = { version = "2.0.9", default-features = false } diff --git a/src/eth_provider/error.rs b/src/eth_provider/error.rs index bbdc6992b..29e1612e7 100644 --- a/src/eth_provider/error.rs +++ b/src/eth_provider/error.rs @@ -1,3 +1,4 @@ +use alloy_sol_types::SolType; use jsonrpsee::types::ErrorObject; use reth_primitives::Bytes; use starknet_crypto::FieldElement; @@ -182,7 +183,7 @@ impl From> for EvmError { let bytes = value.into_iter().filter_map(|x| u8::try_from(x).ok()).collect::>(); let maybe_revert_reason = String::from_utf8(bytes.clone()); if maybe_revert_reason.is_err() { - return Self::Other(format!("{}", Bytes::from(bytes))); + return Self::Other(decode_err(&bytes)); } let revert_reason = maybe_revert_reason.unwrap(); // safe unwrap @@ -208,11 +209,18 @@ impl From> for EvmError { "transfer amount exceeds balance" => Self::BalanceError, "AddressCollision" => Self::AddressCollision, s if s.contains("outOfGas") => Self::OutOfGas, - _ => Self::Other(format!("{}", Bytes::from(bytes))), + _ => Self::Other(decode_err(&bytes)), } } } +fn decode_err(bytes: &[u8]) -> String { + // Skip the first 4 bytes which is the function selector + let msg = &bytes[4..]; + let maybe_decoded_msg = alloy_sol_types::sol_data::String::abi_decode(msg, true); + maybe_decoded_msg.map_or_else(|_| format!("{}", bytes.iter().collect::()), |s| s) +} + /// Error related to a transaction. #[derive(Debug, Error)] pub enum TransactionError { @@ -284,13 +292,42 @@ mod tests { #[test] fn test_assure_source_error_visible_in_kakarot_error() { + // Given let err = KakarotError::ProviderError(starknet::providers::ProviderError::StarknetError( starknet::core::types::StarknetError::UnexpectedError("test".to_string()), )); + // When let eth_err: EthApiError = err.into(); let json_err: ErrorObject<'static> = eth_err.into(); + // Then assert_eq!(json_err.message(), "starknet provider error: StarknetError(UnexpectedError(\"test\"))"); } + + #[test] + fn test_decode_evm_error() { + // Given + let bytes: Vec<_> = vec![ + 0x08u8, 0xc3, 0x79, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x46, 0x61, 0x75, + 0x63, 0x65, 0x74, 0x3a, 0x20, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x20, 0x74, 0x6f, 0x6f, 0x20, 0x73, 0x6f, 0x6f, + 0x6e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + .into_iter() + .map(FieldElement::from) + .collect(); + + // When + let evm_err: EvmError = bytes.into(); + + // Then + if let EvmError::Other(err) = evm_err { + assert_eq!(err, "Faucet: Claim too soon."); + } else { + panic!("Expected EvmError::Other, got {evm_err:?}"); + } + } }