From d809bd77c97b1eea71060f7a4c8777b56c3f2ede Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Tue, 7 Jan 2025 21:02:36 +0100 Subject: [PATCH] feat(contract): improve 'no data' error message (#1898) --- crates/contract/src/error.rs | 14 ++++++++++++++ crates/contract/src/eth_call.rs | 6 ++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/crates/contract/src/error.rs b/crates/contract/src/error.rs index 4b9ebe48762..c817043474d 100644 --- a/crates/contract/src/error.rs +++ b/crates/contract/src/error.rs @@ -22,6 +22,9 @@ pub enum Error { /// `contractAddress` was not found in the deployment transaction’s receipt. #[error("missing `contractAddress` from deployment transaction receipt")] ContractNotDeployed, + /// The contract returned no data. + #[error("contract call to `{0}` returned no data (\"0x\"); the called address might not be a contract")] + ZeroData(String, #[source] AbiError), /// An error occurred ABI encoding or decoding. #[error(transparent)] AbiError(#[from] AbiError), @@ -39,3 +42,14 @@ impl From for Error { Self::AbiError(e.into()) } } + +impl Error { + #[cold] + pub(crate) fn decode(name: &str, data: &[u8], error: AbiError) -> Self { + if data.is_empty() { + let name = name.split('(').next().unwrap_or(name); + return Self::ZeroData(name.to_string(), error); + } + Self::AbiError(error) + } +} diff --git a/crates/contract/src/eth_call.rs b/crates/contract/src/eth_call.rs index ba0818f0ef6..bdaf6cfb338 100644 --- a/crates/contract/src/eth_call.rs +++ b/crates/contract/src/eth_call.rs @@ -169,7 +169,8 @@ impl CallDecoder for Function { #[inline] fn abi_decode_output(&self, data: Bytes, validate: bool) -> Result { - FunctionExt::abi_decode_output(self, &data, validate).map_err(Error::AbiError) + FunctionExt::abi_decode_output(self, &data, validate) + .map_err(|e| Error::decode(&self.name, &data, e)) } #[inline] @@ -183,7 +184,8 @@ impl CallDecoder for PhantomData { #[inline] fn abi_decode_output(&self, data: Bytes, validate: bool) -> Result { - C::abi_decode_returns(&data, validate).map_err(|e| Error::AbiError(e.into())) + C::abi_decode_returns(&data, validate) + .map_err(|e| Error::decode(C::SIGNATURE, &data, e.into())) } #[inline]