forked from zerodevapp/kernel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathKillSwitchValidator.sol
More file actions
85 lines (76 loc) · 3.89 KB
/
KillSwitchValidator.sol
File metadata and controls
85 lines (76 loc) · 3.89 KB
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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {ECDSA} from "solady/utils/ECDSA.sol";
import {UserOperation} from "I4337/interfaces/UserOperation.sol";
import {IKernel} from "../interfaces/IKernel.sol";
import {_intersectValidationData} from "../utils/KernelHelper.sol";
import {WalletKernelStorage, ExecutionDetail} from "../common/Structs.sol";
import {IKernelValidator} from "../interfaces/IKernelValidator.sol";
import {ValidationData, ValidAfter, ValidUntil, packValidationData, parseValidationData} from "../common/Types.sol";
import {KillSwitchAction} from "../executor/KillSwitchAction.sol";
import {SIG_VALIDATION_FAILED} from "../common/Constants.sol";
struct KillSwitchValidatorStorage {
address guardian;
IKernelValidator validator;
ValidAfter pausedUntil;
bytes4 disableMode;
}
contract KillSwitchValidator is IKernelValidator {
mapping(address => KillSwitchValidatorStorage) public killSwitchValidatorStorage;
function enable(bytes calldata enableData) external payable override {
killSwitchValidatorStorage[msg.sender].guardian = address(bytes20(enableData[0:20]));
}
function disable(bytes calldata) external payable override {
delete killSwitchValidatorStorage[msg.sender];
}
function validateSignature(bytes32, bytes calldata) external pure override returns (ValidationData) {
revert NotImplemented();
}
function validateUserOp(UserOperation calldata _userOp, bytes32 _userOpHash, uint256)
external
payable
override
returns (ValidationData)
{
KillSwitchValidatorStorage storage validatorStorage = killSwitchValidatorStorage[msg.sender]; // should use msg.sender to prevent others from changing storage
ValidAfter pausedUntil = validatorStorage.pausedUntil;
ValidationData validationData;
if (address(validatorStorage.validator) != address(0)) {
// check for validator at first
try validatorStorage.validator.validateUserOp(_userOp, _userOpHash, 0) returns (ValidationData res) {
validationData = res;
} catch {
validationData = SIG_VALIDATION_FAILED;
}
(,, address result) = parseValidationData(validationData);
if (result != address(1)) {
// if signature verification has not been failed, return with the result
ValidationData delayedData = packValidationData(pausedUntil, ValidUntil.wrap(0));
return _intersectValidationData(validationData, delayedData);
} else if (bytes4(_userOp.callData[0:4]) == KillSwitchAction.toggleKillSwitch.selector) {
bytes32 hash = ECDSA.toEthSignedMessageHash(_userOpHash);
address recovered = ECDSA.recover(hash, _userOp.signature);
if (validatorStorage.guardian == recovered) {
return packValidationData(ValidAfter.wrap(0), ValidUntil.wrap(0));
}
}
}
if (_userOp.signature.length == 71) {
// save data to this storage
validatorStorage.pausedUntil = ValidAfter.wrap(uint48(bytes6(_userOp.signature[0:6])));
validatorStorage.validator = IKernel(msg.sender).getDefaultValidator();
validatorStorage.disableMode = IKernel(msg.sender).getDisabledMode();
bytes32 hash = ECDSA.toEthSignedMessageHash(keccak256(bytes.concat(_userOp.signature[0:6], _userOpHash)));
address recovered = ECDSA.recover(hash, _userOp.signature[6:]);
if (validatorStorage.guardian != recovered) {
return SIG_VALIDATION_FAILED;
}
return packValidationData(pausedUntil, ValidUntil.wrap(0));
} else {
return SIG_VALIDATION_FAILED;
}
}
function validCaller(address, bytes calldata) external pure override returns (bool) {
revert NotImplemented();
}
}