Skip to content

Commit

Permalink
Fix encoding of nested static tuples in dynamic tuple (#220)
Browse files Browse the repository at this point in the history
Fixed #202

This PR fixes the "head length" calculation for nested static tuples. This would cause offsets of dynamic data (such as dynamic arrays) to be incorrectly computed in certain cases (such as encoding a dynamic array within a tuple including nested static tuples). If you consider data of:
```
Tuple( // dynamic
  Tuple( // static
    Tuple(
      Bool,
      U256,
    ),
  Array(U256),
)
```

The static tuple was incorrectly computing its "head length" to be 32 instead of 64 - in other words, nested static tuples weren't correctly being flattened. This caused the encoded offset of the dynamic array to be off by 32 bytes, and cause decoding failure described in the linked case.

### Test Plan

Added a new unit test to verify encoding is correct.

We can use Ethers.js as a reference implementation:
```
> ethers.utils.defaultAbiCoder.encode(["(((bool,uint256)),uint256[])"], [[[[false, 0x777]],[0x42,0x1337]]])
0x
0000000000000000000000000000000000000000000000000000000000000020 // offset to start of dynamic tuple data
0000000000000000000000000000000000000000000000000000000000000000 // nested static tuple bool value
0000000000000000000000000000000000000000000000000000000000000777 // nested static tuple uint value
0000000000000000000000000000000000000000000000000000000000000060 // offset to start of dynamic array *within* dynamic tuple "tail"
0000000000000000000000000000000000000000000000000000000000000002 // dynamic array length
0000000000000000000000000000000000000000000000000000000000000042 // first array value
0000000000000000000000000000000000000000000000000000000000001337 // second array value
```
  • Loading branch information
Nicholas Rodrigues Lordello authored Apr 26, 2021
1 parent 970d470 commit 987e031
Showing 1 changed file with 26 additions and 1 deletion.
27 changes: 26 additions & 1 deletion ethabi/src/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl Mediate {
fn head_len(&self) -> u32 {
match *self {
Mediate::Raw(ref raw) => 32 * raw.len() as u32,
Mediate::RawTuple(ref mediates) => 32 * mediates.len() as u32,
Mediate::RawTuple(ref mediates) => mediates.iter().map(|mediate| mediate.head_len()).sum(),
Mediate::Prefixed(_)
| Mediate::PrefixedArray(_)
| Mediate::PrefixedArrayWithLength(_)
Expand Down Expand Up @@ -812,4 +812,29 @@ mod tests {
.to_vec();
assert_eq!(encoded, expected);
}

#[test]
fn encode_dynamic_tuple_with_nested_static_tuples() {
let token = {
use crate::Token::*;
Tuple(vec![
Tuple(vec![Tuple(vec![Bool(false), Uint(0x777.into())])]),
Array(vec![Uint(0x42.into()), Uint(0x1337.into())]),
])
};
let encoded = encode(&[token]);
let expected = hex!(
"
0000000000000000000000000000000000000000000000000000000000000020
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000777
0000000000000000000000000000000000000000000000000000000000000060
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000042
0000000000000000000000000000000000000000000000000000000000001337
"
)
.to_vec();
assert_eq!(encoded, expected);
}
}

0 comments on commit 987e031

Please sign in to comment.