-
Notifications
You must be signed in to change notification settings - Fork 604
/
EIP4337Fallback.sol
89 lines (77 loc) · 2.97 KB
/
EIP4337Fallback.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//SPDX-License-Identifier: GPL
pragma solidity ^0.8.7;
/* solhint-disable no-inline-assembly */
import "@gnosis.pm/safe-contracts/contracts/handler/DefaultCallbackHandler.sol";
import "@gnosis.pm/safe-contracts/contracts/GnosisSafe.sol";
import "@openzeppelin/contracts/interfaces/IERC1271.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "../../interfaces/IAccount.sol";
import "./EIP4337Manager.sol";
using ECDSA for bytes32;
/**
* The GnosisSafe enables adding custom functions implementation to the Safe by setting a 'fallbackHandler'.
* This 'fallbackHandler' adds an implementation of 'validateUserOp' to the GnosisSafe.
* Note that the implementation of the 'validateUserOp' method is located in the EIP4337Manager.
* Upon receiving the 'validateUserOp', a Safe with EIP4337Fallback enabled makes a 'delegatecall' to EIP4337Manager.
*/
contract EIP4337Fallback is DefaultCallbackHandler, IAccount, IERC1271 {
bytes4 internal constant ERC1271_MAGIC_VALUE = 0x1626ba7e;
address immutable public eip4337manager;
constructor(address _eip4337manager) {
eip4337manager = _eip4337manager;
}
/**
* delegate the contract call to the EIP4337Manager
*/
function delegateToManager() internal returns (bytes memory) {
// delegate entire msg.data (including the appended "msg.sender") to the EIP4337Manager
// will work only for GnosisSafe contracts
GnosisSafe safe = GnosisSafe(payable(msg.sender));
(bool success, bytes memory ret) = safe.execTransactionFromModuleReturnData(eip4337manager, 0, msg.data, Enum.Operation.DelegateCall);
if (!success) {
assembly {
revert(add(ret, 32), mload(ret))
}
}
return ret;
}
/**
* called from the Safe. delegate actual work to EIP4337Manager
*/
function validateUserOp(UserOperation calldata, bytes32, uint256) override external returns (uint256 deadline){
bytes memory ret = delegateToManager();
return abi.decode(ret, (uint256));
}
/**
* Helper for wallet to get the next nonce.
*/
function getNonce() public returns (uint256 nonce) {
bytes memory ret = delegateToManager();
(nonce) = abi.decode(ret, (uint256));
}
/**
* called from the Safe. delegate actual work to EIP4337Manager
*/
function executeAndRevert(
address,
uint256,
bytes memory,
Enum.Operation
) external {
delegateToManager();
}
function isValidSignature(
bytes32 _hash,
bytes memory _signature
) external override view returns (bytes4) {
bytes32 hash = _hash.toEthSignedMessageHash();
address recovered = hash.recover(_signature);
GnosisSafe safe = GnosisSafe(payable(address(msg.sender)));
// Validate signatures
if (safe.isOwner(recovered)) {
return ERC1271_MAGIC_VALUE;
} else {
return 0xffffffff;
}
}
}