From e9ff977ae5033322779c9c2cf939a251330c20d8 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 2 May 2023 15:56:54 -0500 Subject: [PATCH] refactor: distinguish SolType from SolDataType --- abi/sol-type-parser/src/lib.rs | 4 +- abi/sol-type-parser/src/struct.rs | 13 +- abi/sol-type-parser/src/type.rs | 64 +-- abi/sol-type-parser/src/udt.rs | 4 +- abi/src/coder/decoder.rs | 76 +-- abi/src/coder/encoder.rs | 143 ++--- abi/src/coder/token.rs | 60 ++- abi/src/eip712.rs | 142 ++--- abi/src/lib.rs | 14 +- abi/src/sol_types/mod.rs | 18 +- abi/src/sol_types/sol_data.rs | 837 +++++++++++++++++++++++++++++ abi/src/sol_types/sol_error.rs | 86 +++ abi/src/sol_types/sol_struct.rs | 43 +- abi/src/sol_types/sol_type.rs | 849 +----------------------------- abi/src/sol_types/sol_udt.rs | 23 +- abi/tests/macros.rs | 2 +- abi/tests/proc.rs | 2 +- abi/tests/proc_no_std.rs | 2 +- dyn-abi/src/eip712/resolver.rs | 5 +- dyn-abi/src/eip712/typed_data.rs | 5 +- dyn-abi/src/type.rs | 18 +- 21 files changed, 1307 insertions(+), 1103 deletions(-) create mode 100644 abi/src/sol_types/sol_data.rs create mode 100644 abi/src/sol_types/sol_error.rs diff --git a/abi/sol-type-parser/src/lib.rs b/abi/sol-type-parser/src/lib.rs index 6692dc9299..d5cf2eb501 100644 --- a/abi/sol-type-parser/src/lib.rs +++ b/abi/sol-type-parser/src/lib.rs @@ -17,7 +17,7 @@ mod udt; use udt::*; enum SolInput { - Type(SolType), + Type(SolDataType), StructDef(SolStructDef), ValueTypeDef(Udt), } @@ -25,7 +25,7 @@ enum SolInput { impl Parse for SolInput { fn parse(input: syn::parse::ParseStream) -> syn::Result { let fork = input.fork(); - if let Ok(sol_ty) = fork.parse::() { + if let Ok(sol_ty) = fork.parse::() { input.advance_to(&fork); return Ok(SolInput::Type(sol_ty)); } diff --git a/abi/sol-type-parser/src/struct.rs b/abi/sol-type-parser/src/struct.rs index f8ff73e9b1..1786f49973 100644 --- a/abi/sol-type-parser/src/struct.rs +++ b/abi/sol-type-parser/src/struct.rs @@ -1,4 +1,4 @@ -use crate::r#type::SolType; +use crate::r#type::SolDataType; use proc_macro2::TokenStream; use quote::{quote, quote_spanned, ToTokens}; use std::fmt; @@ -12,7 +12,7 @@ use syn::{ #[derive(Debug, Clone)] pub struct SolStructField { - ty: SolType, + ty: SolDataType, name: Ident, } @@ -128,7 +128,7 @@ impl SolStructDef { { let mut encoded = String::from(#encoded_type); #( - if let Some(s) = <#props_tys as SolType>::eip712_encode_type() { + if let Some(s) = <#props_tys as SolDataType>::eip712_encode_type() { encoded.push_str(&s); } )* @@ -141,11 +141,11 @@ impl SolStructDef { let encode_data_impl = if self.fields.len() == 1 { let SolStructField { ty, name } = self.fields.first().unwrap(); - quote!(<#ty as SolType>::eip712_data_word(&self.#name).0.to_vec()) + quote!(<#ty as SolDataType>::eip712_data_word(&self.#name).0.to_vec()) } else { quote! { [#( - <#props_tys as SolType>::eip712_data_word(&self.#props).0, + <#props_tys as SolDataType>::eip712_data_word(&self.#props).0, )*].concat() } }; @@ -162,12 +162,13 @@ impl SolStructDef { #[allow(non_snake_case)] const _: () = { - use ::ethers_abi_enc::{SolType, keccak256, no_std_prelude::*}; + use ::ethers_abi_enc::{SolDataType, keccak256, no_std_prelude::*}; #convert impl ::ethers_abi_enc::SolStruct for #name { type Tuple = UnderlyingSolTuple; + type Token = ::TokenType; const NAME: &'static str = stringify!(#name); diff --git a/abi/sol-type-parser/src/type.rs b/abi/sol-type-parser/src/type.rs index e88d994075..ddcbd8fe39 100644 --- a/abi/sol-type-parser/src/type.rs +++ b/abi/sol-type-parser/src/type.rs @@ -51,7 +51,7 @@ impl Parse for ArraySize { pub struct SolTuple { _tup: Option, parenthesized: syn::token::Paren, - inner: Punctuated, + inner: Punctuated, } impl fmt::Debug for SolTuple { @@ -83,7 +83,7 @@ impl Parse for SolTuple { Ok(SolTuple { _tup: input.parse()?, parenthesized: parenthesized!(content in input), - inner: content.parse_terminated(SolType::parse, Token![,])?, + inner: content.parse_terminated(SolDataType::parse, Token![,])?, }) } } @@ -97,9 +97,9 @@ impl ToTokens for SolTuple { } #[derive(Clone)] -pub enum SolType { +pub enum SolDataType { Address, - Array(Box, ArraySize), + Array(Box, ArraySize), Bool, Bytes, FixedBytes(LitInt), @@ -110,7 +110,7 @@ pub enum SolType { Other(Ident), } -impl fmt::Debug for SolType { +impl fmt::Debug for SolDataType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Address => write!(f, "Address"), @@ -130,11 +130,11 @@ impl fmt::Debug for SolType { } } -impl fmt::Display for SolType { +impl fmt::Display for SolDataType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - SolType::Address => write!(f, "address"), - SolType::Array(ty, size) => { + SolDataType::Address => write!(f, "address"), + SolDataType::Array(ty, size) => { write!( f, "{}[{}]", @@ -145,47 +145,49 @@ impl fmt::Display for SolType { .unwrap_or_default() ) } - SolType::Bool => write!(f, "bool"), - SolType::Bytes => write!(f, "bytes"), - SolType::FixedBytes(size) => write!(f, "bytes{}", size.base10_digits()), - SolType::Int(size) => write!(f, "int{}", size.base10_digits()), - SolType::String => write!(f, "string"), - SolType::Uint(size) => write!(f, "uint{}", size.base10_digits()), - SolType::Tuple(inner) => write!(f, "{}", inner), - SolType::Other(name) => write!(f, "{}", name), + SolDataType::Bool => write!(f, "bool"), + SolDataType::Bytes => write!(f, "bytes"), + SolDataType::FixedBytes(size) => write!(f, "bytes{}", size.base10_digits()), + SolDataType::Int(size) => write!(f, "int{}", size.base10_digits()), + SolDataType::String => write!(f, "string"), + SolDataType::Uint(size) => write!(f, "uint{}", size.base10_digits()), + SolDataType::Tuple(inner) => write!(f, "{}", inner), + SolDataType::Other(name) => write!(f, "{}", name), } } } -impl ToTokens for SolType { +impl ToTokens for SolDataType { fn to_tokens(&self, tokens: &mut TokenStream) { let expanded = match self { - SolType::Address => quote! { ::ethers_abi_enc::sol_type::Address }, - SolType::Array(inner, size) => { + SolDataType::Address => quote! { ::ethers_abi_enc::sol_data::Address }, + SolDataType::Array(inner, size) => { if let Some(size) = &size.size { quote! { - ::ethers_abi_enc::sol_type::FixedArray<#inner, #size> + ::ethers_abi_enc::sol_data::FixedArray<#inner, #size> } } else { quote! { - ::ethers_abi_enc::sol_type::Array<#inner> + ::ethers_abi_enc::sol_data::Array<#inner> } } } - SolType::Bool => quote! { ::ethers_abi_enc::sol_type::Bool }, - SolType::Bytes => quote! { ::ethers_abi_enc::sol_type::Bytes }, - SolType::FixedBytes(size) => quote! {::ethers_abi_enc::sol_type::FixedBytes<#size>}, - SolType::Int(size) => quote! { ::ethers_abi_enc::sol_type::Int<#size> }, - SolType::String => quote! { ::ethers_abi_enc::sol_type::String }, - SolType::Uint(size) => quote! { ::ethers_abi_enc::sol_type::Uint<#size> }, - SolType::Tuple(inner) => return inner.to_tokens(tokens), - SolType::Other(ident) => quote! { #ident }, + SolDataType::Bool => quote! { ::ethers_abi_enc::sol_data::Bool }, + SolDataType::Bytes => quote! { ::ethers_abi_enc::sol_data::Bytes }, + SolDataType::FixedBytes(size) => { + quote! {::ethers_abi_enc::sol_data::FixedBytes<#size>} + } + SolDataType::Int(size) => quote! { ::ethers_abi_enc::sol_data::Int<#size> }, + SolDataType::String => quote! { ::ethers_abi_enc::sol_data::String }, + SolDataType::Uint(size) => quote! { ::ethers_abi_enc::sol_data::Uint<#size> }, + SolDataType::Tuple(inner) => return inner.to_tokens(tokens), + SolDataType::Other(ident) => quote! { #ident }, }; tokens.extend(expanded); } } -impl Parse for SolType { +impl Parse for SolDataType { fn parse(input: syn::parse::ParseStream) -> syn::Result { let mut candidate = if input.peek(kw::address) { let _ = input.parse::()?; @@ -247,7 +249,7 @@ impl Parse for SolType { } } -impl SolType { +impl SolDataType { pub fn is_non_primitive(&self) -> bool { matches!(self, Self::Other(_)) } diff --git a/abi/sol-type-parser/src/udt.rs b/abi/sol-type-parser/src/udt.rs index df6c2372cd..6148a62b17 100644 --- a/abi/sol-type-parser/src/udt.rs +++ b/abi/sol-type-parser/src/udt.rs @@ -1,7 +1,7 @@ use quote::{quote, ToTokens}; use syn::parse::Parse; -use crate::r#type::SolType; +use crate::r#type::SolDataType; mod kw { syn::custom_keyword!(is); @@ -12,7 +12,7 @@ pub struct Udt { _type: syn::Token![type], name: syn::Ident, _is: kw::is, - ty: SolType, + ty: SolDataType, _semi: syn::Token![;], } diff --git a/abi/src/coder/decoder.rs b/abi/src/coder/decoder.rs index 3aa83b548a..8071eabd7b 100644 --- a/abi/src/coder/decoder.rs +++ b/abi/src/coder/decoder.rs @@ -310,11 +310,11 @@ mod tests { #[cfg(not(feature = "std"))] use crate::no_std_prelude::*; - use crate::{sol_type, util::pad_u32, SolType}; + use crate::{sol_data, util::pad_u32, SolType}; #[test] fn decode_static_tuple_of_addresses_and_uints() { - type MyTy = (sol_type::Address, sol_type::Address, sol_type::Uint<256>); + type MyTy = (sol_data::Address, sol_data::Address, sol_data::Uint<256>); let encoded = hex!( " @@ -333,7 +333,7 @@ mod tests { #[test] fn decode_dynamic_tuple() { - type MyTy = (sol_type::String, sol_type::String); + type MyTy = (sol_data::String, sol_data::String); let encoded = hex!( " 0000000000000000000000000000000000000000000000000000000000000020 @@ -357,13 +357,13 @@ mod tests { #[test] fn decode_nested_tuple() { type MyTy = ( - sol_type::String, - sol_type::Bool, - sol_type::String, + sol_data::String, + sol_data::Bool, + sol_data::String, ( - sol_type::String, - sol_type::String, - (sol_type::String, sol_type::String), + sol_data::String, + sol_data::String, + (sol_data::String, sol_data::String), ), ); @@ -411,10 +411,10 @@ mod tests { #[test] fn decode_complex_tuple_of_dynamic_and_static_types() { type MyTy = ( - sol_type::Uint<256>, - sol_type::String, - sol_type::Address, - sol_type::Address, + sol_data::Uint<256>, + sol_data::String, + sol_data::Address, + sol_data::Address, ); let encoded = hex!( @@ -441,11 +441,11 @@ mod tests { #[test] fn decode_params_containing_dynamic_tuple() { type MyTy = ( - sol_type::Address, - (sol_type::Bool, sol_type::String, sol_type::String), - sol_type::Address, - sol_type::Address, - sol_type::Bool, + sol_data::Address, + (sol_data::Bool, sol_data::String, sol_data::String), + sol_data::Address, + sol_data::Address, + sol_data::Bool, ); let encoded = hex!( @@ -481,10 +481,10 @@ mod tests { #[test] fn decode_params_containing_static_tuple() { type MyTy = ( - sol_type::Address, - (sol_type::Address, sol_type::Bool, sol_type::Bool), - sol_type::Address, - sol_type::Address, + sol_data::Address, + (sol_data::Address, sol_data::Bool, sol_data::Bool), + sol_data::Address, + sol_data::Address, ); let encoded = hex!( @@ -514,11 +514,11 @@ mod tests { #[test] fn decode_data_with_size_that_is_not_a_multiple_of_32() { type MyTy = ( - sol_type::Uint<256>, - sol_type::String, - sol_type::String, - sol_type::Uint<256>, - sol_type::Uint<256>, + sol_data::Uint<256>, + sol_data::String, + sol_data::String, + sol_data::Uint<256>, + sol_data::Uint<256>, ); let data = ( @@ -553,10 +553,10 @@ mod tests { #[test] fn decode_after_fixed_bytes_with_less_than_32_bytes() { type MyTy = ( - sol_type::Address, - sol_type::FixedBytes<32>, - sol_type::FixedBytes<4>, - sol_type::String, + sol_data::Address, + sol_data::FixedBytes<32>, + sol_data::FixedBytes<4>, + sol_data::String, ); let encoded = hex!( @@ -592,14 +592,14 @@ mod tests { ); assert_eq!( - sol_type::String::decode_single(&encoded, false).unwrap(), + sol_data::String::decode_single(&encoded, false).unwrap(), "不�".to_string() ); } #[test] fn decode_corrupted_dynamic_array() { - type MyTy = sol_type::Array>; + type MyTy = sol_data::Array>; // line 1 at 0x00 = 0: tail offset of array // line 2 at 0x20 = 32: length of array // line 3 at 0x40 = 64: first word @@ -623,15 +623,15 @@ mod tests { 0000000000000000000000000000000000000000000000000000000000054321 " ); - assert!(sol_type::Address::decode_single(&input, false).is_ok()); - assert!(sol_type::Address::decode_single(&input, true).is_err()); - assert!(<(sol_type::Address, sol_type::Address)>::decode_single(&input, true).is_ok()); + assert!(sol_data::Address::decode_single(&input, false).is_ok()); + assert!(sol_data::Address::decode_single(&input, true).is_err()); + assert!(<(sol_data::Address, sol_data::Address)>::decode_single(&input, true).is_ok()); } #[test] fn decode_verify_bytes() { - type MyTy = (sol_type::Address, sol_type::FixedBytes<20>); - type MyTy2 = (sol_type::Address, sol_type::Address); + type MyTy = (sol_data::Address, sol_data::FixedBytes<20>); + type MyTy2 = (sol_data::Address, sol_data::Address); let input = hex!( " diff --git a/abi/src/coder/encoder.rs b/abi/src/coder/encoder.rs index 27134ce90f..53791e8e98 100644 --- a/abi/src/coder/encoder.rs +++ b/abi/src/coder/encoder.rs @@ -194,19 +194,19 @@ mod tests { #[cfg(not(feature = "std"))] use crate::no_std_prelude::*; - use crate::{sol_type, util::pad_u32, SolType}; + use crate::{sol_data, util::pad_u32, SolType}; #[test] fn encode_address() { let address = B160([0x11u8; 20]); let expected = hex!("0000000000000000000000001111111111111111111111111111111111111111"); - let encoded = sol_type::Address::encode_single(address); + let encoded = sol_data::Address::encode_single(address); assert_eq!(encoded, expected); } #[test] fn encode_dynamic_array_of_addresses() { - type MyTy = sol_type::Array; + type MyTy = sol_data::Array; let rust = vec![B160([0x11u8; 20]), B160([0x22u8; 20])]; let encoded = MyTy::encode_single(rust); let expected = hex!( @@ -223,7 +223,7 @@ mod tests { #[test] fn encode_fixed_array_of_addresses() { - type MyTy = sol_type::FixedArray; + type MyTy = sol_data::FixedArray; let addresses = [B160([0x11u8; 20]), B160([0x22u8; 20])]; @@ -242,7 +242,7 @@ mod tests { #[test] fn encode_two_addresses() { - type MyTy = (sol_type::Address, sol_type::Address); + type MyTy = (sol_data::Address, sol_data::Address); let addresses = (B160([0x11u8; 20]), B160([0x22u8; 20])); let encoded = MyTy::encode(addresses); @@ -260,7 +260,7 @@ mod tests { #[test] fn encode_fixed_array_of_dynamic_array_of_addresses() { - type MyTy = sol_type::FixedArray, 2>; + type MyTy = sol_data::FixedArray, 2>; let fixed = [ vec![B160([0x11u8; 20]), B160([0x22u8; 20])], vec![B160([0x33u8; 20]), B160([0x44u8; 20])], @@ -288,8 +288,8 @@ mod tests { #[test] fn encode_dynamic_array_of_fixed_array_of_addresses() { - type TwoAddrs = sol_type::FixedArray; - type MyTy = sol_type::Array; + type TwoAddrs = sol_data::FixedArray; + type MyTy = sol_data::Array; let dynamic = vec![ [B160([0x11u8; 20]), B160([0x22u8; 20])], @@ -316,7 +316,7 @@ mod tests { #[test] fn encode_dynamic_array_of_dynamic_arrays() { - type MyTy = sol_type::Array>; + type MyTy = sol_data::Array>; let dynamic = vec![vec![B160([0x11u8; 20])], vec![B160([0x22u8; 20])]]; @@ -342,7 +342,7 @@ mod tests { #[test] fn encode_dynamic_array_of_dynamic_arrays2() { - type MyTy = sol_type::Array>; + type MyTy = sol_data::Array>; let dynamic = vec![ vec![B160([0x11u8; 20]), B160([0x22u8; 20])], @@ -372,7 +372,8 @@ mod tests { #[test] fn encode_fixed_array_of_fixed_arrays() { - type MyTy = sol_type::FixedArray, 2>; + type MyTy = + sol_data::FixedArray, 2>; let fixed = [ [B160([0x11u8; 20]), B160([0x22u8; 20])], @@ -397,9 +398,13 @@ mod tests { #[test] fn encode_fixed_array_of_static_tuples_followed_by_dynamic_type() { - type Tup = (sol_type::Uint<256>, sol_type::Uint<256>, sol_type::Address); - type Fixed = sol_type::FixedArray; - type MyTy = (Fixed, sol_type::String); + type Tup = ( + sol_data::Uint<256>, + sol_data::Uint<256>, + sol_data::Address, + ); + type Fixed = sol_data::FixedArray; + type MyTy = (Fixed, sol_data::String); let data = ( [ @@ -440,7 +445,7 @@ mod tests { #[test] fn encode_empty_array() { - type MyTy0 = (sol_type::Array,); + type MyTy0 = (sol_data::Array,); let data = (vec![],); @@ -462,8 +467,8 @@ mod tests { assert_eq!(encoded_params.len() + 32, encoded.len()); type MyTy = ( - sol_type::Array, - sol_type::Array, + sol_data::Array, + sol_data::Array, ); let data = (vec![], vec![]); @@ -487,8 +492,8 @@ mod tests { assert_eq!(encoded_params.len() + 32, encoded.len()); type MyTy2 = ( - sol_type::Array>, - sol_type::Array>, + sol_data::Array>, + sol_data::Array>, ); let data = (vec![vec![]], vec![vec![]]); @@ -518,7 +523,7 @@ mod tests { #[test] fn encode_bytes() { - type MyTy = sol_type::Bytes; + type MyTy = sol_data::Bytes; let bytes = vec![0x12, 0x34]; let encoded = MyTy::encode_single(bytes); @@ -535,7 +540,7 @@ mod tests { #[test] fn encode_fixed_bytes() { - let encoded = sol_type::FixedBytes::<2>::encode_single([0x12, 0x34]); + let encoded = sol_data::FixedBytes::<2>::encode_single([0x12, 0x34]); let expected = hex!("1234000000000000000000000000000000000000000000000000000000000000"); assert_eq!(encoded, expected); } @@ -543,7 +548,7 @@ mod tests { #[test] fn encode_string() { let s = "gavofyork".to_string(); - let encoded = sol_type::String::encode_single(s); + let encoded = sol_data::String::encode_single(s); let expected = hex!( " 0000000000000000000000000000000000000000000000000000000000000020 @@ -558,7 +563,7 @@ mod tests { #[test] fn encode_bytes2() { let bytes = hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec(); - let encoded = sol_type::Bytes::encode_single(bytes); + let encoded = sol_data::Bytes::encode_single(bytes); let expected = hex!( " 0000000000000000000000000000000000000000000000000000000000000020 @@ -579,7 +584,7 @@ mod tests { " ) .to_vec(); - let encoded = sol_type::Bytes::encode_single(bytes); + let encoded = sol_data::Bytes::encode_single(bytes); let expected = hex!( " 0000000000000000000000000000000000000000000000000000000000000020 @@ -594,7 +599,7 @@ mod tests { #[test] fn encode_two_bytes() { - type MyTy = (sol_type::Bytes, sol_type::Bytes); + type MyTy = (sol_data::Bytes, sol_data::Bytes); let bytes = ( hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec(), @@ -624,7 +629,7 @@ mod tests { #[test] fn encode_uint() { let uint = 4; - let encoded = sol_type::Uint::<8>::encode_single(uint); + let encoded = sol_data::Uint::<8>::encode_single(uint); let expected = hex!("0000000000000000000000000000000000000000000000000000000000000004"); assert_eq!(encoded, expected); } @@ -632,21 +637,21 @@ mod tests { #[test] fn encode_int() { let int = 4; - let encoded = sol_type::Int::<8>::encode_single(int); + let encoded = sol_data::Int::<8>::encode_single(int); let expected = hex!("0000000000000000000000000000000000000000000000000000000000000004"); assert_eq!(encoded, expected); } #[test] fn encode_bool() { - let encoded = sol_type::Bool::encode_single(true); + let encoded = sol_data::Bool::encode_single(true); let expected = hex!("0000000000000000000000000000000000000000000000000000000000000001"); assert_eq!(encoded, expected); } #[test] fn encode_bool2() { - let encoded = sol_type::Bool::encode_single(false); + let encoded = sol_data::Bool::encode_single(false); let expected = hex!("0000000000000000000000000000000000000000000000000000000000000000"); assert_eq!(encoded, expected); } @@ -654,10 +659,10 @@ mod tests { #[test] fn comprehensive_test() { type MyTy = ( - sol_type::Uint<8>, - sol_type::Bytes, - sol_type::Uint<8>, - sol_type::Bytes, + sol_data::Uint<8>, + sol_data::Bytes, + sol_data::Uint<8>, + sol_data::Bytes, ); let bytes = hex!( @@ -706,12 +711,12 @@ mod tests { #[test] fn comprehensive_test2() { type MyTy = ( - sol_type::Bool, - sol_type::String, - sol_type::Uint<8>, - sol_type::Uint<8>, - sol_type::Uint<8>, - sol_type::Array>, + sol_data::Bool, + sol_data::String, + sol_data::Uint<8>, + sol_data::Uint<8>, + sol_data::Uint<8>, + sol_data::Array>, ); let data = (true, "gavofyork".to_string(), 2, 3, 4, vec![5, 6, 7]); @@ -745,7 +750,7 @@ mod tests { #[test] fn encode_dynamic_array_of_bytes() { - type MyTy = sol_type::Array; + type MyTy = sol_data::Array; let data = vec![hex!( "019c80031b20d5e69c8093a571162299032018d913930d93ab320ae5ea44a4218a274f00d607" ) @@ -771,7 +776,7 @@ mod tests { #[test] fn encode_dynamic_array_of_bytes2() { - type MyTy = sol_type::Array; + type MyTy = sol_data::Array; let data = vec![ hex!("4444444444444444444444444444444444444444444444444444444444444444444444444444") @@ -804,7 +809,7 @@ mod tests { #[test] fn encode_static_tuple_of_addresses() { - type MyTy = (sol_type::Address, sol_type::Address); + type MyTy = (sol_data::Address, sol_data::Address); let data = (B160([0x11u8; 20]), B160([0x22u8; 20])); let encoded = MyTy::encode(data); @@ -823,7 +828,7 @@ mod tests { #[test] fn encode_dynamic_tuple() { - type MyTy = (sol_type::String, sol_type::String); + type MyTy = (sol_data::String, sol_data::String); let data = ("gavofyork".to_string(), "gavofyork".to_string()); let expected = hex!( @@ -849,7 +854,7 @@ mod tests { #[test] fn encode_dynamic_tuple_of_bytes2() { - type MyTy = (sol_type::Bytes, sol_type::Bytes); + type MyTy = (sol_data::Bytes, sol_data::Bytes); let data = ( hex!("4444444444444444444444444444444444444444444444444444444444444444444444444444") @@ -885,10 +890,10 @@ mod tests { #[test] fn encode_complex_tuple() { type MyTy = ( - sol_type::Uint<256>, - sol_type::String, - sol_type::Address, - sol_type::Address, + sol_data::Uint<256>, + sol_data::String, + sol_data::Address, + sol_data::Address, ); let data = ( @@ -922,13 +927,13 @@ mod tests { #[test] fn encode_nested_tuple() { type MyTy = ( - sol_type::String, - sol_type::Bool, - sol_type::String, + sol_data::String, + sol_data::Bool, + sol_data::String, ( - sol_type::String, - sol_type::String, - (sol_type::String, sol_type::String), + sol_data::String, + sol_data::String, + (sol_data::String, sol_data::String), ), ); @@ -983,11 +988,15 @@ mod tests { #[test] fn encode_params_containing_dynamic_tuple() { type MyTy = ( - sol_type::Address, - (sol_type::Bool, sol_type::String, sol_type::String), - sol_type::Address, - sol_type::Address, - sol_type::Bool, + sol_data::Address, + ( + sol_data::Bool, + sol_data::String, + sol_data::String, + ), + sol_data::Address, + sol_data::Address, + sol_data::Bool, ); let data = ( B160([0x22u8; 20]), @@ -1028,10 +1037,14 @@ mod tests { #[test] fn encode_params_containing_static_tuple() { type MyTy = ( - sol_type::Address, - (sol_type::Address, sol_type::Bool, sol_type::Bool), - sol_type::Address, - sol_type::Address, + sol_data::Address, + ( + sol_data::Address, + sol_data::Bool, + sol_data::Bool, + ), + sol_data::Address, + sol_data::Address, ); let data = ( @@ -1064,8 +1077,8 @@ mod tests { #[test] fn encode_dynamic_tuple_with_nested_static_tuples() { type MyTy = ( - ((sol_type::Bool, sol_type::Uint<16>),), - sol_type::Array>, + ((sol_data::Bool, sol_data::Uint<16>),), + sol_data::Array>, ); let data = (((false, 0x777),), vec![0x42, 0x1337]); diff --git a/abi/src/coder/token.rs b/abi/src/coder/token.rs index 85b5a4eecf..eb7fd53eff 100644 --- a/abi/src/coder/token.rs +++ b/abi/src/coder/token.rs @@ -569,6 +569,40 @@ macro_rules! tuple_impls { tuple_impls! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, } +impl TokenType for () { + fn is_dynamic() -> bool { + false + } + + fn decode_from(_dec: &mut Decoder<'_>) -> AbiResult { + Ok(()) + } + + fn head_words(&self) -> usize { + 0 + } + + fn tail_words(&self) -> usize { + 0 + } + + fn head_append(&self, _enc: &mut Encoder) {} + + fn tail_append(&self, _enc: &mut Encoder) {} +} + +impl TokenSeq for () { + fn can_be_params() -> bool { + true + } + + fn encode_sequence(&self, _enc: &mut Encoder) {} + + fn decode_sequence(_dec: &mut Decoder<'_>) -> AbiResult { + Ok(()) + } +} + #[cfg(test)] mod tests { use ethers_primitives::B256; @@ -576,7 +610,7 @@ mod tests { use super::*; #[cfg(not(feature = "std"))] use crate::no_std_prelude::*; - use crate::{sol_type, SolType}; + use crate::{sol_data, SolType}; macro_rules! assert_type_check { ($sol:ty, $token:expr $(,)?) => { @@ -593,36 +627,39 @@ mod tests { #[test] fn test_type_check() { assert_type_check!( - (sol_type::Uint<256>, sol_type::Bool), + (sol_data::Uint<256>, sol_data::Bool), &(WordToken(B256::default()), WordToken(B256::default())), ); // TODO(tests): more like this where we test type check internal logic - assert_not_type_check!(sol_type::Uint<8>, &Word::repeat_byte(0x11).into()); - assert_not_type_check!(sol_type::Bool, &B256::repeat_byte(0x11).into()); - assert_not_type_check!(sol_type::FixedBytes<31>, &B256::repeat_byte(0x11).into()); + assert_not_type_check!(sol_data::Uint<8>, &Word::repeat_byte(0x11).into()); + assert_not_type_check!(sol_data::Bool, &B256::repeat_byte(0x11).into()); + assert_not_type_check!( + sol_data::FixedBytes<31>, + &B256::repeat_byte(0x11).into() + ); assert_type_check!( - (sol_type::Uint<32>, sol_type::Bool), + (sol_data::Uint<32>, sol_data::Bool), &(WordToken(B256::default()), WordToken(B256::default())), ); assert_type_check!( - sol_type::Array, + sol_data::Array, &DynSeqToken(vec![WordToken(B256::default()), WordToken(B256::default()),]), ); assert_type_check!( - sol_type::Array, + sol_data::Array, &DynSeqToken(vec![WordToken(B256::default()), WordToken(B256::default()),]), ); assert_type_check!( - sol_type::Array, + sol_data::Array, &DynSeqToken(vec![WordToken(B256::default()), WordToken(B256::default()),]), ); assert_type_check!( - sol_type::FixedArray, + sol_data::FixedArray, &FixedSeqToken::<_, 2>([ WordToken(B256::default()), WordToken(B256::default()), @@ -630,7 +667,7 @@ mod tests { ); assert_type_check!( - sol_type::FixedArray, + sol_data::FixedArray, &FixedSeqToken::<_, 2>([ WordToken(B256::default()), WordToken(B256::default()), @@ -643,6 +680,7 @@ mod sealed { use super::*; pub trait Sealed {} impl Sealed for WordToken {} + impl Sealed for () {} impl Sealed for FixedSeqToken {} impl Sealed for DynSeqToken {} impl Sealed for PackedSeqToken {} diff --git a/abi/src/eip712.rs b/abi/src/eip712.rs index 93b117dca9..403a226115 100644 --- a/abi/src/eip712.rs +++ b/abi/src/eip712.rs @@ -1,6 +1,6 @@ use crate::{ no_std_prelude::{Cow, String, Vec}, - sol_type, + sol_data, util::keccak256, SolType, }; @@ -130,53 +130,53 @@ impl Eip712Domain { ) { (None, None, None, None, None) => vec![], (None, None, None, None, Some(salt)) => { - <(sol_type::FixedBytes<32>,)>::encode((salt.0,)) + <(sol_data::FixedBytes<32>,)>::encode((salt.0,)) } (None, None, None, Some(verifying_contract), None) => { - <(sol_type::Address,)>::encode((verifying_contract,)) + <(sol_data::Address,)>::encode((verifying_contract,)) } (None, None, None, Some(verifying_contract), Some(salt)) => { - <(sol_type::Address, sol_type::FixedBytes<32>)>::encode(( + <(sol_data::Address, sol_data::FixedBytes<32>)>::encode(( verifying_contract, salt.0, )) } (None, None, Some(chain_id), None, None) => { - <(sol_type::Uint<256>,)>::encode((chain_id,)) + <(sol_data::Uint<256>,)>::encode((chain_id,)) } (None, None, Some(chain_id), None, Some(salt)) => { - <(sol_type::Uint<256>, sol_type::FixedBytes<32>)>::encode((chain_id, salt.0)) + <(sol_data::Uint<256>, sol_data::FixedBytes<32>)>::encode((chain_id, salt.0)) } (None, None, Some(chain_id), Some(verifying_contract), None) => { - <(sol_type::Uint<256>, sol_type::Address)>::encode((chain_id, verifying_contract)) + <(sol_data::Uint<256>, sol_data::Address)>::encode((chain_id, verifying_contract)) } (None, None, Some(chain_id), Some(verifying_contract), Some(salt)) => { <( - sol_type::Uint<256>, - sol_type::Address, - sol_type::FixedBytes<32>, + sol_data::Uint<256>, + sol_data::Address, + sol_data::FixedBytes<32>, )>::encode((chain_id, verifying_contract, salt.0)) } (None, Some(version), None, None, None) => { - <(sol_type::FixedBytes<32>,)>::encode((keccak256(version.as_bytes()).0,)) + <(sol_data::FixedBytes<32>,)>::encode((keccak256(version.as_bytes()).0,)) } (None, Some(version), None, None, Some(salt)) => { - <(sol_type::FixedBytes<32>, sol_type::FixedBytes<32>)>::encode(( + <(sol_data::FixedBytes<32>, sol_data::FixedBytes<32>)>::encode(( keccak256(version.as_bytes()).0, salt.0, )) } (None, Some(version), None, Some(verifying_contract), None) => { - <(sol_type::FixedBytes<32>, sol_type::Address)>::encode(( + <(sol_data::FixedBytes<32>, sol_data::Address)>::encode(( keccak256(version.as_bytes()).0, verifying_contract, )) } (None, Some(version), None, Some(verifying_contract), Some(salt)) => { <( - sol_type::FixedBytes<32>, - sol_type::Address, - sol_type::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Address, + sol_data::FixedBytes<32>, )>::encode(( keccak256(version.as_bytes()).0, verifying_contract, @@ -184,23 +184,23 @@ impl Eip712Domain { )) } (None, Some(version), Some(chain_id), None, None) => { - <(sol_type::FixedBytes<32>, sol_type::Uint<256>)>::encode(( + <(sol_data::FixedBytes<32>, sol_data::Uint<256>)>::encode(( keccak256(version.as_bytes()).0, chain_id, )) } (None, Some(version), Some(chain_id), None, Some(salt)) => { <( - sol_type::FixedBytes<32>, - sol_type::Uint<256>, - sol_type::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Uint<256>, + sol_data::FixedBytes<32>, )>::encode((keccak256(version.as_bytes()).0, chain_id, salt.0)) } (None, Some(version), Some(chain_id), Some(verifying_contract), None) => { <( - sol_type::FixedBytes<32>, - sol_type::Uint<256>, - sol_type::Address, + sol_data::FixedBytes<32>, + sol_data::Uint<256>, + sol_data::Address, )>::encode(( keccak256(version.as_bytes()).0, chain_id, @@ -209,10 +209,10 @@ impl Eip712Domain { } (None, Some(version), Some(chain_id), Some(verifying_contract), Some(salt)) => { <( - sol_type::FixedBytes<32>, - sol_type::Uint<256>, - sol_type::Address, - sol_type::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Uint<256>, + sol_data::Address, + sol_data::FixedBytes<32>, )>::encode(( keccak256(version.as_bytes()).0, chain_id, @@ -221,25 +221,25 @@ impl Eip712Domain { )) } (Some(name), None, None, None, None) => { - <(sol_type::FixedBytes<32>,)>::encode((keccak256(name.as_bytes()).0,)) + <(sol_data::FixedBytes<32>,)>::encode((keccak256(name.as_bytes()).0,)) } (Some(name), None, None, None, Some(salt)) => { - <(sol_type::FixedBytes<32>, sol_type::FixedBytes<32>)>::encode(( + <(sol_data::FixedBytes<32>, sol_data::FixedBytes<32>)>::encode(( keccak256(name.as_bytes()).0, salt.0, )) } (Some(name), None, None, Some(verifying_contract), None) => { - <(sol_type::FixedBytes<32>, sol_type::Address)>::encode(( + <(sol_data::FixedBytes<32>, sol_data::Address)>::encode(( keccak256(name.as_bytes()).0, verifying_contract, )) } (Some(name), None, None, Some(verifying_contract), Some(salt)) => { <( - sol_type::FixedBytes<32>, - sol_type::Address, - sol_type::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Address, + sol_data::FixedBytes<32>, )>::encode(( keccak256(name.as_bytes()).0, verifying_contract, @@ -247,23 +247,23 @@ impl Eip712Domain { )) } (Some(name), None, Some(chain_id), None, None) => { - <(sol_type::FixedBytes<32>, sol_type::Uint<256>)>::encode(( + <(sol_data::FixedBytes<32>, sol_data::Uint<256>)>::encode(( keccak256(name.as_bytes()).0, chain_id, )) } (Some(name), None, Some(chain_id), None, Some(salt)) => { <( - sol_type::FixedBytes<32>, - sol_type::Uint<256>, - sol_type::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Uint<256>, + sol_data::FixedBytes<32>, )>::encode((keccak256(name.as_bytes()).0, chain_id, salt.0)) } (Some(name), None, Some(chain_id), Some(verifying_contract), None) => { <( - sol_type::FixedBytes<32>, - sol_type::Uint<256>, - sol_type::Address, + sol_data::FixedBytes<32>, + sol_data::Uint<256>, + sol_data::Address, )>::encode(( keccak256(name.as_bytes()).0, chain_id, @@ -272,10 +272,10 @@ impl Eip712Domain { } (Some(name), None, Some(chain_id), Some(verifying_contract), Some(salt)) => { <( - sol_type::FixedBytes<32>, - sol_type::Uint<256>, - sol_type::Address, - sol_type::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Uint<256>, + sol_data::Address, + sol_data::FixedBytes<32>, )>::encode(( keccak256(name.as_bytes()).0, chain_id, @@ -284,15 +284,15 @@ impl Eip712Domain { )) } (Some(name), Some(version), None, None, None) => { - <(sol_type::FixedBytes<32>, sol_type::FixedBytes<32>)>::encode(( + <(sol_data::FixedBytes<32>, sol_data::FixedBytes<32>)>::encode(( keccak256(name.as_bytes()).0, keccak256(version.as_bytes()).0, )) } (Some(name), Some(version), None, None, Some(salt)) => <( - sol_type::FixedBytes<32>, - sol_type::FixedBytes<32>, - sol_type::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::FixedBytes<32>, )>::encode(( keccak256(name.as_bytes()).0, keccak256(version.as_bytes()).0, @@ -300,9 +300,9 @@ impl Eip712Domain { )), (Some(name), Some(version), None, Some(verifying_contract), None) => { <( - sol_type::FixedBytes<32>, - sol_type::FixedBytes<32>, - sol_type::Address, + sol_data::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Address, )>::encode(( keccak256(name.as_bytes()).0, keccak256(version.as_bytes()).0, @@ -311,10 +311,10 @@ impl Eip712Domain { } (Some(name), Some(version), None, Some(verifying_contract), Some(salt)) => { <( - sol_type::FixedBytes<32>, - sol_type::FixedBytes<32>, - sol_type::Address, - sol_type::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Address, + sol_data::FixedBytes<32>, )>::encode(( keccak256(name.as_bytes()).0, keccak256(version.as_bytes()).0, @@ -323,9 +323,9 @@ impl Eip712Domain { )) } (Some(name), Some(version), Some(chain_id), None, None) => <( - sol_type::FixedBytes<32>, - sol_type::FixedBytes<32>, - sol_type::Uint<256>, + sol_data::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Uint<256>, )>::encode(( keccak256(name.as_bytes()).0, keccak256(version.as_bytes()).0, @@ -333,10 +333,10 @@ impl Eip712Domain { )), (Some(name), Some(version), Some(chain_id), None, Some(salt)) => { <( - sol_type::FixedBytes<32>, - sol_type::FixedBytes<32>, - sol_type::Uint<256>, - sol_type::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Uint<256>, + sol_data::FixedBytes<32>, )>::encode(( keccak256(name.as_bytes()).0, keccak256(version.as_bytes()).0, @@ -346,10 +346,10 @@ impl Eip712Domain { } (Some(name), Some(version), Some(chain_id), Some(verifying_contract), None) => { <( - sol_type::FixedBytes<32>, - sol_type::FixedBytes<32>, - sol_type::Uint<256>, - sol_type::Address, + sol_data::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Uint<256>, + sol_data::Address, )>::encode(( keccak256(name.as_bytes()).0, keccak256(version.as_bytes()).0, @@ -359,11 +359,11 @@ impl Eip712Domain { } (Some(name), Some(version), Some(chain_id), Some(verifying_contract), Some(salt)) => { <( - sol_type::FixedBytes<32>, - sol_type::FixedBytes<32>, - sol_type::Uint<256>, - sol_type::Address, - sol_type::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::FixedBytes<32>, + sol_data::Uint<256>, + sol_data::Address, + sol_data::FixedBytes<32>, )>::encode(( keccak256(name.as_bytes()).0, keccak256(version.as_bytes()).0, diff --git a/abi/src/lib.rs b/abi/src/lib.rs index c199ee26db..8e0f710bb4 100644 --- a/abi/src/lib.rs +++ b/abi/src/lib.rs @@ -40,7 +40,7 @@ //! [`TokenType`]. //! //! ``` -//! use ethers_abi_enc::sol_type::*; +//! use ethers_abi_enc::{SolType, sol_data::*}; //! # pub fn main() -> ethers_abi_enc::AbiResult<()> { //! // Represent a solidity type in rust //! type MySolType = FixedArray; @@ -59,8 +59,6 @@ //! # } //! ``` //! -//! See the [`SolType`] docs for an implementer's guide. -//! //! ## `sol!` type parsing //! //! The `sol!` proc macro parses complex soltypes from valid solidity. Right now @@ -70,7 +68,7 @@ //! In the future, `sol!` will support macro definitions, functions, and more! //! //! ``` -//! # use ethers_abi_enc::{sol, sol_type, SolType}; +//! # use ethers_abi_enc::{sol, sol_data, SolType}; //! # pub fn main() { //! // outputs a type built that implements `SolType` //! type B32 = sol! {bytes32}; @@ -102,7 +100,7 @@ //! type Abstract = sol! { A[] }; //! //! // Incredible! -//! assert_eq!(Abstract::::sol_type_name(), "address[]"); +//! assert_eq!(Abstract::::sol_type_name(), "address[]"); //! # } //! ``` //! @@ -170,7 +168,7 @@ //! features! //! //! ``` -//! # use ethers_abi_enc::{sol, sol_type, SolType}; +//! # use ethers_abi_enc::{sol, sol_data, SolType}; //! # use ethers_primitives::U256; //! // We also also support solidity value types //! sol! { @@ -182,7 +180,7 @@ //! let mvt = MyValueType::from(U256::from(1)); //! assert_eq!( //! mvt.encode_single(), -//! sol_type::Uint::<256>::encode_single(U256::from(1)) +//! sol_data::Uint::<256>::encode_single(U256::from(1)) //! ); //! # } //! ``` @@ -258,7 +256,7 @@ mod errors; pub use errors::{AbiResult, Error}; mod sol_types; -pub use sol_types::{sol_type, SolStruct, SolType}; +pub use sol_types::{sol_data, SolDataType, SolError, SolStruct, SolType}; mod util; #[doc(hidden)] diff --git a/abi/src/sol_types/mod.rs b/abi/src/sol_types/mod.rs index 0a203395c8..00c2218f33 100644 --- a/abi/src/sol_types/mod.rs +++ b/abi/src/sol_types/mod.rs @@ -1,11 +1,19 @@ -/// A solidity struct trait +/// A solidity error +mod sol_error; +pub use sol_error::SolError; + +/// A solidity type that can be encoded/decoded via ABI +mod sol_type; +pub use sol_type::SolType; + +/// A solidity struct mod sol_struct; pub use sol_struct::SolStruct; -/// Solidity Types -pub mod sol_type; -pub use sol_type::SolType; +/// Solidity Primitives. These are the types that are built in to solidity. +pub mod sol_data; +pub use sol_data::SolDataType; /// Solidity user-defined value types -mod sol_udt; // no export needed as only item is a macro +mod sol_udt; diff --git a/abi/src/sol_types/sol_data.rs b/abi/src/sol_types/sol_data.rs new file mode 100644 index 0000000000..1f44d78f1a --- /dev/null +++ b/abi/src/sol_types/sol_data.rs @@ -0,0 +1,837 @@ +use alloc::borrow::Cow; +use core::marker::PhantomData; +use ethers_primitives::{B160, I256, U256}; + +#[cfg(not(feature = "std"))] +use crate::no_std_prelude::{Borrow, String as RustString, ToOwned, Vec}; +#[cfg(feature = "std")] +use std::{borrow::Borrow, string::String as RustString}; + +use crate::{keccak256, token::*, util, AbiResult, SolType, Word}; + +/// This trait describes types that exist in normal Solidity operation +/// (i.e. NOT events, errors, function calls) +pub trait SolDataType: SolType { + /// The encoded struct type (as EIP-712), if any. None for non-structs + fn eip712_encode_type() -> Option> { + None + } + + /// Encode this data according to EIP-712 `encodeData` rules, and hash it + /// if necessary. + /// + /// Implementer's note: All single-word types are encoded as their word. + /// All multi-word types are encoded as the hash the concatenated data + /// words for each element + /// + /// + fn eip712_data_word>(rust: B) -> Word; + + /// Implemens Solidity's `encodePacked()` function, writing into the given buffer. + fn encode_packed_to>(target: &mut Vec, rust: B); + + /// Implements Solidity's `encodePacked()` function. + fn encode_packed>(rust: B) -> Vec { + let mut res = Vec::new(); + Self::encode_packed_to(&mut res, rust); + res + } +} + +/// Address - `address` +#[derive(Copy, Clone, Debug)] +pub struct Address; + +impl SolType for Address { + type RustType = B160; + type TokenType = WordToken; + + fn sol_type_name() -> Cow<'static, str> { + "address".into() + } + + fn is_dynamic() -> bool { + false + } + + fn detokenize(token: Self::TokenType) -> AbiResult { + let sli = &token.as_slice()[12..]; + Ok(B160::from_slice(sli)) + } + + fn tokenize(rust: B) -> Self::TokenType + where + B: Borrow, + { + WordToken::from(*rust.borrow()) + } + + fn type_check(token: &Self::TokenType) -> AbiResult<()> { + if !util::check_zeroes(&token.inner()[..12]) { + return Err(Self::type_check_fail(token.as_slice())); + } + Ok(()) + } +} + +impl SolDataType for Address { + fn eip712_data_word(rust: B) -> Word + where + B: Borrow, + { + Self::tokenize(rust).inner() + } + + fn encode_packed_to>(target: &mut Vec, rust: B) { + // push the last 20 bytes of the word to the target + target.extend_from_slice(&rust.borrow().as_bytes()[12..]); + } +} + +/// Bytes - `bytes` +#[derive(Copy, Clone, Debug)] +pub struct Bytes; + +impl SolType for Bytes { + type RustType = Vec; + type TokenType = PackedSeqToken; + + fn is_dynamic() -> bool { + true + } + + fn sol_type_name() -> Cow<'static, str> { + "bytes".into() + } + + fn type_check(_token: &Self::TokenType) -> AbiResult<()> { + Ok(()) + } + + fn detokenize(token: Self::TokenType) -> AbiResult { + Ok(token.take_vec()) + } + + fn tokenize(rust: B) -> Self::TokenType + where + B: Borrow, + { + rust.borrow().to_owned().into() + } +} + +impl SolDataType for Bytes { + fn eip712_data_word(rust: B) -> Word + where + B: Borrow, + { + keccak256(Self::encode_packed(rust.borrow())) + } + + fn encode_packed_to>(target: &mut Vec, rust: B) { + // push the buf to the vec + target.extend_from_slice(rust.borrow()); + } +} + +macro_rules! impl_int_sol_type { + ($ity:ty, $bits:literal) => { + impl SolType for Int<$bits> { + type RustType = $ity; + type TokenType = WordToken; + + fn is_dynamic() -> bool { + false + } + + fn sol_type_name() -> Cow<'static, str> { + concat!("int", $bits).into() + } + + fn type_check(_token: &Self::TokenType) -> AbiResult<()> { + Ok(()) + } + + + fn detokenize(token: Self::TokenType) -> AbiResult { + let bytes = (<$ity>::BITS / 8) as usize; + let sli = &token.as_slice()[32 - bytes..]; + Ok(<$ity>::from_be_bytes(sli.try_into().unwrap())) + } + + fn tokenize(rust: B) -> Self::TokenType + where + B: Borrow + { + let rust = rust.borrow(); + let bytes = (<$ity>::BITS / 8) as usize; + let mut word = if *rust < 0 { + // account for negative + Word::repeat_byte(0xff) + } else { + Word::default() + }; + let slice = rust.to_be_bytes(); + word[32 - bytes..].copy_from_slice(&slice); + word.into() + } + } + + impl SolDataType for Int<$bits> { + fn eip712_data_word(rust: B) -> Word + where + B: Borrow + { + Self::tokenize(rust).inner().into() + } + + fn encode_packed_to(target: &mut Vec, rust: B) + where + B: Borrow + { + let rust = rust.borrow(); + if rust.is_negative(){ + let bytes = rust.to_be_bytes(); + target.extend(bytes); + } else { + Uint::<$bits>::encode_packed_to(target, *rust as as SolType>::RustType); + } + } + } + }; + + ($bits:literal) => { + impl SolType for Int<$bits> { + type RustType = I256; + type TokenType = WordToken; + + fn is_dynamic() -> bool { + false + } + + fn sol_type_name() -> Cow<'static, str> { + concat!("int", $bits).into() + } + + fn type_check(_token: &Self::TokenType) -> AbiResult<()> { + Ok(()) + } + + fn detokenize(token: Self::TokenType) -> AbiResult { + Ok(I256::from_be_bytes::<32>(token.into())) + } + + fn tokenize(rust: B) -> Self::TokenType where B: Borrow{ + rust.borrow().to_be_bytes().into() + } + } + impl SolDataType for Int<$bits> { + fn eip712_data_word(rust: B) -> Word + where + B: Borrow + { + Self::tokenize(rust).inner().into() + } + + fn encode_packed_to(target: &mut Vec, rust: B) where B: Borrow{ + let rust = rust.borrow(); + if rust.is_negative(){ + let bytes = rust.to_be_bytes(); + target.extend(bytes); + } else { + Uint::<$bits>::encode_packed_to( + target, + rust.into_raw(), + ) + } + } + } + }; + + ($($bits:literal,)+) => { + $( + impl_int_sol_type!($bits); + )+ + }; +} + +/// Int - `intX` +#[derive(Copy, Clone, Debug)] +pub struct Int; +impl_int_sol_type!(i8, 8); +impl_int_sol_type!(i16, 16); +impl_int_sol_type!(i32, 24); +impl_int_sol_type!(i32, 32); +impl_int_sol_type!(i64, 40); +impl_int_sol_type!(i64, 48); +impl_int_sol_type!(i64, 56); +impl_int_sol_type!(i64, 64); +impl_int_sol_type!( + 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, + 232, 240, 248, 256, +); + +macro_rules! impl_uint_sol_type { + ($uty:ty, $bits:literal) => { + impl SolType for Uint<$bits> { + type RustType = $uty; + type TokenType = WordToken; + + fn is_dynamic() -> bool { + false + } + + fn sol_type_name() -> Cow<'static, str> { + concat!("uint", $bits).into() + } + + fn type_check(token: &Self::TokenType) -> AbiResult<()> { + let bytes = (<$uty>::BITS / 8) as usize; + let sli = &token.as_slice()[..32 - bytes]; + if !util::check_zeroes(sli) { + return Err(Self::type_check_fail(token.as_slice())); + } + Ok(()) + } + + fn detokenize(token: Self::TokenType) -> AbiResult { + let bytes = (<$uty>::BITS / 8) as usize; + let sli = &token.as_slice()[32 - bytes..]; + Ok(<$uty>::from_be_bytes(sli.try_into().unwrap())) + } + + fn tokenize(rust: B) -> Self::TokenType where B: Borrow{ + let bytes = (<$uty>::BITS / 8) as usize; + let mut word = Word::default(); + let slice = rust.borrow().to_be_bytes(); + word[32 - bytes..].copy_from_slice(&slice); + word.into() + } + + } + impl SolDataType for Uint<$bits> { + fn eip712_data_word(rust: B) -> Word + where + B: Borrow + { + Self::tokenize(rust).inner().into() + } + + fn encode_packed_to(target: &mut Vec, rust: B) where B: Borrow{ + // encode the rust to be bytes, strip leading zeroes, then push to the target + let bytes = rust.borrow().to_be_bytes(); + target.extend(bytes); + } + } + }; + + ($bits:literal) => { + impl SolType for Uint<$bits> { + type RustType = U256; + type TokenType = WordToken; + + fn is_dynamic() -> bool { + false + } + + fn sol_type_name() -> Cow<'static, str> { + concat!("uint", $bits).into() + } + + fn type_check(token: &Self::TokenType) -> AbiResult<()> { + let bytes = $bits / 8 as usize; + let sli = &token.as_slice()[..32 - bytes]; + if !util::check_zeroes(sli) { + return Err(Self::type_check_fail(token.as_slice())); + } + Ok(()) + } + + fn detokenize(token: Self::TokenType) -> AbiResult { + Ok(U256::from_be_bytes::<32>(*token.inner())) + } + + fn tokenize(rust: B) -> Self::TokenType where B: Borrow{ + (*rust.borrow()).into() + } + } + impl SolDataType for Uint<$bits> { + fn eip712_data_word(rust: B) -> Word + where + B: Borrow + { + Self::tokenize(rust).inner().into() + } + + fn encode_packed_to(target: &mut Vec, rust: B) where B: Borrow{ + // encode the rust to be bytes, strip leading zeroes, then push to the target + let bytes: [u8; $bits / 8] = rust.borrow().to_be_bytes(); + target.extend(bytes); + } + } + }; + + ($($bits:literal,)+) => { + $( + impl_uint_sol_type!($bits); + )+ + } +} + +/// Uint - `uintX` +#[derive(Copy, Clone, Debug)] +pub struct Uint; + +impl_uint_sol_type!(u8, 8); +impl_uint_sol_type!(u16, 16); +impl_uint_sol_type!(u32, 24); +impl_uint_sol_type!(u32, 32); +impl_uint_sol_type!(u64, 40); +impl_uint_sol_type!(u64, 48); +impl_uint_sol_type!(u64, 56); +impl_uint_sol_type!(u64, 64); +impl_uint_sol_type!( + 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, + 232, 240, 248, 256, +); + +/// Bool - `bool` +#[derive(Copy, Clone, Debug)] +pub struct Bool; + +impl SolType for Bool { + type RustType = bool; + type TokenType = WordToken; + + fn is_dynamic() -> bool { + false + } + + fn sol_type_name() -> Cow<'static, str> { + "bool".into() + } + + fn type_check(token: &Self::TokenType) -> AbiResult<()> { + if !util::check_bool(token.inner()) { + return Err(Self::type_check_fail(token.as_slice())); + } + Ok(()) + } + + fn detokenize(token: Self::TokenType) -> AbiResult { + Ok(token.inner() != Word::repeat_byte(0)) + } + + fn tokenize(rust: B) -> Self::TokenType + where + B: Borrow, + { + let mut word = Word::default(); + word[31..32].copy_from_slice(&[*rust.borrow() as u8]); + word.into() + } +} + +impl SolDataType for Bool { + fn eip712_data_word(rust: B) -> Word + where + B: Borrow, + { + Self::tokenize(rust).inner() + } + + fn encode_packed_to(target: &mut Vec, rust: B) + where + B: Borrow, + { + // write the bool as a u8 + target.push(*rust.borrow() as u8); + } +} + +/// Array - `T[]` +#[derive(Copy, Clone, Debug)] +pub struct Array(PhantomData); + +impl SolType for Array +where + T: SolType, +{ + type RustType = Vec; + type TokenType = DynSeqToken; + + fn is_dynamic() -> bool { + true + } + + fn sol_type_name() -> Cow<'static, str> { + format!("{}[]", T::sol_type_name()).into() + } + + fn type_check(token: &Self::TokenType) -> AbiResult<()> { + for token in token.as_slice() { + T::type_check(token)?; + } + Ok(()) + } + + fn detokenize(token: Self::TokenType) -> AbiResult { + token.take_vec().into_iter().map(T::detokenize).collect() + } + + fn tokenize(rust: B) -> Self::TokenType + where + B: Borrow, + { + rust.borrow() + .iter() + .map(|r| T::tokenize(r)) + .collect::>() + .into() + } +} + +impl SolDataType for Array +where + T: SolDataType, +{ + fn eip712_data_word(rust: B) -> Word + where + B: Borrow, + { + let mut encoded = Vec::new(); + for item in rust.borrow() { + encoded.extend(T::eip712_data_word(item).as_slice()); + } + keccak256(encoded) + } + + fn encode_packed_to(target: &mut Vec, rust: B) + where + B: Borrow, + { + for item in rust.borrow() { + T::encode_packed_to(target, item); + } + } +} + +/// String - `string` +#[derive(Copy, Clone, Debug)] +pub struct String; + +impl SolType for String { + type RustType = RustString; + type TokenType = PackedSeqToken; + + fn is_dynamic() -> bool { + true + } + + fn sol_type_name() -> Cow<'static, str> { + "string".into() + } + + fn type_check(token: &Self::TokenType) -> AbiResult<()> { + if core::str::from_utf8(token.as_slice()).is_err() { + return Err(Self::type_check_fail(token.as_slice())); + } + Ok(()) + } + + fn detokenize(token: Self::TokenType) -> AbiResult { + // NOTE: We're decoding strings using lossy UTF-8 decoding to + // prevent invalid strings written into contracts by either users or + // Solidity bugs from causing graph-node to fail decoding event + // data. + Ok(RustString::from_utf8_lossy(&Bytes::detokenize(token)?).into_owned()) + } + + fn tokenize(rust: B) -> Self::TokenType + where + B: Borrow, + { + rust.borrow().as_bytes().to_vec().into() + } +} + +impl SolDataType for String { + fn eip712_data_word(rust: B) -> Word + where + B: Borrow, + { + keccak256(Self::encode_packed(rust.borrow())) + } + + fn encode_packed_to(target: &mut Vec, rust: B) + where + B: Borrow, + { + target.extend(rust.borrow().as_bytes()); + } +} + +macro_rules! impl_fixed_bytes_sol_type { + ($bytes:literal) => { + impl SolType for FixedBytes<$bytes> { + type RustType = [u8; $bytes]; + type TokenType = WordToken; + + fn is_dynamic() -> bool { + false + } + + fn sol_type_name() -> Cow<'static, str> { + concat!("bytes", $bytes).into() + } + + fn type_check(token: &Self::TokenType) -> AbiResult<()> { + if !util::check_fixed_bytes(token.inner(), $bytes) { + return Err(Self::type_check_fail(token.as_slice())); + } + Ok(()) + } + + fn detokenize(token: Self::TokenType) -> AbiResult { + let word = token.as_slice(); + let mut res = Self::RustType::default(); + res[..$bytes].copy_from_slice(&word[..$bytes]); + Ok(res) + } + + fn tokenize(rust: B) -> Self::TokenType where B: Borrow{ + let mut word = Word::default(); + word[..$bytes].copy_from_slice(&rust.borrow()[..]); + word.into() + } + } + + impl SolDataType for FixedBytes<$bytes> { + fn eip712_data_word(rust: B) -> Word where B: Borrow { + Self::tokenize(rust).inner() + } + fn encode_packed_to(target: &mut Vec, rust: B) where B: Borrow { + // write only the first n bytes + target.extend_from_slice(&rust.borrow()[..$bytes]); + } + } + }; + + ($($bytes:literal,)+) => { + $(impl_fixed_bytes_sol_type!($bytes);)+ + }; +} + +/// FixedBytes - `bytesX` +#[derive(Copy, Clone, Debug)] +pub struct FixedBytes; +impl_fixed_bytes_sol_type!( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, +); + +/// FixedArray - `T[M]` +#[derive(Copy, Clone, Debug)] +pub struct FixedArray(PhantomData); + +impl SolType for FixedArray +where + T: SolType, +{ + type RustType = [T::RustType; N]; + type TokenType = FixedSeqToken; + + fn is_dynamic() -> bool { + T::is_dynamic() + } + + fn sol_type_name() -> Cow<'static, str> { + format!("{}[{}]", T::sol_type_name(), N).into() + } + + fn type_check(token: &Self::TokenType) -> AbiResult<()> { + for token in token.as_array().iter() { + T::type_check(token)?; + } + Ok(()) + } + + fn detokenize(token: Self::TokenType) -> AbiResult { + let res = token + .take_array() + .into_iter() + .map(|t| T::detokenize(t)) + .collect::>>()? + .try_into(); + match res { + Ok(tokens) => Ok(tokens), + Err(_) => panic!("input is exact len"), + } + } + + fn tokenize(rust: B) -> Self::TokenType + where + B: Borrow, + { + match rust + .borrow() + .iter() + .map(|r| T::tokenize(r)) + .collect::>() + .try_into() + { + Ok(tokens) => tokens, + Err(_) => unreachable!(), + } + } +} + +impl SolDataType for FixedArray +where + T: SolDataType, +{ + fn eip712_data_word(rust: B) -> Word + where + B: Borrow, + { + let rust = rust.borrow(); + let encoded = rust + .iter() + .flat_map(|element| T::eip712_data_word(element).to_fixed_bytes()) + .collect::>(); + keccak256(encoded) + } + + fn encode_packed_to(target: &mut Vec, rust: B) + where + B: Borrow, + { + for item in rust.borrow() { + T::encode_packed_to(target, item); + } + } +} + +macro_rules! tuple_impls { + () => {}; + + (@peel $_:ident, $($other:ident,)*) => { tuple_impls! { $($other,)* } }; + + // compile time `join(",")` format string + (@fmt $other:ident) => { ",{}" }; + (@fmt $first:ident, $($other:ident,)*) => { + concat!( + "{}", + $(tuple_impls! { @fmt $other }),* + ) + }; + + ($($ty:ident,)+) => { + #[allow(non_snake_case)] + impl<$($ty: SolType,)+> SolType for ($($ty,)+) { + type RustType = ($( $ty::RustType, )+); + type TokenType = ($( $ty::TokenType, )+); + + fn is_dynamic() -> bool { + $( <$ty as SolType>::is_dynamic() )||+ + } + + fn sol_type_name() -> Cow<'static, str> { + format!( + concat!( + "tuple(", + tuple_impls! { @fmt $($ty,)+ }, + ")", + ), + $(<$ty as SolType>::sol_type_name(),)+ + ).into() + } + + fn type_check(token: &Self::TokenType) -> AbiResult<()> { + let ($(ref $ty,)+) = *token; + $( + <$ty as SolType>::type_check($ty)?; + )+ + Ok(()) + } + + fn detokenize(token: Self::TokenType) -> AbiResult { + let ($($ty,)+) = token; + Ok(($( + <$ty as SolType>::detokenize($ty)?, + )+)) + } + + fn tokenize>(rust: B_) -> Self::TokenType { + let ($(ref $ty,)+) = *rust.borrow(); + ($( + <$ty as SolType>::tokenize($ty), + )+) + } + } + #[allow(non_snake_case)] + impl<$($ty: SolDataType,)+> SolDataType for ($($ty,)+) { + fn eip712_data_word>(rust: B_) -> Word { + let ($(ref $ty,)+) = *rust.borrow(); + let encoding: Vec = [$( + <$ty as SolDataType>::eip712_data_word($ty).0, + )+].concat(); + keccak256(&encoding).into() + } + + fn encode_packed_to>(target: &mut Vec, rust: B_) { + let ($(ref $ty,)+) = *rust.borrow(); + // TODO: Reserve + $( + <$ty as SolDataType>::encode_packed_to(target, $ty); + )+ + } + } + + tuple_impls! { @peel $($ty,)+ } + }; +} + +tuple_impls! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, } + +impl SolType for () { + type RustType = (); + type TokenType = (); + + fn is_dynamic() -> bool { + false + } + + fn sol_type_name() -> Cow<'static, str> { + "tuple()".into() + } + + fn type_check(_token: &Self::TokenType) -> AbiResult<()> { + Err(crate::Error::type_check_fail("", "tuple()")) + } + + fn detokenize(_token: Self::TokenType) -> AbiResult { + Err(crate::Error::type_check_fail("", "tuple()")) + } + + fn tokenize(_rust: B) -> Self::TokenType + where + B: Borrow, + { + } +} + +impl SolDataType for () { + fn eip712_data_word(_rust: B) -> Word + where + B: Borrow, + { + Word::zero() + } + + fn encode_packed_to(_target: &mut Vec, _rust: B) + where + B: Borrow, + { + } +} diff --git a/abi/src/sol_types/sol_error.rs b/abi/src/sol_types/sol_error.rs new file mode 100644 index 0000000000..7f144cf901 --- /dev/null +++ b/abi/src/sol_types/sol_error.rs @@ -0,0 +1,86 @@ +use crate::{no_std_prelude::*, token::TokenSeq, SolDataType}; + +use super::SolType; + +/// Solidity Error (a tuple with a selector) +/// +/// ### Implementer's Guide +/// +/// We do not recommend implementing this trait directly. Instead, we recommend +/// using the [`crate::sol`] proc macro to parse a solidity structdef. +pub trait SolError: Sized { + /// The corresponding Token type + type Token: TokenSeq; + /// The underlying tuple type which represents the error's members. + /// If the error is empty, this will be the unit type `()` + type Tuple: SolDataType; + + /// The error selector + const SELECTOR: [u8; 4]; + + /// The error name + const NAME: &'static str; + + /// The error fields + const FIELDS: &'static [&'static str]; + + /// Convert to the tuple type used for ABI encoding/decoding + fn to_rust(&self) -> ::RustType; + + /// Convert from the tuple type used for ABI encoding/decoding + fn from_rust(tuple: ::RustType) -> Self + where + Self: Sized; + + /// Get the error selector + fn selector() -> [u8; 4] { + Self::SELECTOR + } + + /// Get the error name + fn name() -> &'static str { + Self::NAME + } + + /// Get the error fields + fn fields() -> &'static [&'static str] { + Self::FIELDS + } + + /// Decode an error contents from an ABI-encoded byte slice WITHOUT its + /// selector + fn decode_raw(data: &[u8], validate: bool) -> crate::AbiResult { + let tuple = ::decode(data, validate)?; + Ok(Self::from_rust(tuple)) + } + + /// Decode an error from an ABI-encoded byte slice with its selector + fn decode(data: &[u8], validate: bool) -> crate::AbiResult + where + Self: Sized, + { + if data.len() < 4 { + return Err(crate::Error::type_check_fail( + hex::encode(data), + Self::name(), + )); + } + let data = data + .strip_prefix(&Self::SELECTOR) + .ok_or_else(|| crate::Error::type_check_fail(hex::encode(&data[..4]), Self::name()))?; + Self::decode_raw(data, validate) + } + + /// Encode the error contents to the provided buffer WITHOUT the error selector + fn encode_raw(&self, out: &mut Vec) { + out.extend(::encode(self.to_rust())); + } + + /// Encode an error to an ABI-encoded byte vector + fn encode_with_selector(&self) -> Vec { + let mut out = Vec::new(); + out.extend(&Self::SELECTOR); + self.encode_raw(&mut out); + out + } +} diff --git a/abi/src/sol_types/sol_struct.rs b/abi/src/sol_types/sol_struct.rs index bcfca5ad72..020959c4c6 100644 --- a/abi/src/sol_types/sol_struct.rs +++ b/abi/src/sol_types/sol_struct.rs @@ -3,10 +3,13 @@ use ethers_primitives::B256; -use crate::{util::keccak256, SolType, Word}; +use crate::token::TokenSeq; +use crate::{util::keccak256, SolDataType, Word}; use crate::{no_std_prelude::*, Eip712Domain}; +use super::SolType; + type TupleFor = ::Tuple; type TupleTokenTypeFor = as SolType>::TokenType; @@ -16,6 +19,11 @@ type TupleTokenTypeFor = as SolType>::TokenType; /// recommend implementing this via the [`crate::sol`] proc macro. Or by /// deriving. /// +/// # Implementer's Guide +/// +/// We do not recommend implementing this trait directly. Instead, we recommend +/// using the [`crate::sol`] proc macro to parse a solidity structdef. +/// /// # Note /// /// Special attention should be payed to `encode_type` for complex solidity @@ -24,7 +32,9 @@ type TupleTokenTypeFor = as SolType>::TokenType; /// See: pub trait SolStruct { /// The corresponding Tuple type, used for encoding/decoding - type Tuple: SolType; + type Tuple: SolDataType; + /// The corresponding Token type + type Token: TokenSeq; /// The struct name const NAME: &'static str; @@ -114,10 +124,6 @@ where true } - fn eip712_encode_type() -> Option> { - Some(Self::encode_type()) - } - fn type_check(token: &Self::TokenType) -> crate::AbiResult<()> { TupleFor::::type_check(token) } @@ -126,11 +132,9 @@ where Self::NAME.into() } - fn eip712_data_word(rust: B) -> Word - where - B: Borrow, - { - keccak256(SolStruct::hash_struct(rust.borrow())) + fn detokenize(token: Self::TokenType) -> crate::AbiResult { + let tuple = TupleFor::::detokenize(token)?; + Ok(T::from_rust(tuple)) } fn tokenize(rust: Borrower) -> Self::TokenType @@ -140,10 +144,21 @@ where let tuple = rust.borrow().to_rust(); TupleFor::::tokenize(tuple) } +} - fn detokenize(token: Self::TokenType) -> crate::AbiResult { - let tuple = TupleFor::::detokenize(token)?; - Ok(T::from_rust(tuple)) +impl SolDataType for T +where + T: SolStruct, +{ + fn eip712_encode_type() -> Option> { + Some(Self::encode_type()) + } + + fn eip712_data_word(rust: B) -> Word + where + B: Borrow, + { + keccak256(SolStruct::hash_struct(rust.borrow())) } fn encode_packed_to(target: &mut Vec, rust: Borrower) diff --git a/abi/src/sol_types/sol_type.rs b/abi/src/sol_types/sol_type.rs index 857d05e809..30814bdfe2 100644 --- a/abi/src/sol_types/sol_type.rs +++ b/abi/src/sol_types/sol_type.rs @@ -1,15 +1,4 @@ -use alloc::borrow::Cow; -use core::marker::PhantomData; -use ethers_primitives::{B160, I256, U256}; - -#[cfg(not(feature = "std"))] -use crate::no_std_prelude::{Borrow, String as RustString, ToOwned, Vec}; -#[cfg(feature = "std")] -use std::{borrow::Borrow, string::String as RustString}; - -use crate::{ - decode, decode_params, decode_single, keccak256, token::*, util, AbiResult, Error, Word, -}; +use crate::{no_std_prelude::*, token::TokenSeq, AbiResult, TokenType}; /// A Solidity Type, for ABI enc/decoding /// @@ -20,7 +9,7 @@ use crate::{ /// Future work will add derive for this trait :) /// /// ``` -/// use ethers_abi_enc::sol_type::*; +/// use ethers_abi_enc::{SolType, sol_data::*}; /// /// // uint256[] /// type DynUint256Array = Array>; @@ -39,14 +28,16 @@ use crate::{ /// /// ### Implementer's Guide /// -/// You may want to implement this on your own struct, for example, to encode a -/// named solidity struct. +/// We do not recommend implementing this trait directly. Instead, we recommend +/// using the [`crate::sol`] proc macro to parse a solidity structdef. /// -/// Overall, implementing this trait is straightforward. +/// You may want to implement this on your own struct, for example, to encode a +/// named solidity struct. Overall, implementing this trait is straightforward, +/// because we can delegate to an underlying combination of primitive types. /// /// ``` -/// # use ethers_abi_enc::{AbiResult, Word, no_std_prelude::Borrow}; -/// # use ethers_abi_enc::sol_type::*; +/// # use ethers_abi_enc::{AbiResult, SolType}; +/// # use ethers_abi_enc::sol_data::*; /// # use ethers_primitives::U256; /// /// // This is the solidity type: @@ -98,20 +89,6 @@ use crate::{ /// UnderlyingTuple::type_check(token) /// } /// -/// // This function defines the EIP-712 encoding of the type. This is -/// // used to encode types for EIP-712 typed data signing. For value types -/// // it is equal to the ABI encoding. For compound types, it is the -/// // keccak256 hash of the encoding of the components. -/// // -/// // Our implementation is easy, we just delegate :) -/// fn eip712_data_word(rust: B) -> Word -/// where -/// B: Borrow -/// { -/// let rust = rust.borrow(); -/// UnderlyingTuple::eip712_data_word((rust.a, rust.b)) -/// } -/// /// // Convert from the token to the rust type. We cheat here again by /// // delegating. /// fn detokenize(token: Self::TokenType) -> AbiResult { @@ -128,39 +105,12 @@ use crate::{ /// let MyRustStruct { a, b } = *rust.borrow(); /// UnderlyingTuple::tokenize((a, b)) /// } -/// -/// // Implement packed encoding -/// fn encode_packed_to(target: &mut Vec, rust: B) -/// where -/// B: std::borrow::Borrow, -/// { -/// let MyRustStruct { a, b } = *rust.borrow(); -/// UnderlyingTuple::encode_packed_to(target, (a, b)) -/// } -/// /// } /// ``` /// -/// As you can see, because any NEW soltype corresponds to some combination of -/// OLD sol types, it's really easy to implement [`SolType`] for anything you -/// want! -/// -/// #### Note on implementing type size -/// -/// Any type implementing this should be 0-sized. This trait exposes only -/// associated functions and types, and not methods. -/// -/// ```ignore -/// // Bad - This type is sized. -/// pub struct MyStruct(usize); -/// -/// impl SolType for MyStruct { ... } -/// -/// // Good - This type is 0 sized. -/// pub struct MyStruct; -/// -/// impl SolType for MyStruct { ... } -/// ``` +/// As you can see, because any NEW SolPrimitive corresponds to some +/// combination of OLD sol types, it's really easy to implement +/// [`SolPrimitive`] for anything you want! pub trait SolType { /// The corresponding Rust type. This type may be borrowed (e.g. `str`) type RustType; @@ -182,45 +132,20 @@ pub trait SolType { false } - /// The encoded struct type (as EIP-712), if any. None for non-structs - fn eip712_encode_type() -> Option> { - None - } - /// Check a token to see if it can be detokenized with this type fn type_check(token: &Self::TokenType) -> AbiResult<()>; + #[doc(hidden)] + fn type_check_fail(data: &[u8]) -> crate::Error { + crate::Error::type_check_fail(hex::encode(data), Self::sol_type_name()) + } + /// Detokenize fn detokenize(token: Self::TokenType) -> AbiResult; /// Tokenize fn tokenize>(rust: B) -> Self::TokenType; - /// Implemens Solidity's `encodePacked()` function, writing into the given buffer. - fn encode_packed_to>(target: &mut Vec, rust: B); - - /// Implements Solidity's `encodePacked()` function. - fn encode_packed>(rust: B) -> Vec { - let mut res = Vec::new(); - Self::encode_packed_to(&mut res, rust); - res - } - - #[doc(hidden)] - fn type_check_fail(data: &[u8]) -> Error { - Error::type_check_fail(hex::encode(data), Self::sol_type_name()) - } - - /// Encode this data according to EIP-712 `encodeData` rules, and hash it - /// if necessary. - /// - /// Implementer's note: All single-word types are encoded as their word. - /// All multi-word types are encoded as the hash the concatenated data - /// words for each element - /// - /// - fn eip712_data_word>(rust: B) -> Word; - /// Encode a single ABI token by wrapping it in a 1-length sequence fn encode_single>(rust: B) -> Vec { let token = Self::tokenize(rust); @@ -248,7 +173,7 @@ pub trait SolType { } /// Hex output of encode - fn hex_encode(rust: B) -> RustString + fn hex_encode(rust: B) -> String where Self::TokenType: TokenSeq, B: Borrow, @@ -257,12 +182,12 @@ pub trait SolType { } /// Hex output of encode_single - fn hex_encode_single>(rust: B) -> RustString { + fn hex_encode_single>(rust: B) -> String { format!("0x{}", hex::encode(Self::encode_single(rust))) } /// Hex output of encode_params - fn hex_encode_params(rust: B) -> RustString + fn hex_encode_params(rust: B) -> String where Self::TokenType: TokenSeq, B: Borrow, @@ -275,7 +200,7 @@ pub trait SolType { where Self::TokenType: TokenSeq, { - let decoded = decode::(data, validate)?; + let decoded = crate::decode::(data, validate)?; if validate { Self::type_check(&decoded)?; } @@ -287,7 +212,7 @@ pub trait SolType { where Self::TokenType: TokenSeq, { - let decoded = decode_params::(data, validate)?; + let decoded = crate::decode_params::(data, validate)?; if validate { Self::type_check(&decoded)?; } @@ -296,7 +221,7 @@ pub trait SolType { /// Decode a Rust type from an ABI blob fn decode_single(data: &[u8], validate: bool) -> AbiResult { - let decoded = decode_single::(data, validate)?; + let decoded = crate::decode_single::(data, validate)?; if validate { Self::type_check(&decoded)?; } @@ -333,731 +258,3 @@ pub trait SolType { .and_then(|buf| Self::decode_params(&buf, validate)) } } - -/// Address - `address` -#[derive(Copy, Clone, Debug)] -pub struct Address; - -impl SolType for Address { - type RustType = B160; - type TokenType = WordToken; - - fn sol_type_name() -> Cow<'static, str> { - "address".into() - } - - fn is_dynamic() -> bool { - false - } - - fn type_check(token: &Self::TokenType) -> AbiResult<()> { - if !util::check_zeroes(&token.inner()[..12]) { - return Err(Self::type_check_fail(token.as_slice())); - } - Ok(()) - } - - fn eip712_data_word(rust: B) -> Word - where - B: Borrow, - { - Self::tokenize(rust).inner() - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - let sli = &token.as_slice()[12..]; - Ok(B160::from_slice(sli)) - } - - fn tokenize(rust: B) -> Self::TokenType - where - B: Borrow, - { - WordToken::from(*rust.borrow()) - } - - fn encode_packed_to>(target: &mut Vec, rust: B) { - // push the last 20 bytes of the word to the target - target.extend_from_slice(&rust.borrow().as_bytes()[12..]); - } -} - -/// Bytes - `bytes` -#[derive(Copy, Clone, Debug)] -pub struct Bytes; - -impl SolType for Bytes { - type RustType = Vec; - type TokenType = PackedSeqToken; - - fn is_dynamic() -> bool { - true - } - - fn sol_type_name() -> Cow<'static, str> { - "bytes".into() - } - - fn type_check(_token: &Self::TokenType) -> AbiResult<()> { - Ok(()) - } - - fn eip712_data_word(rust: B) -> Word - where - B: Borrow, - { - keccak256(Self::encode_packed(rust.borrow())) - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - Ok(token.take_vec()) - } - - fn tokenize(rust: B) -> Self::TokenType - where - B: Borrow, - { - rust.borrow().to_owned().into() - } - - fn encode_packed_to>(target: &mut Vec, rust: B) { - // push the buf to the vec - target.extend_from_slice(rust.borrow()); - } -} - -macro_rules! impl_int_sol_type { - ($ity:ty, $bits:literal) => { - impl SolType for Int<$bits> { - type RustType = $ity; - type TokenType = WordToken; - - fn is_dynamic() -> bool { - false - } - - fn sol_type_name() -> Cow<'static, str> { - concat!("int", $bits).into() - } - - fn type_check(_token: &Self::TokenType) -> AbiResult<()> { - Ok(()) - } - - fn eip712_data_word(rust: B) -> Word - where - B: Borrow - { - Self::tokenize(rust).inner().into() - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - let bytes = (<$ity>::BITS / 8) as usize; - let sli = &token.as_slice()[32 - bytes..]; - Ok(<$ity>::from_be_bytes(sli.try_into().unwrap())) - } - - fn tokenize(rust: B) -> Self::TokenType - where - B: Borrow - { - let rust = rust.borrow(); - let bytes = (<$ity>::BITS / 8) as usize; - let mut word = if *rust < 0 { - // account for negative - Word::repeat_byte(0xff) - } else { - Word::default() - }; - let slice = rust.to_be_bytes(); - word[32 - bytes..].copy_from_slice(&slice); - word.into() - } - - fn encode_packed_to(target: &mut Vec, rust: B) - where - B: Borrow - { - let rust = rust.borrow(); - if rust.is_negative(){ - let bytes = rust.to_be_bytes(); - target.extend(bytes); - } else { - Uint::<$bits>::encode_packed_to(target, *rust as as SolType>::RustType); - } - } - } - }; - - ($bits:literal) => { - impl SolType for Int<$bits> { - type RustType = I256; - type TokenType = WordToken; - - fn is_dynamic() -> bool { - false - } - - fn sol_type_name() -> Cow<'static, str> { - concat!("int", $bits).into() - } - - fn type_check(_token: &Self::TokenType) -> AbiResult<()> { - Ok(()) - } - - fn eip712_data_word(rust: B) -> Word - where - B: Borrow - { - Self::tokenize(rust).inner().into() - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - Ok(I256::from_be_bytes::<32>(token.into())) - } - - fn tokenize(rust: B) -> Self::TokenType where B: Borrow{ - rust.borrow().to_be_bytes().into() - } - - fn encode_packed_to(target: &mut Vec, rust: B) where B: Borrow{ - let rust = rust.borrow(); - if rust.is_negative(){ - let bytes = rust.to_be_bytes(); - target.extend(bytes); - } else { - Uint::<$bits>::encode_packed_to( - target, - rust.into_raw(), - ) - } - } - } - }; - - ($($bits:literal,)+) => { - $( - impl_int_sol_type!($bits); - )+ - }; -} - -/// Int - `intX` -#[derive(Copy, Clone, Debug)] -pub struct Int; -impl_int_sol_type!(i8, 8); -impl_int_sol_type!(i16, 16); -impl_int_sol_type!(i32, 24); -impl_int_sol_type!(i32, 32); -impl_int_sol_type!(i64, 40); -impl_int_sol_type!(i64, 48); -impl_int_sol_type!(i64, 56); -impl_int_sol_type!(i64, 64); -impl_int_sol_type!( - 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, - 232, 240, 248, 256, -); - -macro_rules! impl_uint_sol_type { - ($uty:ty, $bits:literal) => { - impl SolType for Uint<$bits> { - type RustType = $uty; - type TokenType = WordToken; - - fn is_dynamic() -> bool { - false - } - - fn sol_type_name() -> Cow<'static, str> { - concat!("uint", $bits).into() - } - - fn type_check(token: &Self::TokenType) -> AbiResult<()> { - let bytes = (<$uty>::BITS / 8) as usize; - let sli = &token.as_slice()[..32 - bytes]; - if !util::check_zeroes(sli) { - return Err(Self::type_check_fail(token.as_slice())); - } - Ok(()) - } - - fn eip712_data_word(rust: B) -> Word - where - B: Borrow - { - Self::tokenize(rust).inner().into() - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - let bytes = (<$uty>::BITS / 8) as usize; - let sli = &token.as_slice()[32 - bytes..]; - Ok(<$uty>::from_be_bytes(sli.try_into().unwrap())) - } - - fn tokenize(rust: B) -> Self::TokenType where B: Borrow{ - let bytes = (<$uty>::BITS / 8) as usize; - let mut word = Word::default(); - let slice = rust.borrow().to_be_bytes(); - word[32 - bytes..].copy_from_slice(&slice); - word.into() - } - - fn encode_packed_to(target: &mut Vec, rust: B) where B: Borrow{ - // encode the rust to be bytes, strip leading zeroes, then push to the target - let bytes = rust.borrow().to_be_bytes(); - target.extend(bytes); - } - } - }; - - ($bits:literal) => { - impl SolType for Uint<$bits> { - type RustType = U256; - type TokenType = WordToken; - - fn is_dynamic() -> bool { - false - } - - fn sol_type_name() -> Cow<'static, str> { - concat!("uint", $bits).into() - } - - fn type_check(token: &Self::TokenType) -> AbiResult<()> { - let bytes = $bits / 8 as usize; - let sli = &token.as_slice()[..32 - bytes]; - if !util::check_zeroes(sli) { - return Err(Self::type_check_fail(token.as_slice())); - } - Ok(()) - } - - fn eip712_data_word(rust: B) -> Word - where - B: Borrow - { - Self::tokenize(rust).inner().into() - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - Ok(U256::from_be_bytes::<32>(*token.inner())) - } - - fn tokenize(rust: B) -> Self::TokenType where B: Borrow{ - (*rust.borrow()).into() - } - - fn encode_packed_to(target: &mut Vec, rust: B) where B: Borrow{ - // encode the rust to be bytes, strip leading zeroes, then push to the target - let bytes: [u8; $bits / 8] = rust.borrow().to_be_bytes(); - target.extend(bytes); - } - } - }; - - ($($bits:literal,)+) => { - $( - impl_uint_sol_type!($bits); - )+ - } -} - -/// Uint - `uintX` -#[derive(Copy, Clone, Debug)] -pub struct Uint; - -impl_uint_sol_type!(u8, 8); -impl_uint_sol_type!(u16, 16); -impl_uint_sol_type!(u32, 24); -impl_uint_sol_type!(u32, 32); -impl_uint_sol_type!(u64, 40); -impl_uint_sol_type!(u64, 48); -impl_uint_sol_type!(u64, 56); -impl_uint_sol_type!(u64, 64); -impl_uint_sol_type!( - 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, - 232, 240, 248, 256, -); - -/// Bool - `bool` -#[derive(Copy, Clone, Debug)] -pub struct Bool; - -impl SolType for Bool { - type RustType = bool; - type TokenType = WordToken; - - fn is_dynamic() -> bool { - false - } - - fn sol_type_name() -> Cow<'static, str> { - "bool".into() - } - - fn type_check(token: &Self::TokenType) -> AbiResult<()> { - if !util::check_bool(token.inner()) { - return Err(Self::type_check_fail(token.as_slice())); - } - Ok(()) - } - - fn eip712_data_word(rust: B) -> Word - where - B: Borrow, - { - Self::tokenize(rust).inner() - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - Ok(token.inner() != Word::repeat_byte(0)) - } - - fn tokenize(rust: B) -> Self::TokenType - where - B: Borrow, - { - let mut word = Word::default(); - word[31..32].copy_from_slice(&[*rust.borrow() as u8]); - word.into() - } - - fn encode_packed_to(target: &mut Vec, rust: B) - where - B: Borrow, - { - // write the bool as a u8 - target.push(*rust.borrow() as u8); - } -} - -/// Array - `T[]` -#[derive(Copy, Clone, Debug)] -pub struct Array(PhantomData); - -impl SolType for Array -where - T: SolType, -{ - type RustType = Vec; - type TokenType = DynSeqToken; - - fn is_dynamic() -> bool { - true - } - - fn sol_type_name() -> Cow<'static, str> { - format!("{}[]", T::sol_type_name()).into() - } - - fn type_check(token: &Self::TokenType) -> AbiResult<()> { - for token in token.as_slice() { - T::type_check(token)?; - } - Ok(()) - } - - fn eip712_data_word(rust: B) -> Word - where - B: Borrow, - { - let mut encoded = Vec::new(); - for item in rust.borrow() { - encoded.extend(T::eip712_data_word(item).as_slice()); - } - keccak256(encoded) - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - token.take_vec().into_iter().map(T::detokenize).collect() - } - - fn tokenize(rust: B) -> Self::TokenType - where - B: Borrow, - { - rust.borrow() - .iter() - .map(|r| T::tokenize(r)) - .collect::>() - .into() - } - - fn encode_packed_to(target: &mut Vec, rust: B) - where - B: Borrow, - { - for item in rust.borrow() { - T::encode_packed_to(target, item); - } - } -} - -/// String - `string` -#[derive(Copy, Clone, Debug)] -pub struct String; - -impl SolType for String { - type RustType = RustString; - type TokenType = PackedSeqToken; - - fn is_dynamic() -> bool { - true - } - - fn sol_type_name() -> Cow<'static, str> { - "string".into() - } - - fn type_check(token: &Self::TokenType) -> AbiResult<()> { - if core::str::from_utf8(token.as_slice()).is_err() { - return Err(Self::type_check_fail(token.as_slice())); - } - Ok(()) - } - - fn eip712_data_word(rust: B) -> Word - where - B: Borrow, - { - keccak256(Self::encode_packed(rust.borrow())) - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - // NOTE: We're decoding strings using lossy UTF-8 decoding to - // prevent invalid strings written into contracts by either users or - // Solidity bugs from causing graph-node to fail decoding event - // data. - Ok(RustString::from_utf8_lossy(&Bytes::detokenize(token)?).into_owned()) - } - - fn tokenize(rust: B) -> Self::TokenType - where - B: Borrow, - { - rust.borrow().as_bytes().to_vec().into() - } - - fn encode_packed_to(target: &mut Vec, rust: B) - where - B: Borrow, - { - target.extend(rust.borrow().as_bytes()); - } -} - -macro_rules! impl_fixed_bytes_sol_type { - ($bytes:literal) => { - impl SolType for FixedBytes<$bytes> { - type RustType = [u8; $bytes]; - type TokenType = WordToken; - - fn is_dynamic() -> bool { - false - } - - fn sol_type_name() -> Cow<'static, str> { - concat!("bytes", $bytes).into() - } - - fn type_check(token: &Self::TokenType) -> AbiResult<()> { - if !util::check_fixed_bytes(token.inner(), $bytes) { - return Err(Self::type_check_fail(token.as_slice())); - } - Ok(()) - } - - fn eip712_data_word(rust: B) -> Word where B: Borrow { - Self::tokenize(rust).inner() - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - let word = token.as_slice(); - let mut res = Self::RustType::default(); - res[..$bytes].copy_from_slice(&word[..$bytes]); - Ok(res) - } - - fn tokenize(rust: B) -> Self::TokenType where B: Borrow{ - let mut word = Word::default(); - word[..$bytes].copy_from_slice(&rust.borrow()[..]); - word.into() - } - - fn encode_packed_to(target: &mut Vec, rust: B) where B: Borrow { - // write only the first n bytes - target.extend_from_slice(&rust.borrow()[..$bytes]); - } - } - }; - - ($($bytes:literal,)+) => { - $(impl_fixed_bytes_sol_type!($bytes);)+ - }; -} - -/// FixedBytes - `bytesX` -#[derive(Copy, Clone, Debug)] -pub struct FixedBytes; -impl_fixed_bytes_sol_type!( - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, -); - -/// FixedArray - `T[M]` -#[derive(Copy, Clone, Debug)] -pub struct FixedArray(PhantomData); - -impl SolType for FixedArray -where - T: SolType, -{ - type RustType = [T::RustType; N]; - type TokenType = FixedSeqToken; - - fn is_dynamic() -> bool { - T::is_dynamic() - } - - fn sol_type_name() -> Cow<'static, str> { - format!("{}[{}]", T::sol_type_name(), N).into() - } - - fn type_check(token: &Self::TokenType) -> AbiResult<()> { - for token in token.as_array().iter() { - T::type_check(token)?; - } - Ok(()) - } - - fn eip712_data_word(rust: B) -> Word - where - B: Borrow, - { - let rust = rust.borrow(); - let encoded = rust - .iter() - .flat_map(|element| T::eip712_data_word(element).to_fixed_bytes()) - .collect::>(); - keccak256(encoded) - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - let res = token - .take_array() - .into_iter() - .map(|t| T::detokenize(t)) - .collect::>>()? - .try_into(); - match res { - Ok(tokens) => Ok(tokens), - Err(_) => panic!("input is exact len"), - } - } - - fn tokenize(rust: B) -> Self::TokenType - where - B: Borrow, - { - match rust - .borrow() - .iter() - .map(|r| T::tokenize(r)) - .collect::>() - .try_into() - { - Ok(tokens) => tokens, - Err(_) => unreachable!(), - } - } - - fn encode_packed_to(target: &mut Vec, rust: B) - where - B: Borrow, - { - for item in rust.borrow() { - T::encode_packed_to(target, item); - } - } -} - -macro_rules! tuple_impls { - () => {}; - - (@peel $_:ident, $($other:ident,)*) => { tuple_impls! { $($other,)* } }; - - // compile time `join(",")` format string - (@fmt $other:ident) => { ",{}" }; - (@fmt $first:ident, $($other:ident,)*) => { - concat!( - "{}", - $(tuple_impls! { @fmt $other }),* - ) - }; - - ($($ty:ident,)+) => { - #[allow(non_snake_case)] - impl<$($ty: SolType,)+> SolType for ($($ty,)+) { - type RustType = ($( $ty::RustType, )+); - type TokenType = ($( $ty::TokenType, )+); - - fn is_dynamic() -> bool { - $( <$ty as SolType>::is_dynamic() )||+ - } - - fn sol_type_name() -> Cow<'static, str> { - format!( - concat!( - "tuple(", - tuple_impls! { @fmt $($ty,)+ }, - ")", - ), - $(<$ty as SolType>::sol_type_name(),)+ - ).into() - } - - fn type_check(token: &Self::TokenType) -> AbiResult<()> { - let ($(ref $ty,)+) = *token; - $( - <$ty as SolType>::type_check($ty)?; - )+ - Ok(()) - } - - fn eip712_data_word>(rust: B_) -> Word { - let ($(ref $ty,)+) = *rust.borrow(); - let encoding: Vec = [$( - <$ty as SolType>::eip712_data_word($ty).0, - )+].concat(); - keccak256(&encoding).into() - } - - fn detokenize(token: Self::TokenType) -> AbiResult { - let ($($ty,)+) = token; - Ok(($( - <$ty as SolType>::detokenize($ty)?, - )+)) - } - - fn tokenize>(rust: B_) -> Self::TokenType { - let ($(ref $ty,)+) = *rust.borrow(); - ($( - <$ty as SolType>::tokenize($ty), - )+) - } - - fn encode_packed_to>(target: &mut Vec, rust: B_) { - let ($(ref $ty,)+) = *rust.borrow(); - // TODO: Reserve - $( - <$ty as SolType>::encode_packed_to(target, $ty); - )+ - } - } - - tuple_impls! { @peel $($ty,)+ } - }; -} - -tuple_impls! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, } diff --git a/abi/src/sol_types/sol_udt.rs b/abi/src/sol_types/sol_udt.rs index 784fcfa11f..d9c4d7b482 100644 --- a/abi/src/sol_types/sol_udt.rs +++ b/abi/src/sol_types/sol_udt.rs @@ -41,7 +41,7 @@ macro_rules! define_udt { /// Return the packed encoding of this value, delegating to the /// underlying type pub fn encode_packed(&self) -> $crate::no_std_prelude::Vec { - ::encode_packed(self.0) + ::encode_packed(self.0) } } @@ -66,13 +66,6 @@ macro_rules! define_udt { $path(token) } - fn eip712_data_word(rust: B) -> $crate::Word - where - B: $crate::no_std_prelude::Borrow - { - Self::tokenize(rust).inner() - } - fn tokenize(rust: B) -> Self::TokenType where B: $crate::no_std_prelude::Borrow @@ -84,11 +77,21 @@ macro_rules! define_udt { <$underlying as $crate::SolType>::detokenize(token) } + } + + impl $crate::SolDataType for $name { + fn eip712_data_word(rust: B) -> $crate::Word + where + B: $crate::no_std_prelude::Borrow + { + ::tokenize(rust).inner() + } + fn encode_packed_to(target: &mut $crate::no_std_prelude::Vec, rust: B) where B: $crate::no_std_prelude::Borrow { - <$underlying as $crate::SolType>::encode_packed_to(target, rust) + <$underlying as $crate::SolDataType>::encode_packed_to(target, rust) } } }; @@ -114,7 +117,7 @@ macro_rules! define_udt { define_udt!( $(#[$outer])* $name, - underlying: $crate::sol_type::FixedBytes<32>, + underlying: $crate::sol_data::FixedBytes<32>, type_check: $type_check, ); }; diff --git a/abi/tests/macros.rs b/abi/tests/macros.rs index 0f4f27c4d0..dd6a5e8e26 100644 --- a/abi/tests/macros.rs +++ b/abi/tests/macros.rs @@ -8,7 +8,7 @@ fn ret_ok(_: T) -> ethers_abi_enc::AbiResult<()> { define_udt!( /// My Sol UDT MyUdt, - underlying: ethers_abi_enc::sol_type::Bool, + underlying: ethers_abi_enc::sol_data::Bool, type_check: ret_ok, ); diff --git a/abi/tests/proc.rs b/abi/tests/proc.rs index 8470cf72c0..f1b2d02112 100644 --- a/abi/tests/proc.rs +++ b/abi/tests/proc.rs @@ -89,6 +89,6 @@ fn proc_macro_expansion() { let mvt = MyValueType::from(U256::from(1)); assert_eq!( mvt.encode_single(), - ethers_abi_enc::sol_type::Uint::<256>::encode_single(U256::from(1)) + ethers_abi_enc::sol_data::Uint::<256>::encode_single(U256::from(1)) ); } diff --git a/abi/tests/proc_no_std.rs b/abi/tests/proc_no_std.rs index df1da2765d..b4d6648091 100644 --- a/abi/tests/proc_no_std.rs +++ b/abi/tests/proc_no_std.rs @@ -70,6 +70,6 @@ fn no_std_proc_macro() { let mvt = MyValueType::from(U256::from(1)); assert_eq!( mvt.encode_single(), - ethers_abi_enc::sol_type::Uint::<256>::encode_single(U256::from(1)) + ethers_abi_enc::sol_data::Uint::<256>::encode_single(U256::from(1)) ); } diff --git a/dyn-abi/src/eip712/resolver.rs b/dyn-abi/src/eip712/resolver.rs index 605885b023..91bec41e23 100644 --- a/dyn-abi/src/eip712/resolver.rs +++ b/dyn-abi/src/eip712/resolver.rs @@ -284,7 +284,10 @@ impl Resolver { } /// Ingest a sol struct typedef - pub fn ingest_sol_struct(&mut self) { + pub fn ingest_sol_struct(&mut self) + where + S: SolStruct, + { self.ingest_string(S::encode_type()).unwrap(); } diff --git a/dyn-abi/src/eip712/typed_data.rs b/dyn-abi/src/eip712/typed_data.rs index 0194710281..1cb9655335 100644 --- a/dyn-abi/src/eip712/typed_data.rs +++ b/dyn-abi/src/eip712/typed_data.rs @@ -153,7 +153,10 @@ impl<'de> Deserialize<'de> for TypedData { impl TypedData { /// Instantiate [`TypedData`] from a [`SolStruct`] that implements /// [`serde::Serialize`]. - pub fn from_struct(s: &S, domain: Option) -> Self { + pub fn from_struct(s: &S, domain: Option) -> Self + where + S: SolStruct + Serialize, + { Self { domain: domain.unwrap_or_default(), resolver: Resolver::from_struct::(), diff --git a/dyn-abi/src/type.rs b/dyn-abi/src/type.rs index 05814ec755..7d033bfdc3 100644 --- a/dyn-abi/src/type.rs +++ b/dyn-abi/src/type.rs @@ -3,7 +3,7 @@ use crate::{ no_std_prelude::*, AbiResult, DynAbiError, DynSolValue, DynToken, SolType, Word, }; -use ethers_abi_enc::sol_type; +use ethers_abi_enc::sol_data; #[derive(Debug, Clone, PartialEq, Eq)] struct StructProp { @@ -86,10 +86,10 @@ impl DynSolType { pub fn tokenize(&self, value: DynSolValue) -> AbiResult { match (self, value) { (DynSolType::Address, DynSolValue::Address(val)) => { - Ok(DynToken::Word(sol_type::Address::tokenize(val).inner())) + Ok(DynToken::Word(sol_data::Address::tokenize(val).inner())) } (DynSolType::Bool, DynSolValue::Bool(val)) => { - Ok(DynToken::Word(sol_type::Bool::tokenize(val).inner())) + Ok(DynToken::Word(sol_data::Bool::tokenize(val).inner())) } (DynSolType::Bytes, DynSolValue::Bytes(val)) => Ok(DynToken::PackedSeq(val)), (DynSolType::FixedBytes(len), DynSolValue::FixedBytes(word, size)) => { @@ -222,28 +222,28 @@ impl DynSolType { pub fn detokenize(&self, token: DynToken) -> AbiResult { match (self, token) { (DynSolType::Address, DynToken::Word(word)) => Ok(DynSolValue::Address( - sol_type::Address::detokenize(word.into())?, + sol_data::Address::detokenize(word.into())?, )), (DynSolType::Bool, DynToken::Word(word)) => { - Ok(DynSolValue::Bool(sol_type::Bool::detokenize(word.into())?)) + Ok(DynSolValue::Bool(sol_data::Bool::detokenize(word.into())?)) } (DynSolType::Bytes, DynToken::PackedSeq(buf)) => Ok(DynSolValue::Bytes(buf)), (DynSolType::FixedBytes(size), DynToken::Word(word)) => Ok(DynSolValue::FixedBytes( - sol_type::FixedBytes::<32>::detokenize(word.into())?.into(), + sol_data::FixedBytes::<32>::detokenize(word.into())?.into(), *size, )), // cheating here, but it's ok (DynSolType::Int(size), DynToken::Word(word)) => Ok(DynSolValue::Int( - sol_type::Int::<256>::detokenize(word.into())?, + sol_data::Int::<256>::detokenize(word.into())?, *size, )), (DynSolType::Uint(size), DynToken::Word(word)) => Ok(DynSolValue::Uint( - sol_type::Uint::<256>::detokenize(word.into())?, + sol_data::Uint::<256>::detokenize(word.into())?, *size, )), (DynSolType::String, DynToken::PackedSeq(buf)) => Ok(DynSolValue::String( - sol_type::String::detokenize(buf.into())?, + sol_data::String::detokenize(buf.into())?, )), (DynSolType::Tuple(types), DynToken::FixedSeq(tokens, _)) => { if types.len() != tokens.len() {