diff --git a/src/Interfaces.sol b/src/Interfaces.sol index 2eb5a176..bc6f3b2e 100644 --- a/src/Interfaces.sol +++ b/src/Interfaces.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.23 <0.9.0; /* solhint-disable no-unused-import */ /*////////////////////////////////////////////////////////////// - ERCs + ERCs/EIPs //////////////////////////////////////////////////////////////*/ import { IERC1271, EIP1271_MAGIC_VALUE } from "./module-bases/interfaces/IERC1271.sol"; @@ -14,6 +14,7 @@ import { IERC3156FlashLender, IERC3156FlashBorrower } from "./module-bases/interfaces/Flashloan.sol"; +import { IERC712 } from "./module-bases/interfaces/IERC712.sol"; /*////////////////////////////////////////////////////////////// MODULES diff --git a/src/module-bases/interfaces/IERC712.sol b/src/module-bases/interfaces/IERC712.sol new file mode 100644 index 00000000..9b88f2c7 --- /dev/null +++ b/src/module-bases/interfaces/IERC712.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +interface IERC712 { + function domainSeparator() external view returns (bytes32); +} diff --git a/src/test/helpers/SafeHelpers.sol b/src/test/helpers/SafeHelpers.sol index 531e7c8c..8186a055 100644 --- a/src/test/helpers/SafeHelpers.sol +++ b/src/test/helpers/SafeHelpers.sol @@ -23,13 +23,21 @@ import { ISafe7579Launchpad } from "../../accounts/safe/interfaces/ISafe7579Laun import { IERC7579Account } from "../../accounts/common/interfaces/IERC7579Account.sol"; import { IAccountFactory } from "../../accounts/factory/interface/IAccountFactory.sol"; import { IAccountModulesPaginated } from "./interfaces/IAccountModulesPaginated.sol"; -import { IERC1271, EIP1271_MAGIC_VALUE } from "../../Interfaces.sol"; +import { IERC1271, EIP1271_MAGIC_VALUE, IERC712 } from "../../Interfaces.sol"; // Utils import { startPrank, stopPrank } from "../utils/Vm.sol"; /// @notice Helper functions for the Safe7579 implementation contract SafeHelpers is HelperBase { + /*////////////////////////////////////////////////////////////////////////// + CONSTANTS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice The typehash for EIP712 Safe messages + bytes32 constant SAFE_MSG_TYPEHASH = + 0x60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca; + /*////////////////////////////////////////////////////////////////////////// EXECUTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -316,6 +324,34 @@ contract SafeHelpers is HelperBase { ) == EIP1271_MAGIC_VALUE; } + /// @notice Format a Safe compatible hash for an account instance + /// @param instance AccountInstance the account instance to format the hash for + /// @param hash bytes32 the hash to format + /// @return bytes32 the formatted hash + function formatERC1271Hash( + AccountInstance memory instance, + address validator, + bytes32 hash + ) + public + virtual + override + deployAccountForAction(instance) + returns (bytes32) + { + // Revert if validator is installed + if (isModuleInstalled(instance, MODULE_TYPE_VALIDATOR, validator, "")) { + revert("formatERC1271Hash: validator is installed"); + } + bytes memory messageData = abi.encodePacked( + bytes1(0x19), + bytes1(0x01), + IERC712(instance.account).domainSeparator(), + keccak256(abi.encodePacked(SAFE_MSG_TYPEHASH, abi.encode(keccak256(abi.encode(hash))))) + ); + return keccak256(messageData); + } + /// @notice Format a ERC1271 signature for an account /// @param validator address the address of the validator /// @param signature bytes the signature to format