Skip to content

Commit

Permalink
fix(ExecutionLib): fix decodeBatch
Browse files Browse the repository at this point in the history
  • Loading branch information
highskore committed Dec 19, 2024
1 parent e926afb commit 6065eb0
Showing 1 changed file with 45 additions and 15 deletions.
60 changes: 45 additions & 15 deletions src/accounts/erc7579/lib/ExecutionLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,55 @@ import { Execution } from "../../common/interfaces/IERC7579Account.sol";
* malloc for memory allocation is bad for gas. use this assembly instead
*/
library ExecutionLib {
function decodeBatch(bytes calldata callData)
error ERC7579DecodingError();

function decodeBatch(bytes calldata executionCalldata)
internal
pure
returns (Execution[] calldata executionBatch)
{
/*
* Batch Call Calldata Layout
* Offset (in bytes) | Length (in bytes) | Contents
* 0x0 | 0x4 | bytes4 function selector
* 0x4 | - |
abi.encode(IERC7579Execution.Execution[])
*/
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
let dataPointer := add(callData.offset, calldataload(callData.offset))

// Extract the ERC7579 Executions
executionBatch.offset := add(dataPointer, 32)
executionBatch.length := calldataload(dataPointer)
unchecked {
uint256 bufferLength = executionCalldata.length;

// Check executionCalldata is not empty.
if (bufferLength < 32) revert ERC7579DecodingError();

// Get the offset of the array (pointer to the array length).
uint256 arrayLengthPointer = uint256(bytes32(executionCalldata[0:32]));

// The array length (at arrayLengthPointer) should be 32 bytes long. We check that this
// is within the
// buffer bounds. Since we know bufferLength is at least 32, we can subtract with no
// overflow risk.
if (arrayLengthPointer > bufferLength - 32) revert ERC7579DecodingError();

// Get the array length. arrayLengthPointer + 32 is bounded by bufferLength so it does
// not overflow.
uint256 arrayLength =
uint256(bytes32(executionCalldata[arrayLengthPointer:arrayLengthPointer + 32]));

// Check that the buffer is long enough to store the array elements as "offset pointer":
// - each element of the array is an "offset pointer" to the data.
// - each "offset pointer" (to an array element) takes 32 bytes.
// - validity of the calldata at that location is checked when the array element is
// accessed, so we only
// need to check that the buffer is large enough to hold the pointers.
//
// Since we know bufferLength is at least arrayLengthPointer + 32, we can subtract with
// no overflow risk.
// Solidity limits length of such arrays to 2**64-1, this guarantees `arrayLength * 32`
// does not overflow.
if (
arrayLength > type(uint64).max
|| bufferLength - arrayLengthPointer - 32 < arrayLength * 32
) {
revert ERC7579DecodingError();
}

assembly ("memory-safe") {
executionBatch.offset := add(add(executionCalldata.offset, arrayLengthPointer), 32)
executionBatch.length := arrayLength
}
}
}

Expand Down

0 comments on commit 6065eb0

Please sign in to comment.