|
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