--- a/crates/evm-coder/Cargo.toml +++ b/crates/evm-coder/Cargo.toml @@ -22,6 +22,7 @@ # We want to assert some large binary blobs equality in tests hex = "0.4.3" hex-literal = "0.3.4" +similar-asserts = "1.4.2" [features] default = ["std"] --- a/crates/evm-coder/src/abi.rs +++ b/crates/evm-coder/src/abi.rs @@ -25,7 +25,7 @@ use crate::{ execution::{Error, ResultWithPostInfo, WithPostDispatchInfo}, - types::{string, self}, + types::*, }; use crate::execution::Result; @@ -56,7 +56,7 @@ } } /// Start reading RLP buffer, parsing first 4 bytes as selector - pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> { + pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> { if buf.len() < 4 { return Err(Error::Error(ExitError::OutOfOffset)); } @@ -252,11 +252,11 @@ self.static_part.extend(block); } - fn write_padright(&mut self, bytes: &[u8]) { - assert!(bytes.len() <= ABI_ALIGNMENT); - self.static_part.extend(bytes); + fn write_padright(&mut self, block: &[u8]) { + assert!(block.len() <= ABI_ALIGNMENT); + self.static_part.extend(block); self.static_part - .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]); + .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]); } /// Write [`H160`] to end of buffer @@ -369,16 +369,30 @@ }; } -impl_abi_readable!(u8, uint8, false); -impl_abi_readable!(u32, uint32, false); -impl_abi_readable!(u64, uint64, false); -impl_abi_readable!(u128, uint128, false); -impl_abi_readable!(U256, uint256, false); -impl_abi_readable!([u8; 4], bytes4, false); -impl_abi_readable!(H160, address, false); -impl_abi_readable!(Vec, bytes, true); -impl_abi_readable!(bool, bool, true); +impl_abi_readable!(bool, bool, false); +impl_abi_readable!(uint8, uint8, false); +impl_abi_readable!(uint32, uint32, false); +impl_abi_readable!(uint64, uint64, false); +impl_abi_readable!(uint128, uint128, false); +impl_abi_readable!(uint256, uint256, false); +impl_abi_readable!(bytes4, bytes4, false); +impl_abi_readable!(address, address, false); impl_abi_readable!(string, string, true); +// impl_abi_readable!(bytes, bytes, true); + +impl TypeHelper for bytes { + fn is_dynamic() -> bool { + true + } + fn size() -> usize { + ABI_ALIGNMENT + } +} +impl AbiRead for AbiReader<'_> { + fn abi_read(&mut self) -> Result { + Ok(bytes(self.bytes()?)) + } +} mod sealed { /// Not all types can be placed in vec, i.e `Vec` is restricted, `bytes` should be used instead @@ -524,17 +538,19 @@ impl_abi_writeable!(H160, address); impl_abi_writeable!(bool, bool); impl_abi_writeable!(&str, string); + impl AbiWrite for string { fn abi_write(&self, writer: &mut AbiWriter) { writer.string(self) } } -// impl AbiWrite for Vec { -// fn abi_write(&self, writer: &mut AbiWriter) { -// writer.bytes(self) -// } -// } +impl AbiWrite for bytes { + fn abi_write(&self, writer: &mut AbiWriter) { + writer.bytes(self.0.as_slice()) + } +} + impl AbiWrite for Vec { fn abi_write(&self, writer: &mut AbiWriter) { let is_dynamic = T::is_dynamic(); --- a/crates/evm-coder/src/lib.rs +++ b/crates/evm-coder/src/lib.rs @@ -133,8 +133,10 @@ pub type string = ::alloc::string::String; #[cfg(feature = "std")] pub type string = ::std::string::String; - pub type bytes = Vec; + #[derive(Default, Debug)] + pub struct bytes(pub Vec); + /// Solidity doesn't have `void` type, however we have special implementation /// for empty tuple return type pub type void = (); @@ -157,6 +159,30 @@ /// and there is no `receiver()` function defined. pub value: U256, } + + impl From> for bytes { + fn from(src: Vec) -> Self { + Self(src) + } + } + + impl Into> for bytes { + fn into(self) -> Vec { + self.0 + } + } + + impl bytes { + #[must_use] + pub fn len(&self) -> usize { + self.0.len() + } + + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + } } /// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro --- a/pallets/common/src/erc.rs +++ b/pallets/common/src/erc.rs @@ -85,7 +85,7 @@ let key = >::from(key) .try_into() .map_err(|_| "key too large")?; - let value = value.try_into().map_err(|_| "value too large")?; + let value = value.0.try_into().map_err(|_| "value too large")?; >::set_collection_property(self, &caller, Property { key, value }) .map_err(dispatch_to_evm::) @@ -120,7 +120,7 @@ let props = >::get(self.id); let prop = props.get(&key).ok_or("key not found")?; - Ok(prop.to_vec()) + Ok(bytes(prop.to_vec())) } /// Set the sponsor of the collection. --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -97,7 +97,7 @@ let key = >::from(key) .try_into() .map_err(|_| "key too long")?; - let value = value.try_into().map_err(|_| "value too long")?; + let value = value.0.try_into().map_err(|_| "value too long")?; let nesting_budget = self .recorder @@ -146,7 +146,7 @@ let props = >::get((self.id, token_id)); let prop = props.get(&key).ok_or("key not found")?; - Ok(prop.to_vec()) + Ok(prop.to_vec().into()) } } --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -100,7 +100,7 @@ let key = >::from(key) .try_into() .map_err(|_| "key too long")?; - let value = value.try_into().map_err(|_| "value too long")?; + let value = value.0.try_into().map_err(|_| "value too long")?; let nesting_budget = self .recorder @@ -149,7 +149,7 @@ let props = >::get((self.id, token_id)); let prop = props.get(&key).ok_or("key not found")?; - Ok(prop.to_vec()) + Ok(prop.to_vec().into()) } }