diff --git a/contracts/modules/utils/L2Compressor.sol b/contracts/modules/utils/L2Compressor.sol index f1218879..d4d0cc8d 100644 --- a/contracts/modules/utils/L2Compressor.sol +++ b/contracts/modules/utils/L2Compressor.sol @@ -8,8 +8,6 @@ import "../commons/submodules/auth/SequenceBaseSig.sol"; import "../../utils/LibBytesPointer.sol"; import "../../utils/LibBytes.sol"; -import "forge-std/console.sol"; - function bytesToUint256( bytes memory _b ) pure returns (uint256 result) { diff --git a/foundry_test/modules/utils/L2CompressorEncoder.sol b/foundry_test/modules/utils/L2CompressorEncoder.sol index c1ae0d7e..2e2891dd 100644 --- a/foundry_test/modules/utils/L2CompressorEncoder.sol +++ b/foundry_test/modules/utils/L2CompressorEncoder.sol @@ -148,6 +148,10 @@ function packToBytes(uint256 value, uint256 b) pure returns (bytes memory) { } } +function encodeWord(bytes32 _value) pure returns (bytes memory) { + return encodeWord(uint256(_value)); +} + function encodeWord(uint256 _value) pure returns (bytes memory) { uint8 b = requiredBytesFor(_value); return abi.encodePacked(b, packToBytes(_value, b)); @@ -187,3 +191,31 @@ function encode_raw_address(address _addr) pure returns (bytes memory) { function encode_bytes_n(bytes memory _data) pure returns (bytes memory) { return abi.encodePacked(uint8(0x2b), encodeWord(_data.length), _data); } + +function encode_abi_call(bytes4 _selector) pure returns (bytes memory) { + return abi.encodePacked(uint8(0x2d), _selector); +} + +function encode_abi_call(bytes4 _selector, bytes32 _v1) pure returns (bytes memory) { + return abi.encodePacked(uint8(0x2e), _selector, encodeWord(_v1)); +} + +function encode_abi_call(bytes4 _selector, bytes32 _v1, bytes32 _v2) pure returns (bytes memory) { + return abi.encodePacked(uint8(0x2f), _selector, encodeWord(_v1), encodeWord(_v2)); +} + +function encode_abi_call(bytes4 _selector, bytes32 _v1, bytes32 _v2, bytes32 _v3) pure returns (bytes memory) { + return abi.encodePacked(uint8(0x30), _selector, encodeWord(_v1), encodeWord(_v2), encodeWord(_v3)); +} + +function encode_abi_call(bytes4 _selector, bytes32 _v1, bytes32 _v2, bytes32 _v3, bytes32 _v4) pure returns (bytes memory) { + return abi.encodePacked(uint8(0x31), _selector, encodeWord(_v1), encodeWord(_v2), encodeWord(_v3), encodeWord(_v4)); +} + +function encode_abi_call(bytes4 _selector, bytes32 _v1, bytes32 _v2, bytes32 _v3, bytes32 _v4, bytes32 _v5) pure returns (bytes memory) { + return abi.encodePacked(uint8(0x32), _selector, encodeWord(_v1), encodeWord(_v2), encodeWord(_v3), encodeWord(_v4), encodeWord(_v5)); +} + +function encode_abi_call(bytes4 _selector, bytes32 _v1, bytes32 _v2, bytes32 _v3, bytes32 _v4, bytes32 _v5, bytes32 _v6) pure returns (bytes memory) { + return abi.encodePacked(uint8(0x33), _selector, encodeWord(_v1), encodeWord(_v2), encodeWord(_v3), encodeWord(_v4), encodeWord(_v5), encodeWord(_v6)); +} diff --git a/foundry_test/modules/utils/L2CompressorHuffReadFlag.t.sol b/foundry_test/modules/utils/L2CompressorHuffReadFlag.t.sol index ccd4f960..f3d42dc6 100644 --- a/foundry_test/modules/utils/L2CompressorHuffReadFlag.t.sol +++ b/foundry_test/modules/utils/L2CompressorHuffReadFlag.t.sol @@ -9,6 +9,8 @@ import "forge-std/console2.sol"; import { HuffConfig } from "foundry-huff/HuffConfig.sol"; import { HuffDeployer } from "foundry-huff/HuffDeployer.sol"; +import "./L2CompressorEncoder.sol"; + uint256 constant FMS = 0xa0; contract L2CompressorHuffReadFlagTests is AdvTest { @@ -244,18 +246,115 @@ contract L2CompressorHuffReadFlagTests is AdvTest { assertEq(res, _data); } - function test_read_flag_abi_encode_1() external { - bytes4 selector = 0x9988aabb; - uint256 val = type(uint64).max; + function test_read_flag_abi_encode_0(bytes4 _selector) external { + bytes memory encoded = encode_abi_call(_selector); + (bool s, bytes memory r) = imp.staticcall(encoded); - (bool s, bytes memory r) = imp.staticcall( - abi.encodePacked(hex"2e", selector, hex"08", uint64(val)) - ); + assertTrue(s); + + (uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes)); + + assertEq(rindex, encoded.length); + assertEq(windex, FMS + res.length); + assertEq(abi.encodePacked(_selector), res); + } + + function test_read_flag_abi_encode_1(bytes4 _selector, bytes32 _v1) external { + bytes memory encoded = encode_abi_call(_selector, _v1); + (bool s, bytes memory r) = imp.staticcall(encoded); + + assertTrue(s); + + (uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes)); + + assertEq(rindex, encoded.length); + assertEq(windex, FMS + res.length); + assertEq(abi.encodePacked(_selector, _v1), res); + } + + function test_read_flag_abi_encode_2(bytes4 _selector, bytes32 _v1, bytes32 _v2) external { + bytes memory encoded = encode_abi_call(_selector, _v1, _v2); + (bool s, bytes memory r) = imp.staticcall(encoded); + + assertTrue(s); + + (uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes)); + + assertEq(rindex, encoded.length); + assertEq(windex, FMS + res.length); + assertEq(abi.encodePacked(_selector, _v1, _v2), res); + } + + function test_read_flag_abi_encode_3(bytes4 _selector, bytes32 _v1, bytes32 _v2, bytes32 _v3) external { + bytes memory encoded = encode_abi_call(_selector, _v1, _v2, _v3); + (bool s, bytes memory r) = imp.staticcall(encoded); assertTrue(s); - console.logBytes(r); (uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes)); - console.logBytes(res); + + assertEq(rindex, encoded.length); + assertEq(windex, FMS + res.length); + assertEq(abi.encodePacked(_selector, _v1, _v2, _v3), res); + } + + function test_read_flag_abi_encode_4( + bytes4 _selector, + bytes32 _v1, + bytes32 _v2, + bytes32 _v3, + bytes32 _v4 + ) external { + bytes memory encoded = encode_abi_call(_selector, _v1, _v2, _v3, _v4); + (bool s, bytes memory r) = imp.staticcall(encoded); + + assertTrue(s); + + (uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes)); + + assertEq(rindex, encoded.length); + assertEq(windex, FMS + res.length); + assertEq(abi.encodePacked(_selector, _v1, _v2, _v3, _v4), res); + } + + function test_read_flag_abi_encode_5( + bytes4 _selector, + bytes32 _v1, + bytes32 _v2, + bytes32 _v3, + bytes32 _v4, + bytes32 _v5 + ) external { + bytes memory encoded = encode_abi_call(_selector, _v1, _v2, _v3, _v4, _v5); + (bool s, bytes memory r) = imp.staticcall(encoded); + + assertTrue(s); + + (uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes)); + + assertEq(rindex, encoded.length); + assertEq(windex, FMS + res.length); + assertEq(abi.encodePacked(_selector, _v1, _v2, _v3, _v4, _v5), res); + } + + function test_read_flag_abi_encode_5( + bytes4 _selector, + bytes32 _v1, + bytes32 _v2, + bytes32 _v3, + bytes32 _v4, + bytes32 _v5, + bytes32 _v6 + ) external { + bytes memory encoded = encode_abi_call(_selector, _v1, _v2, _v3, _v4, _v5, _v6); + (bool s, bytes memory r) = imp.staticcall(encoded); + + assertTrue(s); + + (uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes)); + + assertEq(rindex, encoded.length); + assertEq(windex, FMS + res.length); + assertEq(abi.encodePacked(_selector, _v1, _v2, _v3, _v4, _v5, _v6), res); } } diff --git a/src/L2Compressor.huff b/src/L2Compressor.huff index 11a573a1..b51c9515 100644 --- a/src/L2Compressor.huff +++ b/src/L2Compressor.huff @@ -322,25 +322,25 @@ end jump FLAG_ABI_0_PARAM: - READ_ABI(nrfs, 0x00) // [windex, rindex] + READ_ABI_0() // [windex, rindex] end jump FLAG_ABI_1_PARAM: - READ_ABI(nrfs, 0x01) // [windex, rindex] + READ_ABI_1(nrfs) // [windex, rindex] end jump FLAG_ABI_2_PARAMS: - READ_ABI(nrfs, 0x02) // [windex, rindex] + READ_ABI_2(nrfs) // [windex, rindex] end jump FLAG_ABI_3_PARAMS: - READ_ABI(nrfs, 0x03) // [windex, rindex] + READ_ABI_3(nrfs) // [windex, rindex] end jump FLAG_ABI_4_PARAMS: - READ_ABI(nrfs, 0x04) // [windex, rindex] + READ_ABI_4(nrfs) // [windex, rindex] end jump FLAG_ABI_5_PARAMS: - READ_ABI(nrfs, 0x05) // [windex, rindex] + READ_ABI_5(nrfs) // [windex, rindex] end jump FLAG_ABI_6_PARAMS: - READ_ABI(nrfs, 0x06) // [windex, rindex] + READ_ABI_6(nrfs) // [windex, rindex] end jump default: @@ -876,13 +876,8 @@ end_data_if: } -#define macro READ_ABI(nrfs, nparams) = takes (3) returns (2) { - // input stack: [windex, rindex] - - // Reserve 32 bytes to store the size, dynamic values - // use the first 32 bytes to store the size of the value - 0x20 // [0x20, windex, rindex] - add // [0x20 + windex, rindex] +#define macro READ_ABI_4_BYTES() = takes (2) returns (2) { + // input stack: [windex, rindex] 0x04 // [0x04, windex, rindex] dup1 // [0x04, 0x04, windex, rindex] @@ -890,73 +885,88 @@ dup4 // [windex, rindex, 0x04, 0x04, windex, rindex] calldatacopy // [0x04, windex, rindex] - dup2 // [windex, 0x04, windex, rindex] + swap2 // [rindex, windex, 0x04] + dup3 // [0x04, rindex, windex, 0x04] + add // [(0x04 + rindex), windex, 0x04] + swap2 // [0x04, windex, (0x04 + rindex)] + add // [(0x04 + windex), (0x04 + rindex)] - swap3 // [rindex, 0x04, windex, windex] - add // [rindex + 0x04, windex, windex] + // output stack: [windex, rindex] +} - swap1 // [windex, rindex + 0x04, windex] - 0x04 add // [windex + 0x04, rindex + 0x04, windex] - swap1 // [rindex + 0x04, windex + 0x04, windex] +#define macro READ_ABI_0() = takes (2) returns (2) { + // input stack: [windex, rindex] - 0x00 // [i, rindex, windex, prev_windex] - read_param: // [i, rindex, windex, prev_windex] - swap2 // [windex, rindex, i, prev_windex] + READ_ABI_4_BYTES() - PERFORM_NESTED_READ_FLAG() // [windex, rindex, i, prev_windex] - BACKREAD_SINGLE_VALUE() // [val, windex, rindex, i, prev_windex] + // output stack: [windex, rindex] +} - dup2 // [windex, val, windex, rindex, i, prev_windex] - mstore // [windex, rindex, i, prev_windex] +#define macro READ_ABI_1(nrfs) = takes (2) returns (2) { + // input stack: [windex, rindex] - 0x20 add // [windex + 0x20, rindex, i, prev_windex] + READ_ABI_4_BYTES() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] - swap2 // [i, rindex, windex + 0x20, prev_windex] + // output stack: [windex, rindex] +} - 0x01 add // [i + 1, rindex, windex, prev_windex] +#define macro READ_ABI_2(nrfs) = takes (2) returns (2) { + // input stack: [windex, rindex] - dup1 // [i + 1, i + 1, rindex, windex, prev_windex] - lt // [i + 1 < nparams, i + 1, rindex, windex, prev_windex] - read_param // [read_param, i + 1 < nparams, i + 1, rindex, windex, prev_windex] - jumpi // [i + 1, rindex, windex, prev_windex] + READ_ABI_4_BYTES() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] - pop // [rindex, windex, prev_windex] + // output stack: [windex, rindex] +} - // We need to fill the last 32 bytes with 0x00, dynamic values - // must be padded to 32 bytes +#define macro READ_ABI_3(nrfs) = takes (2) returns (2) { + // input stack: [windex, rindex] - dup3 // [prev_windex, rindex, windex, prev_windex] - dup3 // [windex, prev_windex, rindex, windex, prev_windex] - - sub // [size, rindex, windex, prev_index] - dup1 // [size, size, rindex, windex, prev_index] + READ_ABI_4_BYTES() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] - 0x1f and // [size % 32, size, rindex, windex, prev_index] - 0x20 sub // [32 - size % 32, size, rindex, windex, prev_index] - 0x1f and // [(32 - size % 32) % 32, size, rindex, windex, prev_index] + // output stack: [windex, rindex] +} - // Zero out the memory, just in case +#define macro READ_ABI_4(nrfs) = takes (2) returns (2) { + // input stack: [windex, rindex] - 0x00 // [0x00, 32 - size % 32, size, rindex, windex, prev_index] - dup5 // [windex, 0x00, 32 - size % 32, size, rindex, windex, prev_index] - mstore // [32 - size % 32, size, rindex, windex, prev_index] + READ_ABI_4_BYTES() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + + // output stack: [windex, rindex] +} + +#define macro READ_ABI_5(nrfs) = takes (2) returns (2) { + // input stack: [windex, rindex] - // Advance the windex by the number of required bytes - swap1 // [size, 32 - size % 32, rindex, windex, prev_index] - swap3 // [windex, 32 - size % 32, rindex, size, prev_index] - add // [windex, rindex, size, prev_index] + READ_ABI_4_BYTES() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] - // Now we need to store the full size of the value - // luckly windex - prev_index should give us the padded index + // output stack: [windex, rindex] +} - swap2 // [size, rindex, windex, prev_index] - 0x20 // [0x20, size, rindex, windex, prev_index] - dup5 // [prev_index, size, rindex, windex, prev_index] - sub // [(0x20 - prev_index), size, rindex, windex, prev_index] - mstore // [rindex, windex, prev_index] +#define macro READ_ABI_6(nrfs) = takes (2) returns (2) { + // input stack: [windex, rindex] - swap2 // [prev_index, windex, rindex] - pop // [windex, rindex] + READ_ABI_4_BYTES() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] + PERFORM_NESTED_READ_FLAG() // [windex, rindex] // output stack: [windex, rindex] }