Created
October 24, 2025 16:21
-
-
Save ernestognw/af0e14e819a57004308bcc528b693d84 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function _tryDecodeInstallModules( | |
| bytes calldata signature | |
| ) | |
| private | |
| pure | |
| returns ( | |
| bool success, | |
| uint256[] calldata moduleTypeIds, | |
| address[] calldata modules, | |
| bytes[] calldata initDatas, | |
| bytes calldata installationSignature, | |
| bytes calldata userOpSignature | |
| ) | |
| { | |
| // Minimum length to hold 5 offset pointers: 5 * 32 = 160 bytes (0xa0) | |
| if (signature.length < 0xa0) { | |
| return _emptyDecodeInstallModules(); | |
| } | |
| uint256 moduleTypeIdsOffset = uint256(bytes32(signature[0x00:0x20])); | |
| uint256 modulesOffset = uint256(bytes32(signature[0x20:0x40])); | |
| uint256 initDatasOffset = uint256(bytes32(signature[0x40:0x60])); | |
| uint256 installationSignatureOffset = uint256(bytes32(signature[0x60:0x80])); | |
| uint256 userOpSignatureOffset = uint256(bytes32(signature[0x80:0xa0])); | |
| // Check all offsets are within bounds (need at least 32 bytes for length) | |
| if ( | |
| signature.length < moduleTypeIdsOffset + 0x20 || | |
| moduleTypeIdsOffset < 0xa0 || | |
| signature.length < modulesOffset + 0x20 || | |
| modulesOffset < 0xa0 || | |
| signature.length < initDatasOffset + 0x20 || | |
| initDatasOffset < 0xa0 || | |
| signature.length < installationSignatureOffset + 0x20 || | |
| installationSignatureOffset < 0xa0 || | |
| signature.length < userOpSignatureOffset + 0x20 || | |
| userOpSignatureOffset < 0xa0 | |
| ) { | |
| return _emptyDecodeInstallModules(); | |
| } | |
| // Get array lengths | |
| uint256 moduleTypeIdsLength = uint256(bytes32(signature[moduleTypeIdsOffset:moduleTypeIdsOffset + 0x20])); | |
| uint256 modulesLength = uint256(bytes32(signature[modulesOffset:modulesOffset + 0x20])); | |
| uint256 initDatasLength = uint256(bytes32(signature[initDatasOffset:initDatasOffset + 0x20])); | |
| if (moduleTypeIdsLength != modulesLength || modulesLength != initDatasLength) { | |
| return _emptyDecodeInstallModules(); | |
| } | |
| // Check bounds for fixed-size arrays (uint256[] and address[]) | |
| if ( | |
| signature.length < moduleTypeIdsOffset + 0x20 + moduleTypeIdsLength * 0x20 || | |
| signature.length < modulesOffset + 0x20 + modulesLength * 0x20 | |
| ) { | |
| return _emptyDecodeInstallModules(); | |
| } | |
| // Extract arrays directly from calldata | |
| assembly ("memory-safe") { | |
| moduleTypeIds.offset := add(signature.offset, add(moduleTypeIdsOffset, 0x20)) | |
| moduleTypeIds.length := moduleTypeIdsLength // Length in elements | |
| modules.offset := add(signature.offset, add(modulesOffset, 0x20)) | |
| modules.length := modulesLength // Length in elements | |
| } | |
| initDatas = _extractBytesArray(signature, initDatasOffset, initDatasLength); | |
| if (initDatas.length == 0 && initDatasLength > 0) { | |
| return _emptyDecodeInstallModules(); | |
| } | |
| // Get lengths of the signature data | |
| uint256 installationSignatureLength = uint256( | |
| bytes32(signature[installationSignatureOffset:installationSignatureOffset + 0x20]) | |
| ); | |
| uint256 userOpSignatureLength = uint256(bytes32(signature[userOpSignatureOffset:userOpSignatureOffset + 0x20])); | |
| // Check bounds for signature data | |
| if ( | |
| installationSignatureLength > signature.length || | |
| userOpSignatureLength > signature.length || | |
| signature.length < installationSignatureOffset + 0x20 + installationSignatureLength || | |
| signature.length < userOpSignatureOffset + 0x20 + userOpSignatureLength | |
| ) { | |
| return _emptyDecodeInstallModules(); | |
| } | |
| // Extract signature data (skip the 32-byte length prefix) | |
| installationSignature = signature[ | |
| installationSignatureOffset + 0x20:installationSignatureOffset + 0x20 + installationSignatureLength | |
| ]; | |
| userOpSignature = signature[userOpSignatureOffset + 0x20:userOpSignatureOffset + 0x20 + userOpSignatureLength]; | |
| return (true, moduleTypeIds, modules, initDatas, installationSignature, userOpSignature); | |
| } | |
| /** | |
| * @dev Validates and determines the end offset of a bytes[] array structure. | |
| * | |
| * This function checks that: | |
| * 1. The array length is within bounds | |
| * 2. All offset pointers are valid | |
| * 3. All individual bytes elements are within bounds | |
| */ | |
| function _extractBytesArray( | |
| bytes calldata data, | |
| uint256 arrayOffset, | |
| uint256 arrayLength | |
| ) private pure returns (bytes[] calldata result) { | |
| // Start after the array length (32 bytes) | |
| uint256 currentOffset = arrayOffset + 0x20; | |
| // Check if we have enough space for all offset pointers (arrayLength * 32 bytes) | |
| if (data.length < currentOffset + arrayLength * 0x20) return _emptyBytesArray(); | |
| // Track the maximum end position we've seen | |
| uint256 maxEndOffset = currentOffset + arrayLength * 0x20; | |
| // Validate each bytes element | |
| for (uint256 i = 0; i < arrayLength; (i++, currentOffset += 0x20)) { | |
| // Get the offset for this bytes element (relative to array start) | |
| uint256 elementOffset = arrayOffset + uint256(bytes32(data[currentOffset:currentOffset + 0x20])); | |
| // Check if the element offset is within bounds (need at least 32 bytes for length) | |
| if (data.length < elementOffset + 0x20) return _emptyBytesArray(); | |
| // Get the length of this bytes element | |
| uint256 elementLength = uint256(bytes32(data[elementOffset:elementOffset + 0x20])); | |
| // Check if the element data is within bounds | |
| uint256 elementEnd = elementOffset + 0x20 + elementLength; | |
| if (data.length < elementEnd) return _emptyBytesArray(); | |
| // Update max end offset | |
| if (elementEnd > maxEndOffset) maxEndOffset = elementEnd; | |
| } | |
| // Extract bytes array directly from calldata | |
| assembly ("memory-safe") { | |
| result.offset := add(data.offset, arrayOffset) | |
| result.length := sub(maxEndOffset, arrayOffset) | |
| } | |
| return result; | |
| } | |
| function _emptyDecodeInstallModules() | |
| private | |
| pure | |
| returns ( | |
| bool success, | |
| uint256[] calldata moduleTypeIds, | |
| address[] calldata modules, | |
| bytes[] calldata initDatas, | |
| bytes calldata installationSignature, | |
| bytes calldata userOpSignature | |
| ) | |
| { | |
| return ( | |
| false, | |
| _emptyUint256Array(), | |
| _emptyAddressArray(), | |
| _emptyBytesArray(), | |
| Calldata.emptyBytes(), | |
| Calldata.emptyBytes() | |
| ); | |
| } | |
| function _emptyBytesArray() private pure returns (bytes[] calldata result) { | |
| assembly ("memory-safe") { | |
| result.offset := 0 | |
| result.length := 0 | |
| } | |
| } | |
| function _emptyAddressArray() private pure returns (address[] calldata result) { | |
| assembly ("memory-safe") { | |
| result.offset := 0 | |
| result.length := 0 | |
| } | |
| } | |
| function _emptyUint256Array() private pure returns (uint256[] calldata result) { | |
| assembly ("memory-safe") { | |
| result.offset := 0 | |
| result.length := 0 | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment