Skip to content

Commit 78f2e3c

Browse files
committed
docs(contracts): update code comments
1 parent 4d51d42 commit 78f2e3c

File tree

7 files changed

+66
-284
lines changed

7 files changed

+66
-284
lines changed

packages/contracts/contracts/extensions/SemaphoreChecker.sol

+20-22
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,59 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity >=0.8.23 <=0.8.28;
2+
pragma solidity ^0.8.20;
33

44
import {ISemaphore} from "@semaphore-protocol/contracts/interfaces/ISemaphore.sol";
55
import {BaseChecker} from "../checker/BaseChecker.sol";
66

77
/// @title SemaphoreChecker
8-
/// @notice Semaphore proof of membership validator.
9-
/// @dev Extends BaseChecker to implement proof of membership validation logic using Semaphore.
10-
/// Please note that once a identity is used to register, it cannot be used again, thanks to the nullifier.
8+
/// @notice Implements proof of membership validation using Semaphore.
9+
/// @dev Inherits from BaseChecker to extend the validation logic.
10+
/// Ensures unique identity usage through nullifier tracking.
1111
contract SemaphoreChecker is BaseChecker {
12-
/// @notice Address of the Semaphore contract used for proof of membership validation.
12+
/// @notice Address of the Semaphore contract used for proof verification.
1313
ISemaphore public semaphore;
1414

15-
/// @notice The unique identifier of the Semaphore group.
16-
/// @dev The subject can prove membership only for the group having the following identifier.
15+
/// @notice Unique identifier for the Semaphore group.
16+
/// @dev Proofs are validated against this specific group ID.
1717
uint256 public groupId;
1818

19-
/// @notice Error thrown when the subject sends a proof with an invalid or mismatching prover in the scope.
19+
/// @notice Error thrown when the provided proof does not match the subject's address.
2020
error IncorrectProver();
2121

22-
/// @notice Error thrown when the subject sends a proof with an invalid or mismatching group id in the scope.
22+
/// @notice Error thrown when the provided proof does not match the expected group ID.
2323
error IncorrectGroupId();
2424

25-
/// @notice Error thrown when the subject sends an invalid proof.
25+
/// @notice Error thrown when the proof is invalid or fails verification.
2626
error InvalidProof();
2727

28-
/// @notice Initializes the contract with necessary parameters values.
29-
/// @dev Decodes the appended bytes from the clone to set the parameters values.
28+
/// @notice Initializes the SemaphoreChecker with the provided Semaphore contract address and group ID.
29+
/// @dev Decodes initialization parameters from appended bytes for clone deployments.
3030
function _initialize() internal override {
3131
super._initialize();
3232

3333
bytes memory data = _getAppendedBytes();
34-
3534
(address _semaphore, uint256 _groupId) = abi.decode(data, (address, uint256));
3635

3736
semaphore = ISemaphore(_semaphore);
3837
groupId = _groupId;
3938
}
4039

41-
/// @notice Validates whether the subject is a member of the group.
42-
/// @dev Decodes the proof from evidence and checks group membership based on proof validity.
43-
/// @param subject Address to validate ownership for.
44-
/// @param evidence Encoded proof used for validation.
45-
/// @return Boolean indicating whether the subject is a member of the group or not.
40+
/// @notice Verifies if the given subject is a valid member of the Semaphore group.
41+
/// @dev Decodes the evidence to extract the Semaphore proof and validates the subject's membership.
42+
/// @param subject The address of the user whose membership is being verified.
43+
/// @param evidence Encoded Semaphore proof containing membership verification details.
44+
/// @return Boolean indicating the success or failure of the membership verification.
4645
function _check(address subject, bytes calldata evidence) internal view override returns (bool) {
4746
super._check(subject, evidence);
4847

4948
ISemaphore.SemaphoreProof memory proof = abi.decode(evidence, (ISemaphore.SemaphoreProof));
5049

51-
// the scope is (uint256(uint160(_addr)) << 96) | uint256(_num).
52-
// this can avoid frontrunning (ie. subject encoded in the scope of the proof).
50+
// The proof scope encodes both the subject address and group ID to prevent front-running attacks.
5351
uint256 _scope = proof.scope;
5452

55-
// first 20 byte (160bits) are the address.
53+
// Extract the subject's address (first 20 bytes, 160 bits) from the scope.
5654
address _prover = address(uint160(_scope >> 96));
5755

58-
// remaining 12 bytes (96bits) are for the group identifier.
56+
// Extract the group ID (remaining 12 bytes, 96 bits) from the scope.
5957
uint96 _groupId = uint96(_scope & ((1 << 96) - 1));
6058

6159
if (_prover != subject) revert IncorrectProver();

packages/contracts/contracts/extensions/SemaphoreCheckerFactory.sol

+4-5
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,19 @@ import {Factory} from "../proxy/Factory.sol";
66

77
/// @title SemaphoreCheckerFactory
88
/// @notice Factory contract for deploying minimal proxy instances of SemaphoreChecker.
9-
/// @dev Simplifies deployment of Semaphore checker clones with appended configuration data.
9+
/// @dev Utilizes the Factory pattern to streamline deployment of SemaphoreChecker clones with configuration data.
1010
contract SemaphoreCheckerFactory is Factory {
1111
/// @notice Initializes the factory with the SemaphoreChecker implementation.
12+
/// @dev The constructor sets the SemaphoreChecker contract as the implementation for cloning.
1213
constructor() Factory(address(new SemaphoreChecker())) {}
1314

14-
/// @notice Deploys a new SemaphoreChecker clone with the specified target Semaphore contract and group identifier.
15-
/// @dev Encodes the Semaphore contract and group identifier as configuration data for the clone.
15+
/// @notice Deploys a new SemaphoreChecker clone with the specified Semaphore contract and group ID.
16+
/// @dev Encodes the Semaphore contract address and group ID as initialization data for the clone.
1617
/// @param _semaphore Address of the Semaphore contract.
1718
/// @param _groupId Unique identifier of the Semaphore group.
1819
function deploy(address _semaphore, uint256 _groupId) public {
1920
bytes memory data = abi.encode(_semaphore, _groupId);
20-
2121
address clone = super._deploy(data);
22-
2322
SemaphoreChecker(clone).initialize();
2423
}
2524
}

packages/contracts/contracts/extensions/SemaphorePolicy.sol

+11-10
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,26 @@ import {ISemaphore} from "@semaphore-protocol/contracts/interfaces/ISemaphore.so
55
import {BasePolicy} from "../policy/BasePolicy.sol";
66

77
/// @title SemaphorePolicy
8-
/// @notice Policy contract enforcing proof of membership of Semaphore group validation.
9-
/// @dev Extends BasePolicy to add specific behavior for Semaphore proof of membership validation.
8+
/// @notice Policy contract enforcing Semaphore group membership validation.
9+
/// @dev Extends BasePolicy to add logic for tracking and preventing nullifier reuse, ensuring one-time proof validity.
1010
contract SemaphorePolicy is BasePolicy {
11-
/// @notice Tracks nullifier spent for each valid proof / check.
11+
/// @notice Mapping to track spent nullifiers for each validated proof.
1212
mapping(uint256 => bool) public spentNullifiers;
1313

14-
/// @notice Error thrown when the subject sends a proof with an already spent nullifier.
14+
/// @notice Error thrown when a proof is submitted with an already spent nullifier.
1515
error AlreadySpentNullifier();
1616

17-
/// @notice Returns a trait identifier for the policy.
18-
/// @dev Used to identify the policy type.
19-
/// @return The trait string "Semaphore".
17+
/// @notice Returns the policy trait identifier.
18+
/// @dev Identifies the policy as a Semaphore-based validation mechanism.
19+
/// @return The trait identifier string "Semaphore".
2020
function trait() external pure returns (string memory) {
2121
return "Semaphore";
2222
}
2323

24-
/// @notice Internal logic for enforcing checks.
25-
/// @param subject Address to enforce the policy on.
26-
/// @param evidence Custom validation data.
24+
/// @notice Internal enforcement logic to validate proofs and track nullifier usage.
25+
/// @dev Decodes the Semaphore proof from evidence and ensures the nullifier hasn't been previously used.
26+
/// @param subject Address of the entity being validated.
27+
/// @param evidence Encoded Semaphore proof data.
2728
function _enforce(address subject, bytes calldata evidence) internal override {
2829
ISemaphore.SemaphoreProof memory proof = abi.decode(evidence, (ISemaphore.SemaphoreProof));
2930
uint256 _nullifier = proof.nullifier;

packages/contracts/contracts/extensions/SemaphorePolicyFactory.sol

+4-6
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,18 @@ import {Factory} from "../proxy/Factory.sol";
66

77
/// @title SemaphorePolicyFactory
88
/// @notice Factory contract for deploying minimal proxy instances of SemaphorePolicy.
9-
/// @dev Simplifies deployment of Semaphore policy clones with appended configuration data.
9+
/// @dev Utilizes the Factory pattern to deploy SemaphorePolicy clones with custom configuration data.
1010
contract SemaphorePolicyFactory is Factory {
1111
/// @notice Initializes the factory with the SemaphorePolicy implementation.
12+
/// @dev The constructor sets the SemaphorePolicy contract as the implementation for cloning.
1213
constructor() Factory(address(new SemaphorePolicy())) {}
1314

1415
/// @notice Deploys a new SemaphorePolicy clone with the specified checker address.
15-
/// @dev Encodes the checker address and caller as configuration data for the clone.
16-
/// @param _checker Address of the Semaphore checker to use for validation.
16+
/// @dev Encodes the deployer (as owner) and checker address as initialization data for the clone.
17+
/// @param _checker Address of the Semaphore checker used for proof validation.
1718
function deploy(address _checker) public {
18-
// Encode the caller (owner) and checker address for appended data.
1919
bytes memory data = abi.encode(msg.sender, _checker);
20-
2120
address clone = super._deploy(data);
22-
2321
SemaphorePolicy(clone).initialize();
2422
}
2523
}

packages/contracts/contracts/test/extensions/Semaphore.t.sol

-188
Original file line numberDiff line numberDiff line change
@@ -466,191 +466,3 @@ contract SemaphoreMockTest is Test {
466466
semaphoreMock.validateProof(0, validProof);
467467
}
468468
}
469-
470-
// contract Voting is Test {
471-
// event Registered(address voter);
472-
// event Voted(address voter, uint8 option);
473-
474-
// NFT internal nft;
475-
// BaseERC721Checker internal checker;
476-
// BaseERC721CheckerFactory internal checkerFactory;
477-
// BaseERC721Policy internal policy;
478-
// BaseERC721PolicyFactory internal policyFactory;
479-
// BaseVoting internal voting;
480-
481-
// address public deployer = vm.addr(0x1);
482-
// address public subject = vm.addr(0x2);
483-
// address public notOwner = vm.addr(0x3);
484-
485-
// function setUp() public virtual {
486-
// vm.startPrank(deployer);
487-
488-
// nft = new NFT();
489-
490-
// checkerFactory = new BaseERC721CheckerFactory();
491-
// policyFactory = new BaseERC721PolicyFactory();
492-
493-
// vm.recordLogs();
494-
// checkerFactory.deploy(address(nft));
495-
// Vm.Log[] memory entries = vm.getRecordedLogs();
496-
// address checkerClone = address(uint160(uint256(entries[0].topics[1])));
497-
// checker = BaseERC721Checker(checkerClone);
498-
499-
// vm.recordLogs();
500-
// policyFactory.deploy(address(checker));
501-
// entries = vm.getRecordedLogs();
502-
// address policyClone = address(uint160(uint256(entries[0].topics[1])));
503-
// policy = BaseERC721Policy(policyClone);
504-
505-
// voting = new BaseVoting(policy);
506-
507-
// vm.stopPrank();
508-
// }
509-
510-
// function test_voting_deployed() public view {
511-
// assertEq(address(voting.POLICY()), address(policy));
512-
// assertEq(voting.hasVoted(subject), false);
513-
// assertEq(voting.registered(subject), false);
514-
// }
515-
516-
// function test_register_whenCallerNotTarget_reverts() public {
517-
// vm.startPrank(deployer);
518-
519-
// policy.setTarget(deployer);
520-
// nft.mint(subject);
521-
522-
// vm.stopPrank();
523-
524-
// vm.startPrank(notOwner);
525-
526-
// vm.expectRevert(abi.encodeWithSelector(IPolicy.TargetOnly.selector));
527-
// voting.register(0);
528-
529-
// vm.stopPrank();
530-
// }
531-
532-
// function test_register_whenTokenDoesNotExist_reverts() public {
533-
// vm.startPrank(deployer);
534-
535-
// policy.setTarget(address(voting));
536-
// nft.mint(subject);
537-
538-
// vm.stopPrank();
539-
540-
// vm.startPrank(subject);
541-
542-
// vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1)));
543-
// voting.register(1);
544-
545-
// vm.stopPrank();
546-
// }
547-
548-
// function test_register_whenCheckFails_reverts() public {
549-
// vm.startPrank(deployer);
550-
551-
// policy.setTarget(address(voting));
552-
// nft.mint(subject);
553-
554-
// vm.stopPrank();
555-
556-
// vm.startPrank(notOwner);
557-
558-
// vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector));
559-
// voting.register(0);
560-
561-
// vm.stopPrank();
562-
// }
563-
564-
// function test_register_whenValid_succeeds() public {
565-
// vm.startPrank(deployer);
566-
567-
// policy.setTarget(address(voting));
568-
// nft.mint(subject);
569-
570-
// vm.stopPrank();
571-
572-
// vm.startPrank(subject);
573-
574-
// vm.expectEmit(true, true, true, true);
575-
// emit Registered(subject);
576-
577-
// voting.register(0);
578-
579-
// vm.stopPrank();
580-
// }
581-
582-
// function test_vote_whenNotRegistered_reverts() public {
583-
// vm.startPrank(deployer);
584-
585-
// policy.setTarget(address(voting));
586-
// nft.mint(subject);
587-
588-
// vm.stopPrank();
589-
590-
// vm.startPrank(subject);
591-
592-
// vm.expectRevert(abi.encodeWithSelector(BaseVoting.NotRegistered.selector));
593-
// voting.vote(0);
594-
595-
// vm.stopPrank();
596-
// }
597-
598-
// function test_vote_whenInvalidOption_reverts() public {
599-
// vm.startPrank(deployer);
600-
601-
// policy.setTarget(address(voting));
602-
// nft.mint(subject);
603-
604-
// vm.stopPrank();
605-
606-
// vm.startPrank(subject);
607-
// voting.register(0);
608-
609-
// vm.expectRevert(abi.encodeWithSelector(BaseVoting.InvalidOption.selector));
610-
// voting.vote(3);
611-
612-
// vm.stopPrank();
613-
// }
614-
615-
// function test_vote_whenValid_succeeds() public {
616-
// vm.startPrank(deployer);
617-
618-
// policy.setTarget(address(voting));
619-
// nft.mint(subject);
620-
621-
// vm.stopPrank();
622-
623-
// vm.startPrank(subject);
624-
// voting.register(0);
625-
626-
// assertEq(voting.registered(subject), true);
627-
628-
// vm.expectEmit(true, true, true, true);
629-
// emit Voted(subject, 0);
630-
631-
// voting.vote(0);
632-
633-
// assertEq(voting.hasVoted(subject), true);
634-
635-
// vm.stopPrank();
636-
// }
637-
638-
// function test_vote_whenAlreadyVoted_reverts() public {
639-
// vm.startPrank(deployer);
640-
641-
// policy.setTarget(address(voting));
642-
// nft.mint(subject);
643-
644-
// vm.stopPrank();
645-
646-
// vm.startPrank(subject);
647-
648-
// voting.register(0);
649-
// voting.vote(0);
650-
651-
// vm.expectRevert(abi.encodeWithSelector(BaseVoting.AlreadyVoted.selector));
652-
// voting.vote(0);
653-
654-
// vm.stopPrank();
655-
// }
656-
// }

packages/contracts/contracts/test/extensions/mocks/BaseCheckerMock.sol

+6-3
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ pragma solidity ^0.8.20;
44
import {IBaseChecker} from "../../../interfaces/IBaseChecker.sol";
55

66
/// @title BaseCheckerMock
7-
/// @notice This contract is a mock implementation of the IBaseChecker interface for testing purposes.
7+
/// @notice Mock implementation of the IBaseChecker interface for testing purposes.
8+
/// @dev Provides a dummy check function that always returns false.
89
contract BaseCheckerMock is IBaseChecker {
9-
///@dev mock check() method that returns always false.
10-
function check(address /*subject*/, bytes calldata /*evidence*/) external pure override returns (bool) {
10+
/// @notice Mock check function that always returns false.
11+
/// @dev This function simulates a failed check for testing.
12+
/// @return Always returns false.
13+
function check(address, bytes calldata) external pure override returns (bool) {
1114
return false;
1215
}
1316
}

0 commit comments

Comments
 (0)