diff --git a/ethers-contract/tests/abigen.rs b/ethers-contract/tests/abigen.rs index b5d6ded5..63a55ce0 100644 --- a/ethers-contract/tests/abigen.rs +++ b/ethers-contract/tests/abigen.rs @@ -189,18 +189,18 @@ fn can_gen_human_readable_with_structs() { let call = BarCall { x: 1u64.into(), y: 0u64.into(), addr: Address::random() }; let encoded_call = contract.encode("bar", (call.x, call.y, call.addr)).unwrap(); - assert_eq!(encoded_call, call.clone().encode().into()); + assert_eq!(encoded_call, call.clone().encode()); let decoded_call = BarCall::decode(encoded_call.as_ref()).unwrap(); assert_eq!(call, decoded_call); let contract_call = SimpleContractCalls::Bar(call); let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap(); assert_eq!(contract_call, decoded_enum); - assert_eq!(encoded_call, contract_call.encode().into()); + assert_eq!(encoded_call, contract_call.encode()); let call = YeetCall(1u64.into(), 0u64.into(), Address::zero()); let encoded_call = contract.encode("yeet", (call.0, call.1, call.2)).unwrap(); - assert_eq!(encoded_call, call.clone().encode().into()); + assert_eq!(encoded_call, call.clone().encode()); let decoded_call = YeetCall::decode(encoded_call.as_ref()).unwrap(); assert_eq!(call, decoded_call); @@ -208,7 +208,7 @@ fn can_gen_human_readable_with_structs() { let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap(); assert_eq!(contract_call, decoded_enum); assert_eq!(contract_call, call.into()); - assert_eq!(encoded_call, contract_call.encode().into()); + assert_eq!(encoded_call, contract_call.encode()); } #[test] @@ -235,26 +235,26 @@ fn can_handle_overloaded_functions() { let call = GetValueCall; let encoded_call = contract.encode("getValue", ()).unwrap(); - assert_eq!(encoded_call, call.clone().encode().into()); + assert_eq!(encoded_call, call.clone().encode()); let decoded_call = GetValueCall::decode(encoded_call.as_ref()).unwrap(); assert_eq!(call, decoded_call); let contract_call = SimpleContractCalls::GetValue(call); let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap(); assert_eq!(contract_call, decoded_enum); - assert_eq!(encoded_call, contract_call.encode().into()); + assert_eq!(encoded_call, contract_call.encode()); let call = GetValueWithOtherValueCall { other_value: 420u64.into() }; let encoded_call = contract.encode_with_selector([15, 244, 201, 22], call.other_value).unwrap(); - assert_eq!(encoded_call, call.clone().encode().into()); + assert_eq!(encoded_call, call.clone().encode()); let decoded_call = GetValueWithOtherValueCall::decode(encoded_call.as_ref()).unwrap(); assert_eq!(call, decoded_call); let contract_call = SimpleContractCalls::GetValueWithOtherValue(call); let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap(); assert_eq!(contract_call, decoded_enum); - assert_eq!(encoded_call, contract_call.encode().into()); + assert_eq!(encoded_call, contract_call.encode()); let call = GetValueWithOtherValueAndAddrCall { other_value: 420u64.into(), addr: Address::random() }; @@ -267,7 +267,7 @@ fn can_handle_overloaded_functions() { let contract_call = SimpleContractCalls::GetValueWithOtherValueAndAddr(call); let decoded_enum = SimpleContractCalls::decode(encoded_call.as_ref()).unwrap(); assert_eq!(contract_call, decoded_enum); - assert_eq!(encoded_call, contract_call.encode().into()); + assert_eq!(encoded_call, contract_call.encode()); let call = SetValue0Call("message".to_string()); let _contract_call = SimpleContractCalls::SetValue0(call); @@ -443,7 +443,7 @@ fn can_generate_nested_types() { let call = MyfunCall { a: a.clone() }; let encoded_call = contract.encode("myfun", (a,)).unwrap(); - assert_eq!(encoded_call, call.clone().encode().into()); + assert_eq!(encoded_call, call.clone().encode()); let decoded_call = MyfunCall::decode(encoded_call.as_ref()).unwrap(); assert_eq!(call, decoded_call); } diff --git a/ethers-core/src/abi/codec.rs b/ethers-core/src/abi/codec.rs index d9f6c456..6a888aa0 100644 --- a/ethers-core/src/abi/codec.rs +++ b/ethers-core/src/abi/codec.rs @@ -57,6 +57,7 @@ macro_rules! impl_abi_codec { impl_abi_codec!( Vec, Bytes, + bytes::Bytes, Address, bool, String, diff --git a/ethers-core/src/abi/mod.rs b/ethers-core/src/abi/mod.rs index 7b9c34ac..4a332e6d 100644 --- a/ethers-core/src/abi/mod.rs +++ b/ethers-core/src/abi/mod.rs @@ -125,6 +125,7 @@ macro_rules! impl_abi_type { impl_abi_type!( Bytes => Bytes, + bytes::Bytes => Bytes, Vec => Array(Box::new(ParamType::Uint(8))), Address => Address, bool => Bool, diff --git a/ethers-core/src/abi/tokens.rs b/ethers-core/src/abi/tokens.rs index ca567078..e0684bb0 100644 --- a/ethers-core/src/abi/tokens.rs +++ b/ethers-core/src/abi/tokens.rs @@ -159,6 +159,19 @@ impl Tokenizable for Bytes { } } +impl Tokenizable for bytes::Bytes { + fn from_token(token: Token) -> Result { + match token { + Token::Bytes(s) => Ok(s.into()), + other => Err(InvalidOutputType(format!("Expected `Bytes`, got {:?}", other))), + } + } + + fn into_token(self) -> Token { + Token::Bytes(self.to_vec()) + } +} + impl Tokenizable for H256 { fn from_token(token: Token) -> Result { match token { @@ -287,7 +300,7 @@ macro_rules! tokenizable_item { tokenizable_item! { Token, String, Address, H256, U256, I256, U128, bool, Vec, - i8, i16, i32, i64, i128, u16, u32, u64, u128, Bytes, + i8, i16, i32, i64, i128, u16, u32, u64, u128, Bytes, bytes::Bytes, } macro_rules! impl_tokenizable_item_tuple { diff --git a/ethers-core/src/types/bytes.rs b/ethers-core/src/types/bytes.rs index d8728362..35c0e28d 100644 --- a/ethers-core/src/types/bytes.rs +++ b/ethers-core/src/types/bytes.rs @@ -2,8 +2,10 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use thiserror::Error; use std::{ + borrow::Borrow, clone::Clone, fmt::{Debug, Display, Formatter, LowerHex, Result as FmtResult}, + ops::Deref, str::FromStr, }; @@ -36,12 +38,45 @@ impl Bytes { } } +impl Deref for Bytes { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.as_ref() + } +} + impl AsRef<[u8]> for Bytes { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } +impl Borrow<[u8]> for Bytes { + fn borrow(&self) -> &[u8] { + self.as_ref() + } +} + +impl IntoIterator for Bytes { + type Item = u8; + type IntoIter = bytes::buf::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a> IntoIterator for &'a Bytes { + type Item = &'a u8; + type IntoIter = core::slice::Iter<'a, u8>; + + fn into_iter(self) -> Self::IntoIter { + self.as_ref().iter() + } +} + impl From for Bytes { fn from(src: bytes::Bytes) -> Self { Self(src) @@ -66,6 +101,36 @@ impl<'a, const N: usize> From<&'a [u8; N]> for Bytes { } } +impl PartialEq<[u8]> for Bytes { + fn eq(&self, other: &[u8]) -> bool { + self.as_ref() == other + } +} + +impl PartialEq for [u8] { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialEq> for Bytes { + fn eq(&self, other: &Vec) -> bool { + self.as_ref() == &other[..] + } +} + +impl PartialEq for Vec { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialEq for Bytes { + fn eq(&self, other: &bytes::Bytes) -> bool { + other == self.as_ref() + } +} + #[derive(Debug, Clone, Error)] #[error("Failed to parse bytes: {0}")] pub struct ParseBytesError(String);