Skip to content

Commit 4a3b172

Browse files
committed
refactor(contracts): add common clone contract for proxies
1 parent a2eb791 commit 4a3b172

File tree

11 files changed

+53
-51
lines changed

11 files changed

+53
-51
lines changed

packages/contracts/contracts/src/core/checker/AdvancedChecker.sol

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
pragma solidity ^0.8.20;
33

44
import {IAdvancedChecker, Check, CheckStatus} from "../interfaces/IAdvancedChecker.sol";
5-
import {Checker} from "./Checker.sol";
5+
import {Clone} from "../proxy/Clone.sol";
66

77
/// @title AdvancedChecker.
88
/// @notice Multi-phase validation checker with pre, main, and post checks.
99
/// @dev Base contract for implementing complex validation logic with configurable check phases.
10-
abstract contract AdvancedChecker is Checker, IAdvancedChecker {
10+
abstract contract AdvancedChecker is Clone, IAdvancedChecker {
1111
/// @notice Entry point for validation checks.
1212
/// @param subject Address to validate.
1313
/// @param evidence Validation data.

packages/contracts/contracts/src/core/checker/BaseChecker.sol

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
pragma solidity ^0.8.20;
33

44
import {IBaseChecker} from "../interfaces/IBaseChecker.sol";
5-
import {Checker} from "./Checker.sol";
5+
import {Clone} from "../proxy/Clone.sol";
66

77
/// @title BaseChecker
88
/// @notice Abstract base contract for implementing validation checks.
99
/// @dev Provides a standardized interface for implementing custom validation logic
1010
/// through the internal _check method.
11-
abstract contract BaseChecker is Checker, IBaseChecker {
11+
abstract contract BaseChecker is Clone, IBaseChecker {
1212
/// @notice Validates evidence for a given subject address.
1313
/// @dev External view function that delegates to internal _check implementation.
1414
/// @param subject Address to validate.

packages/contracts/contracts/src/core/checker/Checker.sol

-21
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.20;
3+
4+
interface IClone {
5+
error AlreadyInitialized();
6+
7+
function initialize() external;
8+
9+
function getAppendedBytes() external returns (bytes memory);
10+
}

packages/contracts/contracts/src/core/interfaces/IPolicy.sol

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ interface IPolicy {
1414
error TargetOnly();
1515
error TargetAlreadySet();
1616
error AlreadyEnforced();
17-
error AlreadyInitialized();
1817

1918
/// @notice Returns policy trait identifier.
2019
/// @return Policy trait string (e.g., "Semaphore").

packages/contracts/contracts/src/core/policy/AdvancedPolicy.sol

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ abstract contract AdvancedPolicy is IAdvancedPolicy, Policy {
2929
* @notice Initialize function for minimal proxy clones.
3030
* Decodes appended bytes for (AdvancedChecker, skipPre, skipPost, allowMultipleMain).
3131
*/
32-
function initialize() public virtual override {
32+
function _initialize() internal virtual override {
3333
// 1. Call Policy’s initialize to set ownership and `_initialized`.
34-
super.initialize();
34+
super._initialize();
3535

3636
// 2. Decode the appended bytes for the advanced config.
3737
bytes memory data = _getAppendedBytes();

packages/contracts/contracts/src/core/policy/BasePolicy.sol

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ abstract contract BasePolicy is Policy, IBasePolicy {
2222
* @notice Initializes the contract with a BaseChecker instance, reading from appended bytes.
2323
* Replaces the old constructor-based approach.
2424
*/
25-
function initialize() public virtual override {
25+
function _initialize() internal virtual override {
2626
// 1. Call the base `Policy.initialize()` to set ownership / handle `_initialized`.
27-
super.initialize();
27+
super._initialize();
2828

2929
// 2. Decode the appended bytes to get the BaseChecker address (and anything else you might need).
3030
bytes memory data = _getAppendedBytes();

packages/contracts/contracts/src/core/policy/Policy.sol

+4-16
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,21 @@ pragma solidity ^0.8.20;
33

44
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
55
import {IPolicy} from "../interfaces/IPolicy.sol";
6+
import {Clone} from "../proxy/Clone.sol";
67
import {LibClone} from "solady/src/utils/LibClone.sol";
78

8-
abstract contract Policy is IPolicy, Ownable(msg.sender) {
9-
/// @notice One-time initialization guard.
10-
bool private _initialized;
11-
9+
abstract contract Policy is Clone, IPolicy, Ownable(msg.sender) {
1210
/// @notice The “gatekeeped” contract address set once by the owner (if at all).
1311
address internal target;
1412

15-
/**
16-
* @notice The base init. By default, transfers ownership to `msg.sender` (i.e., the caller).
17-
* @dev If you want the factory to always be the owner, you just have the factory call this function,
18-
* so `msg.sender` is the factory in that transaction.
19-
*/
20-
function initialize() public virtual {
21-
if (_initialized) revert AlreadyInitialized();
22-
_initialized = true;
13+
function _initialize() internal virtual override {
14+
super._initialize();
2315

2416
// By default, set the owner to the caller (likely the factory).
2517
// this is not the zero address as above!
2618
_transferOwnership(msg.sender);
2719
}
2820

29-
function _getAppendedBytes() internal view returns (bytes memory) {
30-
return LibClone.argsOnClone(address(this));
31-
}
32-
3321
/**
3422
* @notice Only the owner can call `setTarget` once.
3523
* @param _target The contract to be protected by this policy.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.20;
3+
4+
import {IClone} from "../interfaces/IClone.sol";
5+
import {LibClone} from "solady/src/utils/LibClone.sol";
6+
7+
// @todo refactoring & comments
8+
abstract contract Clone is IClone {
9+
bool private _initialized;
10+
11+
function initialize() external {
12+
_initialize();
13+
}
14+
15+
function getAppendedBytes() external returns (bytes memory) {
16+
return _getAppendedBytes();
17+
}
18+
19+
function _initialize() internal virtual {
20+
if (_initialized) revert AlreadyInitialized();
21+
_initialized = true;
22+
}
23+
24+
function _getAppendedBytes() internal virtual returns (bytes memory) {
25+
return LibClone.argsOnClone(address(this));
26+
}
27+
}

packages/contracts/contracts/src/test/advanced/AdvancedERC721Checker.sol

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ contract AdvancedERC721Checker is AdvancedChecker {
2525
uint256 public minTokenId;
2626
uint256 public maxTokenId;
2727

28-
function initialize() public virtual override {
28+
function _initialize() internal override {
2929
// 1. Call super to handle `_initialized` check.
30-
super.initialize();
30+
super._initialize();
3131

3232
// 2. Retrieve appended bytes from the clone.
3333
bytes memory data = _getAppendedBytes();

packages/contracts/contracts/src/test/base/BaseERC721Checker.sol

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
pragma solidity ^0.8.20;
33

44
import {BaseChecker} from "../../core/checker/BaseChecker.sol";
5-
import {Checker} from "../../core/checker/Checker.sol";
65
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
76

87
/// @title BaseERC721Checker.
@@ -12,9 +11,9 @@ contract BaseERC721Checker is BaseChecker {
1211
/// @notice NFT contract reference.
1312
IERC721 public nft;
1413

15-
function initialize() public virtual override {
14+
function _initialize() internal override {
1615
// 1. Call super to handle `_initialized` check.
17-
super.initialize();
16+
super._initialize();
1817

1918
// 2. Retrieve appended bytes from the clone.
2019
bytes memory data = _getAppendedBytes();

0 commit comments

Comments
 (0)