1

I've been messing around with the abi.encode... functions and I think I have a good grasp of the differences, except abi.encode and abi.encodeWithSelector. Because, they give similar but slightly different results, so I'm not sure when to use one or the other.

  abi.encodeWithSelector(bytes4(keccak256("add(uint256,uint256)")), 10,10);
  abi.encode(bytes4(keccak256("add(uint256,uint256)")), 10, 10);

The output of encodeWithSelector is

0x771602f7000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a

and the output of encode is

0x771602f700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a

and when I use delegatecall the return value of encodeWithSelector is 20, as expected, but encode is 42949672960

1 Answer 1

1

The normal abi.encode encodes values according to the abicoder. A bytes4 value is padded to 32 bytes

0x771602f700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a
  ^ first 32 byte word                                            ^ second 32 byte word                                           ^ third 32 byte word

Using abi.encodeWithSelector allows you to correctly encode function calldata by adding a 4 bytes selector at the beginning (which can also be accessed using add.selector). The encoding becomes

0x771602f7000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a
  ^ 4 bytes selector
          ^ first 32 byte word                                            ^ second 32 byte word

When using encode, the function reads the parameters from calldata with their expected offset. When incorrectly encoding with abi.encode, the first parameter (first 32 bytes after the 4 bytes selector) are 0, the second 32 bytes read a00000000, because of how the calldata is shifted now, as can be seen here (the third word is simply ignored):

0x771602f700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a
  ^ 4 bytes selector
          ^ first 32 byte word                                            ^ second 32 byte word                                           ^ third 32 byte word

0xa00000000 is 42949672960 encoded. So abi.encode essentially returns the result of add(0, 42949672960)

3
  • Thank you for the detailed answer. But then in what situation would I use encode?
    – Pedro
    Jun 6, 2022 at 13:30
  • It's often used for calculating the keccak256 hash of some data (it requires bytes as input). Or when sending arbitrary data (to another contract for example) it can be encoded as bytes and then decoded later. This is for example done for L1 <-> L2 message passing.
    – phaze
    Jun 6, 2022 at 14:12
  • thank you for the clarification
    – Pedro
    Jun 6, 2022 at 14:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.