From 90ac009503b32fd417c7923060c2af2d0ca11681 Mon Sep 17 00:00:00 2001
From: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
Date: Wed, 30 Oct 2024 12:24:58 +0100
Subject: [PATCH] chore(json-abi): clean up utils (#794)
---
crates/json-abi/src/item.rs | 10 +-
crates/json-abi/src/param.rs | 10 +-
crates/json-abi/src/utils.rs | 175 +++++++++++++++--------------------
3 files changed, 85 insertions(+), 110 deletions(-)
diff --git a/crates/json-abi/src/item.rs b/crates/json-abi/src/item.rs
index dc8023642c..89ed2a119f 100644
--- a/crates/json-abi/src/item.rs
+++ b/crates/json-abi/src/item.rs
@@ -90,7 +90,7 @@ abi_items! {
/// A JSON ABI function.
pub struct Function: "function" {
/// The name of the function.
- #[serde(deserialize_with = "validate_identifier")]
+ #[serde(deserialize_with = "validated_identifier")]
pub name: String,
/// The input types of the function. May be empty.
pub inputs: Vec,
@@ -104,7 +104,7 @@ abi_items! {
/// A JSON ABI event.
pub struct Event: "event" {
/// The name of the event.
- #[serde(deserialize_with = "validate_identifier")]
+ #[serde(deserialize_with = "validated_identifier")]
pub name: String,
/// A list of the event's inputs, in order.
pub inputs: Vec,
@@ -117,7 +117,7 @@ abi_items! {
/// A JSON ABI error.
pub struct Error: "error" {
/// The name of the error.
- #[serde(deserialize_with = "validate_identifier")]
+ #[serde(deserialize_with = "validated_identifier")]
pub name: String,
/// A list of the error's components, in order.
pub inputs: Vec,
@@ -125,9 +125,9 @@ abi_items! {
}
#[inline]
-fn validate_identifier<'de, D: Deserializer<'de>>(deserializer: D) -> Result {
+fn validated_identifier<'de, D: Deserializer<'de>>(deserializer: D) -> Result {
let s = String::deserialize(deserializer)?;
- validate_identifier!(&s);
+ validate_identifier(&s)?;
Ok(s)
}
diff --git a/crates/json-abi/src/param.rs b/crates/json-abi/src/param.rs
index 8e03341776..b44e137717 100644
--- a/crates/json-abi/src/param.rs
+++ b/crates/json-abi/src/param.rs
@@ -223,7 +223,7 @@ impl Param {
if self.components.is_empty() {
s.push_str(&self.ty);
} else {
- crate::utils::signature_raw(&self.components, s);
+ crate::utils::params_abi_tuple(&self.components, s);
// checked during deserialization, but might be invalid from a user
if let Some(suffix) = self.ty.strip_prefix("tuple") {
s.push_str(suffix);
@@ -239,7 +239,7 @@ impl Param {
s.push_str(&self.ty);
} else {
s.push_str("tuple");
- crate::utils::full_signature_raw(&self.components, s);
+ crate::utils::params_tuple(&self.components, s);
// checked during deserialization, but might be invalid from a user
if let Some(suffix) = self.ty.strip_prefix("tuple") {
s.push_str(suffix);
@@ -516,7 +516,7 @@ impl EventParam {
if self.components.is_empty() {
s.push_str(&self.ty);
} else {
- crate::utils::signature_raw(&self.components, s);
+ crate::utils::params_abi_tuple(&self.components, s);
// checked during deserialization, but might be invalid from a user
if let Some(suffix) = self.ty.strip_prefix("tuple") {
s.push_str(suffix);
@@ -532,7 +532,7 @@ impl EventParam {
s.push_str(&self.ty);
} else {
s.push_str("tuple");
- crate::utils::full_signature_raw(&self.components, s);
+ crate::utils::params_tuple(&self.components, s);
// checked during deserialization, but might be invalid from a user
if let Some(suffix) = self.ty.strip_prefix("tuple") {
s.push_str(suffix);
@@ -626,7 +626,7 @@ struct BorrowedParamInner<'a> {
impl BorrowedParamInner<'_> {
fn validate_fields(&self) -> Result<(), E> {
- validate_identifier!(self.name);
+ validate_identifier(self.name)?;
// any components means type is "tuple" + maybe brackets, so we can skip
// parsing with TypeSpecifier
diff --git a/crates/json-abi/src/utils.rs b/crates/json-abi/src/utils.rs
index 8c2197b5ca..4688227681 100644
--- a/crates/json-abi/src/utils.rs
+++ b/crates/json-abi/src/utils.rs
@@ -1,74 +1,23 @@
use crate::{EventParam, Param, StateMutability};
-use alloc::string::{String, ToString};
+use alloc::string::String;
use alloy_primitives::Selector;
use core::{fmt::Write, num::NonZeroUsize};
use parser::{utils::ParsedSignature, ParameterSpecifier, TypeSpecifier, TypeStem};
/// Capacity to allocate per [Param].
-const PARAM: usize = 32;
-
-macro_rules! validate_identifier {
- ($name:expr) => {
- if !$name.is_empty() && !parser::is_valid_identifier($name) {
- return Err(serde::de::Error::invalid_value(
- serde::de::Unexpected::Str($name),
- &"a valid Solidity identifier",
- ));
- }
- };
-}
-pub(crate) use validate_identifier;
+const PARAM_CAP: usize = 32;
/// `($($params),*)`
-macro_rules! signature {
- ($inputs:expr, $preimage:expr) => {
- $preimage.push('(');
- for (i, input) in $inputs.iter().enumerate() {
- if i > 0 {
- $preimage.push(',');
- }
- input.selector_type_raw($preimage);
- }
- $preimage.push(')');
- };
-}
-
-macro_rules! event_full_signature {
- ($inputs:expr, $preimage:expr) => {
- $preimage.push('(');
+macro_rules! params_abi_tuple {
+ ($inputs:expr, $s:expr) => {
+ $s.push('(');
for (i, input) in $inputs.iter().enumerate() {
if i > 0 {
- $preimage.push(',');
- $preimage.push(' ');
- }
- input.full_selector_type_raw($preimage);
- if input.indexed {
- $preimage.push_str(" indexed");
- }
- if !input.name.is_empty() {
- $preimage.push(' ');
- $preimage.push_str(&input.name);
- }
- }
- $preimage.push(')');
- };
-}
-
-macro_rules! full_signature {
- ($inputs:expr, $preimage:expr) => {
- $preimage.push('(');
- for (i, input) in $inputs.iter().enumerate() {
- if i > 0 {
- $preimage.push(',');
- $preimage.push(' ');
- }
- input.full_selector_type_raw($preimage);
- if !input.name.is_empty() {
- $preimage.push(' ');
- $preimage.push_str(&input.name);
+ $s.push(',');
}
+ input.selector_type_raw($s);
}
- $preimage.push(')');
+ $s.push(')');
};
}
@@ -76,14 +25,14 @@ macro_rules! full_signature {
pub(crate) fn signature(name: &str, inputs: &[Param], outputs: Option<&[Param]>) -> String {
let parens = 2 + outputs.is_some() as usize * 2;
let n_outputs = outputs.map(<[_]>::len).unwrap_or(0);
- let cap = name.len() + parens + (inputs.len() + n_outputs) * PARAM;
- let mut preimage = String::with_capacity(cap);
- preimage.push_str(name);
- signature_raw(inputs, &mut preimage);
+ let cap = name.len() + parens + (inputs.len() + n_outputs) * PARAM_CAP;
+ let mut sig = String::with_capacity(cap);
+ sig.push_str(name);
+ params_abi_tuple(inputs, &mut sig);
if let Some(outputs) = outputs {
- signature_raw(outputs, &mut preimage);
+ params_abi_tuple(outputs, &mut sig);
}
- preimage
+ sig
}
pub(crate) fn full_signature(
@@ -94,67 +43,83 @@ pub(crate) fn full_signature(
) -> String {
let parens = 2 + outputs.is_some() as usize * 2;
let n_outputs = outputs.map(<[_]>::len).unwrap_or(0);
- let mut state_mutability_str = format!(" {}", state_mutability.as_str().unwrap_or_default());
- if state_mutability_str.trim().is_empty() {
- state_mutability_str = "".to_string();
- }
+ let state_mutability_str = state_mutability.as_str();
let cap = "function ".len()
+ name.len()
+ parens
- + (inputs.len() + n_outputs) * PARAM
- + state_mutability_str.len();
- let mut preimage = String::with_capacity(cap);
-
- preimage.push_str("function ");
- preimage.push_str(name);
- full_signature_raw(inputs, &mut preimage);
- preimage.push_str(&state_mutability_str);
+ + (inputs.len() + n_outputs) * PARAM_CAP
+ + state_mutability_str.map(|s| s.len() + 1).unwrap_or(0);
+ let mut sig = String::with_capacity(cap);
+ sig.push_str("function ");
+ sig.push_str(name);
+ params_tuple(inputs, &mut sig);
+ if let Some(state_mutability_str) = state_mutability_str {
+ sig.push(' ');
+ sig.push_str(state_mutability_str);
+ }
if let Some(outputs) = outputs {
if !outputs.is_empty() {
- preimage.push_str(" returns ");
- full_signature_raw(outputs, &mut preimage);
+ sig.push_str(" returns ");
+ params_tuple(outputs, &mut sig);
}
}
- preimage
+ sig
}
/// `($($params),*)`
-pub(crate) fn signature_raw(params: &[Param], preimage: &mut String) {
- signature!(params, preimage);
+pub(crate) fn params_abi_tuple(params: &[Param], s: &mut String) {
+ params_abi_tuple!(params, s);
}
-pub(crate) fn full_signature_raw(params: &[Param], preimage: &mut String) {
- full_signature!(params, preimage);
+pub(crate) fn params_tuple(params: &[Param], s: &mut String) {
+ s.push('(');
+ for (i, input) in params.iter().enumerate() {
+ if i > 0 {
+ s.push_str(", ");
+ }
+ input.full_selector_type_raw(s);
+ if !input.name.is_empty() {
+ s.push(' ');
+ s.push_str(&input.name);
+ }
+ }
+ s.push(')');
}
/// `$name($($inputs),*)`
pub(crate) fn event_signature(name: &str, inputs: &[EventParam]) -> String {
- let mut preimage = String::with_capacity(name.len() + 2 + inputs.len() * PARAM);
+ let mut preimage = String::with_capacity(name.len() + 2 + inputs.len() * PARAM_CAP);
preimage.push_str(name);
- signature!(inputs, &mut preimage);
+ params_abi_tuple!(inputs, &mut preimage);
preimage
}
/// `$name($($inputs indexed names),*)`
pub(crate) fn event_full_signature(name: &str, inputs: &[EventParam]) -> String {
- let mut preimage =
- String::with_capacity("event ".len() + name.len() + 2 + inputs.len() * PARAM);
- preimage.push_str("event ");
- preimage.push_str(name);
- event_full_signature!(inputs, &mut preimage);
- preimage
+ let mut sig = String::with_capacity("event ".len() + name.len() + 2 + inputs.len() * PARAM_CAP);
+ sig.push_str("event ");
+ sig.push_str(name);
+ sig.push('(');
+ for (i, input) in inputs.iter().enumerate() {
+ if i > 0 {
+ sig.push_str(", ");
+ }
+ input.full_selector_type_raw(&mut sig);
+ if input.indexed {
+ sig.push_str(" indexed");
+ }
+ if !input.name.is_empty() {
+ sig.push(' ');
+ sig.push_str(&input.name);
+ }
+ }
+ sig.push(')');
+ sig
}
/// `keccak256(preimage)[..4]`
pub(crate) fn selector(preimage: &str) -> Selector {
- // SAFETY: splitting an array
- unsafe {
- alloy_primitives::keccak256(preimage.as_bytes())
- .0
- .get_unchecked(..4)
- .try_into()
- .unwrap_unchecked()
- }
+ alloy_primitives::keccak256(preimage.as_bytes())[..4].try_into().unwrap()
}
/// Strips `prefix` from `s` before parsing with `parser`. `prefix` must be followed by whitespace.
@@ -221,6 +186,16 @@ fn ty_string(s: &str, sizes: &[Option]) -> String {
ty
}
+pub(crate) fn validate_identifier(name: &str) -> Result<(), E> {
+ if !name.is_empty() && !parser::is_valid_identifier(name) {
+ return Err(serde::de::Error::invalid_value(
+ serde::de::Unexpected::Str(name),
+ &"a valid Solidity identifier",
+ ));
+ }
+ Ok(())
+}
+
#[cfg(test)]
mod tests {
use super::*;