Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: do not implement SolType for SolStruct generically #275

Merged
merged 2 commits into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/sol-macro/src/expand/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ fn expand_from_into_tuples<P>(name: &Ident, fields: &Parameters<P>) -> TokenStre
}

#[automatically_derived]
#[doc(hidden)]
impl ::alloy_sol_types::Encodable<UnderlyingSolTuple<'_>> for #name {
fn to_tokens(&self) -> <UnderlyingSolTuple<'_> as ::alloy_sol_types::SolType>::TokenType<'_> {
(#(
Expand Down
55 changes: 44 additions & 11 deletions crates/sol-macro/src/expand/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,25 +76,58 @@ pub(super) fn expand(cx: &ExpCtxt<'_>, s: &ItemStruct) -> Result<TokenStream> {
const _: () = {
#convert

#[automatically_derived]
impl ::alloy_sol_types::SolStruct for #name {
type Tuple<'a> = UnderlyingSolTuple<'a>;
type Token<'a> = <Self::Tuple<'a> as ::alloy_sol_types::SolType>::TokenType<'a>;
impl ::alloy_sol_types::Encodable<Self> for #name {
fn to_tokens(&self) -> <Self as ::alloy_sol_types::SolType>::TokenType<'_> {
#tokenize_impl
}
}

const NAME: &'static str = #name_s;
impl ::alloy_sol_types::SolType for #name {
type RustType = Self;
type TokenType<'a> = <UnderlyingSolTuple<'a> as ::alloy_sol_types::SolType>::TokenType<'a>;

fn to_rust<'a>(&self) -> UnderlyingRustTuple<'a> {
self.clone().into()
#[inline]
fn sol_type_name() -> ::alloy_sol_types::private::Cow<'static, str> {
::alloy_sol_types::private::Cow::Borrowed(
<Self as ::alloy_sol_types::SolStruct>::NAME
)
}

fn new<'a>(tuple: UnderlyingRustTuple<'a>) -> Self {
tuple.into()
#[inline]
fn encoded_size(rust: &Self::RustType) -> usize {
// TODO: Avoid cloning
let tuple = <UnderlyingRustTuple<'_> as ::core::convert::From<Self>>::from(rust.clone());
<UnderlyingSolTuple<'_> as ::alloy_sol_types::SolType>::encoded_size(&tuple)
}

fn tokenize<'a>(&'a self) -> Self::Token<'a> {
#tokenize_impl
#[inline]
fn type_check(token: &Self::TokenType<'_>) -> ::alloy_sol_types::Result<()> {
<UnderlyingSolTuple<'_> as ::alloy_sol_types::SolType>::type_check(token)
}

#[inline]
fn detokenize(token: Self::TokenType<'_>) -> Self::RustType {
let tuple = <UnderlyingSolTuple<'_> as ::alloy_sol_types::SolType>::detokenize(token);
<Self as ::core::convert::From<UnderlyingRustTuple<'_>>>::from(tuple)
}

#[inline]
fn eip712_data_word(rust: &Self::RustType) -> ::alloy_sol_types::Word {
<Self as ::alloy_sol_types::SolStruct>::eip712_hash_struct(rust)
}

#[inline]
fn encode_packed_to(rust: &Self::RustType, out: &mut ::alloy_sol_types::private::Vec<u8>) {
// TODO: Avoid cloning
let tuple = <UnderlyingRustTuple<'_> as ::core::convert::From<Self>>::from(rust.clone());
<UnderlyingSolTuple<'_> as ::alloy_sol_types::SolType>::encode_packed_to(&tuple, out)
}
}

#[automatically_derived]
impl ::alloy_sol_types::SolStruct for #name {
const NAME: &'static str = #name_s;

#eip712_encode_type_fns

