Skip to content

Commit

Permalink
fix(sol-macro): correctly determine whether event parameters are hashes
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes committed Sep 10, 2024
1 parent 00076ee commit 6724941
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 31 deletions.
6 changes: 3 additions & 3 deletions crates/sol-macro-expander/src/expand/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub(super) fn expand(cx: &ExpCtxt<'_>, event: &ItemEvent) -> Result<TokenStream>
let name = anon_name((i, p.name.as_ref()));
let ty = expand_type(&p.ty, &cx.crates);

if p.indexed_as_hash() {
if cx.indexed_as_hash(p) {
quote! {
<alloy_sol_types::sol_data::FixedBytes<32> as alloy_sol_types::EventTopic>::encode_topic(&self.#name)
}
Expand Down Expand Up @@ -225,7 +225,7 @@ pub(super) fn expand(cx: &ExpCtxt<'_>, event: &ItemEvent) -> Result<TokenStream>
fn expand_event_topic_type(param: &EventParameter, cx: &ExpCtxt<'_>) -> TokenStream {
let alloy_sol_types = &cx.crates.sol_types;
assert!(param.is_indexed());
if param.is_abi_dynamic() {
if cx.indexed_as_hash(param) {
quote_spanned! {param.ty.span()=> #alloy_sol_types::sol_data::FixedBytes<32> }
} else {
expand_type(&param.ty, &cx.crates)
Expand All @@ -239,7 +239,7 @@ fn expand_event_topic_field(
cx: &ExpCtxt<'_>,
) -> TokenStream {
let name = anon_name((i, name));
let ty = if param.indexed_as_hash() {
let ty = if cx.indexed_as_hash(param) {
let bytes32 = ast::Type::FixedBytes(name.span(), core::num::NonZeroU16::new(32).unwrap());
ty::expand_rust_type(&bytes32, &cx.crates)
} else {
Expand Down
18 changes: 17 additions & 1 deletion crates/sol-macro-expander/src/expand/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,23 @@ impl<'ast> ExpCtxt<'ast> {
}

fn try_custom_type(&self, name: &SolPath) -> Option<&Type> {
self.custom_types.resolve(name, &self.current_namespace)
self.custom_types.resolve(name, &self.current_namespace).inspect(|&ty| {
if ty.is_custom() {
abort!(
ty.span(),
"unresolved custom type in map";
note = name.span() => "name span";
);
}
})
}

fn indexed_as_hash(&self, param: &EventParameter) -> bool {
param.indexed_as_hash(self.custom_is_value_type())
}

fn custom_is_value_type(&self) -> impl Fn(&SolPath) -> bool + '_ {
move |ty| self.custom_type(ty).is_value_type(self.custom_is_value_type())
}

/// Returns the name of the function, adjusted for overloads.
Expand Down
1 change: 1 addition & 0 deletions crates/sol-types/src/types/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub trait SolEvent: Sized {
///
/// For non-anonymous events, this will be the first topic (`topic0`).
/// For anonymous events, this is unused, but is still present.
#[doc(alias = "SELECTOR")]
const SIGNATURE_HASH: FixedBytes<32>;

/// Whether the event is anonymous.
Expand Down
64 changes: 64 additions & 0 deletions crates/sol-types/tests/macros/sol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1084,3 +1084,67 @@ fn regression_nested_namespaced_structs() {
assert_eq!(inner::C::libCNested1Call::SIGNATURE, format!("libCNested1({c_nested1})"));
assert_eq!(inner::C::libCNested2Call::SIGNATURE, format!("libCNested2({c_nested2})"));
}

// https://github.com/alloy-rs/core/issues/734
#[test]
fn event_indexed_udvt() {
use alloy_primitives::aliases::*;

sol! {
type Currency is address;
type PoolId is bytes32;

event Initialize(
PoolId indexed id,
Currency indexed currency0,
Currency indexed currency1,
uint24 fee,
int24 tickSpacing,
address hooks,
uint160 sqrtPriceX96,
int24 tick
);
}

assert_eq!(
Initialize::SIGNATURE,
"Initialize(bytes32,address,address,uint24,int24,address,uint160,int24)",
);
assert_eq!(
Initialize::SIGNATURE_HASH,
b256!("dd466e674ea557f56295e2d0218a125ea4b4f0f6f3307b95f85e6110838d6438"),
);

let _ = Initialize {
id: B256::ZERO,
currency0: Address::ZERO,
currency1: Address::ZERO,
fee: U24::ZERO,
tickSpacing: I24::ZERO,
hooks: Address::ZERO,
sqrtPriceX96: U160::ZERO,
tick: I24::ZERO,
};
}

#[test]
fn event_indexed_elementary_arrays() {
sol! {
event AddrArray(address[1] indexed x);
event AddrDynArray(address[] indexed x);

type MyAddress is address;
event AddrUdvtArray(MyAddress[1] indexed y);
event AddrUdvtDynArray(MyAddress[] indexed y);
}

assert_eq!(AddrArray::SIGNATURE, "AddrArray(address[1])");
let _ = AddrArray { x: B256::ZERO };
assert_eq!(AddrDynArray::SIGNATURE, "AddrDynArray(address[])");
let _ = AddrDynArray { x: B256::ZERO };

assert_eq!(AddrUdvtArray::SIGNATURE, "AddrUdvtArray(address[1])");
let _ = AddrUdvtArray { y: B256::ZERO };
assert_eq!(AddrUdvtDynArray::SIGNATURE, "AddrUdvtDynArray(address[])");
let _ = AddrUdvtDynArray { y: B256::ZERO };
}
18 changes: 6 additions & 12 deletions crates/syn-solidity/src/item/event.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
kw, utils::DebugPunctuated, ParameterList, SolIdent, Spanned, Type, VariableDeclaration,
kw, utils::DebugPunctuated, ParameterList, SolIdent, SolPath, Spanned, Type,
VariableDeclaration,
};
use proc_macro2::Span;
use std::fmt;
Expand Down Expand Up @@ -153,10 +154,6 @@ impl ItemEvent {
self.parameters.iter().filter(|p| p.is_indexed())
}

pub fn dynamic_params(&self) -> impl Iterator<Item = &EventParameter> {
self.parameters.iter().filter(|p| p.is_abi_dynamic())
}

pub fn as_type(&self) -> Type {
let mut ty = Type::Tuple(self.parameters.iter().map(|arg| arg.ty.clone()).collect());
ty.set_span(self.span());
Expand Down Expand Up @@ -252,17 +249,14 @@ impl EventParameter {
self.indexed.is_none()
}

/// Returns true if the event parameter is a dynamically sized type.
pub fn is_abi_dynamic(&self) -> bool {
self.ty.is_abi_dynamic()
}

/// Returns `true` if the event parameter is indexed and dynamically sized.
/// These types are hashed, and then stored in the topics as specified in
/// [the Solidity spec][ref].
///
/// `custom_is_value_type` accounts for custom value types.
///
/// [ref]: https://docs.soliditylang.org/en/latest/abi-spec.html#events
pub fn indexed_as_hash(&self) -> bool {
self.is_indexed() && self.is_abi_dynamic()
pub fn indexed_as_hash(&self, custom_is_value_type: impl Fn(&SolPath) -> bool) -> bool {
self.is_indexed() && !self.ty.is_value_type(custom_is_value_type)
}
}
46 changes: 31 additions & 15 deletions crates/syn-solidity/src/type/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,21 +278,17 @@ impl Type {
Ok(self)
}

/// Returns whether this type is ABI-encoded as a single EVM word (32
/// bytes).
pub const fn is_one_word(&self) -> bool {
matches!(
self,
Self::Bool(_)
| Self::Int(..)
| Self::Uint(..)
| Self::FixedBytes(..)
| Self::Address(..)
| Self::Function(_)
)
/// Returns whether this type is ABI-encoded as a single EVM word (32 bytes).
///
/// This is the same as [`is_value_type`](Self::is_value_type).
#[deprecated = "use `is_value_type` instead"]
pub fn is_one_word(&self, custom_is_value_type: impl Fn(&SolPath) -> bool) -> bool {
self.is_value_type(custom_is_value_type)
}

/// Returns whether this type is dynamic according to ABI rules.
///
/// Note that this does not account for custom types, such as UDVTs.
pub fn is_abi_dynamic(&self) -> bool {
match self {
Self::Bool(_)
Expand All @@ -308,17 +304,37 @@ impl Type {
Self::Tuple(tuple) => tuple.is_abi_dynamic(),

// not applicable
Self::Mapping(_) => false,
Self::Mapping(_) => true,
}
}

/// Returns whether this type is a value type.
///
/// These types' variables are always passed by value.
///
/// `custom_is_value_type` accounts for custom value types.
///
/// See the [Solidity docs](https://docs.soliditylang.org/en/latest/types.html#value-types) for more information.
pub const fn is_value_type(&self) -> bool {
self.is_one_word()
pub fn is_value_type(&self, custom_is_value_type: impl Fn(&SolPath) -> bool) -> bool {
match self {
Self::Custom(custom) => custom_is_value_type(custom),
_ => self.is_value_type_simple(),
}
}

/// Returns whether this type is a simple value type.
///
/// See [`is_value_type`](Self::is_value_type) for more information.
pub fn is_value_type_simple(&self) -> bool {
matches!(
self,
Self::Bool(_)
| Self::Int(..)
| Self::Uint(..)
| Self::FixedBytes(..)
| Self::Address(..)
| Self::Function(_)
)
}

pub const fn is_array(&self) -> bool {
Expand Down

0 comments on commit 6724941

Please sign in to comment.