-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Complete porting for MACI gatekeepers (#31)
<!-- Please refer to our CONTRIBUTING documentation for any questions on submitting a pull request. --> <!-- Provide a general summary of your changes in the Title above. --> ## Description This PR adds the `GitcoinPassportExcubia`, `ZKEdDSAEventTicketPCDExcubia` (prev Zupass) and, `HatsExcubia`. During the porting process, certain interfaces were extended and controls and methods generalised. The code coverage is 100%. Also, this PR introduces the concept of `trait` aka the specific type of an Excubia contract. For example, `SemaphoreExcubia` has trait `Semaphore` and so on. This will make easy to discriminate and query multiple Excubiae sharing the same characteristics. <!-- Describe your changes in detail. --> <!-- You may want to answer some of the following questions: --> <!-- What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...) --> <!-- What is the current behavior?** (You can also link to an open issue here) --> <!-- What is the new behavior (if this is a feature change)? --> <!-- Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?) --> ## Related Issue(s) closes #18 <!-- This project accepts pull requests related to open issues. --> <!-- If suggesting a new feature or change, please discuss it in an issue first. --> <!-- If fixing a bug, there should be an issue describing it with steps to reproduce. --> <!-- Please link to the issue(s) here --> <!-- Closes # --> <!-- Fixes # --> ## Checklist <!-- Please check if the PR fulfills these requirements. --> - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] My changes generate no new warnings - [x] I have run `yarn format` and `yarn compile` without getting any errors - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes
- Loading branch information
Showing
24 changed files
with
1,601 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
packages/excubiae/contracts/extensions/GitcoinPassportExcubia.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.0; | ||
|
||
import {Excubia} from "../Excubia.sol"; | ||
import {IGitcoinPassportDecoder} from "./interfaces/IGitcoinPassportDecoder.sol"; | ||
|
||
/// @title Gitcoin Passport Excubia Contract. | ||
/// @notice This contract extends the Excubia contract to integrate with the Gitcoin Passport Decoder. | ||
/// This contract checks the Gitcoin Passport user score to permit access through the gate. | ||
/// The Gitcoin Passport smart contract stack is built on top of Ethereum Attestation Service (EAS) contracts. | ||
/// @dev The contract uses a fixed threshold score to admit only passersby with a passport score | ||
/// equal to or greater than the fixed threshold based on their score (see _check() for more). | ||
contract GitcoinPassportExcubia is Excubia { | ||
/// @notice The factor used to scale the score. | ||
/// @dev https://docs.passport.xyz/building-with-passport/smart-contracts/contract-reference#available-methods | ||
uint256 public constant FACTOR = 100; | ||
|
||
/// @notice The Gitcoin Passport Decoder contract interface. | ||
IGitcoinPassportDecoder public immutable DECODER; | ||
|
||
/// @notice The minimum threshold score required to pass the gate. | ||
uint256 public immutable THRESHOLD_SCORE; | ||
|
||
/// @notice Mapping to track which users have already passed through the gate. | ||
mapping(address => bool) public passedUsers; | ||
|
||
/// @notice Error thrown when the user's score is insufficient to pass the gate. | ||
error InsufficientScore(); | ||
|
||
/// @notice Error thrown when the threshold score is negative or zero. | ||
error NegativeOrZeroThresholdScore(); | ||
|
||
/// @notice Constructor to initialize the contract with the target decoder and threshold score. | ||
/// @param _decoder The address of the Gitcoin Passport Decoder contract. | ||
/// @param _thresholdScore The minimum threshold score required to pass the gate. | ||
constructor(address _decoder, uint256 _thresholdScore) { | ||
if (_decoder == address(0)) revert ZeroAddress(); | ||
if (_thresholdScore <= 0) revert NegativeOrZeroThresholdScore(); | ||
|
||
DECODER = IGitcoinPassportDecoder(_decoder); | ||
THRESHOLD_SCORE = _thresholdScore; | ||
} | ||
|
||
/// @notice The trait of the Excubia contract. | ||
function trait() external pure override returns (string memory) { | ||
return "GitcoinPassport"; | ||
} | ||
|
||
/// @notice Internal function to handle the passing logic with check. | ||
/// @dev Calls the parent `_pass` function and stores the user to avoid passing the gate twice. | ||
/// @param passerby The address of the entity attempting to pass the gate. | ||
/// @param data Additional data required for the check. | ||
function _pass(address passerby, bytes calldata data) internal override { | ||
if (passedUsers[passerby]) revert AlreadyPassed(); | ||
|
||
passedUsers[passerby] = true; | ||
|
||
super._pass(passerby, data); | ||
} | ||
|
||
/// @notice Internal function to handle the gate protection (score check) logic. | ||
/// @dev Checks if the user's Gitcoin Passport score meets the threshold. | ||
/// @param passerby The address of the entity attempting to pass the gate. | ||
/// @param data Additional data required for the check. | ||
function _check(address passerby, bytes calldata data) internal view override { | ||
super._check(passerby, data); | ||
|
||
if ((DECODER.getScore(passerby) / FACTOR) < THRESHOLD_SCORE) revert InsufficientScore(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.0; | ||
|
||
import {Excubia} from "../Excubia.sol"; | ||
import {IHatsMinimal} from "./interfaces/IHatsMinimal.sol"; | ||
|
||
/// @title Hats Excubia Contract. | ||
/// @notice This contract extends the Excubia contract to integrate with the Hats protocol. | ||
/// This contract checks if a user is wearing a specific hat to permit access through the gate. | ||
/// @dev The contract uses a specific set of hats to admit the passerby wearing any of those hats. | ||
contract HatsExcubia is Excubia { | ||
/// @notice The Hats contract interface. | ||
IHatsMinimal public immutable HATS; | ||
|
||
/// @notice Mapping to track which hats are considered valid for passing the gate. | ||
mapping(uint256 => bool) public criterionHat; | ||
/// @notice Mapping to track which users have already passed through the gate. | ||
mapping(address => bool) public passedUsers; | ||
|
||
/// @notice Error thrown when the user is not wearing the required hat. | ||
error NotWearingCriterionHat(); | ||
/// @notice Error thrown when the specified hat is not a criterion hat. | ||
error NotCriterionHat(); | ||
/// @notice Error thrown when the array of criterion hats is empty. | ||
error ZeroCriterionHats(); | ||
|
||
/// @notice Constructor to initialize the contract with the target Hats contract and criterion hats. | ||
/// @param _hats The address of the Hats contract. | ||
/// @param _criterionHats An array of hat IDs that are considered as criteria for passing the gate. | ||
constructor(address _hats, uint256[] memory _criterionHats) { | ||
if (_hats == address(0)) revert ZeroAddress(); | ||
if (_criterionHats.length == 0) revert ZeroCriterionHats(); | ||
|
||
HATS = IHatsMinimal(_hats); | ||
|
||
uint256 numberOfCriterionHats = _criterionHats.length; | ||
|
||
for (uint256 i = 0; i < numberOfCriterionHats; ++i) { | ||
criterionHat[_criterionHats[i]] = true; | ||
} | ||
} | ||
|
||
/// @notice The trait of the Excubia contract. | ||
function trait() external pure override returns (string memory) { | ||
return "Hats"; | ||
} | ||
|
||
/// @notice Internal function to handle the passing logic with check. | ||
/// @dev Calls the parent `_pass` function and stores the user to avoid passing the gate twice. | ||
/// @param passerby The address of the entity attempting to pass the gate. | ||
/// @param data Additional data required for the check. | ||
function _pass(address passerby, bytes calldata data) internal override { | ||
// Avoiding passing the gate twice for the same user. | ||
if (passedUsers[passerby]) revert AlreadyPassed(); | ||
|
||
passedUsers[passerby] = true; | ||
|
||
super._pass(passerby, data); | ||
} | ||
|
||
/// @notice Internal function to handle the gate protection (hat check) logic. | ||
/// @dev Checks if the user is wearing one of the criterion hats. | ||
/// @param passerby The address of the entity attempting to pass the gate. | ||
/// @param data Additional data required for the check. | ||
function _check(address passerby, bytes calldata data) internal view override { | ||
super._check(passerby, data); | ||
|
||
uint256 hat = abi.decode(data, (uint256)); | ||
|
||
// Check if the hat is a criterion hat. | ||
if (!criterionHat[hat]) revert NotCriterionHat(); | ||
|
||
// Check if the user is wearing the criterion hat. | ||
if (!HATS.isWearerOfHat(passerby, hat)) revert NotWearingCriterionHat(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.