Skip to content

Commit e629d29

Browse files
committed
feat(contracts)!: add base and advanced Checker and Excubia contracts
1 parent a6d6b68 commit e629d29

18 files changed

+409
-156
lines changed

packages/contracts/.solhint.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"extends": "solhint:recommended",
33
"rules": {
4-
"code-complexity": ["error", 7],
4+
"code-complexity": ["error", 10],
55
"compiler-version": ["error", ">=0.8.0"],
66
"var-name-mixedcase": "off",
77
"const-name-snakecase": "off",

packages/contracts/contracts/src/core/Excubia.sol

Lines changed: 0 additions & 69 deletions
This file was deleted.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.27;
3+
4+
import {IAdvancedChecker, Check} from "./IAdvancedChecker.sol";
5+
6+
struct CheckStatus {
7+
bool pre;
8+
uint8 main;
9+
bool post;
10+
}
11+
12+
/// @title AdvancedChecker.
13+
/// @notice Abstract base contract which can be extended to implement a specific `AdvancedChecker`.
14+
/// @dev The `AdvancedChecker` contract builds upon the `BaseChecker` by introducing additional validation phases.
15+
/// It allows for pre-condition (`PRE`), main (`MAIN`), and post-condition (`POST`) checks, with the option to skip
16+
/// pre and post checks based on constructor parameters. The `_check` method orchestrates the validation process
17+
/// based on the specified check type.
18+
abstract contract AdvancedChecker is IAdvancedChecker {
19+
/// @notice Flag to determine if pre-condition checks should be skipped.
20+
bool public skipPre;
21+
22+
/// @notice Flag to determine if post-condition checks should be skipped.
23+
bool public skipPost;
24+
25+
/// @notice Flag to determine if main checks can be executed multiple times.
26+
bool public allowMultipleMain;
27+
28+
/// @param _skipPre Indicates whether to skip pre-condition checks.
29+
/// @param _skipPost Indicates whether to skip post-condition checks.
30+
/// @param _allowMultipleMain Indicates whether the main check can be executed multiple times.
31+
constructor(bool _skipPre, bool _skipPost, bool _allowMultipleMain) {
32+
skipPre = _skipPre;
33+
skipPost = _skipPost;
34+
allowMultipleMain = _allowMultipleMain;
35+
}
36+
37+
/// @notice Public method to check the validity of the provided data for a given address and check type.
38+
/// @param passerby The address to be checked.
39+
/// @param data The data associated with the check.
40+
/// @param checkType The type of check to perform (PRE, MAIN, POST).
41+
function check(address passerby, bytes memory data, Check checkType) external view override {
42+
_check(passerby, data, checkType);
43+
}
44+
45+
/// @notice Internal method to orchestrate the validation process based on the specified check type.
46+
/// @param passerby The address to be checked.
47+
/// @param data The data associated with the check.
48+
/// @param checkType The type of check to perform (PRE, MAIN, POST).
49+
function _check(address passerby, bytes memory data, Check checkType) internal view {
50+
if (!skipPre && checkType == Check.PRE) {
51+
_checkPre(passerby, data);
52+
} else if (!skipPost && checkType == Check.POST) {
53+
_checkPost(passerby, data);
54+
} else if (checkType == Check.MAIN) {
55+
_checkMain(passerby, data);
56+
}
57+
}
58+
59+
/// @notice Internal method for performing pre-condition checks.
60+
/// @param passerby The address to be checked.
61+
/// @param data The data associated with the check.
62+
function _checkPre(address passerby, bytes memory data) internal view virtual {}
63+
64+
/// @notice Internal method for performing main checks.
65+
/// @param passerby The address to be checked.
66+
/// @param data The data associated with the check.
67+
function _checkMain(address passerby, bytes memory data) internal view virtual;
68+
69+
/// @notice Internal method for performing post-condition checks.
70+
/// @param passerby The address to be checked.
71+
/// @param data The data associated with the check.
72+
function _checkPost(address passerby, bytes memory data) internal view virtual {}
73+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.27;
3+
4+
import {IBaseChecker} from "./IBaseChecker.sol";
5+
6+
/// @title BaseChecker.
7+
/// @notice Abstract base contract which can be extended to implement a specific `BaseChecker`.
8+
/// @dev The `BaseChecker` contract provides a foundational structure for implementing specific checker logic.
9+
/// It defines a method `check` that invokes a protected `_check` method, which must be implemented by derived
10+
/// contracts.
11+
abstract contract BaseChecker is IBaseChecker {
12+
/// @notice Checks the validity of the provided data for a given address.
13+
/// @param passerby The address to be checked.
14+
/// @param data The data associated with the check.
15+
function check(address passerby, bytes memory data) external view override {
16+
_check(passerby, data);
17+
}
18+
19+
/// @notice Internal method to perform the actual check logic.
20+
/// @param passerby The address to be checked.
21+
/// @param data The data associated with the check.
22+
function _check(address passerby, bytes memory data) internal view virtual;
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.27;
3+
4+
/// @notice This enum defines the types of checks that can be performed in the AdvancedChecker system.
5+
/// @dev The `Check` enum represents the different phases of validation in the AdvancedChecker system.
6+
/// - `PRE`: Represents the pre-condition check that must be satisfied before the `MAIN` check can occur.
7+
/// - `MAIN`: The primary check that is executed, which can be validated multiple times.
8+
/// - `POST`: Represents the post-condition check that can be validated after the `MAIN` check has been completed.
9+
enum Check {
10+
PRE,
11+
MAIN,
12+
POST
13+
}
14+
15+
/// @title IAdvancedChecker.
16+
/// @notice AdvancedChecker contract interface.
17+
interface IAdvancedChecker {
18+
/// @dev Defines the custom `gate` protection logic.
19+
/// @param passerby The address of the entity attempting to pass the `gate`.
20+
/// @param data Additional data that may be required for the check.
21+
/// @param checkType The type of check to be enforced (e.g., PRE, MAIN, POST).
22+
function check(address passerby, bytes calldata data, Check checkType) external view; // Function to check if the
23+
// passerby can pass the gate with a specific check type.
24+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.27;
3+
4+
/// @title IBaseChecker
5+
/// @notice BaseChecker contract interface that defines the basic check functionality.
6+
interface IBaseChecker {
7+
/// @dev Defines the custom `gate` protection logic.
8+
/// @param passerby The address of the entity attempting to pass the `gate`.
9+
/// @param data Additional data that may be required for the check.
10+
function check(address passerby, bytes calldata data) external view;
11+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.27;
3+
4+
import {Excubia} from "./Excubia.sol";
5+
import {IAdvancedExcubia, Check} from "./IAdvancedExcubia.sol";
6+
import {AdvancedChecker, CheckStatus} from "../checker/AdvancedChecker.sol";
7+
8+
/// @title AdvancedExcubia
9+
/// @notice Abstract base contract which can be extended to implement a specific `AdvancedExcubia`.
10+
abstract contract AdvancedExcubia is IAdvancedExcubia, Excubia {
11+
/// @dev Reference to the AdvancedChecker contract for validation.
12+
AdvancedChecker public immutable ADVANCED_CHECKER;
13+
14+
/// @dev Tracks the check status of each address.
15+
mapping(address => CheckStatus) public isPassed;
16+
17+
/// @notice Constructor to initialize the AdvancedChecker contract.
18+
/// @param _advancedChecker The address of the AdvancedChecker contract.
19+
constructor(AdvancedChecker _advancedChecker) {
20+
ADVANCED_CHECKER = _advancedChecker;
21+
}
22+
23+
/// @notice Passes the gate check for a given address.
24+
/// @dev Calls the internal `_pass` function to enforce the gate logic.
25+
/// @param passerby The address attempting to pass the gate.
26+
/// @param data Additional data required for the check.
27+
/// @param checkType The type of check being performed (PRE, MAIN, POST).
28+
function pass(address passerby, bytes calldata data, Check checkType) external override onlyGate {
29+
_pass(passerby, data, checkType);
30+
}
31+
32+
/// @notice Internal function to enforce the gate passing logic.
33+
/// @param passerby The address attempting to pass the gate.
34+
/// @param data Additional data required for the check.
35+
/// @param checkType The type of check being performed (PRE, MAIN, POST).
36+
function _pass(address passerby, bytes calldata data, Check checkType) internal {
37+
ADVANCED_CHECKER.check(passerby, data, checkType);
38+
39+
if (checkType == Check.PRE) {
40+
if (ADVANCED_CHECKER.skipPre()) revert PreCheckSkipped();
41+
else if (isPassed[passerby].pre) revert AlreadyPassed();
42+
else isPassed[passerby].pre = true;
43+
} else if (checkType == Check.POST) {
44+
if (ADVANCED_CHECKER.skipPost()) revert PostCheckSkipped();
45+
else if (isPassed[passerby].post) revert AlreadyPassed();
46+
else isPassed[passerby].post = true;
47+
} else if (checkType == Check.MAIN) {
48+
if (!ADVANCED_CHECKER.allowMultipleMain() && isPassed[passerby].main > 0) revert MainCheckAlreadyEnforced();
49+
else isPassed[passerby].main += 1;
50+
}
51+
52+
emit GatePassed(passerby, gate, data, checkType);
53+
}
54+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.27;
3+
4+
import {IBaseExcubia} from "./IBaseExcubia.sol";
5+
import {Excubia} from "./Excubia.sol";
6+
import {BaseChecker} from "../checker/BaseChecker.sol";
7+
8+
/// @title BaseExcubia
9+
/// @notice Abstract base contract which can be extended to implement a specific `BaseExcubia`.
10+
abstract contract BaseExcubia is Excubia, IBaseExcubia {
11+
/// @dev Reference to the BaseChecker contract for validation.
12+
BaseChecker public immutable BASE_CHECKER;
13+
14+
/// @dev Tracks whether an address has passed the gate check.
15+
mapping(address => bool) public isPassed;
16+
17+
/// @notice Constructor to initialize the BaseChecker contract.
18+
/// @param _baseChecker The address of the BaseChecker contract.
19+
constructor(BaseChecker _baseChecker) {
20+
BASE_CHECKER = _baseChecker;
21+
}
22+
23+
/// @notice Passes the gate check for a given address.
24+
/// @dev Calls the internal `_pass` function to enforce the gate logic.
25+
/// @param passerby The address attempting to pass the gate.
26+
/// @param data Additional data required for the check.
27+
function pass(address passerby, bytes calldata data) external override onlyGate {
28+
_pass(passerby, data);
29+
}
30+
31+
/// @notice Internal function to enforce the gate passing logic.
32+
/// @param passerby The address attempting to pass the gate.
33+
/// @param data Additional data required for the check.
34+
function _pass(address passerby, bytes calldata data) internal {
35+
BASE_CHECKER.check(passerby, data);
36+
37+
if (isPassed[passerby]) revert AlreadyPassed();
38+
39+
isPassed[passerby] = true;
40+
41+
emit GatePassed(passerby, gate, data);
42+
}
43+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.27;
3+
4+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
5+
import {IExcubia} from "./IExcubia.sol";
6+
7+
/// @title Excubia abstract contract.
8+
/// @dev This contract implements the IExcubia interface and manages the gate address.
9+
abstract contract Excubia is IExcubia, Ownable(msg.sender) {
10+
/// @notice The Excubia-protected contract address.
11+
/// @dev The gate can be any contract address that requires a prior check to enable logic.
12+
/// For example, the gate is a Semaphore group that requires the passerby
13+
/// to meet certain criteria before joining.
14+
address public gate;
15+
16+
/// @notice Modifier that restricts access to the gate address.
17+
modifier onlyGate() {
18+
if (msg.sender != gate) revert GateOnly();
19+
_;
20+
}
21+
22+
/// @notice Sets the gate address.
23+
/// @dev Only the owner can set the destination `gate` address.
24+
/// @param _gate The address of the contract to be set as the gate.
25+
function setGate(address _gate) public virtual onlyOwner {
26+
if (_gate == address(0)) revert ZeroAddress();
27+
if (gate != address(0)) revert GateAlreadySet();
28+
29+
gate = _gate;
30+
31+
emit GateSet(_gate);
32+
}
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.27;
3+
4+
import {IExcubia} from "./IExcubia.sol";
5+
import {Check} from "../checker/IAdvancedChecker.sol";
6+
7+
/// @title IAdvancedExcubia
8+
/// @notice AdvancedExcubia contract interface that extends the IExcubia interface.
9+
interface IAdvancedExcubia is IExcubia {
10+
/// @notice Error thrown when the PRE check is skipped.
11+
error PreCheckSkipped();
12+
13+
/// @notice Error thrown when the MAIN check cannot be executed more than once.
14+
error MainCheckAlreadyEnforced();
15+
16+
/// @notice Error thrown when the POST check is skipped.
17+
error PostCheckSkipped();
18+
19+
/// @notice Event emitted when someone passes the `gate` check.
20+
/// @param passerby The address of those who have successfully passed the check.
21+
/// @param gate The address of the excubia-protected contract address.
22+
/// @param data Additional data related to the gate check.
23+
/// @param checkType The type of check that was performed (e.g., PRE, MAIN, POST).
24+
event GatePassed(address indexed passerby, address indexed gate, bytes data, Check checkType);
25+
26+
/// @notice Enforces the custom gate passing logic.
27+
/// @dev Must call the right `check` method based on the `checkType` to handle the logic of checking
28+
/// passerby for specific gate.
29+
/// @param passerby The address of the entity attempting to pass the gate.
30+
/// @param data Additional data required for the check (e.g., encoded token identifier).
31+
/// @param checkType The type of the check to be enforced for the passerby with the given data.
32+
function pass(address passerby, bytes calldata data, Check checkType) external;
33+
}

0 commit comments

Comments
 (0)