Skip to content

Commit 589fe9b

Browse files
authored
Merge pull request #732 from RickyLB/feat/bytes_32
2 parents 125c763 + 6f2db3e commit 589fe9b

File tree

1 file changed

+105
-2
lines changed

1 file changed

+105
-2
lines changed

src/contract/contract_function_parameters.rs

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use num_bigint::{
77
Sign,
88
};
99

10+
use self::private::Sealed;
1011
use crate::contract::contract_function_selector::ContractFunctionSelector;
1112
use crate::ethereum::SolidityAddress;
1213

@@ -23,6 +24,23 @@ struct Argument {
2324
is_dynamic: bool,
2425
}
2526

27+
mod private {
28+
pub trait Sealed {}
29+
impl Sealed for String {}
30+
impl Sealed for str {}
31+
impl Sealed for [u8; 32] {}
32+
}
33+
34+
pub trait AsBytes32: Sealed {
35+
fn as_bytes32(&self) -> &[u8];
36+
}
37+
38+
impl<T: Sealed + AsRef<[u8]> + ?Sized> AsBytes32 for T {
39+
fn as_bytes32(&self) -> &[u8] {
40+
self.as_ref()
41+
}
42+
}
43+
2644
trait IntEncode {
2745
fn get_is_negative_and_be_bytes(&self) -> (bool, Vec<u8>);
2846
}
@@ -190,10 +208,10 @@ impl ContractFunctionParameters {
190208
}
191209

192210
/// Add a `bytes32` argument to the `ContractFunctionParameters`
193-
pub fn add_bytes32(&mut self, val: &[u8; 32]) -> &mut Self {
211+
pub fn add_bytes32<T: AsBytes32 + ?Sized>(&mut self, val: &T) -> &mut Self {
194212
self.args.push(Argument {
195213
type_name: "bytes32",
196-
value_bytes: val.to_vec(),
214+
value_bytes: encode_array_of_32_byte(val),
197215
is_dynamic: false,
198216
});
199217
self
@@ -1013,6 +1031,17 @@ where
10131031
out_bytes
10141032
}
10151033

1034+
fn encode_array_of_32_byte<T: AsBytes32 + ?Sized>(elements: &T) -> Vec<u8> {
1035+
let slice = elements.as_bytes32();
1036+
if slice.len() > 32 {
1037+
panic!("32 bytes exceeded in contract function call")
1038+
}
1039+
1040+
let mut new_bytes = slice.to_vec();
1041+
right_pad_32_bytes(&mut new_bytes);
1042+
new_bytes
1043+
}
1044+
10161045
#[cfg(test)]
10171046
mod tests {
10181047
use num_bigint::{
@@ -1138,6 +1167,7 @@ mod tests {
11381167
ContractFunctionSelector::new("randomFunction").add_bool().clone(),
11391168
)
11401169
.to_bytes(Some("foo"));
1170+
11411171
assert_eq!(
11421172
hex::encode(param_bytes),
11431173
"c99c40cd\
@@ -1176,4 +1206,77 @@ mod tests {
11761206
6162636461626364616263646162636461626364616263646162636400000000"#]]
11771207
.assert_eq(&buf);
11781208
}
1209+
1210+
#[test]
1211+
fn string_to_bytes32() {
1212+
let s = "alice".to_string();
1213+
1214+
let bytes = ContractFunctionParameters::new().add_bytes32(&s).to_bytes(None);
1215+
1216+
// sigh, the things we do to not have to manually format.
1217+
let mut buf = String::with_capacity(bytes.len() * 2 + ((bytes.len() * 2) / 64));
1218+
for line in bytes.chunks(32).map(hex::encode) {
1219+
if !buf.is_empty() {
1220+
buf.push('\n');
1221+
}
1222+
1223+
buf.push_str(&line);
1224+
}
1225+
1226+
expect_test::expect!["616c696365000000000000000000000000000000000000000000000000000000"]
1227+
.assert_eq(&buf);
1228+
}
1229+
1230+
#[test]
1231+
fn str_to_bytes32() {
1232+
let s = "alice";
1233+
1234+
let bytes = ContractFunctionParameters::new().add_bytes32(s).to_bytes(None);
1235+
1236+
let mut buf = String::with_capacity(bytes.len() * 2 + ((bytes.len() * 2) / 64));
1237+
for line in bytes.chunks(32).map(hex::encode) {
1238+
if !buf.is_empty() {
1239+
buf.push('\n');
1240+
}
1241+
1242+
buf.push_str(&line);
1243+
}
1244+
1245+
expect_test::expect!["616c696365000000000000000000000000000000000000000000000000000000"]
1246+
.assert_eq(&buf);
1247+
}
1248+
1249+
#[test]
1250+
fn bytes_to_bytes32() {
1251+
let mut array = [0u8; 32];
1252+
1253+
let str_sample = "aliceandbob".as_bytes();
1254+
1255+
for (i, &byte) in str_sample.iter().enumerate() {
1256+
array[i] = byte;
1257+
}
1258+
1259+
let bytes = ContractFunctionParameters::new().add_bytes32(&array).to_bytes(None);
1260+
1261+
let mut buf = String::with_capacity(bytes.len() * 2 + ((bytes.len() * 2) / 64));
1262+
for line in bytes.chunks(32).map(hex::encode) {
1263+
if !buf.is_empty() {
1264+
buf.push('\n');
1265+
}
1266+
1267+
buf.push_str(&line);
1268+
}
1269+
1270+
expect_test::expect!["616c696365616e64626f62000000000000000000000000000000000000000000"]
1271+
.assert_eq(&buf);
1272+
}
1273+
1274+
#[test]
1275+
#[should_panic]
1276+
fn bytes32_panic() {
1277+
let str_sample = "alice bought some burgers from bob";
1278+
1279+
// should panic if input is more than 32 bytes in add_bytes32
1280+
ContractFunctionParameters::new().add_bytes32(str_sample).to_bytes(None);
1281+
}
11791282
}

0 commit comments

Comments
 (0)