11use crate :: Codegen ;
22use alloy_primitives:: { hex, keccak256} ;
33use huff_neo_utils:: bytecode:: { BytecodeRes , Bytes , CircularCodeSizeIndices , Jump , Jumps } ;
4- use huff_neo_utils:: bytes_util:: { bytes32_to_string , format_even_bytes, pad_n_bytes} ;
4+ use huff_neo_utils:: bytes_util:: { bytes32_to_hex_string , format_even_bytes, literal_gen , pad_n_bytes} ;
55use huff_neo_utils:: error:: { CodegenError , CodegenErrorKind } ;
66use huff_neo_utils:: evm_version:: EVMVersion ;
77use huff_neo_utils:: opcodes:: Opcode ;
@@ -98,7 +98,7 @@ pub fn builtin_function_gen<'a>(
9898 bytes. push ( ( starting_offset, Bytes ( push_bytes) ) ) ;
9999 }
100100 BuiltinFunctionKind :: RightPad => {
101- let push_bytes = right_pad ( contract, bf) ?;
101+ let push_bytes = right_pad ( evm_version , contract, bf) ?;
102102 * offset += push_bytes. len ( ) / 2 ;
103103 bytes. push ( ( starting_offset, Bytes ( push_bytes) ) ) ;
104104 }
@@ -218,6 +218,11 @@ pub fn builtin_function_gen<'a>(
218218
219219 bytes. push ( ( starting_offset, Bytes ( push_bytes) ) ) ;
220220 }
221+ BuiltinFunctionKind :: Bytes => {
222+ let push_bytes = builtin_bytes ( evm_version, bf) ?;
223+ * offset += push_bytes. len ( ) / 2 ;
224+ bytes. push ( ( starting_offset, Bytes ( push_bytes) ) ) ;
225+ }
221226 }
222227 Ok ( ( ) )
223228}
@@ -373,7 +378,7 @@ fn tablesize(contract: &Contract, bf: &BuiltinFunctionCall) -> Result<(TableDefi
373378 } ) ;
374379 } ;
375380
376- let size = bytes32_to_string ( & ir_table. size , false ) ;
381+ let size = bytes32_to_hex_string ( & ir_table. size , false ) ;
377382 let push_bytes = format ! ( "{:02x}{size}" , 95 + size. len( ) / 2 ) ;
378383 Ok ( ( ir_table, push_bytes) )
379384}
@@ -402,7 +407,7 @@ fn event_hash(contract: &Contract, bf: &BuiltinFunctionCall) -> Result<String, C
402407 } ) ;
403408 } ;
404409 let push_bytes = if let Some ( event) = contract. events . iter ( ) . find ( |e| first_arg. name . as_ref ( ) . unwrap ( ) . eq ( & e. name ) ) {
405- let hash = bytes32_to_string ( & event. hash , false ) ;
410+ let hash = bytes32_to_hex_string ( & event. hash , false ) ;
406411 format ! ( "{}{hash}" , Opcode :: Push32 )
407412 } else if let Some ( s) = & first_arg. name {
408413 let event_selector = keccak256 ( s) . 0 ;
@@ -468,7 +473,7 @@ fn function_signature(contract: &Contract, bf: &BuiltinFunctionCall) -> Result<S
468473 Ok ( push_bytes)
469474}
470475
471- fn right_pad ( contract : & Contract , bf : & BuiltinFunctionCall ) -> Result < String , CodegenError > {
476+ fn right_pad ( evm_version : & EVMVersion , contract : & Contract , bf : & BuiltinFunctionCall ) -> Result < String , CodegenError > {
472477 if bf. args . len ( ) != 1 {
473478 tracing:: error!( target = "codegen" , "Incorrect number of arguments passed to __RIGHTPAD, should be 1: {}" , bf. args. len( ) ) ;
474479 return Err ( CodegenError {
@@ -488,6 +493,10 @@ fn right_pad(contract: &Contract, bf: &BuiltinFunctionCall) -> Result<String, Co
488493 let push_bytes = function_signature ( contract, inner_call) ?;
489494 push_bytes[ 2 ..] . to_string ( ) // remove opcode
490495 }
496+ BuiltinFunctionKind :: Bytes => {
497+ let push_bytes = builtin_bytes ( evm_version, inner_call) ?;
498+ push_bytes[ 2 ..] . to_string ( ) // remove opcode
499+ }
491500 _ => {
492501 tracing:: error!( target: "codegen" , "Invalid argument type passed to __RIGHTPAD" ) ;
493502 return Err ( CodegenError {
@@ -511,3 +520,50 @@ fn right_pad(contract: &Contract, bf: &BuiltinFunctionCall) -> Result<String, Co
511520 let push_bytes = format ! ( "{}{hex}{}" , Opcode :: Push32 , "0" . repeat( 64 - hex. len( ) ) ) ;
512521 Ok ( push_bytes)
513522}
523+
524+ fn builtin_bytes ( evm_version : & EVMVersion , bf : & BuiltinFunctionCall ) -> Result < String , CodegenError > {
525+ if bf. args . len ( ) != 1 {
526+ tracing:: error!( target = "codegen" , "Incorrect number of arguments passed to __BYTES, should be 1: {}" , bf. args. len( ) ) ;
527+ return Err ( CodegenError {
528+ kind : CodegenErrorKind :: InvalidArguments ( format ! (
529+ "Incorrect number of arguments passed to __BYTES, should be 1: {}" ,
530+ bf. args. len( )
531+ ) ) ,
532+ span : bf. span . clone ( ) ,
533+ token : None ,
534+ } ) ;
535+ }
536+ let first_arg = match bf. args [ 0 ] {
537+ BuiltinFunctionArg :: Argument ( ref arg) => arg. name . clone ( ) . unwrap_or_default ( ) ,
538+ _ => {
539+ tracing:: error!( target: "codegen" , "Invalid argument type passed to __BYTES" ) ;
540+ return Err ( CodegenError {
541+ kind : CodegenErrorKind :: InvalidArguments ( String :: from ( "Invalid argument type passed to __BYTES" ) ) ,
542+ span : bf. span . clone ( ) ,
543+ token : None ,
544+ } ) ;
545+ }
546+ } ;
547+
548+ if first_arg. is_empty ( ) {
549+ return Err ( CodegenError {
550+ kind : CodegenErrorKind :: InvalidArguments ( String :: from ( "Empty string passed to __BYTES" ) ) ,
551+ span : bf. span . clone ( ) ,
552+ token : None ,
553+ } ) ;
554+ }
555+
556+ let bytes = first_arg. as_bytes ( ) ;
557+ if bytes. len ( ) > 32 {
558+ return Err ( CodegenError {
559+ kind : CodegenErrorKind :: InvalidArguments ( String :: from ( "Encoded bytes length exceeds 32 bytes" ) ) ,
560+ span : bf. span . clone ( ) ,
561+ token : None ,
562+ } ) ;
563+ }
564+ let mut bytes_array = [ 0u8 ; 32 ] ;
565+ bytes_array[ 32 - bytes. len ( ) ..] . copy_from_slice ( bytes) ;
566+
567+ let push_bytes = literal_gen ( evm_version, & bytes_array) ;
568+ Ok ( push_bytes)
569+ }
0 commit comments