From d6e40dd4742872279face532c11a8944c7da1cb9 Mon Sep 17 00:00:00 2001 From: alessandromazza Date: Tue, 26 Sep 2023 15:49:50 +0200 Subject: [PATCH 1/8] move decode_revert_reason to alloy and add tests --- crates/sol-types/src/lib.rs | 2 +- crates/sol-types/src/types/error.rs | 51 +++++++++++++++++++++++++++-- crates/sol-types/src/types/mod.rs | 2 +- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/crates/sol-types/src/lib.rs b/crates/sol-types/src/lib.rs index 507d95fca..52f66e213 100644 --- a/crates/sol-types/src/lib.rs +++ b/crates/sol-types/src/lib.rs @@ -183,7 +183,7 @@ mod types; pub use types::{ data_type as sol_data, ContractError, Encodable, EventTopic, GenericContractError, Panic, PanicKind, Revert, Selectors, SolCall, SolEnum, SolError, SolEvent, SolInterface, SolStruct, - SolType, TopicList, + SolType, TopicList, decode_revert_reason, }; pub mod utils; diff --git a/crates/sol-types/src/types/error.rs b/crates/sol-types/src/types/error.rs index fd8080539..3d8358f2c 100644 --- a/crates/sol-types/src/types/error.rs +++ b/crates/sol-types/src/types/error.rs @@ -1,9 +1,9 @@ use crate::{ token::{PackedSeqToken, TokenSeq, WordToken}, - Result, SolType, TokenType, Word, + Result, SolType, TokenType, Word, GenericContractError, SolInterface, }; use alloc::{string::String, vec::Vec}; -use alloy_primitives::U256; +use alloy_primitives::{U256, Selector}; use core::{borrow::Borrow, fmt}; /// Solidity Error (a tuple with a selector) @@ -408,6 +408,31 @@ impl PanicKind { } } +/// Returns the revert reason from the given output data, if it's an abi encoded String. Returns +/// `None` if the output is not long enough to contain a function selector or the content is not a +/// valid abi encoded String. +/// +/// **Note:** it's assumed the `out` buffer starts with the call's signature +pub fn decode_revert_reason(out: &[u8]) -> Option { + // Ensure the output data is long enough to contain a function selector. + if out.len() < Selector::len_bytes() { + return None + } + + // Try to decode as a generic contract error. + if let Ok(error) = GenericContractError::decode(out, true) { + return Some(error.to_string()) + } + + // If that fails, try to decode as a regular string. + if let Ok(decoded_string) = std::str::from_utf8(out) { + return Some(decoded_string.to_string()) + } + + // If both attempts fail, return None. + None +} + #[cfg(test)] mod tests { use super::*; @@ -448,4 +473,26 @@ mod tests { "Panic selector is incorrect" ); } + + #[test] + fn test_decode_solidity_revert_reason() { + let revert = Revert::from("test_revert_reason"); + let encoded = revert.encode(); + let decoded = decode_revert_reason(&encoded).unwrap(); + assert_eq!(decoded, String::from("revert: test_revert_reason")); + } + + #[test] + fn test_decode_random_revert_reason() { + let revert_reason = String::from("test_revert_reason"); + let decoded = decode_revert_reason(revert_reason.as_bytes()).unwrap(); + assert_eq!(decoded, String::from("test_revert_reason")); + } + + #[test] + fn test_decode_too_short_revert_reason() { + let revert_reason = String::from(""); + let decoded = decode_revert_reason(revert_reason.as_bytes()); + assert_eq!(decoded, None); + } } diff --git a/crates/sol-types/src/types/mod.rs b/crates/sol-types/src/types/mod.rs index 67cd65a39..b599819ef 100644 --- a/crates/sol-types/src/types/mod.rs +++ b/crates/sol-types/src/types/mod.rs @@ -4,7 +4,7 @@ mod r#enum; pub use r#enum::SolEnum; mod error; -pub use error::{Panic, PanicKind, Revert, SolError}; +pub use error::{Panic, PanicKind, Revert, SolError, decode_revert_reason}; mod event; pub use event::{EventTopic, SolEvent, TopicList}; From 2654823f475ebb9430b942af67195c070c24bcb1 Mon Sep 17 00:00:00 2001 From: alessandromazza Date: Tue, 26 Sep 2023 16:01:07 +0200 Subject: [PATCH 2/8] fmt --- crates/sol-types/src/lib.rs | 6 +++--- crates/sol-types/src/types/error.rs | 10 +++++----- crates/sol-types/src/types/mod.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/sol-types/src/lib.rs b/crates/sol-types/src/lib.rs index 52f66e213..cba098b39 100644 --- a/crates/sol-types/src/lib.rs +++ b/crates/sol-types/src/lib.rs @@ -181,9 +181,9 @@ mod impl_core; mod types; pub use types::{ - data_type as sol_data, ContractError, Encodable, EventTopic, GenericContractError, Panic, - PanicKind, Revert, Selectors, SolCall, SolEnum, SolError, SolEvent, SolInterface, SolStruct, - SolType, TopicList, decode_revert_reason, + data_type as sol_data, decode_revert_reason, ContractError, Encodable, EventTopic, + GenericContractError, Panic, PanicKind, Revert, Selectors, SolCall, SolEnum, SolError, + SolEvent, SolInterface, SolStruct, SolType, TopicList, }; pub mod utils; diff --git a/crates/sol-types/src/types/error.rs b/crates/sol-types/src/types/error.rs index 3d8358f2c..a375d01f2 100644 --- a/crates/sol-types/src/types/error.rs +++ b/crates/sol-types/src/types/error.rs @@ -1,9 +1,9 @@ use crate::{ token::{PackedSeqToken, TokenSeq, WordToken}, - Result, SolType, TokenType, Word, GenericContractError, SolInterface, + GenericContractError, Result, SolInterface, SolType, TokenType, Word, }; use alloc::{string::String, vec::Vec}; -use alloy_primitives::{U256, Selector}; +use alloy_primitives::{Selector, U256}; use core::{borrow::Borrow, fmt}; /// Solidity Error (a tuple with a selector) @@ -408,9 +408,9 @@ impl PanicKind { } } -/// Returns the revert reason from the given output data, if it's an abi encoded String. Returns -/// `None` if the output is not long enough to contain a function selector or the content is not a -/// valid abi encoded String. +/// Returns the revert reason from the given output data, if it's an abi encoded +/// String. Returns `None` if the output is not long enough to contain a +/// function selector or the content is not a valid abi encoded String. /// /// **Note:** it's assumed the `out` buffer starts with the call's signature pub fn decode_revert_reason(out: &[u8]) -> Option { diff --git a/crates/sol-types/src/types/mod.rs b/crates/sol-types/src/types/mod.rs index b599819ef..da6f7ebe8 100644 --- a/crates/sol-types/src/types/mod.rs +++ b/crates/sol-types/src/types/mod.rs @@ -4,7 +4,7 @@ mod r#enum; pub use r#enum::SolEnum; mod error; -pub use error::{Panic, PanicKind, Revert, SolError, decode_revert_reason}; +pub use error::{decode_revert_reason, Panic, PanicKind, Revert, SolError}; mod event; pub use event::{EventTopic, SolEvent, TopicList}; From 130ed395eea988a4ad1b59d1b9112b3f68b3c290 Mon Sep 17 00:00:00 2001 From: alessandromazza Date: Tue, 26 Sep 2023 16:24:12 +0200 Subject: [PATCH 3/8] fix function and use core instead of std library --- crates/sol-types/src/types/error.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/crates/sol-types/src/types/error.rs b/crates/sol-types/src/types/error.rs index a375d01f2..170adaf11 100644 --- a/crates/sol-types/src/types/error.rs +++ b/crates/sol-types/src/types/error.rs @@ -411,21 +411,14 @@ impl PanicKind { /// Returns the revert reason from the given output data, if it's an abi encoded /// String. Returns `None` if the output is not long enough to contain a /// function selector or the content is not a valid abi encoded String. -/// -/// **Note:** it's assumed the `out` buffer starts with the call's signature pub fn decode_revert_reason(out: &[u8]) -> Option { - // Ensure the output data is long enough to contain a function selector. - if out.len() < Selector::len_bytes() { - return None - } - // Try to decode as a generic contract error. if let Ok(error) = GenericContractError::decode(out, true) { return Some(error.to_string()) } // If that fails, try to decode as a regular string. - if let Ok(decoded_string) = std::str::from_utf8(out) { + if let Ok(decoded_string) = core::str::from_utf8(out) { return Some(decoded_string.to_string()) } From 962f3f4727fed7b0bfccf98584120e43ee4ddcf5 Mon Sep 17 00:00:00 2001 From: alessandromazza Date: Tue, 26 Sep 2023 16:25:25 +0200 Subject: [PATCH 4/8] fix doc --- crates/sol-types/src/types/error.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/sol-types/src/types/error.rs b/crates/sol-types/src/types/error.rs index 170adaf11..3412aab58 100644 --- a/crates/sol-types/src/types/error.rs +++ b/crates/sol-types/src/types/error.rs @@ -409,8 +409,7 @@ impl PanicKind { } /// Returns the revert reason from the given output data, if it's an abi encoded -/// String. Returns `None` if the output is not long enough to contain a -/// function selector or the content is not a valid abi encoded String. +/// String. Returns `None` if the content is not a valid abi encoded String. pub fn decode_revert_reason(out: &[u8]) -> Option { // Try to decode as a generic contract error. if let Ok(error) = GenericContractError::decode(out, true) { From 9778f8e7f830a444b4b6ddad8f1e1f94c6f487b3 Mon Sep 17 00:00:00 2001 From: alessandromazza Date: Tue, 26 Sep 2023 16:27:30 +0200 Subject: [PATCH 5/8] better doc --- crates/sol-types/src/types/error.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/sol-types/src/types/error.rs b/crates/sol-types/src/types/error.rs index 3412aab58..79a8a41f2 100644 --- a/crates/sol-types/src/types/error.rs +++ b/crates/sol-types/src/types/error.rs @@ -408,8 +408,9 @@ impl PanicKind { } } -/// Returns the revert reason from the given output data, if it's an abi encoded -/// String. Returns `None` if the content is not a valid abi encoded String. +/// Returns the revert reason from the given output data. Returns `None` if the +/// content is not a valid abi encoded String or a regular utf8 string (for +/// Vyper reverts). pub fn decode_revert_reason(out: &[u8]) -> Option { // Try to decode as a generic contract error. if let Ok(error) = GenericContractError::decode(out, true) { From e43dc191120d145e7749c2e7fef60d7220a6c380 Mon Sep 17 00:00:00 2001 From: alessandromazza Date: Tue, 26 Sep 2023 16:30:44 +0200 Subject: [PATCH 6/8] fix no_std --- crates/sol-types/src/types/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/sol-types/src/types/error.rs b/crates/sol-types/src/types/error.rs index 79a8a41f2..8f0feceb8 100644 --- a/crates/sol-types/src/types/error.rs +++ b/crates/sol-types/src/types/error.rs @@ -2,8 +2,8 @@ use crate::{ token::{PackedSeqToken, TokenSeq, WordToken}, GenericContractError, Result, SolInterface, SolType, TokenType, Word, }; -use alloc::{string::String, vec::Vec}; -use alloy_primitives::{Selector, U256}; +use alloc::{string::{String, ToString}, vec::Vec}; +use alloy_primitives::U256; use core::{borrow::Borrow, fmt}; /// Solidity Error (a tuple with a selector) From b1476c657795f439cdf03dcb504d0bca803b78d9 Mon Sep 17 00:00:00 2001 From: alessandromazza Date: Tue, 26 Sep 2023 16:32:09 +0200 Subject: [PATCH 7/8] fmt --- crates/sol-types/src/types/error.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/sol-types/src/types/error.rs b/crates/sol-types/src/types/error.rs index 8f0feceb8..8a361d73d 100644 --- a/crates/sol-types/src/types/error.rs +++ b/crates/sol-types/src/types/error.rs @@ -2,7 +2,10 @@ use crate::{ token::{PackedSeqToken, TokenSeq, WordToken}, GenericContractError, Result, SolInterface, SolType, TokenType, Word, }; -use alloc::{string::{String, ToString}, vec::Vec}; +use alloc::{ + string::{String, ToString}, + vec::Vec, +}; use alloy_primitives::U256; use core::{borrow::Borrow, fmt}; From d43430dccfdd4822625ca2d07ee07578d09f058c Mon Sep 17 00:00:00 2001 From: alessandromazza Date: Tue, 26 Sep 2023 16:51:38 +0200 Subject: [PATCH 8/8] add non utf8 revert reason test --- crates/sol-types/src/types/error.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/sol-types/src/types/error.rs b/crates/sol-types/src/types/error.rs index 8a361d73d..29e7bd5b9 100644 --- a/crates/sol-types/src/types/error.rs +++ b/crates/sol-types/src/types/error.rs @@ -486,9 +486,9 @@ mod tests { } #[test] - fn test_decode_too_short_revert_reason() { - let revert_reason = String::from(""); - let decoded = decode_revert_reason(revert_reason.as_bytes()); + fn test_decode_non_utf8_revert_reason() { + let revert_reason = [0xFF]; + let decoded = decode_revert_reason(&revert_reason); assert_eq!(decoded, None); } }