|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +pragma solidity >=0.8.0; |
| 3 | + |
| 4 | +import {Excubia} from "../Excubia.sol"; |
| 5 | +import {IHatsMinimal} from "./interfaces/IHatsMinimal.sol"; |
| 6 | + |
| 7 | +/// @title Hats Excubia Contract. |
| 8 | +/// @notice This contract extends the Excubia contract to integrate with the Hats protocol. |
| 9 | +/// This contract checks if a user is wearing a specific hat to permit access through the gate. |
| 10 | +/// @dev The contract uses a specific set of hats to admit the passerby wearing any of those hats. |
| 11 | +contract HatsExcubia is Excubia { |
| 12 | + /// @notice The Hats contract interface. |
| 13 | + IHatsMinimal public immutable HATS; |
| 14 | + |
| 15 | + /// @notice Mapping to track which hats are considered valid for passing the gate. |
| 16 | + mapping(uint256 => bool) public criterionHat; |
| 17 | + /// @notice Mapping to track which users have already passed through the gate. |
| 18 | + mapping(address => bool) public passedUsers; |
| 19 | + |
| 20 | + /// @notice Error thrown when the user is not wearing the required hat. |
| 21 | + error NotWearingCriterionHat(); |
| 22 | + /// @notice Error thrown when the specified hat is not a criterion hat. |
| 23 | + error NotCriterionHat(); |
| 24 | + /// @notice Error thrown when the array of criterion hats is empty. |
| 25 | + error ZeroCriterionHats(); |
| 26 | + |
| 27 | + /// @notice Constructor to initialize the contract with the target Hats contract and criterion hats. |
| 28 | + /// @param _hats The address of the Hats contract. |
| 29 | + /// @param _criterionHats An array of hat IDs that are considered as criteria for passing the gate. |
| 30 | + constructor(address _hats, uint256[] memory _criterionHats) { |
| 31 | + if (_hats == address(0)) revert ZeroAddress(); |
| 32 | + if (_criterionHats.length == 0) revert ZeroCriterionHats(); |
| 33 | + |
| 34 | + HATS = IHatsMinimal(_hats); |
| 35 | + |
| 36 | + uint256 numberOfCriterionHats = _criterionHats.length; |
| 37 | + |
| 38 | + for (uint256 i = 0; i < numberOfCriterionHats; ++i) { |
| 39 | + criterionHat[_criterionHats[i]] = true; |
| 40 | + } |
| 41 | + } |
| 42 | + |
| 43 | + /// @notice The trait of the Excubia contract. |
| 44 | + function trait() external pure override returns (string memory) { |
| 45 | + return "Hats"; |
| 46 | + } |
| 47 | + |
| 48 | + /// @notice Internal function to handle the passing logic with check. |
| 49 | + /// @dev Calls the parent `_pass` function and stores the user to avoid passing the gate twice. |
| 50 | + /// @param passerby The address of the entity attempting to pass the gate. |
| 51 | + /// @param data Additional data required for the check. |
| 52 | + function _pass(address passerby, bytes calldata data) internal override { |
| 53 | + // Avoiding passing the gate twice for the same user. |
| 54 | + if (passedUsers[passerby]) revert AlreadyPassed(); |
| 55 | + |
| 56 | + passedUsers[passerby] = true; |
| 57 | + |
| 58 | + super._pass(passerby, data); |
| 59 | + } |
| 60 | + |
| 61 | + /// @notice Internal function to handle the gate protection (hat check) logic. |
| 62 | + /// @dev Checks if the user is wearing one of the criterion hats. |
| 63 | + /// @param passerby The address of the entity attempting to pass the gate. |
| 64 | + /// @param data Additional data required for the check. |
| 65 | + function _check(address passerby, bytes calldata data) internal view override { |
| 66 | + super._check(passerby, data); |
| 67 | + |
| 68 | + uint256 hat = abi.decode(data, (uint256)); |
| 69 | + |
| 70 | + // Check if the hat is a criterion hat. |
| 71 | + if (!criterionHat[hat]) revert NotCriterionHat(); |
| 72 | + |
| 73 | + // Check if the user is wearing the criterion hat. |
| 74 | + if (!HATS.isWearerOfHat(passerby, hat)) revert NotWearingCriterionHat(); |
| 75 | + } |
| 76 | +} |
0 commit comments