fn eip712_encode_data(&self) -> Vec<u8> {
Expand Down
3 changes: 2 additions & 1 deletion crates/sol-types/src/coder/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ pub fn encode<'a, T: TokenType<'a>>(token: &T) -> Vec<u8> {
encode_sequence::<(T,)>(unsafe { &*(token as *const T).cast::<(T,)>() })
}

/// Encode a tuple as ABI function params, suitable for passing to a function.
/// ABI-encode a tuple as ABI function params, suitable for passing to a
/// function.
#[inline]
pub fn encode_params<'a, T: TokenSeq<'a>>(token: &T) -> Vec<u8> {
if T::IS_TUPLE {
Expand Down
88 changes: 3 additions & 85 deletions crates/sol-types/src/types/struct.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
//! This module contains the [`SolStruct`] trait, which is used to implement
//! Solidity structs logic, particularly for EIP-712 encoding/decoding.

use super::{Encodable, SolType};
use crate::{token::TokenSeq, Eip712Domain, TokenType, Word};
use super::SolType;
use crate::Eip712Domain;
use alloc::{borrow::Cow, vec::Vec};
use alloy_primitives::{keccak256, B256};

type TupleFor<'a, T> = <T as SolStruct>::Tuple<'a>;
type TupleTokenTypeFor<'a, T> = <TupleFor<'a, T> as SolType>::TokenType<'a>;

/// A Solidity Struct.
///
/// This trait is used to implement ABI and EIP-712 encoding and decoding.
Expand All @@ -31,38 +28,12 @@ type TupleTokenTypeFor<'a, T> = <TupleFor<'a, T> as SolType>::TokenType<'a>;
///
/// [`eip712_encode_type`]: SolStruct::eip712_encode_type
/// [ref]: https://eips.ethereum.org/EIPS/eip-712#definition-of-encodetype
pub trait SolStruct: 'static {
/// The corresponding Tuple type, used for encoding/decoding.
type Tuple<'a>: SolType<TokenType<'a> = Self::Token<'a>>;

/// The corresponding Token type.
type Token<'a>: TokenSeq<'a>;

pub trait SolStruct: SolType<RustType = Self> {
/// The struct name.
///
/// Used in [`eip712_encode_type`][SolType::sol_type_name].
const NAME: &'static str;

// TODO: avoid clones here
/// Convert to the tuple type used for ABI encoding and decoding.
fn to_rust<'a>(&self) -> <Self::Tuple<'a> as SolType>::RustType;

/// Convert from the tuple type used for ABI encoding and decoding.
fn new(tuple: <Self::Tuple<'_> as SolType>::RustType) -> Self;

/// Convert to the token type used for EIP-712 encoding and decoding.
fn tokenize(&self) -> Self::Token<'_>;

/// The size of the struct when encoded, in bytes
#[inline]
fn encoded_size(&self) -> usize {
if let Some(size) = <Self::Tuple<'_> as SolType>::ENCODED_SIZE {
return size
}

self.tokenize().total_words() * Word::len_bytes()
}

/// Returns component EIP-712 types. These types are used to construct
/// the `encodeType` string. These are the types of the struct's fields,
/// and should not include the root type.
Expand Down Expand Up @@ -122,56 +93,3 @@ pub trait SolStruct: 'static {
keccak256(digest_input)
}
}

impl<T: SolStruct> Encodable<T> for T {
#[inline]
fn to_tokens(&self) -> <Self as SolType>::TokenType<'_> {
<Self as SolStruct>::tokenize(self)
}
}

// blanket impl
// TODO: Maybe move this to `sol!`?
impl<T: SolStruct> SolType for T {
type RustType = T;
type TokenType<'a> = TupleTokenTypeFor<'a, T>;

const DYNAMIC: bool = TupleFor::<T>::DYNAMIC;

#[inline]
fn type_check(token: &Self::TokenType<'_>) -> crate::Result<()> {
TupleFor::<T>::type_check(token)
}

#[inline]
fn encoded_size<'a>(rust: &Self::RustType) -> usize {
rust.encoded_size()
}

#[inline]
fn sol_type_name() -> Cow<'static, str> {
Self::NAME.into()
}

#[inline]
fn detokenize(token: Self::TokenType<'_>) -> Self::RustType {
let tuple = TupleFor::<T>::detokenize(token);
T::new(tuple)
}

#[inline]
fn eip712_encode_type() -> Option<Cow<'static, str>> {
Some(<Self as SolStruct>::eip712_encode_type())
}

#[inline]
fn eip712_data_word<'a>(rust: &Self::RustType) -> Word {
rust.eip712_hash_struct()
}

#[inline]
fn encode_packed_to<'a>(rust: &Self::RustType, out: &mut Vec<u8>) {
let tuple = rust.to_rust();
TupleFor::<T>::encode_packed_to(&tuple, out);
}
}
6 changes: 0 additions & 6 deletions crates/sol-types/src/types/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,6 @@ pub trait SolType {
rust.to_tokens()
}

/// The encoded struct type (as EIP-712), if any. None for non-structs.
#[inline]
fn eip712_encode_type() -> Option<Cow<'static, str>> {
None
}

/// Encode this data according to EIP-712 `encodeData` rules, and hash it
/// if necessary.
///
Expand Down
10 changes: 5 additions & 5 deletions crates/sol-types/tests/sol.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use alloy_primitives::{keccak256, Address, B256, U256};
use alloy_sol_types::{eip712_domain, sol, SolCall, SolError, SolType};
use alloy_sol_types::{eip712_domain, sol, SolCall, SolError, SolStruct, SolType};
use serde::Serialize;
use serde_json::Value;

Expand Down Expand Up @@ -432,14 +432,14 @@ fn eip712_encode_type_nesting() {
}
}

assert_eq!(A::eip712_encode_type().unwrap(), "A(uint256 a)");
assert_eq!(B::eip712_encode_type().unwrap(), "B(bytes32 b)");
assert_eq!(A::eip712_encode_type(), "A(uint256 a)");
assert_eq!(B::eip712_encode_type(), "B(bytes32 b)");
assert_eq!(
C::eip712_encode_type().unwrap(),
C::eip712_encode_type(),
"C(A a,B b)A(uint256 a)B(bytes32 b)"
);
assert_eq!(
D::eip712_encode_type().unwrap(),
D::eip712_encode_type(),
"D(C c,A a,B b)A(uint256 a)B(bytes32 b)C(A a,B b)"
);
}
Expand Down
Loading