generated from exp-table/nplate
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDarkSafe.sol
100 lines (81 loc) · 3.88 KB
/
DarkSafe.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
90
91
92
93
94
95
96
97
98
99
100
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.27;
import {Module, Enum as ZodiacEnum} from "zodiac/core/Module.sol";
import {Safe, Enum as SafeEnum} from "safe-contracts/Safe.sol";
import {DarkSafeVerifier} from "./Verifier.sol";
import {LibString} from "solady/utils/LibString.sol";
contract DarkSafe is Module {
/// @notice the hash of the polynomial
bytes32 public polynomialHash;
DarkSafeVerifier public immutable verifier;
bool public isMasterCopy;
using LibString for bytes;
error PROOF_VERIFICATION_FAILED();
error CANNOT_SETUP_MASTER_COPY();
/// @dev emit the polynomial hash and the polynomial as an easy way to
/// decentralize the polynomial for later proof generation
event SignersRotated(bytes32 indexed polynomialHash, bytes32[] polynomial);
constructor(address _safe, bytes32 _polynomialHash, bytes32[] memory _polynomial, DarkSafeVerifier _verifier) {
setUp(abi.encode(_safe, _polynomialHash, _polynomial));
verifier = _verifier;
isMasterCopy = true;
}
/// @dev a setup function to ensure factory friendly compatibility
function setUp(bytes memory initializeParams) public override initializer {
if (isMasterCopy) revert CANNOT_SETUP_MASTER_COPY();
(address _safe, bytes32 _polynomialHash, bytes32[] memory _polynomial) =
abi.decode(initializeParams, (address, bytes32, bytes32[]));
__Ownable_init();
setAvatar(_safe);
setTarget(_safe);
transferOwnership(_safe);
_updateSigners(_polynomialHash, _polynomial);
}
/// @dev updates polynomialHash, thus changing the valid signer sets
function _updateSigners(bytes32 newHash, bytes32[] memory polynomial) internal {
polynomialHash = newHash;
emit SignersRotated(newHash, polynomial);
}
function updateSigners(bytes32 newHash, bytes32[] memory polynomial) external onlyOwner {
_updateSigners(newHash, polynomial);
}
function _execute(address to, uint256 value, bytes calldata data, SafeEnum.Operation operation, bytes memory proof)
internal
returns (bool success, bytes memory returnData)
{
Safe safe = Safe(payable(address(avatar)));
uint256 nonce = safe.nonce();
bytes32 safeTxHash = safe.getTransactionHash(to, value, data, operation, 0, 0, 0, address(0), payable(0), nonce);
bytes32 messageHash = keccak256(
(bytes.concat("\x19Ethereum Signed Message:\n", "66", bytes(abi.encode(safeTxHash).toHexString())))
);
bytes32[] memory publicInputs = new bytes32[](33);
for (uint256 i; i < 32; ++i) {
uint256 shift = 248 - i * 8;
publicInputs[i] = bytes32(uint256(uint8(uint256(messageHash) >> shift)));
}
publicInputs[32] = polynomialHash;
if (verifier.verify(proof, publicInputs) == false) revert PROOF_VERIFICATION_FAILED();
(success, returnData) = execAndReturnData(to, value, data, ZodiacEnum.Operation(uint8(operation)));
}
/// @notice execute a safe call on the `target` with `proof` data instead of the safe message
/// @return success if the call succeeded
/// @return returnData any return data from the callee
function execAndReturnData(
address to,
uint256 value,
bytes calldata data,
SafeEnum.Operation operation,
bytes memory proof
) external returns (bool success, bytes memory returnData) {
(success, returnData) = _execute(to, value, data, operation, proof);
}
/// @notice execute a safe call on the `target` with `proof` data instead of the safe message
/// @return success if the call succeeded
function exec(address to, uint256 value, bytes calldata data, SafeEnum.Operation operation, bytes memory proof)
external
returns (bool success)
{
(success,) = _execute(to, value, data, operation, proof);
}
}