On March 10th, 2022, the Solidity team discovered a bug in the implementation of
abi.encodeCall when used together with fixed-length bytes literals.
It was introduced together with
abi.encodeCall in Solidity 0.8.11 and is fixed in 0.8.13.
We assigned the bug a severity of “very low”.
Which Contracts are Affected?
You might be affected if you use
abi.encodeCall(f, (...)) where
f takes a
bytesNN parameter and you provide the value for that parameter either as a
hex literal (
as a string literal (
If you only pass variables to
abi.encodeCall, your code is not affected.
The compiler did check that the types of the values are all implicitly convertible
to the types of the parameters of the function (this was the main advantage of
abi.encode and the reason for adding the feature),
but it did not take the types properly into account when generating the code for
this function call. The generated code was still the same as the one for
abi.encode, which just encodes according to the types of the arguments.
The problem is that literals like
"abcd" can be implicitly converted to
different types: The first can be converted to both
uint16 and the
second can be converted to
In the first case, the compiler chose to encode
0x1234 as a
uint16. This means it
right-aligned it instead of left-aligning it for
bytes2. In the second case, it
was encoded as
bytes memory, which is a dynamic type, and thus at the place of
bytes4 value, an offset pointer was stored and additional data was added at the end.
Since the bug is only present for literals (actual variables have proper types and implicit conversions are always no-ops), it should be easy to detect with simple testing.