@@ -345,23 +345,77 @@ impl SolEncode<'_> for EmptyArgumentList<Sol> {
345
345
fn to_sol_type ( & self ) { }
346
346
}
347
347
348
- impl < ' a , Head , Rest > SolEncode < ' a > for ArgumentList < Argument < Head > , Rest , Sol >
348
+ impl < Head , Rest > SolEncode < ' _ > for ArgumentList < Argument < Head > , Rest , Sol >
349
349
where
350
- Head : SolEncode < ' a > ,
351
- Rest : SolEncode < ' a > ,
350
+ Self : SolEncodeArgsList ,
352
351
{
353
- type SolType = ( Rest :: SolType , Head :: SolType ) ;
352
+ // NOTE: Not actually used for encoding because of `encode` override below.
353
+ type SolType = ( ) ;
354
354
355
- fn encode ( & ' a self ) -> Vec < u8 > {
356
- let mut encoded = Vec :: new ( ) ;
357
- encoded. extend ( Rest :: encode ( & self . rest ) ) ;
358
- encoded. extend ( Head :: encode ( & self . head . arg ) ) ;
359
- encoded
355
+ fn encode ( & self ) -> Vec < u8 > {
356
+ let mut encoded_args_info = Vec :: new ( ) ;
357
+ // Collects encoding info for each arg in `Argument list`.
358
+ let mut offset = self . encode_args ( & mut encoded_args_info) ;
359
+ let mut head = Vec :: new ( ) ;
360
+ let mut tail = Vec :: < u8 > :: new ( ) ;
361
+
362
+ // Composes the head and tail parts of the parameter encoding.
363
+ // Ref: <https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector-and-argument-encoding>
364
+ for ( dynamic, encoded) in encoded_args_info {
365
+ if dynamic {
366
+ head. extend ( SolEncode :: encode ( & ( offset as u128 ) ) ) ;
367
+ // Standalone encoding for dynamic types includes a 32 bytes offset.
368
+ let data = & encoded[ 32 ..] ;
369
+ offset += data. len ( ) ;
370
+ tail. extend ( data) ;
371
+ } else {
372
+ head. extend ( encoded) ;
373
+ }
374
+ }
375
+
376
+ head. extend ( tail) ;
377
+ head
360
378
}
361
379
362
- fn to_sol_type ( & ' a self ) -> Self :: SolType {
363
- // NOTE: Not actually used for encoding because of `encode` override above.
364
- ( self . rest . to_sol_type ( ) , self . head . arg . to_sol_type ( ) )
380
+ // NOTE: Not actually used for encoding because of `encode` override above.
381
+ fn to_sol_type ( & self ) { }
382
+ }
383
+
384
+ /// Helper trait for Solidity ABI encoding `ArgumentList`.
385
+ trait SolEncodeArgsList {
386
+ /// Solidity ABI encodes each arg in `ArgumentList`,
387
+ /// and returns the `offset` for dynamic data for the entire argument list.
388
+ ///
389
+ /// Ref: <https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector-and-argument-encoding>
390
+ fn encode_args ( & self , results : & mut Vec < ( bool , Vec < u8 > ) > ) -> usize ;
391
+ }
392
+
393
+ impl SolEncodeArgsList for EmptyArgumentList < Sol > {
394
+ fn encode_args ( & self , _: & mut Vec < ( bool , Vec < u8 > ) > ) -> usize {
395
+ 0
396
+ }
397
+ }
398
+
399
+ impl < Head , Rest > SolEncodeArgsList for ArgumentList < Argument < Head > , Rest , Sol >
400
+ where
401
+ Head : for < ' a > SolEncode < ' a > ,
402
+ Rest : SolEncodeArgsList ,
403
+ {
404
+ fn encode_args ( & self , results : & mut Vec < ( bool , Vec < u8 > ) > ) -> usize {
405
+ let mut offset = self . rest . encode_args ( results) ;
406
+ let dynamic = <Head as SolEncode >:: DYNAMIC ;
407
+ let encoded = self . head . arg . encode ( ) ;
408
+
409
+ if dynamic {
410
+ // Dynamic types are represented (in the head) by their offset,
411
+ // which is always 32 bytes long.
412
+ offset += 32 ;
413
+ } else {
414
+ offset += encoded. len ( ) ;
415
+ }
416
+
417
+ results. push ( ( dynamic, encoded) ) ;
418
+ offset
365
419
}
366
420
}
367
421
@@ -407,4 +461,20 @@ mod tests {
407
461
<( i32 , bool , [ u8 ; 4 ] ) as scale:: Decode >:: decode ( & mut & encoded[ ..] ) . unwrap ( ) ;
408
462
assert_eq ! ( decoded, ( 42i32 , true , [ 0x66 ; 4 ] ) ) ;
409
463
}
464
+
465
+ #[ test]
466
+ fn sol_encoding_arguments_works ( ) {
467
+ let args_list = EmptyArgumentList :: < Sol > :: empty ( )
468
+ . push_arg ( 100u8 )
469
+ . push_arg ( vec ! [ 1 , 2 , 3 , 4 ] )
470
+ . push_arg ( String :: from ( "Hello, world!" ) )
471
+ . push_arg ( true ) ;
472
+ let encoded_args_list = SolEncode :: encode ( & args_list) ;
473
+
474
+ let args_tuple = ( 100u8 , vec ! [ 1 , 2 , 3 , 4 ] , String :: from ( "Hello, world!" ) , true ) ;
475
+ let encoded_args_tuple =
476
+ ink_primitives:: sol:: SolParamsEncode :: encode ( & args_tuple) ;
477
+
478
+ assert_eq ! ( encoded_args_list, encoded_args_tuple) ;
479
+ }
410
480
}
0 commit comments