--- a/crates/evm-coder/procedural/src/abi_derive.rs +++ b/crates/evm-coder/procedural/src/abi_derive.rs @@ -137,7 +137,7 @@ let abi_write = if is_named_fields { quote!( #( - self.#field_names.abi_write(writer); + self.#field_names.abi_write(sub); )* ) } else { @@ -146,14 +146,24 @@ .map(proc_macro2::Literal::usize_unsuffixed); quote!( #( - self.#field_names.abi_write(writer); + self.#field_names.abi_write(sub); )* ) }; quote!( impl ::evm_coder::abi::AbiWrite for #name { fn abi_write(&self, writer: &mut ::evm_coder::abi::AbiWriter) { - #abi_write + if ::is_dynamic() { + let mut sub = ::evm_coder::abi::AbiWriter::new(); + { + let sub = &mut sub; + #abi_write + } + writer.write_subresult(sub); + } else { + let sub = writer; + #abi_write + } } } ) --- a/crates/evm-coder/src/abi/impls.rs +++ b/crates/evm-coder/src/abi/impls.rs @@ -310,11 +310,11 @@ #[allow(non_snake_case)] impl<$($ident),+> AbiWrite for ($($ident,)+) where - $($ident: AbiWrite,)+ + $($ident: AbiWrite + AbiType,)+ { fn abi_write(&self, writer: &mut AbiWriter) { let ($($ident,)+) = self; - if writer.is_dynamic { + if ::is_dynamic() { let mut sub = AbiWriter::new(); $($ident.abi_write(&mut sub);)+ writer.write_subresult(sub); --- a/crates/evm-coder/src/lib.rs +++ b/crates/evm-coder/src/lib.rs @@ -137,7 +137,7 @@ #[cfg(feature = "std")] pub type string = ::std::string::String; - #[derive(Default, Debug, PartialEq)] + #[derive(Default, Debug, PartialEq, Clone)] pub struct bytes(pub Vec); /// Solidity doesn't have `void` type, however we have special implementation --- a/crates/evm-coder/tests/abi_derive_generation.rs +++ b/crates/evm-coder/tests/abi_derive_generation.rs @@ -1,64 +1,64 @@ use evm_coder_procedural::AbiCoder; use evm_coder::{ types::*, - abi::{AbiType}, + abi::{AbiType, AbiRead, AbiWrite}, }; // TODO: move to build_failed tests -// #[derive(AbiCoder)] +// #[derive(AbiCoder, PartialEq, Debug)] // struct TypeStructUnit {} -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TypeStruct1SimpleParam { _a: u8, } -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TypeStruct1DynamicParam { _a: String, } -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TypeStruct2SimpleParam { _a: u8, _b: u32, } -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TypeStruct2DynamicParam { _a: String, _b: bytes, } -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TypeStruct2MixedParam { _a: u8, _b: bytes, } -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TypeStruct1DerivedSimpleParam { _a: TypeStruct1SimpleParam, } -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TypeStruct2DerivedSimpleParam { _a: TypeStruct1SimpleParam, _b: TypeStruct2SimpleParam, } -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TypeStruct1DerivedDynamicParam { _a: TypeStruct1DynamicParam, } -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TypeStruct2DerivedDynamicParam { _a: TypeStruct1DynamicParam, _b: TypeStruct2DynamicParam, } -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TypeStruct3DerivedMixedParam { _a: TypeStruct1SimpleParam, _b: TypeStruct2DynamicParam, @@ -200,34 +200,34 @@ ); } -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TupleStruct1SimpleParam(u8); -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TupleStruct1DynamicParam(String); -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TupleStruct2SimpleParam(u8, u32); -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TupleStruct2DynamicParam(String, bytes); -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TupleStruct2MixedParam(u8, bytes); -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam); -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TupleStruct2DerivedSimpleParam(TupleStruct1SimpleParam, TupleStruct2SimpleParam); -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TupleStruct1DerivedDynamicParam(TupleStruct1DynamicParam); -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TupleStruct2DerivedDynamicParam(TupleStruct1DynamicParam, TupleStruct2DynamicParam); -#[derive(AbiCoder)] +#[derive(AbiCoder, PartialEq, Debug)] struct TupleStruct3DerivedMixedParam( TupleStruct1SimpleParam, TupleStruct2DynamicParam, @@ -406,7 +406,66 @@ ); } -// #[test] -// fn impl_abi_read() { -// TypeStruct1SimpleParam:: -// } +fn test_impl( + type_struct_data: TypeStruct, + tuple_struct_data: TupleStruct, + tuple_data: Tuple, +) where + TypeStruct: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug, + Tuple: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug, +{ + use evm_coder::abi::{AbiReader, AbiWriter}; + const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef; + + let mut writer = AbiWriter::new_call(FUNCTION_IDENTIFIER); + tuple_data.abi_write(&mut writer); + let encoded_tuple = writer.finish(); + + let mut writer = AbiWriter::new_call(FUNCTION_IDENTIFIER); + type_struct_data.abi_write(&mut writer); + let encoded_struct = writer.finish(); + + similar_asserts::assert_eq!(encoded_tuple, encoded_struct); + + // let (_, mut decoder) = AbiReader::new_call(&encoded_tuple).unwrap(); + // let restored_struct_data = ::abi_read(&mut decoder).unwrap(); + // assert_eq!(restored_struct_data, type_struct_data); + + // let (_, mut decoder) = AbiReader::new_call(&encoded_struct).unwrap(); + // let restored_tuple_data = ::abi_read(&mut decoder).unwrap(); + // assert_eq!(restored_tuple_data, tuple_data); +} + +#[test] +fn codec_struct_1_simple() { + let _a = 0xff; + test_impl::( + TypeStruct1SimpleParam { _a }, + TupleStruct1SimpleParam(_a), + (_a,), + ); +} + +#[test] +fn codec_struct_1_dynamic() { + let _a: String = "some string".into(); + test_impl::( + TypeStruct1DynamicParam { _a: _a.clone() }, + TupleStruct1DynamicParam(_a.clone()), + (_a,), + ); +} + +#[test] +fn codec_struct_2_dynamic() { + let _a: String = "some string".into(); + let _b: bytes = bytes(vec![0x11, 0x22, 0x33]); + test_impl::( + TypeStruct2DynamicParam { + _a: _a.clone(), + _b: _b.clone(), + }, + TupleStruct2DynamicParam(_a.clone(), _b.clone()), + (_a, _b), + ); +}