Skip to content

Commit

Permalink
Merge pull request #87 from rhinestonewtf/account/safe7579-fix1271
Browse files Browse the repository at this point in the history
Account/safe7579 fix1271
  • Loading branch information
zeroknots authored Mar 18, 2024
2 parents 8510513 + 00261ac commit d37a77a
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 4 deletions.
54 changes: 52 additions & 2 deletions accounts/safe7579/src/SafeERC7579.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
import { _packValidationData } from "@ERC4337/account-abstraction/contracts/core/Helpers.sol";
import { IEntryPoint } from "@ERC4337/account-abstraction/contracts/interfaces/IEntryPoint.sol";
import { ISafe7579Init } from "./interfaces/ISafe7579Init.sol";
import { IERC1271 } from "./interfaces/IERC1271.sol";

/**
* @title ERC7579 Adapter for Safe accounts.
Expand All @@ -56,6 +57,12 @@ contract SafeERC7579 is
bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH =
0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;

// keccak256("SafeMessage(bytes message)");
bytes32 private constant SAFE_MSG_TYPEHASH =
0x60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca;
// keccak256("safeSignature(bytes32,bytes32,bytes,bytes)");
bytes4 private constant SAFE_SIGNATURE_MAGIC_VALUE = 0x5fd7e97d;

/**
* @inheritdoc IERC7579Account
*/
Expand Down Expand Up @@ -201,7 +208,13 @@ contract SafeERC7579 is
}

/**
* @inheritdoc IERC7579Account
* Will use Safe's signed messages or checkSignatures features or ERC7579 validation modules
* if no signature is provided, it makes use of Safe's signedMessages
* if address(0) or a non-installed validator module is provided, it will use Safe's
* checkSignatures
* if a valid validator module is provided, it will use the module's validateUserOp function
* @param hash message hash of ERC1271 request
* @param data abi.encodePacked(address validationModule, bytes signatures)
*/
function isValidSignature(
bytes32 hash,
Expand All @@ -211,9 +224,27 @@ contract SafeERC7579 is
view
returns (bytes4 magicValue)
{
ISafe safe = ISafe(msg.sender);

// check for safe's approved hashes
if (data.length == 0 && safe.signedMessages(hash) != 0) {
// return magic value
return IERC1271.isValidSignature.selector;
}
address validationModule = address(bytes20(data[:20]));

if (!_isValidatorInstalled(validationModule)) return 0xFFFFFFFF;
if (validationModule == address(0) || !_isValidatorInstalled(validationModule)) {
bytes memory messageData = EIP712.encodeMessageData(
safe.domainSeparator(), SAFE_MSG_TYPEHASH, abi.encode(keccak256(abi.encode(hash)))
);

bytes32 messageHash = keccak256(messageData);

safe.checkSignatures(messageHash, messageData, data[20:]);
return IERC1271.isValidSignature.selector;
}

// use 7579 validation module
magicValue =
IValidator(validationModule).isValidSignatureWithSender(msg.sender, hash, data[20:]);
}
Expand Down Expand Up @@ -454,3 +485,22 @@ contract SafeERC7579 is
nonce = IEntryPoint(entryPoint()).getNonce(safe, key);
}
}

library EIP712 {
function encodeMessageData(
bytes32 domainSeparator,
bytes32 typeHash,
bytes memory message
)
internal
pure
returns (bytes memory)
{
return abi.encodePacked(
bytes1(0x19),
bytes1(0x01),
domainSeparator,
keccak256(abi.encodePacked(typeHash, message))
);
}
}
2 changes: 0 additions & 2 deletions accounts/safe7579/src/core/ModuleManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import { Receiver } from "erc7579/core/Receiver.sol";
import { AccessControl } from "./AccessControl.sol";
import { CallType, CALLTYPE_SINGLE, CALLTYPE_DELEGATECALL } from "erc7579/lib/ModeLib.sol";

CallType constant CALLTYPE_STATIC = CallType.wrap(0xFE);

struct FallbackHandler {
address handler;
CallType calltype;
Expand Down
22 changes: 22 additions & 0 deletions accounts/safe7579/src/interfaces/IERC1271.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.23;

interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param _dataHash Arbitrary length data signed on behalf of address(this)
* @param _signature Signature byte array associated with _data
*
* MUST return the bytes4 magic value 0x1626ba7e when function passes.
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc >
* 0.5)
* MUST allow external calls
*/
function isValidSignature(
bytes32 _dataHash,
bytes calldata _signature
)
external
view
returns (bytes4);
}
2 changes: 2 additions & 0 deletions accounts/safe7579/src/interfaces/ISafe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ interface ISafe {
external
view;

function signedMessages(bytes32) external view returns (uint256);

/**
* @dev Returns the domain separator for this contract, as defined in the EIP-712 standard.
* @return bytes32 The domain separator hash.
Expand Down

0 comments on commit d37a77a

Please sign in to comment.