diff --git a/packages/foundry/contracts/HatsEligibilityModule.sol b/packages/foundry/contracts/HatsEligibilityModule.sol new file mode 100644 index 0000000..11a11a8 --- /dev/null +++ b/packages/foundry/contracts/HatsEligibilityModule.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +// import { console2 } from "forge-std/Test.sol"; // remove before deploy +import { HatsModule } from "./HatsModule.sol"; +import { IHatsEligibility } from "hats-protocol/Interfaces/IHatsEligibility.sol"; + +abstract contract HatsEligibilityModule is HatsModule, IHatsEligibility { + /** + * @dev Contracts that inherit from HatsEligibilityModule must call the HatsModule constructor: + * `HatsModule(_version)`. + */ + + /*////////////////////////////////////////////////////////////// + HATS ELIGIBILITY FUNCTION + //////////////////////////////////////////////////////////////*/ + + /// @inheritdoc IHatsEligibility + function getWearerStatus(address _wearer, uint256 _hatId) + public + view + virtual + override + returns (bool eligible, bool standing) + { } +} diff --git a/packages/foundry/contracts/HatsModule.sol b/packages/foundry/contracts/HatsModule.sol new file mode 100644 index 0000000..e14283f --- /dev/null +++ b/packages/foundry/contracts/HatsModule.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +// import { console2 } from "forge-std/Test.sol"; // remove before deploy +import { IHats } from "hats-protocol/Interfaces/IHats.sol"; +import { IHatsModule } from "./IHatsModule.sol"; +import { Clone } from "solady/utils/Clone.sol"; +import { Initializable } from "@openzeppelin-contracts/contracts/proxy/utils/Initializable.sol"; + +contract HatsModule is IHatsModule, Clone, Initializable { + /*////////////////////////////////////////////////////////////// + PUBLIC CONSTANTS + //////////////////////////////////////////////////////////////*/ + + /** + * This contract is a clone with immutable args, which means that it is deployed with a set of + * immutable storage variables (ie constants). Accessing these constants is cheaper than accessing + * regular storage variables (such as those set on initialization of a typical EIP-1167 clone), + * but requires a slightly different approach since they are read from calldata instead of storage. + * + * Below is a table of constants and their location. + * + * For more, see here: https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args + * + * --------------------------------------------------------------------+ + * CLONE IMMUTABLE "STORAGE" | + * --------------------------------------------------------------------| + * Offset | Constant | Type | Length | | + * --------------------------------------------------------------------| + * 0 | IMPLEMENTATION | address | 20 | | + * 20 | HATS | address | 20 | | + * 40 | hatId | uint256 | 32 | | + * 72+ | [other args] | [type] | [len] | | + * --------------------------------------------------------------------+ + */ + + /// @inheritdoc IHatsModule + function IMPLEMENTATION() public pure returns (address) { + return _getArgAddress(0); + } + + /// @inheritdoc IHatsModule + function HATS() public pure returns (IHats) { + return IHats(_getArgAddress(20)); + } + + /// @inheritdoc IHatsModule + function hatId() public pure returns (uint256) { + return _getArgUint256(40); + } + + /// @inheritdoc IHatsModule + string public version_; + + /// @inheritdoc IHatsModule + function version() public view returns (string memory) { + return HatsModule(IMPLEMENTATION()).version_(); + } + + /*////////////////////////////////////////////////////////////// + INITIALIZER + //////////////////////////////////////////////////////////////*/ + + /// @inheritdoc IHatsModule + function setUp(bytes calldata _initData) public initializer { + _setUp(_initData); + } + + /// @dev Override this function to set initial operational values for module instances + function _setUp(bytes calldata _initData) internal virtual { } + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + /// @notice Deploy the implementation contract and set its version + /// @dev This is only used to deploy the implementation contract, and should not be used to deploy clones + constructor(string memory _version) { + version_ = _version; + // prevent the implementation contract from being initialized + _disableInitializers(); + } +} diff --git a/packages/foundry/contracts/IHatsModule.sol b/packages/foundry/contracts/IHatsModule.sol new file mode 100644 index 0000000..fa624c4 --- /dev/null +++ b/packages/foundry/contracts/IHatsModule.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { IHats } from "hats-protocol/Interfaces/IHats.sol"; + +interface IHatsModule { + /// @notice Hats Protocol address + function HATS() external pure returns (IHats); + + /// @notice The address of the implementation contract of which this instance is a clone + function IMPLEMENTATION() external pure returns (address); + + /// @notice The hat id for which this HatsModule instance has been deployed + function hatId() external pure returns (uint256); + + /** + * @notice Sets up this instance with initial operational values (`_initData`) + * @dev This function can only be called once, on initialization + * @param _initData Data to set up initial operational values for this instance + */ + function setUp(bytes memory _initData) external; + + /// @notice The version of this HatsModule + /// @dev Used only for the implementation contract; for clones, use {version} + function version_() external view returns (string memory); + + /// @notice The version of this HatsModule + function version() external view returns (string memory); +}