From fc64eed27959e39ecf43200568a0145b19e7775d Mon Sep 17 00:00:00 2001 From: theghostmac Date: Tue, 28 May 2024 07:19:06 +0100 Subject: [PATCH 1/7] [Ethereum]: Add support for abi.encodePacked() --- rust/Cargo.lock | 1 + rust/tw_evm/Cargo.toml | 1 + rust/tw_evm/src/abi/encode.rs | 182 +++++++++++++++++++++++++++++++++- rust/tw_evm/src/address.rs | 6 ++ rust/tw_number/src/i256.rs | 2 +- rust/tw_number/src/u256.rs | 2 +- 6 files changed, 191 insertions(+), 3 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 3d7c0c29603..6d16a2e590d 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1820,6 +1820,7 @@ dependencies = [ name = "tw_evm" version = "0.1.0" dependencies = [ + "hex", "itertools", "lazy_static", "rlp", diff --git a/rust/tw_evm/Cargo.toml b/rust/tw_evm/Cargo.toml index 857a8f1bd5a..fd1116a0f03 100644 --- a/rust/tw_evm/Cargo.toml +++ b/rust/tw_evm/Cargo.toml @@ -17,6 +17,7 @@ tw_memory = { path = "../tw_memory" } tw_misc = { path = "../tw_misc" } tw_number = { path = "../tw_number" } tw_proto = { path = "../tw_proto" } +hex = "0.4.3" [dev-dependencies] tw_coin_entry = { path = "../tw_coin_entry", features = ["test-utils"] } diff --git a/rust/tw_evm/src/abi/encode.rs b/rust/tw_evm/src/abi/encode.rs index 5ab9acd7068..a79235752ad 100644 --- a/rust/tw_evm/src/abi/encode.rs +++ b/rust/tw_evm/src/abi/encode.rs @@ -5,6 +5,7 @@ use crate::abi::token::Token; use tw_hash::H256; use tw_memory::Data; +use crate::abi::uint::UintBits; pub fn encode_tokens(tokens: &[Token]) -> Data { let mediates = tokens.iter().map(mediate_token).collect::>(); @@ -202,8 +203,67 @@ fn fixed_bytes_append(result: &mut Vec, bytes: &[u8]) { } } +pub fn encode_packed_tokens(tokens: &[Token]) -> Data { + let mut encoded = Vec::new(); + + for token in tokens { + match token { + Token::Address(address) => { + encoded.extend_from_slice(address.as_slice()); + }, + Token::Bytes(bytes) => { + encoded.extend_from_slice(bytes); + }, + Token::String(s) => { + encoded.extend_from_slice(s.as_bytes()); + }, + Token::FixedBytes(bytes) => { + encoded.extend_from_slice(bytes); + }, + Token::Int { int, .. } => { + let buf = int.to_big_endian(); + let trimmed_buf = trim_leading_zeros(buf.as_slice()); + encoded.extend_from_slice(trimmed_buf); + }, + Token::Uint { uint, .. } => { + let buf = uint.to_big_endian(); + let trimmed_buf = trim_leading_zeros(buf.as_slice()); + encoded.extend_from_slice(trimmed_buf); + }, + Token::Bool(b) => { + encoded.push(*b as u8); + }, + Token::Array { arr, .. } => { + for element in arr.iter() { + let element_data = encode_packed_tokens(&[element.clone()]); + encoded.extend_from_slice(&element_data); + } + }, + Token::FixedArray { arr, .. } => { + for element in arr.iter() { + let element_data = encode_packed_tokens(&[element.clone()]); + encoded.extend_from_slice(&element_data); + } + }, + Token::Tuple { params } => { + for element in params.iter() { + let element_data = encode_packed_tokens(&[element.value.clone()]); + encoded.extend_from_slice(&element_data); + } + }, + } + } + encoded +} + +fn trim_leading_zeros(buf: &[u8]) -> &[u8] { + let first_non_zero = buf.iter().position(|&x| x != 0).unwrap_or(buf.len() - 1); + &buf[first_non_zero..] +} + #[cfg(test)] mod tests { + use hex::FromHex; use super::*; use crate::abi::non_empty_array::{NonEmptyArray, NonEmptyBytes}; use crate::abi::param::Param; @@ -1083,4 +1143,124 @@ mod tests { .unwrap(); assert_eq!(encoded, expected); } -} + + #[test] + fn encode_packed_address() { + let address = Token::Address("0x1111111111111111111111111111111111111111".into()); + let encoded = encode_packed_tokens(&[address]); + let expected = "1111111111111111111111111111111111111111".decode_hex().unwrap(); + assert_eq!(encoded, expected); + } + + #[test] + fn encode_packed_bytes() { + let bytes = Token::Bytes(vec![0x12, 0x34]); + let encoded = encode_packed_tokens(&[bytes]); + let expected = "1234".decode_hex().unwrap(); + assert_eq!(encoded, expected); + } + + #[test] + fn encode_packed_string() { + let s = Token::String("Hello, world!".to_owned()); + let encoded = encode_packed_tokens(&[s]); + let expected = "48656c6c6f2c20776f726c6421".decode_hex().unwrap(); + assert_eq!(encoded, expected); + } + + #[test] + fn encode_packed_int() { + let int = Token::Int { + int: I256::from(-1), + bits: UintBits::new(256).unwrap(), + }; + let encoded = encode_packed_tokens(&[int]); + let expected = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".decode_hex().unwrap(); + assert_eq!(encoded, expected); + } + + #[test] + fn encode_packed_bool() { + let b = Token::Bool(true); + let encoded = encode_packed_tokens(&[b]); + let expected = "01".decode_hex().unwrap(); + assert_eq!(encoded, expected); + + let b = Token::Bool(false); + let encoded = encode_packed_tokens(&[b]); + let expected = "00".decode_hex().unwrap(); + assert_eq!(encoded, expected); + } + + #[test] + fn encode_packed_uint() { + let uint = Token::Uint { + uint: U256::from(3_u64), + bits: UintBits::new(256).unwrap(), + }; + let encoded = encode_packed_tokens(&[uint]); + let expected = "03".decode_hex().unwrap(); + assert_eq!(encoded, expected); + } + + #[test] + fn encode_packed_fixed_bytes() { + let bytes = Token::FixedBytes(NonEmptyBytes::new(vec![0x12, 0x34]).unwrap()); + let encoded = encode_packed_tokens(&[bytes]); + let expected = "1234".decode_hex().unwrap(); + assert_eq!(encoded, expected); + } + + #[test] + fn encode_packed_mixed() { + let tokens = vec![ + Token::Int { + int: I256::from(-1), + bits: UintBits::new(256).unwrap(), + }, + Token::FixedBytes(NonEmptyBytes::new(vec![0x42]).unwrap()), + Token::Uint { + uint: U256::from(3_u64), + bits: UintBits::new(256).unwrap(), + }, + Token::String("Hello, world!".to_owned()), + ]; + let encoded = encode_packed_tokens(&tokens); + // The expected value must match the packed representation of the tokens. + // The integer -1 as 32 bytes of f, followed by 0x42, followed by the integer 3, + // followed by the ASCII representation of "Hello, world!" + let expected = concat!( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // -1 + "42", // 0x42 + "03", // 3 + "48656c6c6f2c20776f726c6421" // "Hello, world!" in ASCII + ).decode_hex().unwrap(); + assert_eq!(encoded, expected); + } + + #[test] + fn encode_packed_array() { + let array = Token::Array { + arr: vec![ + Token::Uint { + uint: U256::from(1_u64), + bits: UintBits::new(256).unwrap(), + }, + Token::Uint { + uint: U256::from(2_u64), + bits: UintBits::new(256).unwrap(), + }, + Token::Uint { + uint: U256::from(3_u64), + bits: UintBits::new(256).unwrap(), + }, + ], + kind: ParamType::Uint { bits: UintBits::new(256).unwrap() }, + }; + let encoded = encode_packed_tokens(&[array]); + + let expected = Vec::from_hex("010203").unwrap(); + + assert_eq!(encoded, expected); + } +} \ No newline at end of file diff --git a/rust/tw_evm/src/address.rs b/rust/tw_evm/src/address.rs index 8cff9fb514d..3dbccb82b7b 100644 --- a/rust/tw_evm/src/address.rs +++ b/rust/tw_evm/src/address.rs @@ -33,6 +33,12 @@ pub struct Address { bytes: H160, } +impl AsRef<[u8]> for Address { + fn as_ref(&self) -> &[u8] { + self.bytes.as_slice() + } +} + /// cbindgen:ignore impl Address { pub const LEN: usize = 20; diff --git a/rust/tw_number/src/i256.rs b/rust/tw_number/src/i256.rs index 49a617c4d6f..4b15dc9a6a1 100644 --- a/rust/tw_number/src/i256.rs +++ b/rust/tw_number/src/i256.rs @@ -19,7 +19,7 @@ lazy_static! { #[derive(Clone, PartialEq)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct I256(BaseU256); +pub struct I256(pub BaseU256); // cbindgen:ignore impl I256 { diff --git a/rust/tw_number/src/u256.rs b/rust/tw_number/src/u256.rs index a4285f739b4..c747fffae76 100644 --- a/rust/tw_number/src/u256.rs +++ b/rust/tw_number/src/u256.rs @@ -13,7 +13,7 @@ use tw_memory::Data; #[derive(Copy, Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct U256(pub(crate) primitive_types::U256); +pub struct U256(pub primitive_types::U256); impl From for U256 { #[inline] From 31937eac7af785765dae80d39801cbd54cbe31db Mon Sep 17 00:00:00 2001 From: theghostmac Date: Tue, 28 May 2024 18:24:35 +0100 Subject: [PATCH 2/7] [Ethereum]: Add support for abi.encodePacked() | addressed code review comments --- rust/Cargo.lock | 1 - rust/tw_evm/Cargo.toml | 1 - rust/tw_evm/src/abi/encode.rs | 134 +++++++++++++++++++------ rust/tw_evm/src/abi/non_empty_array.rs | 21 ++++ rust/tw_number/src/i256.rs | 14 ++- rust/tw_number/src/u256.rs | 14 ++- 6 files changed, 150 insertions(+), 35 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 6d16a2e590d..3d7c0c29603 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1820,7 +1820,6 @@ dependencies = [ name = "tw_evm" version = "0.1.0" dependencies = [ - "hex", "itertools", "lazy_static", "rlp", diff --git a/rust/tw_evm/Cargo.toml b/rust/tw_evm/Cargo.toml index fd1116a0f03..857a8f1bd5a 100644 --- a/rust/tw_evm/Cargo.toml +++ b/rust/tw_evm/Cargo.toml @@ -17,7 +17,6 @@ tw_memory = { path = "../tw_memory" } tw_misc = { path = "../tw_misc" } tw_number = { path = "../tw_number" } tw_proto = { path = "../tw_proto" } -hex = "0.4.3" [dev-dependencies] tw_coin_entry = { path = "../tw_coin_entry", features = ["test-utils"] } diff --git a/rust/tw_evm/src/abi/encode.rs b/rust/tw_evm/src/abi/encode.rs index a79235752ad..54c7b1d2e38 100644 --- a/rust/tw_evm/src/abi/encode.rs +++ b/rust/tw_evm/src/abi/encode.rs @@ -5,7 +5,6 @@ use crate::abi::token::Token; use tw_hash::H256; use tw_memory::Data; -use crate::abi::uint::UintBits; pub fn encode_tokens(tokens: &[Token]) -> Data { let mediates = tokens.iter().map(mediate_token).collect::>(); @@ -218,17 +217,23 @@ pub fn encode_packed_tokens(tokens: &[Token]) -> Data { encoded.extend_from_slice(s.as_bytes()); }, Token::FixedBytes(bytes) => { - encoded.extend_from_slice(bytes); + encoded.extend_from_slice(bytes.as_ref()); }, - Token::Int { int, .. } => { - let buf = int.to_big_endian(); - let trimmed_buf = trim_leading_zeros(buf.as_slice()); - encoded.extend_from_slice(trimmed_buf); + Token::Int { int, bits } => { + let buf = int.to_big_endian().as_slice().to_vec(); + let bits_value = bits.get(); + let padding_len = (bits_value / 8) - buf.len(); + let padding = vec![0; padding_len]; + encoded.extend_from_slice(&padding); + encoded.extend_from_slice(&buf); }, - Token::Uint { uint, .. } => { - let buf = uint.to_big_endian(); - let trimmed_buf = trim_leading_zeros(buf.as_slice()); - encoded.extend_from_slice(trimmed_buf); + Token::Uint { uint, bits } => { + let buf = uint.to_big_endian().as_slice().to_vec(); + let bits_value = bits.get(); + let padding_len = (bits_value / 8) - buf.len(); + let padding = vec![0; padding_len]; + encoded.extend_from_slice(&padding); + encoded.extend_from_slice(&buf); }, Token::Bool(b) => { encoded.push(*b as u8); @@ -256,22 +261,18 @@ pub fn encode_packed_tokens(tokens: &[Token]) -> Data { encoded } -fn trim_leading_zeros(buf: &[u8]) -> &[u8] { - let first_non_zero = buf.iter().position(|&x| x != 0).unwrap_or(buf.len() - 1); - &buf[first_non_zero..] -} - #[cfg(test)] mod tests { - use hex::FromHex; + use std::str::FromStr; use super::*; use crate::abi::non_empty_array::{NonEmptyArray, NonEmptyBytes}; use crate::abi::param::Param; use crate::abi::param_token::NamedToken; use crate::abi::param_type::constructor::TypeConstructor; use crate::abi::param_type::ParamType; - use tw_encoding::hex::DecodeHex; + use tw_encoding::hex::{DecodeHex}; use tw_number::{I256, U256}; + use crate::abi::uint::UintBits; #[test] fn encode_address() { @@ -1214,25 +1215,16 @@ mod tests { #[test] fn encode_packed_mixed() { let tokens = vec![ - Token::Int { - int: I256::from(-1), - bits: UintBits::new(256).unwrap(), - }, + Token::Int { int: I256::from(-1), bits: UintBits::new(256).unwrap() }, Token::FixedBytes(NonEmptyBytes::new(vec![0x42]).unwrap()), - Token::Uint { - uint: U256::from(3_u64), - bits: UintBits::new(256).unwrap(), - }, + Token::Uint { uint: U256::from(3_u64), bits: UintBits::new(256).unwrap() }, Token::String("Hello, world!".to_owned()), ]; let encoded = encode_packed_tokens(&tokens); - // The expected value must match the packed representation of the tokens. - // The integer -1 as 32 bytes of f, followed by 0x42, followed by the integer 3, - // followed by the ASCII representation of "Hello, world!" let expected = concat!( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // -1 + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // -1 padded "42", // 0x42 - "03", // 3 + "0000000000000000000000000000000000000000000000000000000000000003", // 3 padded "48656c6c6f2c20776f726c6421" // "Hello, world!" in ASCII ).decode_hex().unwrap(); assert_eq!(encoded, expected); @@ -1259,7 +1251,87 @@ mod tests { }; let encoded = encode_packed_tokens(&[array]); - let expected = Vec::from_hex("010203").unwrap(); + let expected = tw_encoding::hex::decode("010203").unwrap(); + + assert_eq!(encoded, expected); + } + + #[test] + fn encode_packed_uint_256bits() { + let uint = Token::Uint { + uint: U256::from(3_u64), + bits: UintBits::new(256).unwrap(), + }; + let encoded = encode_packed_tokens(&[uint]); + let expected = "0000000000000000000000000000000000000000000000000000000000000003" + .decode_hex() + .unwrap(); + assert_eq!(encoded, expected); + } + + #[test] + fn encode_packed_int_256bits() { + let int = Token::Int { + int: I256::from(3), + bits: UintBits::new(256).unwrap(), + }; + let encoded = encode_packed_tokens(&[int]); + let expected = "0000000000000000000000000000000000000000000000000000000000000003" + .decode_hex() + .unwrap(); + assert_eq!(encoded, expected); + } + + #[test] + fn encode_packed_custom_case() { + // bytes32 stateRoots + let state_roots = NonEmptyBytes::from_slice( + "3a53dc4890241dbe03e486e785761577d1c369548f6b09aa38017828dcdf5c27" + .decode_hex() + .unwrap() + .as_slice(), + ).unwrap(); + + // uint256[2] calldata signatures + let signatures = Token::Array { + arr: vec![ + Token::Uint { + uint: U256::from_str( + "3402053321874964899321528271743396700217057178612185975187363512030360053932" + ).unwrap(), + bits: UintBits::new(256).unwrap(), + }, + Token::Uint { + uint: U256::from_str( + "1235124644010117237054094970590473241953434069965207718920579820322861537001" + ).unwrap(), + bits: UintBits::new(256).unwrap(), + }, + ], + kind: ParamType::Uint { + bits: UintBits::new(256).unwrap(), + }, + }; + + // uint256 feeReceivers + let fee_receivers = Token::Uint { + uint: U256::zero(), + bits: UintBits::new(256).unwrap(), + }; + + // bytes calldata txss + let txss = Token::Bytes( + "000000000000000100010000" + .decode_hex() + .unwrap(), + ); + + let tokens = vec![Token::FixedBytes(state_roots), signatures, fee_receivers, txss]; + let encoded = encode_packed_tokens(&tokens); + + let expected = "3a53dc4890241dbe03e486e785761577d1c369548f6b09aa38017828dcdf5c2707857e73108d077c5b7ef89540d6493f70d940f1763a9d34c9d98418a39d28ac02bb0e4743a7d0586711ee3dd6311256579ab7abcd53c9c76f040bfde4d6d6e90000000000000000000000000000000000000000000000000000000000000000000000000000000100010000" + .decode_hex() + .unwrap(); assert_eq!(encoded, expected); } diff --git a/rust/tw_evm/src/abi/non_empty_array.rs b/rust/tw_evm/src/abi/non_empty_array.rs index 5b1c803dca5..517f322c101 100644 --- a/rust/tw_evm/src/abi/non_empty_array.rs +++ b/rust/tw_evm/src/abi/non_empty_array.rs @@ -56,6 +56,27 @@ impl NonEmptyArray { pub fn into_vec(self) -> Vec { self.0 } + + pub fn get(&self) -> &Vec { + &self.0 + } + + pub fn set(&mut self, value: Vec) { + if value.is_empty() { + panic!("`NonEmptyArray` must have at least one element"); + } + self.0 = value; + } + + pub fn from_slice(slice: &[T]) -> AbiResult + where + T: Clone, + { + if slice.is_empty() { + return AbiError::err(AbiErrorKind::Error_empty_type); + } + Ok(NonEmptyArray(slice.to_vec())) + } } impl IntoIterator for NonEmptyArray { diff --git a/rust/tw_number/src/i256.rs b/rust/tw_number/src/i256.rs index 4b15dc9a6a1..73c6d8d1d35 100644 --- a/rust/tw_number/src/i256.rs +++ b/rust/tw_number/src/i256.rs @@ -19,7 +19,7 @@ lazy_static! { #[derive(Clone, PartialEq)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct I256(pub BaseU256); +pub struct I256(BaseU256); // cbindgen:ignore impl I256 { @@ -117,6 +117,18 @@ impl I256 { } } +impl I256 { + // Getter method for the internal value + pub fn get_value(&self) -> BaseU256 { + self.0 + } + + // Setter method for the internal value + pub fn set_value(&mut self, value: BaseU256) { + self.0 = value; + } +} + #[cfg(feature = "helpers")] impl I256 { #[inline] diff --git a/rust/tw_number/src/u256.rs b/rust/tw_number/src/u256.rs index c747fffae76..0ecd37eaac9 100644 --- a/rust/tw_number/src/u256.rs +++ b/rust/tw_number/src/u256.rs @@ -13,7 +13,7 @@ use tw_memory::Data; #[derive(Copy, Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct U256(pub primitive_types::U256); +pub struct U256(pub(crate) primitive_types::U256); impl From for U256 { #[inline] @@ -146,6 +146,18 @@ impl U256 { } } +impl U256 { + // Getter method for the internal value + pub fn get_value(&self) -> primitive_types::U256 { + self.0 + } + + // Setter method for the internal value + pub fn set_value(&mut self, value: primitive_types::U256) { + self.0 = value; + } +} + #[cfg(feature = "helpers")] impl U256 { #[inline] From 8352174f0e61aedf0d56a53610483ea7928d0107 Mon Sep 17 00:00:00 2001 From: theghostmac Date: Wed, 29 May 2024 09:10:07 +0100 Subject: [PATCH 3/7] [Ethereum]: Add support for abi.encodePacked() | addressed code review comments --- rust/tw_evm/src/abi/encode.rs | 11 +++++------ rust/tw_evm/src/abi/non_empty_array.rs | 17 ----------------- rust/tw_number/src/i256.rs | 12 ------------ rust/tw_number/src/u256.rs | 12 ------------ 4 files changed, 5 insertions(+), 47 deletions(-) diff --git a/rust/tw_evm/src/abi/encode.rs b/rust/tw_evm/src/abi/encode.rs index 54c7b1d2e38..6d130fcc9b7 100644 --- a/rust/tw_evm/src/abi/encode.rs +++ b/rust/tw_evm/src/abi/encode.rs @@ -1285,12 +1285,11 @@ mod tests { #[test] fn encode_packed_custom_case() { // bytes32 stateRoots - let state_roots = NonEmptyBytes::from_slice( - "3a53dc4890241dbe03e486e785761577d1c369548f6b09aa38017828dcdf5c27" - .decode_hex() - .unwrap() - .as_slice(), - ).unwrap(); + // bytes32 stateRoots + let state_roots_hex = "3a53dc4890241dbe03e486e785761577d1c369548f6b09aa38017828dcdf5c27" + .decode_hex() + .unwrap(); + let state_roots = NonEmptyBytes::new(state_roots_hex).unwrap(); // uint256[2] calldata signatures let signatures = Token::Array { diff --git a/rust/tw_evm/src/abi/non_empty_array.rs b/rust/tw_evm/src/abi/non_empty_array.rs index 517f322c101..f1e93f10851 100644 --- a/rust/tw_evm/src/abi/non_empty_array.rs +++ b/rust/tw_evm/src/abi/non_empty_array.rs @@ -60,23 +60,6 @@ impl NonEmptyArray { pub fn get(&self) -> &Vec { &self.0 } - - pub fn set(&mut self, value: Vec) { - if value.is_empty() { - panic!("`NonEmptyArray` must have at least one element"); - } - self.0 = value; - } - - pub fn from_slice(slice: &[T]) -> AbiResult - where - T: Clone, - { - if slice.is_empty() { - return AbiError::err(AbiErrorKind::Error_empty_type); - } - Ok(NonEmptyArray(slice.to_vec())) - } } impl IntoIterator for NonEmptyArray { diff --git a/rust/tw_number/src/i256.rs b/rust/tw_number/src/i256.rs index 73c6d8d1d35..49a617c4d6f 100644 --- a/rust/tw_number/src/i256.rs +++ b/rust/tw_number/src/i256.rs @@ -117,18 +117,6 @@ impl I256 { } } -impl I256 { - // Getter method for the internal value - pub fn get_value(&self) -> BaseU256 { - self.0 - } - - // Setter method for the internal value - pub fn set_value(&mut self, value: BaseU256) { - self.0 = value; - } -} - #[cfg(feature = "helpers")] impl I256 { #[inline] diff --git a/rust/tw_number/src/u256.rs b/rust/tw_number/src/u256.rs index 0ecd37eaac9..a4285f739b4 100644 --- a/rust/tw_number/src/u256.rs +++ b/rust/tw_number/src/u256.rs @@ -146,18 +146,6 @@ impl U256 { } } -impl U256 { - // Getter method for the internal value - pub fn get_value(&self) -> primitive_types::U256 { - self.0 - } - - // Setter method for the internal value - pub fn set_value(&mut self, value: primitive_types::U256) { - self.0 = value; - } -} - #[cfg(feature = "helpers")] impl U256 { #[inline] From 75694be0daf141552ac12a5aedc4157b87e654e3 Mon Sep 17 00:00:00 2001 From: theghostmac Date: Wed, 29 May 2024 11:26:49 +0100 Subject: [PATCH 4/7] [Ethereum]: Add support for abi.encodePacked() | addressed code review comments --- rust/tw_evm/src/abi/encode.rs | 21 ++++++++++----------- rust/tw_number/src/i256.rs | 4 ++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/rust/tw_evm/src/abi/encode.rs b/rust/tw_evm/src/abi/encode.rs index 6d130fcc9b7..053f3b06627 100644 --- a/rust/tw_evm/src/abi/encode.rs +++ b/rust/tw_evm/src/abi/encode.rs @@ -220,7 +220,7 @@ pub fn encode_packed_tokens(tokens: &[Token]) -> Data { encoded.extend_from_slice(bytes.as_ref()); }, Token::Int { int, bits } => { - let buf = int.to_big_endian().as_slice().to_vec(); + let buf = int.to_big_endian_compact_min_len(32).as_slice().to_vec(); let bits_value = bits.get(); let padding_len = (bits_value / 8) - buf.len(); let padding = vec![0; padding_len]; @@ -228,7 +228,7 @@ pub fn encode_packed_tokens(tokens: &[Token]) -> Data { encoded.extend_from_slice(&buf); }, Token::Uint { uint, bits } => { - let buf = uint.to_big_endian().as_slice().to_vec(); + let buf = uint.to_big_endian_compact_min_len(32).as_slice().to_vec(); let bits_value = bits.get(); let padding_len = (bits_value / 8) - buf.len(); let padding = vec![0; padding_len]; @@ -1284,26 +1284,25 @@ mod tests { #[test] fn encode_packed_custom_case() { - // bytes32 stateRoots // bytes32 stateRoots let state_roots_hex = "3a53dc4890241dbe03e486e785761577d1c369548f6b09aa38017828dcdf5c27" .decode_hex() - .unwrap(); - let state_roots = NonEmptyBytes::new(state_roots_hex).unwrap(); + .unwrap() + .to_vec(); + let state_roots = NonEmptyArray::new(state_roots_hex).unwrap(); + + let uint1 = "3402053321874964899321528271743396700217057178612185975187363512030360053932"; + let uint2 = "1235124644010117237054094970590473241953434069965207718920579820322861537001"; // uint256[2] calldata signatures let signatures = Token::Array { arr: vec![ Token::Uint { - uint: U256::from_str( - "3402053321874964899321528271743396700217057178612185975187363512030360053932" - ).unwrap(), + uint: U256::from_str(uint1).unwrap(), bits: UintBits::new(256).unwrap(), }, Token::Uint { - uint: U256::from_str( - "1235124644010117237054094970590473241953434069965207718920579820322861537001" - ).unwrap(), + uint: U256::from_str(uint2).unwrap(), bits: UintBits::new(256).unwrap(), }, ], diff --git a/rust/tw_number/src/i256.rs b/rust/tw_number/src/i256.rs index 49a617c4d6f..01073226d21 100644 --- a/rust/tw_number/src/i256.rs +++ b/rust/tw_number/src/i256.rs @@ -81,6 +81,10 @@ impl I256 { self.to_u256_repr().to_big_endian_compact() } + pub fn to_big_endian_compact_min_len(&self, min_len: usize) -> Data { + self.to_u256_repr().to_big_endian_compact_min_len(min_len) + } + /// Returns the sign of the integer. pub fn sign(&self) -> Sign { let most_significant_bit = self.0 & *NEGATIVE_BIT_MASK; From ed6e71b01eafaae03e4f3d233ea116a3e7c4c173 Mon Sep 17 00:00:00 2001 From: theghostmac Date: Wed, 29 May 2024 11:36:22 +0100 Subject: [PATCH 5/7] [Ethereum]: Add support for abi.encodePacked() | addressed code review comments --- rust/tw_evm/src/abi/encode.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/tw_evm/src/abi/encode.rs b/rust/tw_evm/src/abi/encode.rs index 053f3b06627..670876b651c 100644 --- a/rust/tw_evm/src/abi/encode.rs +++ b/rust/tw_evm/src/abi/encode.rs @@ -1258,26 +1258,26 @@ mod tests { #[test] fn encode_packed_uint_256bits() { + let uint1 = "0000000000000000000000000000000000000000000000000000000000000003"; let uint = Token::Uint { uint: U256::from(3_u64), bits: UintBits::new(256).unwrap(), }; let encoded = encode_packed_tokens(&[uint]); - let expected = "0000000000000000000000000000000000000000000000000000000000000003" - .decode_hex() + let expected = uint1.decode_hex() .unwrap(); assert_eq!(encoded, expected); } #[test] fn encode_packed_int_256bits() { + let uint1 = "0000000000000000000000000000000000000000000000000000000000000003"; let int = Token::Int { int: I256::from(3), bits: UintBits::new(256).unwrap(), }; let encoded = encode_packed_tokens(&[int]); - let expected = "0000000000000000000000000000000000000000000000000000000000000003" - .decode_hex() + let expected = uint1.decode_hex() .unwrap(); assert_eq!(encoded, expected); } From ac899c909076cf097c5013e28d9fd7444007fad5 Mon Sep 17 00:00:00 2001 From: theghostmac Date: Wed, 29 May 2024 12:08:26 +0100 Subject: [PATCH 6/7] [Ethereum]: Add support for abi.encodePacked() | addressed code review comments --- rust/tw_evm/src/abi/encode.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rust/tw_evm/src/abi/encode.rs b/rust/tw_evm/src/abi/encode.rs index 670876b651c..3c5c93f17f7 100644 --- a/rust/tw_evm/src/abi/encode.rs +++ b/rust/tw_evm/src/abi/encode.rs @@ -1287,8 +1287,7 @@ mod tests { // bytes32 stateRoots let state_roots_hex = "3a53dc4890241dbe03e486e785761577d1c369548f6b09aa38017828dcdf5c27" .decode_hex() - .unwrap() - .to_vec(); + .unwrap(); let state_roots = NonEmptyArray::new(state_roots_hex).unwrap(); let uint1 = "3402053321874964899321528271743396700217057178612185975187363512030360053932"; From e50705e215124d09b1db6f726ace0084ce7d0703 Mon Sep 17 00:00:00 2001 From: theghostmac Date: Wed, 29 May 2024 12:10:20 +0100 Subject: [PATCH 7/7] [Ethereum]: Add support for abi.encodePacked() | addressed code review comments --- rust/tw_evm/src/abi/encode.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/tw_evm/src/abi/encode.rs b/rust/tw_evm/src/abi/encode.rs index 3c5c93f17f7..dfd4af4c9df 100644 --- a/rust/tw_evm/src/abi/encode.rs +++ b/rust/tw_evm/src/abi/encode.rs @@ -828,7 +828,7 @@ mod tests { .decode_hex() .unwrap(); let encoded = encode_tokens(&[Token::Array { - arr: vec![Token::Bytes(bytes.to_vec())], + arr: vec![Token::Bytes(bytes)], kind: ParamType::Bytes, }]); @@ -854,7 +854,7 @@ mod tests { .decode_hex() .unwrap(); let encoded = encode_tokens(&[Token::Array { - arr: vec![Token::Bytes(bytes.to_vec()), Token::Bytes(bytes2.to_vec())], + arr: vec![Token::Bytes(bytes), Token::Bytes(bytes2)], kind: ParamType::Bytes, }]); @@ -930,8 +930,8 @@ mod tests { .unwrap(); let encoded = encode_tokens(&[Token::Tuple { params: vec![ - NamedToken::with_token(Token::Bytes(bytes.to_vec())), - NamedToken::with_token(Token::Bytes(bytes2.to_vec())), + NamedToken::with_token(Token::Bytes(bytes)), + NamedToken::with_token(Token::Bytes(bytes2)), ], }]);