|
1 | 1 | // SPDX-License-Identifier: MIT |
2 | 2 | pragma solidity ^0.8.20; |
3 | 3 |
|
4 | | -import {Policy} from "./Policy.sol"; |
5 | 4 | import {IAdvancedPolicy, Check} from "../interfaces/IAdvancedPolicy.sol"; |
6 | 5 | import {AdvancedChecker, CheckStatus} from "../checker/AdvancedChecker.sol"; |
| 6 | +import {Policy} from "./Policy.sol"; |
| 7 | +import {LibClone} from "solady/src/utils/LibClone.sol"; |
7 | 8 |
|
8 | | -/// @title AdvancedPolicy. |
| 9 | +/// @title AdvancedPolicy |
9 | 10 | /// @notice Implements advanced policy checks with pre, main, and post validation stages. |
10 | | -/// @dev Extends Policy contract with multi-stage validation capabilities. |
| 11 | +/// @dev Extends Policy with multi-stage validation. Now clone-friendly with `initialize()`. |
11 | 12 | abstract contract AdvancedPolicy is IAdvancedPolicy, Policy { |
12 | | - /// @notice Reference to the validation checker contract. |
13 | | - /// @dev Immutable to ensure checker cannot be changed after deployment. |
14 | | - AdvancedChecker public immutable ADVANCED_CHECKER; |
| 13 | + /// @notice Reference to the validation checker contract. Stored, not immutable. |
| 14 | + AdvancedChecker public ADVANCED_CHECKER; |
15 | 15 |
|
16 | 16 | /// @notice Controls whether pre-condition checks are required. |
17 | | - bool public immutable SKIP_PRE; |
| 17 | + bool public SKIP_PRE; |
18 | 18 |
|
19 | 19 | /// @notice Controls whether post-condition checks are required. |
20 | | - bool public immutable SKIP_POST; |
| 20 | + bool public SKIP_POST; |
21 | 21 |
|
22 | 22 | /// @notice Controls whether main check can be executed multiple times. |
23 | | - bool public immutable ALLOW_MULTIPLE_MAIN; |
| 23 | + bool public ALLOW_MULTIPLE_MAIN; |
24 | 24 |
|
25 | 25 | /// @notice Tracks validation status for each subject per target. |
26 | | - /// @dev Maps subject => CheckStatus. |
27 | 26 | mapping(address => CheckStatus) public enforced; |
28 | 27 |
|
29 | | - /// @notice Initializes contract with an AdvancedChecker instance and checks configs. |
30 | | - /// @param _advancedChecker Address of the AdvancedChecker contract. |
31 | | - /// @param _skipPre Skip pre-condition validation. |
32 | | - /// @param _skipPost Skip post-condition validation. |
33 | | - /// @param _allowMultipleMain Allow multiple main validations. |
34 | | - constructor(AdvancedChecker _advancedChecker, bool _skipPre, bool _skipPost, bool _allowMultipleMain) { |
35 | | - ADVANCED_CHECKER = _advancedChecker; |
36 | | - SKIP_PRE = _skipPre; |
37 | | - SKIP_POST = _skipPost; |
38 | | - ALLOW_MULTIPLE_MAIN = _allowMultipleMain; |
| 28 | + /** |
| 29 | + * @notice Initialize function for minimal proxy clones. |
| 30 | + * Decodes appended bytes for (AdvancedChecker, skipPre, skipPost, allowMultipleMain). |
| 31 | + */ |
| 32 | + function initialize() public virtual override { |
| 33 | + // 1. Call Policy’s initialize to set ownership and `_initialized`. |
| 34 | + super.initialize(); |
| 35 | + |
| 36 | + // 2. Decode the appended bytes for the advanced config. |
| 37 | + bytes memory data = _getAppendedBytes(); |
| 38 | + (address sender, address advCheckerAddr, bool skipPre, bool skipPost, bool allowMultipleMain) = abi.decode( |
| 39 | + data, |
| 40 | + (address, address, bool, bool, bool) |
| 41 | + ); |
| 42 | + |
| 43 | + _transferOwnership(sender); |
| 44 | + |
| 45 | + ADVANCED_CHECKER = AdvancedChecker(advCheckerAddr); |
| 46 | + SKIP_PRE = skipPre; |
| 47 | + SKIP_POST = skipPost; |
| 48 | + ALLOW_MULTIPLE_MAIN = allowMultipleMain; |
39 | 49 | } |
40 | 50 |
|
41 | | - /// @notice Enforces policy check for a subject. |
42 | | - /// @dev Only callable by target contract. |
43 | | - /// @param subject Address to validate. |
44 | | - /// @param evidence Validation data. |
45 | | - /// @param checkType Type of check (PRE, MAIN, POST). |
| 51 | + /// @notice Enforces a policy check for a subject, handling multi-stage logic. |
| 52 | + /// @dev Only callable by the target contract. |
46 | 53 | function enforce(address subject, bytes[] calldata evidence, Check checkType) external override onlyTarget { |
47 | 54 | _enforce(subject, evidence, checkType); |
48 | 55 | } |
49 | 56 |
|
50 | | - /// @notice Internal check enforcement logic. |
51 | | - /// @dev Handles different check types and their dependencies. |
52 | | - /// @param subject Address to validate. |
53 | | - /// @param evidence Validation data. |
54 | | - /// @param checkType Type of check to perform. |
55 | | - /// @custom:throws CannotPreCheckWhenSkipped If PRE check attempted when skipped. |
56 | | - /// @custom:throws CannotPostCheckWhenSkipped If POST check attempted when skipped. |
57 | | - /// @custom:throws UnsuccessfulCheck If validation fails. |
58 | | - /// @custom:throws AlreadyEnforced If check was already completed. |
59 | | - /// @custom:throws PreCheckNotEnforced If PRE check is required but not done. |
60 | | - /// @custom:throws MainCheckNotEnforced If MAIN check is required but not done. |
61 | | - /// @custom:throws MainCheckAlreadyEnforced If multiple MAIN checks not allowed. |
| 57 | + /// @notice Internal check enforcement logic for advanced multi-stage checks. |
62 | 58 | function _enforce(address subject, bytes[] calldata evidence, Check checkType) internal { |
63 | 59 | if (!ADVANCED_CHECKER.check(subject, evidence, checkType)) { |
64 | 60 | revert UnsuccessfulCheck(); |
65 | 61 | } |
66 | 62 |
|
67 | 63 | CheckStatus storage status = enforced[subject]; |
68 | 64 |
|
69 | | - // Handle PRE check. |
70 | 65 | if (checkType == Check.PRE) { |
71 | 66 | if (SKIP_PRE) revert CannotPreCheckWhenSkipped(); |
72 | | - if (status.pre) { |
73 | | - revert AlreadyEnforced(); |
74 | | - } |
75 | | - |
| 67 | + if (status.pre) revert AlreadyEnforced(); |
76 | 68 | status.pre = true; |
77 | 69 | } else if (checkType == Check.POST) { |
78 | | - // Handle POST check. |
79 | 70 | if (SKIP_POST) revert CannotPostCheckWhenSkipped(); |
80 | | - if (status.main == 0) { |
81 | | - revert MainCheckNotEnforced(); |
82 | | - } |
83 | | - if (status.post) { |
84 | | - revert AlreadyEnforced(); |
85 | | - } |
| 71 | + if (status.main == 0) revert MainCheckNotEnforced(); |
| 72 | + if (status.post) revert AlreadyEnforced(); |
86 | 73 | status.post = true; |
87 | 74 | } else { |
88 | | - // Handle MAIN check. |
89 | | - if (!SKIP_PRE && !status.pre) { |
90 | | - revert PreCheckNotEnforced(); |
91 | | - } |
92 | | - if (!ALLOW_MULTIPLE_MAIN && status.main > 0) { |
93 | | - revert MainCheckAlreadyEnforced(); |
94 | | - } |
| 75 | + // MAIN check |
| 76 | + if (!SKIP_PRE && !status.pre) revert PreCheckNotEnforced(); |
| 77 | + if (!ALLOW_MULTIPLE_MAIN && status.main > 0) revert MainCheckAlreadyEnforced(); |
95 | 78 | status.main += 1; |
96 | 79 | } |
97 | 80 |
|
|
0 commit comments