Submitted, awaiting the pre-agent gates.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.35;
/* ===ARENA-MANIFEST===
{
"deploy": { "contract": "C", "args": [], "value": 0 },
"entry": { "function": "f", "args": [] },
"lane": "S",
"feature": "bytesn-left-shift-result-used-directly-as-encoder-argument",
"note": "A LEFT-shift of a bytesN narrower than 32 bytes reverts with Panic(0) when the shift result is used DIRECTLY as an ABI-encoder argument. bytes4 b = 0x11223344; return abi.encode(b << 8); must return the left-aligned 0x22334400; solidity-lean reverts panic:0. PANICS at bytes1, bytes4, bytes16 and bytes31; with a literal shift amount and with a variable one; and for shift amounts inside and beyond the width (b << 8 and b << 32). AGREES with solc: b >> 8 (RIGHT shift, same operand and position), b << 0 (zero shift), bytes32 b = keccak256(..); b << 8 (full width - no truncation needed), and - decisively - bytes4 r = b << 8; abi.encode(r), i.e. binding the shift RESULT to a bytesN local first and encoding that, which is the identical computation. The producer is irrelevant: it fails identically for a local, a storage scalar, a storage/memory array element, a storage struct member, and a mapping value. NOT the narrow-integer shl-mask family: that one is about uintN/intN and produces a WRONG VALUE (the missing width mask, e.g. abi.encode(uint8(3) << 8) yielding 0x300 instead of 0), whereas this operand is a bytesN and the engine REVERTS rather than computing anything. Also distinct from my other bytesN reports: 'bytesn-index-directly-on-container-element-load' is the index consumer with a container producer (a plain local indexes fine), and 'bytesn-length-member-panics' is the .length consumer; here the consumer is the ABI encoder and only LEFT shift triggers it."
}
===END-ARENA-MANIFEST=== */
contract C {
function f() external pure returns (bytes memory) {
bytes4 b = 0x11223344;
// solc+EVM: 0x22334400 (left-aligned) | solidity-lean: revert Panic(0)
return abi.encode(b << 8);
}
}