Let's declare a few variables:
➜ uint16 a = 2344
➜ uint16 b = 359
➜ address _addr = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
2344 = 0x928 and 359 = 0x167
When using abi.encode:
➜ abi.encode(a, b, _addr)
Type: dynamic bytes
├ Hex (Memory):
├─ Length ([0x00:0x20]): 0x0000000000000000000000000000000000000000000000000000000000000060
├─ Contents ([0x20:..]): 0x000000000000000000000000000000000000000000000000000000000000092800000000000000000000000000000000000000000000000000000000000001670000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4
├ Hex (Tuple Encoded):
├─ Pointer ([0x00:0x20]): 0x0000000000000000000000000000000000000000000000000000000000000020
├─ Length ([0x20:0x40]): 0x0000000000000000000000000000000000000000000000000000000000000060
└─ Contents ([0x40:..]): 0x000000000000000000000000000000000000000000000000000000000000092800000000000000000000000000000000000000000000000000000000000001670000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4
- Splitting the single line output:
0x0000000000000000000000000000000000000000000000000000000000000928 0x0000000000000000000000000000000000000000000000000000000000000167 0x0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4
Here we can see that it follows the abi encoding specifications.
Now what if I have a scenario where I want to concatenate them or in the sense just pack all of them into one, why waste the extra space ?
When using abi.encodepacked()
➜ abi.encodePacked(a, b, _addr)
Type: dynamic bytes
├ Hex (Memory):
├─ Length ([0x00:0x20]): 0x0000000000000000000000000000000000000000000000000000000000000018
├─ Contents ([0x20:..]): 0x092801675b38da6a701c568545dcfcb03fcb875f56beddc40000000000000000
├ Hex (Tuple Encoded):
├─ Pointer ([0x00:0x20]): 0x0000000000000000000000000000000000000000000000000000000000000020
├─ Length ([0x20:0x40]): 0x0000000000000000000000000000000000000000000000000000000000000018
└─ Contents ([0x40:..]): 0x092801675b38da6a701c568545dcfcb03fcb875f56beddc40000000000000000
Output: 0x092801675b38da6a701c568545dcfcb03fcb875f56beddc40000000000000000
Here we can see that all the variables has been packed together, both the uints and the address.
- Hashing using abi.encodePacked() is not recommended because hash collisions can occur since the values are concatenated, Here's an example.
Using "AAA","BBB"
➜ abi.encodePacked("AAA","BBB")
Type: dynamic bytes
├ Hex (Memory):
├─ Length ([0x00:0x20]): 0x0000000000000000000000000000000000000000000000000000000000000006
├─ Contents ([0x20:..]): 0x4141414242420000000000000000000000000000000000000000000000000000
├ Hex (Tuple Encoded):
├─ Pointer ([0x00:0x20]): 0x0000000000000000000000000000000000000000000000000000000000000020
├─ Length ([0x20:0x40]): 0x0000000000000000000000000000000000000000000000000000000000000006
└─ Contents ([0x40:..]): 0x4141414242420000000000000000000000000000000000000000000000000000
Output: 0x4141414242420000000000000000000000000000000000000000000000000000
Now let's encode it with "AA", "ABBB"
➜ abi.encodePacked("AA","ABBB")
Type: dynamic bytes
├ Hex (Memory):
├─ Length ([0x00:0x20]): 0x0000000000000000000000000000000000000000000000000000000000000006
├─ Contents ([0x20:..]): 0x4141414242420000000000000000000000000000000000000000000000000000
├ Hex (Tuple Encoded):
├─ Pointer ([0x00:0x20]): 0x0000000000000000000000000000000000000000000000000000000000000020
├─ Length ([0x20:0x40]): 0x0000000000000000000000000000000000000000000000000000000000000006
└─ Contents ([0x40:..]): 0x4141414242420000000000000000000000000000000000000000000000000000
Output: 0x4141414242420000000000000000000000000000000000000000000000000000
It also produces the same output because it's being concatenated and packed.