Skip to content

Commit

Permalink
refactor(HatsGatekeepers): split into one file per contract per @0xmad
Browse files Browse the repository at this point in the history
…suggestion

Breaks HatsGatekeepers.sol into multiple files to conform to solhint style guide. Also:

- Adds IHats interface
- Adds HatsGatekeeperBase abstract contract for common elements
  • Loading branch information
spengrah committed Mar 18, 2024
1 parent d8cd814 commit a4d1dce
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 142 deletions.
127 changes: 0 additions & 127 deletions contracts/contracts/gatekeepers/HatsGatekeepers.sol

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { SignUpGatekeeper } from "../SignUpGatekeeper.sol";
import { IHats } from "../../interfaces/IHats.sol";

/// @title HatsGatekeeperBase
/// @notice Abastract contract containing the base elements of a Hats Gatekeeper contract
abstract contract HatsGatekeeperBase is SignUpGatekeeper, Ownable {
/*//////////////////////////////////////////////////////////////
CUSTOM ERRORS
//////////////////////////////////////////////////////////////*/

error OnlyMACI();
error NotWearingCriterionHat();
error AlreadyRegistered();

/*//////////////////////////////////////////////////////////////
PUBLIC CONSTANTS
//////////////////////////////////////////////////////////////*/

/// @notice The Hats Protocol contract address
IHats public immutable hats;

/*//////////////////////////////////////////////////////////////
PUBLIC STATE VARIABLES
//////////////////////////////////////////////////////////////*/

/// @notice the reference to the MACI contract
address public maci;

/// @notice Tracks registered users
mapping(address => bool) public registered;

/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/

/// @notice Deploy an instance of HatsGatekeeper
/// @param _hats The Hats Protocol contract
constructor(address _hats) payable {
hats = IHats(_hats);
}

/*//////////////////////////////////////////////////////////////
OWNER FUNCTIONS
//////////////////////////////////////////////////////////////*/

/// @notice Allows to set the MACI contract
/// @param _maci The MACI contract interface to be stored
function setMaciInstance(address _maci) public override onlyOwner {
maci = _maci;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import { HatsGatekeeperBase } from "./HatsGatekeeperBase.sol";

/// @title HatsGatekeeperMultiple
/// @notice A gatekeeper contract which allows users to sign up to MACI
/// only if they are wearing one of the specified hats
contract HatsGatekeeperMultiple is HatsGatekeeperBase {
/*//////////////////////////////////////////////////////////////
CUSTOM ERRORS
//////////////////////////////////////////////////////////////*/

error NotCriterionHat();

/*//////////////////////////////////////////////////////////////
PUBLIC CONSTANTS
//////////////////////////////////////////////////////////////*/

/// @notice Tracks hats that users must wear to be eligible to register
mapping(uint256 => bool) public criterionHat;

/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/

/// @notice Deploy an instance of HatsGatekeeperMultiple
/// @param _hats The Hats Protocol contract
/// @param _criterionHats Array of accepted criterion hats
constructor(address _hats, uint256[] memory _criterionHats) payable HatsGatekeeperBase(_hats) {
// add the criterion hats
for (uint256 i; i < _criterionHats.length; ++i) {
criterionHat[_criterionHats[i]] = true;
}
}

/*//////////////////////////////////////////////////////////////
GATEKEEPER FUNCTION
//////////////////////////////////////////////////////////////*/

/// @notice Registers the user
/// @param _user The address of the user
/// @param _data additional data
function register(address _user, bytes memory _data) public override {
// ensure that the caller is the MACI contract
if (maci != msg.sender) revert OnlyMACI();

// _user must not be already registered
if (registered[_user]) revert AlreadyRegistered();

// decode the _data as a hat
uint256 hat = abi.decode(_data, (uint256));

// the hat must be set as a criterion hat
if (!criterionHat[hat]) revert NotCriterionHat();

registered[_user] = true;

// _user must be wearing the criterion hat
if (!hats.isWearerOfHat(_user, hat)) revert NotWearingCriterionHat();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import { HatsGatekeeperBase } from "./HatsGatekeeperBase.sol";

/// @title HatsGatekeeperSingle
/// @notice A gatekeeper contract which allows users to sign up to MACI
/// only if they are wearing a specified hat
contract HatsGatekeeperSingle is HatsGatekeeperBase {
/*//////////////////////////////////////////////////////////////
PUBLIC CONSTANTS
//////////////////////////////////////////////////////////////*/

/// @notice The hat that users must wear to be eligible to register
uint256 public immutable criterionHat;

/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/

/// @notice Deploy an instance of HatsGatekeeperSingle
/// @param _hats The Hats Protocol contract
/// @param _criterionHat The required hat
constructor(address _hats, uint256 _criterionHat) payable HatsGatekeeperBase(_hats) {
criterionHat = _criterionHat;
}

/*//////////////////////////////////////////////////////////////
GATEKEEPER FUNCTION
//////////////////////////////////////////////////////////////*/

/// @notice Registers the user
/// @param _user The address of the user
function register(address _user, bytes memory /*_data*/) public override {
// ensure that the caller is the MACI contract
if (maci != msg.sender) revert OnlyMACI();

// _user must not be already registered
if (registered[_user]) revert AlreadyRegistered();

registered[_user] = true;

// _user must be wearing the criterion hat
if (!hats.isWearerOfHat(_user, criterionHat)) revert NotWearingCriterionHat();
}
}
23 changes: 23 additions & 0 deletions contracts/contracts/interfaces/IHats.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

/// @title IHats
/// @notice Minimal interface for the Hats Protocol contract
/// @dev Includes only the functions required for the HatsGatekeepers and associated tests
interface IHats {
function mintTopHat(address _target, string calldata _details, string calldata _imageURI) external returns (uint256);

function createHat(
uint256 _admin,
string calldata _details,
uint32 _maxSupply,
address _eligibility,
address _toggle,
bool _mutable,
string calldata _imageURI
) external returns (uint256);

function mintHat(uint256 _hatId, address _wearer) external returns (bool success);

function isWearerOfHat(address account, uint256 hat) external view returns (bool);
}
16 changes: 1 addition & 15 deletions contracts/contracts/mocks/MockHatsProtocol.sol
Original file line number Diff line number Diff line change
@@ -1,21 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

/// @title IHats
/// @notice The interface for the Hats Protocol contract
interface IHats {
function mintTopHat(address _target, string calldata _details, string calldata _imageURI) external returns (uint256);
function createHat(
uint256 _admin,
string calldata _details,
uint32 _maxSupply,
address _eligibility,
address _toggle,
bool _mutable,
string calldata _imageURI
) external returns (uint256);
function mintHat(uint256 _hatId, address _wearer) external returns (bool success);
}
import { IHats } from "../interfaces/IHats.sol";

/// @title MockHatsProtocol
/// @notice A mock contract to test the HatsGatekeeper
Expand Down

0 comments on commit a4d1dce

Please sign in to comment.