Skip to content

Commit 87db54b

Browse files
committed
env: Fix SolEncode implementation for ArgumentList
1 parent 14a5a46 commit 87db54b

File tree

1 file changed

+82
-12
lines changed

1 file changed

+82
-12
lines changed

crates/env/src/call/execution.rs

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -345,23 +345,77 @@ impl SolEncode<'_> for EmptyArgumentList<Sol> {
345345
fn to_sol_type(&self) {}
346346
}
347347

348-
impl<'a, Head, Rest> SolEncode<'a> for ArgumentList<Argument<Head>, Rest, Sol>
348+
impl<Head, Rest> SolEncode<'_> for ArgumentList<Argument<Head>, Rest, Sol>
349349
where
350-
Head: SolEncode<'a>,
351-
Rest: SolEncode<'a>,
350+
Self: SolEncodeArgsList,
352351
{
353-
type SolType = (Rest::SolType, Head::SolType);
352+
// NOTE: Not actually used for encoding because of `encode` override below.
353+
type SolType = ();
354354

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
360378
}
361379

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
365419
}
366420
}
367421

@@ -407,4 +461,20 @@ mod tests {
407461
<(i32, bool, [u8; 4]) as scale::Decode>::decode(&mut &encoded[..]).unwrap();
408462
assert_eq!(decoded, (42i32, true, [0x66; 4]));
409463
}
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+
}
410480
}

0 commit comments

Comments
 (0)