@@ -7,6 +7,7 @@ use num_bigint::{
77 Sign ,
88} ;
99
10+ use self :: private:: Sealed ;
1011use crate :: contract:: contract_function_selector:: ContractFunctionSelector ;
1112use 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+
2644trait 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) ]
10171046mod 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