From 0bd434c320f711b41eabbc1f412461635e3f6aac Mon Sep 17 00:00:00 2001 From: 0xjei Date: Tue, 14 Jan 2025 19:15:57 +0100 Subject: [PATCH 1/2] feat(contracts): add standard way to call external verifiers and aggregate their logic --- .../contracts/src/AdvancedChecker.sol | 15 +- .../contracts/src/AdvancedPolicy.sol | 4 +- .../contracts/contracts/src/BaseChecker.sol | 9 +- .../contracts/contracts/src/BasePolicy.sol | 4 +- packages/contracts/contracts/src/Checker.sol | 38 +++ .../src/interfaces/IAdvancedChecker.sol | 6 +- .../src/interfaces/IAdvancedPolicy.sol | 4 +- .../contracts/src/interfaces/IBaseChecker.sol | 6 +- .../contracts/src/interfaces/IBasePolicy.sol | 4 +- .../contracts/src/interfaces/IChecker.sol | 9 + .../contracts/src/test/Advanced.t.sol | 244 +++++++++-------- .../contracts/contracts/src/test/Base.t.sol | 71 +++-- .../test/advanced/AdvancedERC721Checker.sol | 21 +- .../src/test/advanced/AdvancedVoting.sol | 15 +- .../src/test/base/BaseERC721Checker.sol | 10 +- .../contracts/src/test/base/BaseVoting.sol | 5 +- .../wrappers/AdvancedERC721CheckerHarness.sol | 15 +- .../wrappers/AdvancedERC721PolicyHarness.sol | 2 +- .../wrappers/BaseERC721CheckerHarness.sol | 6 +- .../test/wrappers/BaseERC721PolicyHarness.sol | 2 +- packages/contracts/test/Advanced.test.ts | 246 +++++++++--------- packages/contracts/test/Base.test.ts | 63 +++-- 22 files changed, 454 insertions(+), 345 deletions(-) create mode 100644 packages/contracts/contracts/src/Checker.sol create mode 100644 packages/contracts/contracts/src/interfaces/IChecker.sol diff --git a/packages/contracts/contracts/src/AdvancedChecker.sol b/packages/contracts/contracts/src/AdvancedChecker.sol index 2e59e5b..922b245 100644 --- a/packages/contracts/contracts/src/AdvancedChecker.sol +++ b/packages/contracts/contracts/src/AdvancedChecker.sol @@ -2,11 +2,14 @@ pragma solidity ^0.8.20; import {IAdvancedChecker, Check, CheckStatus} from "./interfaces/IAdvancedChecker.sol"; +import {Checker} from "./Checker.sol"; /// @title AdvancedChecker. /// @notice Multi-phase validation checker with pre, main, and post checks. /// @dev Base contract for implementing complex validation logic with configurable check phases. -abstract contract AdvancedChecker is IAdvancedChecker { +abstract contract AdvancedChecker is IAdvancedChecker, Checker { + constructor(address[] memory _verifiers) Checker(_verifiers) {} + /// @notice Entry point for validation checks. /// @param subject Address to validate. /// @param evidence Validation data. @@ -14,7 +17,7 @@ abstract contract AdvancedChecker is IAdvancedChecker { /// @return checked Validation result. function check( address subject, - bytes memory evidence, + bytes[] calldata evidence, Check checkType ) external view override returns (bool checked) { return _check(subject, evidence, checkType); @@ -26,7 +29,7 @@ abstract contract AdvancedChecker is IAdvancedChecker { /// @param evidence Validation data. /// @param checkType Check type to perform. /// @return checked Validation result. - function _check(address subject, bytes memory evidence, Check checkType) internal view returns (bool checked) { + function _check(address subject, bytes[] calldata evidence, Check checkType) internal view returns (bool checked) { if (checkType == Check.PRE) { return _checkPre(subject, evidence); } @@ -43,19 +46,19 @@ abstract contract AdvancedChecker is IAdvancedChecker { /// @param subject Address to validate. /// @param evidence Validation data. /// @return checked Validation result. - function _checkPre(address subject, bytes memory evidence) internal view virtual returns (bool checked) {} + function _checkPre(address subject, bytes[] calldata evidence) internal view virtual returns (bool checked) {} /// @notice Main validation implementation. /// @dev Override to implement main check logic. /// @param subject Address to validate. /// @param evidence Validation data. /// @return checked Validation result. - function _checkMain(address subject, bytes memory evidence) internal view virtual returns (bool checked) {} + function _checkMain(address subject, bytes[] calldata evidence) internal view virtual returns (bool checked) {} /// @notice Post-condition validation implementation. /// @dev Override to implement post-check logic. /// @param subject Address to validate. /// @param evidence Validation data. /// @return checked Validation result. - function _checkPost(address subject, bytes memory evidence) internal view virtual returns (bool checked) {} + function _checkPost(address subject, bytes[] calldata evidence) internal view virtual returns (bool checked) {} } diff --git a/packages/contracts/contracts/src/AdvancedPolicy.sol b/packages/contracts/contracts/src/AdvancedPolicy.sol index d1a9d2f..3d8ccde 100644 --- a/packages/contracts/contracts/src/AdvancedPolicy.sol +++ b/packages/contracts/contracts/src/AdvancedPolicy.sol @@ -43,7 +43,7 @@ abstract contract AdvancedPolicy is IAdvancedPolicy, Policy { /// @param subject Address to validate. /// @param evidence Validation data. /// @param checkType Type of check (PRE, MAIN, POST). - function enforce(address subject, bytes calldata evidence, Check checkType) external override onlyTarget { + function enforce(address subject, bytes[] calldata evidence, Check checkType) external override onlyTarget { _enforce(subject, evidence, checkType); } @@ -59,7 +59,7 @@ abstract contract AdvancedPolicy is IAdvancedPolicy, Policy { /// @custom:throws PreCheckNotEnforced If PRE check is required but not done. /// @custom:throws MainCheckNotEnforced If MAIN check is required but not done. /// @custom:throws MainCheckAlreadyEnforced If multiple MAIN checks not allowed. - function _enforce(address subject, bytes calldata evidence, Check checkType) internal { + function _enforce(address subject, bytes[] calldata evidence, Check checkType) internal { if (!ADVANCED_CHECKER.check(subject, evidence, checkType)) { revert UnsuccessfulCheck(); } diff --git a/packages/contracts/contracts/src/BaseChecker.sol b/packages/contracts/contracts/src/BaseChecker.sol index 5f2319b..bbb106b 100644 --- a/packages/contracts/contracts/src/BaseChecker.sol +++ b/packages/contracts/contracts/src/BaseChecker.sol @@ -2,18 +2,21 @@ pragma solidity ^0.8.20; import {IBaseChecker} from "./interfaces/IBaseChecker.sol"; +import {Checker} from "./Checker.sol"; /// @title BaseChecker /// @notice Abstract base contract for implementing validation checks. /// @dev Provides a standardized interface for implementing custom validation logic /// through the internal _check method. -abstract contract BaseChecker is IBaseChecker { +abstract contract BaseChecker is Checker, IBaseChecker { + constructor(address[] memory _verifiers) Checker(_verifiers) {} + /// @notice Validates evidence for a given subject address. /// @dev External view function that delegates to internal _check implementation. /// @param subject Address to validate. /// @param evidence Custom validation data. /// @return checked Boolean indicating if the check passed. - function check(address subject, bytes memory evidence) external view override returns (bool checked) { + function check(address subject, bytes[] calldata evidence) external view override returns (bool checked) { return _check(subject, evidence); } @@ -22,5 +25,5 @@ abstract contract BaseChecker is IBaseChecker { /// @param subject Address to validate. /// @param evidence Custom validation data. /// @return checked Boolean indicating if the check passed. - function _check(address subject, bytes memory evidence) internal view virtual returns (bool checked) {} + function _check(address subject, bytes[] calldata evidence) internal view virtual returns (bool checked) {} } diff --git a/packages/contracts/contracts/src/BasePolicy.sol b/packages/contracts/contracts/src/BasePolicy.sol index 6de4251..c9e9c5d 100644 --- a/packages/contracts/contracts/src/BasePolicy.sol +++ b/packages/contracts/contracts/src/BasePolicy.sol @@ -35,7 +35,7 @@ abstract contract BasePolicy is Policy, IBasePolicy { /// @custom:throws AlreadyEnforced if check was previously enforced. /// @custom:throws UnsuccessfulCheck if the check fails. /// @custom:emits Enforced when check succeeds. - function enforce(address subject, bytes calldata evidence) external override onlyTarget { + function enforce(address subject, bytes[] calldata evidence) external override onlyTarget { _enforce(subject, evidence); } @@ -45,7 +45,7 @@ abstract contract BasePolicy is Policy, IBasePolicy { /// @param evidence Additional data required for verification. /// @custom:throws AlreadyEnforced if already enforced for this subject. /// @custom:throws UnsuccessfulCheck if BASE_CHECKER.check returns false. - function _enforce(address subject, bytes calldata evidence) internal { + function _enforce(address subject, bytes[] memory evidence) internal { bool checked = BASE_CHECKER.check(subject, evidence); if (enforced[msg.sender][subject]) revert AlreadyEnforced(); diff --git a/packages/contracts/contracts/src/Checker.sol b/packages/contracts/contracts/src/Checker.sol new file mode 100644 index 0000000..d149fd6 --- /dev/null +++ b/packages/contracts/contracts/src/Checker.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IChecker} from "./interfaces/IChecker.sol"; + +/// @title Checker +/// @notice Abstract base contract for implementing attribute verification logic. +/// @dev Provides infrastructure to orchestrate third-party verifiers for single checks. +abstract contract Checker is IChecker { + /// @notice Array of third-party contract addresses used for verification. + /// @dev Can include existing and already deployed Checkers, NFTs, MACI polls, and/or any other contract + /// that provides evidence verification. These contracts should already be deployed and operational. + address[] internal verifiers; + + /// @notice Initializes the Checker with an optional list of third-party verification contracts. + /// @param _verifiers Array of addresses for existing verification contracts. + /// @dev Each address should point to a deployed contract that will be consulted during verification. + /// This array can remain empty if there's no reliance on external verifiers. + constructor(address[] memory _verifiers) { + verifiers = _verifiers; + } + + /// @notice Retrieves the list of third-party verifiers' addresses. + /// @return Array of addresses for the necessary verification contracts. + function getVerifiers() internal view returns (address[] memory) { + return verifiers; + } + + /// @notice Retrieves the verifier address at a specific index. + /// @param index The index of the verifier in the array. + /// @return The address of the verifier at the specified index. + /// @custom:throws VerifierNotFound if no address have been specified at given index. + function getVerifierAtIndex(uint256 index) internal view returns (address) { + if (index >= verifiers.length) revert VerifierNotFound(); + + return verifiers[index]; + } +} diff --git a/packages/contracts/contracts/src/interfaces/IAdvancedChecker.sol b/packages/contracts/contracts/src/interfaces/IAdvancedChecker.sol index 89b27f9..67d27e1 100644 --- a/packages/contracts/contracts/src/interfaces/IAdvancedChecker.sol +++ b/packages/contracts/contracts/src/interfaces/IAdvancedChecker.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; +import {IChecker} from "./IChecker.sol"; + /// @title Check. /// @notice Defines validation phases in the AdvancedChecker system. /// @custom:values PRE - Pre-condition validation. @@ -26,11 +28,11 @@ struct CheckStatus { /// @title IAdvancedChecker. /// @notice Defines multi-phase validation system interface. /// @dev Implement this for custom validation logic with pre/main/post checks. -interface IAdvancedChecker { +interface IAdvancedChecker is IChecker { /// @notice Validates subject against specified check type. /// @param subject Address to validate. /// @param evidence Validation data. /// @param checkType Check phase to execute. /// @return checked True if validation passes. - function check(address subject, bytes calldata evidence, Check checkType) external view returns (bool checked); + function check(address subject, bytes[] calldata evidence, Check checkType) external view returns (bool checked); } diff --git a/packages/contracts/contracts/src/interfaces/IAdvancedPolicy.sol b/packages/contracts/contracts/src/interfaces/IAdvancedPolicy.sol index fe544fd..d9f719d 100644 --- a/packages/contracts/contracts/src/interfaces/IAdvancedPolicy.sol +++ b/packages/contracts/contracts/src/interfaces/IAdvancedPolicy.sol @@ -27,12 +27,12 @@ interface IAdvancedPolicy is IPolicy { /// @param target Protected contract address. /// @param evidence Validation data. /// @param checkType Type of check performed. - event Enforced(address indexed subject, address indexed target, bytes evidence, Check checkType); + event Enforced(address indexed subject, address indexed target, bytes[] evidence, Check checkType); /// @notice Enforces validation check on subject. /// @dev Delegates to appropriate check method based on checkType. /// @param subject Address to validate. /// @param evidence Validation data. /// @param checkType Check phase to execute. - function enforce(address subject, bytes calldata evidence, Check checkType) external; + function enforce(address subject, bytes[] calldata evidence, Check checkType) external; } diff --git a/packages/contracts/contracts/src/interfaces/IBaseChecker.sol b/packages/contracts/contracts/src/interfaces/IBaseChecker.sol index 489ce06..d2f923d 100644 --- a/packages/contracts/contracts/src/interfaces/IBaseChecker.sol +++ b/packages/contracts/contracts/src/interfaces/IBaseChecker.sol @@ -1,12 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; +import {IChecker} from "./IChecker.sol"; + /// @title IBaseChecker. /// @notice Defines base validation functionality. -interface IBaseChecker { +interface IBaseChecker is IChecker { /// @notice Validates subject against evidence. /// @param subject Address to validate. /// @param evidence Validation data. /// @return checked True if validation passes. - function check(address subject, bytes calldata evidence) external view returns (bool checked); + function check(address subject, bytes[] calldata evidence) external view returns (bool checked); } diff --git a/packages/contracts/contracts/src/interfaces/IBasePolicy.sol b/packages/contracts/contracts/src/interfaces/IBasePolicy.sol index a7fbe8f..faef64e 100644 --- a/packages/contracts/contracts/src/interfaces/IBasePolicy.sol +++ b/packages/contracts/contracts/src/interfaces/IBasePolicy.sol @@ -10,10 +10,10 @@ interface IBasePolicy is IPolicy { /// @param subject Address that passed validation. /// @param target Protected contract address. /// @param evidence Validation data. - event Enforced(address indexed subject, address indexed target, bytes evidence); + event Enforced(address indexed subject, address indexed target, bytes[] evidence); /// @notice Enforces validation check on subject. /// @param subject Address to validate. /// @param evidence Validation data. - function enforce(address subject, bytes calldata evidence) external; + function enforce(address subject, bytes[] calldata evidence) external; } diff --git a/packages/contracts/contracts/src/interfaces/IChecker.sol b/packages/contracts/contracts/src/interfaces/IChecker.sol new file mode 100644 index 0000000..3b1b847 --- /dev/null +++ b/packages/contracts/contracts/src/interfaces/IChecker.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/// @title IChecker +/// @notice Core checker interface for attribute verification functionalities. +interface IChecker { + /// @notice Core error conditions. + error VerifierNotFound(); +} diff --git a/packages/contracts/contracts/src/test/Advanced.t.sol b/packages/contracts/contracts/src/test/Advanced.t.sol index 931dbd8..78902a0 100644 --- a/packages/contracts/contracts/src/test/Advanced.t.sol +++ b/packages/contracts/contracts/src/test/Advanced.t.sol @@ -24,12 +24,22 @@ contract AdvancedChecker is Test { address public subject = vm.addr(0x3); address public notOwner = vm.addr(0x4); + address[] internal verifiers; + bytes[] public evidence = new bytes[](1); + bytes[] public wrongEvidence = new bytes[](1); + function setUp() public virtual { vm.startPrank(deployer); nft = new NFT(); - checker = new AdvancedERC721Checker(nft, 1, 0, 10); - checkerHarness = new AdvancedERC721CheckerHarness(nft, 1, 0, 10); + verifiers = new address[](1); + verifiers[0] = address(nft); + + checker = new AdvancedERC721Checker(verifiers, 1, 0, 10); + checkerHarness = new AdvancedERC721CheckerHarness(verifiers, 1, 0, 10); + + evidence[0] = abi.encode(0); + wrongEvidence[0] = abi.encode(1); vm.stopPrank(); } @@ -38,7 +48,7 @@ contract AdvancedChecker is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(0))); - checker.check(subject, abi.encode(0), Check.PRE); + checker.check(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -48,7 +58,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(!checker.check(notOwner, abi.encode(0), Check.PRE)); + assert(!checker.check(notOwner, evidence, Check.PRE)); vm.stopPrank(); } @@ -58,7 +68,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(checker.check(subject, abi.encode(0), Check.PRE)); + assert(checker.check(subject, evidence, Check.PRE)); vm.stopPrank(); } @@ -68,7 +78,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(!checker.check(notOwner, abi.encode(0), Check.MAIN)); + assert(!checker.check(notOwner, evidence, Check.MAIN)); vm.stopPrank(); } @@ -78,7 +88,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(checker.check(subject, abi.encode(0), Check.MAIN)); + assert(checker.check(subject, evidence, Check.MAIN)); vm.stopPrank(); } @@ -87,7 +97,7 @@ contract AdvancedChecker is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - checker.check(subject, abi.encode(1), Check.POST); + checker.check(subject, wrongEvidence, Check.POST); vm.stopPrank(); } @@ -97,7 +107,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(!checker.check(notOwner, abi.encode(0), Check.POST)); + assert(!checker.check(notOwner, evidence, Check.POST)); vm.stopPrank(); } @@ -107,7 +117,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(checker.check(subject, abi.encode(0), Check.POST)); + assert(checker.check(subject, evidence, Check.POST)); vm.stopPrank(); } @@ -116,7 +126,7 @@ contract AdvancedChecker is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(0))); - checkerHarness.exposed__check(subject, abi.encode(0), Check.PRE); + checkerHarness.exposed__check(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -126,7 +136,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(!checkerHarness.exposed__check(notOwner, abi.encode(0), Check.PRE)); + assert(!checkerHarness.exposed__check(notOwner, evidence, Check.PRE)); vm.stopPrank(); } @@ -136,7 +146,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(checkerHarness.exposed__check(subject, abi.encode(0), Check.PRE)); + assert(checkerHarness.exposed__check(subject, evidence, Check.PRE)); vm.stopPrank(); } @@ -146,7 +156,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(!checkerHarness.exposed__check(notOwner, abi.encode(0), Check.MAIN)); + assert(!checkerHarness.exposed__check(notOwner, evidence, Check.MAIN)); vm.stopPrank(); } @@ -156,7 +166,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(checkerHarness.exposed__check(subject, abi.encode(0), Check.MAIN)); + assert(checkerHarness.exposed__check(subject, evidence, Check.MAIN)); vm.stopPrank(); } @@ -165,7 +175,7 @@ contract AdvancedChecker is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - checkerHarness.exposed__check(subject, abi.encode(1), Check.POST); + checkerHarness.exposed__check(subject, wrongEvidence, Check.POST); vm.stopPrank(); } @@ -175,7 +185,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(!checkerHarness.exposed__check(notOwner, abi.encode(0), Check.POST)); + assert(!checkerHarness.exposed__check(notOwner, evidence, Check.POST)); vm.stopPrank(); } @@ -185,7 +195,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(checkerHarness.exposed__check(subject, abi.encode(0), Check.POST)); + assert(checkerHarness.exposed__check(subject, evidence, Check.POST)); vm.stopPrank(); } @@ -194,7 +204,7 @@ contract AdvancedChecker is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - checkerHarness.exposed__checkPre(subject, abi.encode(1)); + checkerHarness.exposed__checkPre(subject, wrongEvidence); vm.stopPrank(); } @@ -204,7 +214,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(!checkerHarness.exposed__checkPre(notOwner, abi.encode(0))); + assert(!checkerHarness.exposed__checkPre(notOwner, evidence)); vm.stopPrank(); } @@ -214,7 +224,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(checkerHarness.exposed__checkPre(subject, abi.encode(0))); + assert(checkerHarness.exposed__checkPre(subject, evidence)); vm.stopPrank(); } @@ -224,7 +234,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(!checkerHarness.exposed__checkMain(notOwner, abi.encode(0))); + assert(!checkerHarness.exposed__checkMain(notOwner, evidence)); vm.stopPrank(); } @@ -234,7 +244,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(checkerHarness.exposed__checkMain(subject, abi.encode(0))); + assert(checkerHarness.exposed__checkMain(subject, evidence)); vm.stopPrank(); } @@ -243,7 +253,7 @@ contract AdvancedChecker is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - checkerHarness.exposed__checkPost(subject, abi.encode(1)); + checkerHarness.exposed__checkPost(subject, wrongEvidence); vm.stopPrank(); } @@ -253,7 +263,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(!checkerHarness.exposed__checkPost(notOwner, abi.encode(0))); + assert(!checkerHarness.exposed__checkPost(notOwner, evidence)); vm.stopPrank(); } @@ -263,7 +273,7 @@ contract AdvancedChecker is Test { nft.mint(subject); - assert(checkerHarness.exposed__checkPost(subject, abi.encode(0))); + assert(checkerHarness.exposed__checkPost(subject, evidence)); vm.stopPrank(); } @@ -271,7 +281,7 @@ contract AdvancedChecker is Test { contract AdvancedPolicy is Test { event TargetSet(address indexed target); - event Enforced(address indexed subject, address indexed target, bytes evidence, Check checkType); + event Enforced(address indexed subject, address indexed target, bytes[] evidence, Check checkType); NFT internal nft; AdvancedERC721Checker internal checker; @@ -286,17 +296,27 @@ contract AdvancedPolicy is Test { address public subject = vm.addr(0x3); address public notOwner = vm.addr(0x4); + address[] internal verifiers; + bytes[] public evidence = new bytes[](1); + bytes[] public wrongEvidence = new bytes[](1); + function setUp() public virtual { vm.startPrank(deployer); nft = new NFT(); - checker = new AdvancedERC721Checker(nft, 1, 0, 10); - checkerSkipped = new AdvancedERC721Checker(nft, 1, 0, 10); + verifiers = new address[](1); + verifiers[0] = address(nft); + + checker = new AdvancedERC721Checker(verifiers, 1, 0, 10); + checkerSkipped = new AdvancedERC721Checker(verifiers, 1, 0, 10); policy = new AdvancedERC721Policy(checker, false, false, true); policyHarness = new AdvancedERC721PolicyHarness(checker, false, false, true); policySkipped = new AdvancedERC721Policy(checkerSkipped, true, true, false); policyHarnessSkipped = new AdvancedERC721PolicyHarness(checkerSkipped, true, true, false); + evidence[0] = abi.encode(0); + wrongEvidence[0] = abi.encode(1); + vm.stopPrank(); } @@ -354,7 +374,7 @@ contract AdvancedPolicy is Test { vm.startPrank(subject); vm.expectRevert(abi.encodeWithSelector(IPolicy.TargetOnly.selector)); - policy.enforce(subject, abi.encode(0x0), Check.PRE); + policy.enforce(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -369,7 +389,7 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(0))); - policy.enforce(subject, abi.encode(0x0), Check.PRE); + policy.enforce(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -385,7 +405,7 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IAdvancedPolicy.CannotPreCheckWhenSkipped.selector)); - policySkipped.enforce(subject, abi.encode(0x0), Check.PRE); + policySkipped.enforce(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -401,7 +421,7 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector)); - policy.enforce(notOwner, abi.encode(0x0), Check.PRE); + policy.enforce(notOwner, evidence, Check.PRE); vm.stopPrank(); } @@ -417,9 +437,9 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0), Check.PRE); + emit Enforced(subject, target, evidence, Check.PRE); - policy.enforce(subject, abi.encode(0x0), Check.PRE); + policy.enforce(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -434,10 +454,10 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policy.enforce(subject, abi.encode(0x0), Check.PRE); + policy.enforce(subject, evidence, Check.PRE); vm.expectRevert(abi.encodeWithSelector(IPolicy.AlreadyEnforced.selector)); - policy.enforce(subject, abi.encode(0x0), Check.PRE); + policy.enforce(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -452,7 +472,7 @@ contract AdvancedPolicy is Test { vm.startPrank(subject); vm.expectRevert(abi.encodeWithSelector(IPolicy.TargetOnly.selector)); - policy.enforce(subject, abi.encode(0x0), Check.MAIN); + policy.enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -467,7 +487,7 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector)); - policy.enforce(subject, abi.encode(0x0), Check.MAIN); + policy.enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -483,7 +503,7 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IAdvancedPolicy.PreCheckNotEnforced.selector)); - policy.enforce(subject, abi.encode(0x0), Check.MAIN); + policy.enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -498,12 +518,12 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policy.enforce(subject, abi.encode(0x0), Check.PRE); + policy.enforce(subject, evidence, Check.PRE); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0), Check.MAIN); + emit Enforced(subject, target, evidence, Check.MAIN); - policy.enforce(subject, abi.encode(0x0), Check.MAIN); + policy.enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -518,17 +538,17 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policy.enforce(subject, abi.encode(0x0), Check.PRE); + policy.enforce(subject, evidence, Check.PRE); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0), Check.MAIN); + emit Enforced(subject, target, evidence, Check.MAIN); - policy.enforce(subject, abi.encode(0x0), Check.MAIN); + policy.enforce(subject, evidence, Check.MAIN); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0), Check.MAIN); + emit Enforced(subject, target, evidence, Check.MAIN); - policy.enforce(subject, abi.encode(0x0), Check.MAIN); + policy.enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -543,10 +563,10 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policySkipped.enforce(subject, abi.encode(0x0), Check.MAIN); + policySkipped.enforce(subject, evidence, Check.MAIN); vm.expectRevert(abi.encodeWithSelector(IAdvancedPolicy.MainCheckAlreadyEnforced.selector)); - policySkipped.enforce(subject, abi.encode(0x0), Check.MAIN); + policySkipped.enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -560,10 +580,10 @@ contract AdvancedPolicy is Test { vm.stopPrank(); vm.startPrank(target); - policy.enforce(subject, abi.encode(0x0), Check.PRE); + policy.enforce(subject, evidence, Check.PRE); vm.expectRevert(abi.encodeWithSelector(IAdvancedPolicy.MainCheckNotEnforced.selector)); - policy.enforce(subject, abi.encode(0x0), Check.POST); + policy.enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -578,7 +598,7 @@ contract AdvancedPolicy is Test { vm.startPrank(subject); vm.expectRevert(abi.encodeWithSelector(IPolicy.TargetOnly.selector)); - policy.enforce(subject, abi.encode(0x0), Check.POST); + policy.enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -592,11 +612,11 @@ contract AdvancedPolicy is Test { vm.stopPrank(); vm.startPrank(target); - policy.enforce(subject, abi.encode(0x0), Check.PRE); - policy.enforce(subject, abi.encode(0x0), Check.MAIN); + policy.enforce(subject, evidence, Check.PRE); + policy.enforce(subject, evidence, Check.MAIN); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - policy.enforce(subject, abi.encode(0x1), Check.POST); + policy.enforce(subject, wrongEvidence, Check.POST); vm.stopPrank(); } @@ -611,10 +631,10 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policySkipped.enforce(subject, abi.encode(0x0), Check.MAIN); + policySkipped.enforce(subject, evidence, Check.MAIN); vm.expectRevert(abi.encodeWithSelector(IAdvancedPolicy.CannotPostCheckWhenSkipped.selector)); - policySkipped.enforce(subject, abi.encode(0x0), Check.POST); + policySkipped.enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -629,11 +649,11 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policy.enforce(subject, abi.encode(0x0), Check.PRE); - policy.enforce(subject, abi.encode(0x0), Check.MAIN); + policy.enforce(subject, evidence, Check.PRE); + policy.enforce(subject, evidence, Check.MAIN); vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector)); - policy.enforce(notOwner, abi.encode(0x0), Check.POST); + policy.enforce(notOwner, evidence, Check.POST); vm.stopPrank(); } @@ -648,13 +668,13 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policy.enforce(subject, abi.encode(0x0), Check.PRE); - policy.enforce(subject, abi.encode(0x0), Check.MAIN); + policy.enforce(subject, evidence, Check.PRE); + policy.enforce(subject, evidence, Check.MAIN); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0), Check.POST); + emit Enforced(subject, target, evidence, Check.POST); - policy.enforce(subject, abi.encode(0x0), Check.POST); + policy.enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -669,12 +689,12 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policy.enforce(subject, abi.encode(0x0), Check.PRE); - policy.enforce(subject, abi.encode(0x0), Check.MAIN); - policy.enforce(subject, abi.encode(0x0), Check.POST); + policy.enforce(subject, evidence, Check.PRE); + policy.enforce(subject, evidence, Check.MAIN); + policy.enforce(subject, evidence, Check.POST); vm.expectRevert(abi.encodeWithSelector(IPolicy.AlreadyEnforced.selector)); - policy.enforce(subject, abi.encode(0x0), Check.POST); + policy.enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -689,7 +709,7 @@ contract AdvancedPolicy is Test { vm.startPrank(subject); vm.expectRevert(abi.encodeWithSelector(IPolicy.TargetOnly.selector)); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -704,7 +724,7 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(0))); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -720,7 +740,7 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IAdvancedPolicy.CannotPreCheckWhenSkipped.selector)); - policyHarnessSkipped.exposed__enforce(subject, abi.encode(0x0), Check.PRE); + policyHarnessSkipped.exposed__enforce(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -736,7 +756,7 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector)); - policyHarness.exposed__enforce(notOwner, abi.encode(0x0), Check.PRE); + policyHarness.exposed__enforce(notOwner, evidence, Check.PRE); vm.stopPrank(); } @@ -752,9 +772,9 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0), Check.PRE); + emit Enforced(subject, target, evidence, Check.PRE); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -769,10 +789,10 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); vm.expectRevert(abi.encodeWithSelector(IPolicy.AlreadyEnforced.selector)); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -787,7 +807,7 @@ contract AdvancedPolicy is Test { vm.startPrank(subject); vm.expectRevert(abi.encodeWithSelector(IPolicy.TargetOnly.selector)); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarness.exposed__enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -802,7 +822,7 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector)); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarness.exposed__enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -818,7 +838,7 @@ contract AdvancedPolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IAdvancedPolicy.PreCheckNotEnforced.selector)); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarness.exposed__enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -833,12 +853,12 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0), Check.MAIN); + emit Enforced(subject, target, evidence, Check.MAIN); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarness.exposed__enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -853,17 +873,17 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0), Check.MAIN); + emit Enforced(subject, target, evidence, Check.MAIN); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarness.exposed__enforce(subject, evidence, Check.MAIN); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0), Check.MAIN); + emit Enforced(subject, target, evidence, Check.MAIN); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarness.exposed__enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -878,10 +898,10 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policyHarnessSkipped.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarnessSkipped.exposed__enforce(subject, evidence, Check.MAIN); vm.expectRevert(abi.encodeWithSelector(IAdvancedPolicy.MainCheckAlreadyEnforced.selector)); - policyHarnessSkipped.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarnessSkipped.exposed__enforce(subject, evidence, Check.MAIN); vm.stopPrank(); } @@ -895,10 +915,10 @@ contract AdvancedPolicy is Test { vm.stopPrank(); vm.startPrank(target); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); vm.expectRevert(abi.encodeWithSelector(IAdvancedPolicy.MainCheckNotEnforced.selector)); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.POST); + policyHarness.exposed__enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -913,7 +933,7 @@ contract AdvancedPolicy is Test { vm.startPrank(subject); vm.expectRevert(abi.encodeWithSelector(IPolicy.TargetOnly.selector)); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.POST); + policyHarness.exposed__enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -927,11 +947,11 @@ contract AdvancedPolicy is Test { vm.stopPrank(); vm.startPrank(target); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.MAIN); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - policyHarness.exposed__enforce(subject, abi.encode(0x1), Check.POST); + policyHarness.exposed__enforce(subject, wrongEvidence, Check.POST); vm.stopPrank(); } @@ -946,10 +966,10 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policyHarnessSkipped.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarnessSkipped.exposed__enforce(subject, evidence, Check.MAIN); vm.expectRevert(abi.encodeWithSelector(IAdvancedPolicy.CannotPostCheckWhenSkipped.selector)); - policyHarnessSkipped.exposed__enforce(subject, abi.encode(0x0), Check.POST); + policyHarnessSkipped.exposed__enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -964,11 +984,11 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.MAIN); vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector)); - policyHarness.exposed__enforce(notOwner, abi.encode(0x0), Check.POST); + policyHarness.exposed__enforce(notOwner, evidence, Check.POST); vm.stopPrank(); } @@ -983,13 +1003,13 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.MAIN); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0), Check.POST); + emit Enforced(subject, target, evidence, Check.POST); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.POST); + policyHarness.exposed__enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -1004,12 +1024,12 @@ contract AdvancedPolicy is Test { vm.startPrank(target); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.PRE); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.MAIN); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.POST); + policyHarness.exposed__enforce(subject, evidence, Check.PRE); + policyHarness.exposed__enforce(subject, evidence, Check.MAIN); + policyHarness.exposed__enforce(subject, evidence, Check.POST); vm.expectRevert(abi.encodeWithSelector(IPolicy.AlreadyEnforced.selector)); - policyHarness.exposed__enforce(subject, abi.encode(0x0), Check.POST); + policyHarness.exposed__enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -1024,6 +1044,7 @@ contract Voting is Test { AdvancedERC721Checker internal checker; AdvancedERC721Policy internal policy; AdvancedVoting internal voting; + address[] internal verifiers; address public deployer = vm.addr(0x1); address public subject = vm.addr(0x2); @@ -1033,7 +1054,10 @@ contract Voting is Test { vm.startPrank(deployer); nft = new NFT(); - checker = new AdvancedERC721Checker(nft, 1, 0, 10); + verifiers = new address[](1); + verifiers[0] = address(nft); + + checker = new AdvancedERC721Checker(verifiers, 1, 0, 10); policy = new AdvancedERC721Policy(checker, false, false, true); voting = new AdvancedVoting(policy); diff --git a/packages/contracts/contracts/src/test/Base.t.sol b/packages/contracts/contracts/src/test/Base.t.sol index ab40814..eef8978 100644 --- a/packages/contracts/contracts/src/test/Base.t.sol +++ b/packages/contracts/contracts/src/test/Base.t.sol @@ -22,12 +22,20 @@ contract BaseChecker is Test { address public subject = vm.addr(0x3); address public notOwner = vm.addr(0x4); + address[] internal verifiers; + bytes[] public evidence = new bytes[](1); + function setUp() public virtual { vm.startPrank(deployer); nft = new NFT(); - checker = new BaseERC721Checker(nft); - checkerHarness = new BaseERC721CheckerHarness(nft); + verifiers = new address[](1); + verifiers[0] = address(nft); + + checker = new BaseERC721Checker(verifiers); + checkerHarness = new BaseERC721CheckerHarness(verifiers); + + evidence[0] = abi.encode(0); vm.stopPrank(); } @@ -36,7 +44,7 @@ contract BaseChecker is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(0))); - checkerHarness.exposed__check(subject, abi.encode(0)); + checkerHarness.exposed__check(subject, evidence); vm.stopPrank(); } @@ -46,7 +54,7 @@ contract BaseChecker is Test { nft.mint(subject); - assert(!checkerHarness.exposed__check(notOwner, abi.encode(0))); + assert(!checkerHarness.exposed__check(notOwner, evidence)); vm.stopPrank(); } @@ -56,7 +64,7 @@ contract BaseChecker is Test { nft.mint(subject); - assert(checkerHarness.exposed__check(subject, abi.encode(0))); + assert(checkerHarness.exposed__check(subject, evidence)); vm.stopPrank(); } @@ -65,7 +73,7 @@ contract BaseChecker is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(0))); - checker.check(subject, abi.encode(0)); + checker.check(subject, evidence); vm.stopPrank(); } @@ -75,7 +83,7 @@ contract BaseChecker is Test { nft.mint(subject); - assert(!checker.check(notOwner, abi.encode(0))); + assert(!checker.check(notOwner, evidence)); vm.stopPrank(); } @@ -85,7 +93,7 @@ contract BaseChecker is Test { nft.mint(subject); - assert(checker.check(subject, abi.encode(0))); + assert(checker.check(subject, evidence)); vm.stopPrank(); } @@ -93,7 +101,7 @@ contract BaseChecker is Test { contract BasePolicy is Test { event TargetSet(address indexed target); - event Enforced(address indexed subject, address indexed target, bytes evidence); + event Enforced(address indexed subject, address indexed target, bytes[] evidence); NFT internal nft; BaseERC721Checker internal checker; @@ -105,14 +113,22 @@ contract BasePolicy is Test { address public subject = vm.addr(0x3); address public notOwner = vm.addr(0x4); + address[] internal verifiers; + bytes[] public evidence = new bytes[](1); + function setUp() public virtual { vm.startPrank(deployer); nft = new NFT(); - checker = new BaseERC721Checker(nft); + verifiers = new address[](1); + verifiers[0] = address(nft); + + checker = new BaseERC721Checker(verifiers); policy = new BaseERC721Policy(checker); policyHarness = new BaseERC721PolicyHarness(checker); + evidence[0] = abi.encode(0); + vm.stopPrank(); } @@ -180,7 +196,7 @@ contract BasePolicy is Test { vm.startPrank(subject); vm.expectRevert(abi.encodeWithSelector(IPolicy.TargetOnly.selector)); - policy.enforce(subject, abi.encode(0x0)); + policy.enforce(subject, evidence); vm.stopPrank(); } @@ -195,7 +211,7 @@ contract BasePolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(0))); - policy.enforce(subject, abi.encode(0x0)); + policy.enforce(subject, evidence); vm.stopPrank(); } @@ -211,7 +227,7 @@ contract BasePolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector)); - policy.enforce(notOwner, abi.encode(0x0)); + policy.enforce(notOwner, evidence); vm.stopPrank(); } @@ -227,9 +243,9 @@ contract BasePolicy is Test { vm.startPrank(target); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0)); + emit Enforced(subject, target, evidence); - policy.enforce(subject, abi.encode(0x0)); + policy.enforce(subject, evidence); vm.stopPrank(); } @@ -244,10 +260,10 @@ contract BasePolicy is Test { vm.startPrank(target); - policy.enforce(subject, abi.encode(0x0)); + policy.enforce(subject, evidence); vm.expectRevert(abi.encodeWithSelector(IPolicy.AlreadyEnforced.selector)); - policy.enforce(subject, abi.encode(0x0)); + policy.enforce(subject, evidence); vm.stopPrank(); } @@ -262,7 +278,7 @@ contract BasePolicy is Test { vm.startPrank(subject); vm.expectRevert(abi.encodeWithSelector(IPolicy.TargetOnly.selector)); - policyHarness.exposed__enforce(subject, abi.encode(0x0)); + policyHarness.exposed__enforce(subject, evidence); vm.stopPrank(); } @@ -277,7 +293,7 @@ contract BasePolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(0))); - policyHarness.exposed__enforce(subject, abi.encode(0x0)); + policyHarness.exposed__enforce(subject, evidence); vm.stopPrank(); } @@ -293,7 +309,7 @@ contract BasePolicy is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector)); - policyHarness.exposed__enforce(notOwner, abi.encode(0x0)); + policyHarness.exposed__enforce(notOwner, evidence); vm.stopPrank(); } @@ -309,9 +325,9 @@ contract BasePolicy is Test { vm.startPrank(target); vm.expectEmit(true, true, true, true); - emit Enforced(subject, target, abi.encode(0x0)); + emit Enforced(subject, target, evidence); - policyHarness.exposed__enforce(subject, abi.encode(0x0)); + policyHarness.exposed__enforce(subject, evidence); vm.stopPrank(); } @@ -326,10 +342,10 @@ contract BasePolicy is Test { vm.startPrank(target); - policyHarness.exposed__enforce(subject, abi.encode(0x0)); + policyHarness.exposed__enforce(subject, evidence); vm.expectRevert(abi.encodeWithSelector(IPolicy.AlreadyEnforced.selector)); - policyHarness.exposed__enforce(subject, abi.encode(0x0)); + policyHarness.exposed__enforce(subject, evidence); vm.stopPrank(); } @@ -348,11 +364,16 @@ contract Voting is Test { address public subject = vm.addr(0x2); address public notOwner = vm.addr(0x3); + address[] internal verifiers; + function setUp() public virtual { vm.startPrank(deployer); nft = new NFT(); - checker = new BaseERC721Checker(nft); + verifiers = new address[](1); + verifiers[0] = address(nft); + + checker = new BaseERC721Checker(verifiers); policy = new BaseERC721Policy(checker); voting = new BaseVoting(policy); diff --git a/packages/contracts/contracts/src/test/advanced/AdvancedERC721Checker.sol b/packages/contracts/contracts/src/test/advanced/AdvancedERC721Checker.sol index f8dcbc2..309959f 100644 --- a/packages/contracts/contracts/src/test/advanced/AdvancedERC721Checker.sol +++ b/packages/contracts/contracts/src/test/advanced/AdvancedERC721Checker.sol @@ -15,12 +15,17 @@ contract AdvancedERC721Checker is AdvancedChecker { uint256 public immutable MAX_TOKEN_ID; /// @notice Initializes checker with validation parameters. - /// @param _nft ERC721 contract address. + /// @param _verifiers Array of addresses for existing verification contracts. /// @param _minBalance Required token balance. /// @param _minTokenId Minimum valid token ID. /// @param _maxTokenId Maximum valid token ID. - constructor(IERC721 _nft, uint256 _minBalance, uint256 _minTokenId, uint256 _maxTokenId) { - NFT = _nft; + constructor( + address[] memory _verifiers, + uint256 _minBalance, + uint256 _minTokenId, + uint256 _maxTokenId + ) AdvancedChecker(_verifiers) { + NFT = IERC721(getVerifierAtIndex(0)); MIN_BALANCE = _minBalance; MIN_TOKEN_ID = _minTokenId; MAX_TOKEN_ID = _maxTokenId; @@ -30,9 +35,9 @@ contract AdvancedERC721Checker is AdvancedChecker { /// @param subject Address to validate. /// @param evidence Encoded tokenId. /// @return Token ownership status. - function _checkPre(address subject, bytes memory evidence) internal view override returns (bool) { + function _checkPre(address subject, bytes[] calldata evidence) internal view override returns (bool) { super._checkPre(subject, evidence); - uint256 tokenId = abi.decode(evidence, (uint256)); + uint256 tokenId = abi.decode(evidence[0], (uint256)); return NFT.ownerOf(tokenId) == subject; } @@ -40,7 +45,7 @@ contract AdvancedERC721Checker is AdvancedChecker { /// @param subject Address to validate. /// @param evidence Unused parameter. /// @return Balance threshold status. - function _checkMain(address subject, bytes memory evidence) internal view override returns (bool) { + function _checkMain(address subject, bytes[] calldata evidence) internal view override returns (bool) { super._checkMain(subject, evidence); return NFT.balanceOf(subject) >= MIN_BALANCE; } @@ -49,9 +54,9 @@ contract AdvancedERC721Checker is AdvancedChecker { /// @param subject Address to validate. /// @param evidence Encoded tokenId. /// @return Token range validation status. - function _checkPost(address subject, bytes memory evidence) internal view override returns (bool) { + function _checkPost(address subject, bytes[] calldata evidence) internal view override returns (bool) { super._checkPost(subject, evidence); - uint256 tokenId = abi.decode(evidence, (uint256)); + uint256 tokenId = abi.decode(evidence[0], (uint256)); return tokenId >= MIN_TOKEN_ID && tokenId <= MAX_TOKEN_ID && NFT.ownerOf(tokenId) == subject; } } diff --git a/packages/contracts/contracts/src/test/advanced/AdvancedVoting.sol b/packages/contracts/contracts/src/test/advanced/AdvancedVoting.sol index ab0d468..c182f0c 100644 --- a/packages/contracts/contracts/src/test/advanced/AdvancedVoting.sol +++ b/packages/contracts/contracts/src/test/advanced/AdvancedVoting.sol @@ -43,10 +43,11 @@ contract AdvancedVoting { /// @custom:emits Registered on successful registration. function register(uint256 tokenId) external { // Encode token ID for policy verification. - bytes memory evidence = abi.encode(tokenId); + bytes[] memory _evidence = new bytes[](1); + _evidence[0] = abi.encode(tokenId); // Verify NFT ownership through policy's PRE check. - POLICY.enforce(msg.sender, evidence, Check.PRE); + POLICY.enforce(msg.sender, _evidence, Check.PRE); emit Registered(msg.sender); } @@ -66,8 +67,9 @@ contract AdvancedVoting { if (option >= 2) revert InvalidOption(); // Verify voting power through policy's MAIN check. - bytes memory evidence = abi.encode(option); - POLICY.enforce(msg.sender, evidence, Check.MAIN); + bytes[] memory _evidence = new bytes[](1); + _evidence[0] = abi.encode(option); + POLICY.enforce(msg.sender, _evidence, Check.MAIN); // Increment vote count safely. unchecked { @@ -94,8 +96,9 @@ contract AdvancedVoting { if (post) revert AlreadyClaimed(); // Verify reward eligibility through policy's POST check. - bytes memory evidence = abi.encode(rewardId); - POLICY.enforce(msg.sender, evidence, Check.POST); + bytes[] memory _evidence = new bytes[](1); + _evidence[0] = abi.encode(rewardId); + POLICY.enforce(msg.sender, _evidence, Check.POST); emit RewardClaimed(msg.sender, rewardId); } diff --git a/packages/contracts/contracts/src/test/base/BaseERC721Checker.sol b/packages/contracts/contracts/src/test/base/BaseERC721Checker.sol index 7ed5ae1..b8cc57d 100644 --- a/packages/contracts/contracts/src/test/base/BaseERC721Checker.sol +++ b/packages/contracts/contracts/src/test/base/BaseERC721Checker.sol @@ -12,18 +12,18 @@ contract BaseERC721Checker is BaseChecker { IERC721 public immutable NFT; /// @notice Initializes with ERC721 contract. - /// @param _nft ERC721 contract address. - constructor(IERC721 _nft) { - NFT = IERC721(_nft); + /// @param _verifiers Array of addresses for existing verification contracts. + constructor(address[] memory _verifiers) BaseChecker(_verifiers) { + NFT = IERC721(getVerifierAtIndex(0)); } /// @notice Validates token ownership. /// @param subject Address to check. /// @param evidence Encoded tokenId. /// @return True if subject owns token. - function _check(address subject, bytes memory evidence) internal view override returns (bool) { + function _check(address subject, bytes[] calldata evidence) internal view override returns (bool) { super._check(subject, evidence); - uint256 tokenId = abi.decode(evidence, (uint256)); + uint256 tokenId = abi.decode(evidence[0], (uint256)); return NFT.ownerOf(tokenId) == subject; } } diff --git a/packages/contracts/contracts/src/test/base/BaseVoting.sol b/packages/contracts/contracts/src/test/base/BaseVoting.sol index 369d27e..4f37794 100644 --- a/packages/contracts/contracts/src/test/base/BaseVoting.sol +++ b/packages/contracts/contracts/src/test/base/BaseVoting.sol @@ -39,10 +39,11 @@ contract BaseVoting { /// @custom:emits Registered on successful registration. function register(uint256 tokenId) external { // Encode token ID for policy verification. - bytes memory evidence = abi.encode(tokenId); + bytes[] memory _evidence = new bytes[](1); + _evidence[0] = abi.encode(tokenId); // Verify NFT ownership. - POLICY.enforce(msg.sender, evidence); + POLICY.enforce(msg.sender, _evidence); emit Registered(msg.sender); } diff --git a/packages/contracts/contracts/src/test/wrappers/AdvancedERC721CheckerHarness.sol b/packages/contracts/contracts/src/test/wrappers/AdvancedERC721CheckerHarness.sol index 63471ab..1d0511d 100644 --- a/packages/contracts/contracts/src/test/wrappers/AdvancedERC721CheckerHarness.sol +++ b/packages/contracts/contracts/src/test/wrappers/AdvancedERC721CheckerHarness.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.20; import {AdvancedERC721Checker} from "../advanced/AdvancedERC721Checker.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {Check} from "../../interfaces/IAdvancedChecker.sol"; /// @title AdvancedERC721CheckerHarness. @@ -10,23 +9,23 @@ import {Check} from "../../interfaces/IAdvancedChecker.sol"; /// @dev Inherits AdvancedERC721Checker and exposes protected methods for testing. contract AdvancedERC721CheckerHarness is AdvancedERC721Checker { /// @notice Initializes test harness with checker configuration. - /// @param _nft ERC721 contract to validate. + /// @param _verifiers Array of addresses for existing verification contracts. /// @param _minBalance Minimum token balance required. /// @param _minTokenId Minimum valid token ID. /// @param _maxTokenId Maximum valid token ID. constructor( - IERC721 _nft, + address[] memory _verifiers, uint256 _minBalance, uint256 _minTokenId, uint256 _maxTokenId - ) AdvancedERC721Checker(_nft, _minBalance, _minTokenId, _maxTokenId) {} + ) AdvancedERC721Checker(_verifiers, _minBalance, _minTokenId, _maxTokenId) {} /// @notice Test exposure for _check method. /// @param subject Address to validate. /// @param evidence Validation data. /// @param checkType Type of check to perform. /// @return Validation result. - function exposed__check(address subject, bytes calldata evidence, Check checkType) public view returns (bool) { + function exposed__check(address subject, bytes[] calldata evidence, Check checkType) public view returns (bool) { return _check(subject, evidence, checkType); } @@ -34,7 +33,7 @@ contract AdvancedERC721CheckerHarness is AdvancedERC721Checker { /// @param subject Address to validate. /// @param evidence Validation data. /// @return Pre-check validation result. - function exposed__checkPre(address subject, bytes calldata evidence) public view returns (bool) { + function exposed__checkPre(address subject, bytes[] calldata evidence) public view returns (bool) { return _checkPre(subject, evidence); } @@ -42,7 +41,7 @@ contract AdvancedERC721CheckerHarness is AdvancedERC721Checker { /// @param subject Address to validate. /// @param evidence Validation data. /// @return Main validation result. - function exposed__checkMain(address subject, bytes calldata evidence) public view returns (bool) { + function exposed__checkMain(address subject, bytes[] calldata evidence) public view returns (bool) { return _checkMain(subject, evidence); } @@ -50,7 +49,7 @@ contract AdvancedERC721CheckerHarness is AdvancedERC721Checker { /// @param subject Address to validate. /// @param evidence Validation data. /// @return Post-check validation result. - function exposed__checkPost(address subject, bytes calldata evidence) public view returns (bool) { + function exposed__checkPost(address subject, bytes[] calldata evidence) public view returns (bool) { return _checkPost(subject, evidence); } } diff --git a/packages/contracts/contracts/src/test/wrappers/AdvancedERC721PolicyHarness.sol b/packages/contracts/contracts/src/test/wrappers/AdvancedERC721PolicyHarness.sol index 070fb07..46a1518 100644 --- a/packages/contracts/contracts/src/test/wrappers/AdvancedERC721PolicyHarness.sol +++ b/packages/contracts/contracts/src/test/wrappers/AdvancedERC721PolicyHarness.sol @@ -20,7 +20,7 @@ contract AdvancedERC721PolicyHarness is AdvancedERC721Policy { /// @param subject Address to validate. /// @param evidence Validation data. /// @param checkType Check type to enforce. - function exposed__enforce(address subject, bytes calldata evidence, Check checkType) public onlyTarget { + function exposed__enforce(address subject, bytes[] calldata evidence, Check checkType) public onlyTarget { _enforce(subject, evidence, checkType); } } diff --git a/packages/contracts/contracts/src/test/wrappers/BaseERC721CheckerHarness.sol b/packages/contracts/contracts/src/test/wrappers/BaseERC721CheckerHarness.sol index c070d68..d97448d 100644 --- a/packages/contracts/contracts/src/test/wrappers/BaseERC721CheckerHarness.sol +++ b/packages/contracts/contracts/src/test/wrappers/BaseERC721CheckerHarness.sol @@ -2,19 +2,19 @@ pragma solidity ^0.8.20; import {BaseERC721Checker} from "../base/BaseERC721Checker.sol"; -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; /// @title BaseERC721CheckerHarness. /// @notice Test harness for BaseERC721Checker internal methods. contract BaseERC721CheckerHarness is BaseERC721Checker { /// @notice Initializes test harness with NFT contract. - constructor(IERC721 _nft) BaseERC721Checker(_nft) {} + /// @param _verifiers Array of addresses for existing verification contracts. + constructor(address[] memory _verifiers) BaseERC721Checker(_verifiers) {} /// @notice Test exposure for _check method. /// @param subject Address to validate. /// @param evidence Validation data. /// @return Validation result. - function exposed__check(address subject, bytes calldata evidence) public view returns (bool) { + function exposed__check(address subject, bytes[] calldata evidence) public view returns (bool) { return _check(subject, evidence); } } diff --git a/packages/contracts/contracts/src/test/wrappers/BaseERC721PolicyHarness.sol b/packages/contracts/contracts/src/test/wrappers/BaseERC721PolicyHarness.sol index a2d7077..26c047b 100644 --- a/packages/contracts/contracts/src/test/wrappers/BaseERC721PolicyHarness.sol +++ b/packages/contracts/contracts/src/test/wrappers/BaseERC721PolicyHarness.sol @@ -13,7 +13,7 @@ contract BaseERC721PolicyHarness is BaseERC721Policy { /// @notice Test exposure for _enforce method. /// @param subject Address to validate. /// @param evidence Validation data. - function exposed__enforce(address subject, bytes calldata evidence) public onlyTarget { + function exposed__enforce(address subject, bytes[] calldata evidence) public onlyTarget { _enforce(subject, evidence); } } diff --git a/packages/contracts/test/Advanced.test.ts b/packages/contracts/test/Advanced.test.ts index 46d6c04..55c816b 100644 --- a/packages/contracts/test/Advanced.test.ts +++ b/packages/contracts/test/Advanced.test.ts @@ -34,7 +34,7 @@ describe("Advanced", () => { const nft: NFT = await NFTFactory.deploy() const checker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect(deployer).deploy( - await nft.getAddress(), + [await nft.getAddress()], 1, 0, 10 @@ -42,7 +42,7 @@ describe("Advanced", () => { const checkerHarness: AdvancedERC721CheckerHarness = await AdvancedERC721CheckerHarnessFactory.connect( deployer - ).deploy(await nft.getAddress(), 1, 0, 10) + ).deploy([await nft.getAddress()], 1, 0, 10) // mint 0 for subject. await nft.connect(deployer).mint(subjectAddress) @@ -80,7 +80,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) await expect( - checker.connect(target).check(subjectAddress, invalidNFTId, 0) + checker.connect(target).check(subjectAddress, [invalidNFTId], 0) ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") }) @@ -88,14 +88,14 @@ describe("Advanced", () => { const { checker, target, notOwnerAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checker.connect(target).check(notOwnerAddress, validNFTId, 0)).to.be.equal(false) + expect(await checker.connect(target).check(notOwnerAddress, [validNFTId], 0)).to.be.equal(false) }) it("succeeds when valid", async () => { const { checker, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checker.connect(target).check(subjectAddress, validNFTId, 0)).to.be.equal(true) + expect(await checker.connect(target).check(subjectAddress, [validNFTId], 0)).to.be.equal(true) }) }) describe("main check", () => { @@ -103,14 +103,14 @@ describe("Advanced", () => { const { checker, target, notOwnerAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checker.connect(target).check(notOwnerAddress, validNFTId, 1)).to.be.equal(false) + expect(await checker.connect(target).check(notOwnerAddress, [validNFTId], 1)).to.be.equal(false) }) it("succeeds when balance sufficient", async () => { const { checker, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checker.connect(target).check(subjectAddress, validNFTId, 1)).to.be.equal(true) + expect(await checker.connect(target).check(subjectAddress, [validNFTId], 1)).to.be.equal(true) }) }) describe("post check", () => { @@ -119,7 +119,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) await expect( - checker.connect(target).check(subjectAddress, invalidNFTId, 2) + checker.connect(target).check(subjectAddress, [invalidNFTId], 2) ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") }) @@ -127,14 +127,14 @@ describe("Advanced", () => { const { checker, target, notOwnerAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checker.connect(target).check(notOwnerAddress, validNFTId, 2)).to.be.equal(false) + expect(await checker.connect(target).check(notOwnerAddress, [validNFTId], 2)).to.be.equal(false) }) it("succeeds when in valid range", async () => { const { checker, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checker.connect(target).check(subjectAddress, validNFTId, 2)).to.be.equal(true) + expect(await checker.connect(target).check(subjectAddress, [validNFTId], 2)).to.be.equal(true) }) }) }) @@ -146,7 +146,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) await expect( - checkerHarness.connect(target).exposed__check(subjectAddress, invalidNFTId, 0) + checkerHarness.connect(target).exposed__check(subjectAddress, [invalidNFTId], 0) ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") }) @@ -155,7 +155,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__check(notOwnerAddress, validNFTId, 0) + await checkerHarness.connect(target).exposed__check(notOwnerAddress, [validNFTId], 0) ).to.be.equal(false) }) @@ -164,7 +164,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__check(subjectAddress, validNFTId, 0) + await checkerHarness.connect(target).exposed__check(subjectAddress, [validNFTId], 0) ).to.be.equal(true) }) }) @@ -174,7 +174,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__check(notOwnerAddress, validNFTId, 1) + await checkerHarness.connect(target).exposed__check(notOwnerAddress, [validNFTId], 1) ).to.be.equal(false) }) @@ -183,7 +183,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__check(subjectAddress, validNFTId, 1) + await checkerHarness.connect(target).exposed__check(subjectAddress, [validNFTId], 1) ).to.be.equal(true) }) }) @@ -193,7 +193,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) await expect( - checkerHarness.connect(target).exposed__check(subjectAddress, invalidNFTId, 2) + checkerHarness.connect(target).exposed__check(subjectAddress, [invalidNFTId], 2) ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") }) @@ -202,7 +202,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__check(notOwnerAddress, validNFTId, 2) + await checkerHarness.connect(target).exposed__check(notOwnerAddress, [validNFTId], 2) ).to.be.equal(false) }) @@ -211,7 +211,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__check(subjectAddress, validNFTId, 2) + await checkerHarness.connect(target).exposed__check(subjectAddress, [validNFTId], 2) ).to.be.equal(true) }) }) @@ -223,7 +223,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) await expect( - checkerHarness.connect(target).exposed__checkPre(subjectAddress, invalidNFTId) + checkerHarness.connect(target).exposed__checkPre(subjectAddress, [invalidNFTId]) ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") }) @@ -231,18 +231,18 @@ describe("Advanced", () => { const { checkerHarness, target, notOwnerAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checkerHarness.connect(target).exposed__checkPre(notOwnerAddress, validNFTId)).to.be.equal( - false - ) + expect( + await checkerHarness.connect(target).exposed__checkPre(notOwnerAddress, [validNFTId]) + ).to.be.equal(false) }) it("succeeds when valid", async () => { const { checkerHarness, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checkerHarness.connect(target).exposed__checkPre(subjectAddress, validNFTId)).to.be.equal( - true - ) + expect( + await checkerHarness.connect(target).exposed__checkPre(subjectAddress, [validNFTId]) + ).to.be.equal(true) }) }) @@ -252,7 +252,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__checkMain(notOwnerAddress, validNFTId) + await checkerHarness.connect(target).exposed__checkMain(notOwnerAddress, [validNFTId]) ).to.be.equal(false) }) @@ -260,9 +260,9 @@ describe("Advanced", () => { const { checkerHarness, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checkerHarness.connect(target).exposed__checkMain(subjectAddress, validNFTId)).to.be.equal( - true - ) + expect( + await checkerHarness.connect(target).exposed__checkMain(subjectAddress, [validNFTId]) + ).to.be.equal(true) }) }) @@ -272,7 +272,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) await expect( - checkerHarness.connect(target).exposed__checkPost(subjectAddress, invalidNFTId) + checkerHarness.connect(target).exposed__checkPost(subjectAddress, [invalidNFTId]) ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") }) @@ -281,7 +281,7 @@ describe("Advanced", () => { await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__checkPost(notOwnerAddress, validNFTId) + await checkerHarness.connect(target).exposed__checkPost(notOwnerAddress, [validNFTId]) ).to.be.equal(false) }) @@ -289,9 +289,9 @@ describe("Advanced", () => { const { checkerHarness, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checkerHarness.connect(target).exposed__checkPost(subjectAddress, validNFTId)).to.be.equal( - true - ) + expect( + await checkerHarness.connect(target).exposed__checkPost(subjectAddress, [validNFTId]) + ).to.be.equal(true) }) }) }) @@ -314,7 +314,7 @@ describe("Advanced", () => { const iERC721Errors: IERC721Errors = await ethers.getContractAt("IERC721Errors", await nft.getAddress()) const checker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect(deployer).deploy( - await nft.getAddress(), + [await nft.getAddress()], 1, 0, 10 @@ -322,7 +322,7 @@ describe("Advanced", () => { const checkerSkippedPrePostNoMultMain: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect( deployer - ).deploy(await nft.getAddress(), 1, 0, 10) + ).deploy([await nft.getAddress()], 1, 0, 10) const policy: AdvancedERC721Policy = await AdvancedERC721PolicyFactory.connect(deployer).deploy( await checker.getAddress(), @@ -441,7 +441,7 @@ describe("Advanced", () => { await policy.setTarget(await target.getAddress()) await expect( - policy.connect(subject).enforce(subjectAddress, ZeroHash, 0) + policy.connect(subject).enforce(subjectAddress, [ZeroHash], 0) ).to.be.revertedWithCustomError(policy, "TargetOnly") }) @@ -452,7 +452,7 @@ describe("Advanced", () => { await policy.setTarget(await target.getAddress()) await expect( - policy.connect(target).enforce(subjectAddress, invalidEncodedNFTId, 0) + policy.connect(target).enforce(subjectAddress, [invalidEncodedNFTId], 0) ).to.be.revertedWithCustomError(iERC721Errors, "ERC721NonexistentToken") }) @@ -463,7 +463,7 @@ describe("Advanced", () => { await policySkipped.setTarget(await target.getAddress()) await expect( - policySkipped.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) + policySkipped.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) ).to.be.revertedWithCustomError(policySkipped, "CannotPreCheckWhenSkipped") }) @@ -474,7 +474,7 @@ describe("Advanced", () => { await policy.setTarget(await target.getAddress()) expect( - policy.connect(target).enforce(notOwnerAddress, validEncodedNFTId, 0) + policy.connect(target).enforce(notOwnerAddress, [validEncodedNFTId], 0) ).to.be.revertedWithCustomError(policy, "UnsuccessfulCheck") }) @@ -485,7 +485,7 @@ describe("Advanced", () => { await policy.setTarget(targetAddress) - const tx = await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) + const tx = await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) const receipt = await tx.wait() const event = AdvancedERC721PolicyFactory.interface.parseLog( receipt?.logs[0] as unknown as { topics: string[]; data: string } @@ -501,7 +501,7 @@ describe("Advanced", () => { expect(receipt?.status).to.eq(1) expect(event.args.subject).to.eq(subjectAddress) expect(event.args.target).to.eq(targetAddress) - expect(event.args.evidence).to.eq(validEncodedNFTId) + expect(event.args.evidence[0]).to.eq(validEncodedNFTId) expect(event.args.checkType).to.eq(0) expect((await policy.enforced(targetAddress, subjectAddress))[0]).to.be.equal(true) }) @@ -512,10 +512,10 @@ describe("Advanced", () => { await policy.setTarget(await target.getAddress()) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) await expect( - policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) + policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) ).to.be.revertedWithCustomError(policy, "AlreadyEnforced") }) }) @@ -528,7 +528,7 @@ describe("Advanced", () => { await policy.setTarget(await target.getAddress()) expect( - policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 1) + policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) ).to.be.revertedWithCustomError(policy, "PreCheckNotEnforced") }) @@ -537,10 +537,10 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policy.setTarget(await target.getAddress()) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) expect( - policy.connect(target).enforce(notOwnerAddress, validEncodedNFTId, 1) + policy.connect(target).enforce(notOwnerAddress, [validEncodedNFTId], 1) ).to.be.revertedWithCustomError(policy, "UnsuccessfulCheck") }) @@ -550,9 +550,9 @@ describe("Advanced", () => { const targetAddress = await target.getAddress() await policy.setTarget(await target.getAddress()) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) - const tx = await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 1) + const tx = await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) const receipt = await tx.wait() const event = AdvancedERC721PolicyFactory.interface.parseLog( receipt?.logs[0] as unknown as { topics: string[]; data: string } @@ -568,7 +568,7 @@ describe("Advanced", () => { expect(receipt?.status).to.eq(1) expect(event.args.subject).to.eq(subjectAddress) expect(event.args.target).to.eq(targetAddress) - expect(event.args.evidence).to.eq(validEncodedNFTId) + expect(event.args.evidence[0]).to.eq(validEncodedNFTId) expect(event.args.checkType).to.eq(1) expect((await policy.enforced(targetAddress, subjectAddress))[1]).to.be.equal(1) }) @@ -579,10 +579,10 @@ describe("Advanced", () => { const targetAddress = await target.getAddress() await policy.setTarget(targetAddress) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 1) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) - const tx = await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 1) + const tx = await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) const receipt = await tx.wait() const event = AdvancedERC721PolicyFactory.interface.parseLog( receipt?.logs[0] as unknown as { topics: string[]; data: string } @@ -598,7 +598,7 @@ describe("Advanced", () => { expect(receipt?.status).to.eq(1) expect(event.args.subject).to.eq(subjectAddress) expect(event.args.target).to.eq(targetAddress) - expect(event.args.evidence).to.eq(validEncodedNFTId) + expect(event.args.evidence[0]).to.eq(validEncodedNFTId) expect(event.args.checkType).to.eq(1) expect((await policy.enforced(targetAddress, subjectAddress))[1]).to.be.equal(2) }) @@ -608,10 +608,10 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policySkipped.setTarget(await target.getAddress()) - await policySkipped.connect(target).enforce(subjectAddress, validEncodedNFTId, 1) + await policySkipped.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) expect( - policySkipped.connect(target).enforce(notOwnerAddress, validEncodedNFTId, 1) + policySkipped.connect(target).enforce(notOwnerAddress, [validEncodedNFTId], 1) ).to.be.revertedWithCustomError(policySkipped, "MainCheckAlreadyEnforced") }) }) @@ -624,13 +624,13 @@ describe("Advanced", () => { await policy.setTarget(await target.getAddress()) expect( - policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 2) + policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 2) ).to.be.revertedWithCustomError(policy, "PreCheckNotEnforced") - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) expect( - policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 2) + policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 2) ).to.be.revertedWithCustomError(policy, "MainCheckNotEnforced") }) @@ -639,11 +639,11 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policy.setTarget(await target.getAddress()) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 1) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) await expect( - policy.connect(subject).enforce(subjectAddress, ZeroHash, 2) + policy.connect(subject).enforce(subjectAddress, [ZeroHash], 2) ).to.be.revertedWithCustomError(policy, "TargetOnly") }) @@ -652,11 +652,11 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policy.setTarget(await target.getAddress()) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 1) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) await expect( - policy.connect(target).enforce(subjectAddress, invalidEncodedNFTId, 2) + policy.connect(target).enforce(subjectAddress, [invalidEncodedNFTId], 2) ).to.be.revertedWithCustomError(iERC721Errors, "ERC721NonexistentToken") }) @@ -665,10 +665,10 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policySkipped.setTarget(await target.getAddress()) - await policySkipped.connect(target).enforce(subjectAddress, validEncodedNFTId, 1) + await policySkipped.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) await expect( - policySkipped.connect(target).enforce(subjectAddress, validEncodedNFTId, 2) + policySkipped.connect(target).enforce(subjectAddress, [validEncodedNFTId], 2) ).to.be.revertedWithCustomError(policySkipped, "CannotPostCheckWhenSkipped") }) @@ -677,11 +677,11 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policy.setTarget(await target.getAddress()) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 1) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) expect( - policy.connect(target).enforce(notOwnerAddress, validEncodedNFTId, 2) + policy.connect(target).enforce(notOwnerAddress, [validEncodedNFTId], 2) ).to.be.revertedWithCustomError(policy, "UnsuccessfulCheck") }) @@ -691,10 +691,10 @@ describe("Advanced", () => { const targetAddress = await target.getAddress() await policy.setTarget(targetAddress) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 1) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) - const tx = await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 2) + const tx = await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 2) const receipt = await tx.wait() const event = AdvancedERC721PolicyFactory.interface.parseLog( receipt?.logs[0] as unknown as { topics: string[]; data: string } @@ -710,7 +710,7 @@ describe("Advanced", () => { expect(receipt?.status).to.eq(1) expect(event.args.subject).to.eq(subjectAddress) expect(event.args.target).to.eq(targetAddress) - expect(event.args.evidence).to.eq(validEncodedNFTId) + expect(event.args.evidence[0]).to.eq(validEncodedNFTId) expect(event.args.checkType).to.eq(2) expect((await policy.enforced(targetAddress, subjectAddress))[2]).to.be.equal(true) }) @@ -720,12 +720,12 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policy.setTarget(await target.getAddress()) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 1) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 2) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 2) await expect( - policy.connect(target).enforce(subjectAddress, validEncodedNFTId, 2) + policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 2) ).to.be.revertedWithCustomError(policy, "AlreadyEnforced") }) }) @@ -740,7 +740,7 @@ describe("Advanced", () => { await policyHarness.setTarget(await target.getAddress()) await expect( - policyHarness.connect(subject).exposed__enforce(subjectAddress, ZeroHash, 0) + policyHarness.connect(subject).exposed__enforce(subjectAddress, [ZeroHash], 0) ).to.be.revertedWithCustomError(policyHarness, "TargetOnly") }) @@ -751,7 +751,7 @@ describe("Advanced", () => { await policyHarness.setTarget(await target.getAddress()) await expect( - policyHarness.connect(target).exposed__enforce(subjectAddress, invalidEncodedNFTId, 0) + policyHarness.connect(target).exposed__enforce(subjectAddress, [invalidEncodedNFTId], 0) ).to.be.revertedWithCustomError(iERC721Errors, "ERC721NonexistentToken") }) @@ -762,7 +762,7 @@ describe("Advanced", () => { await policyHarnessSkipped.setTarget(await target.getAddress()) await expect( - policyHarnessSkipped.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 0) + policyHarnessSkipped.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) ).to.be.revertedWithCustomError(policyHarnessSkipped, "CannotPreCheckWhenSkipped") }) @@ -773,7 +773,7 @@ describe("Advanced", () => { await policyHarness.setTarget(await target.getAddress()) expect( - policyHarness.connect(target).exposed__enforce(notOwnerAddress, validEncodedNFTId, 0) + policyHarness.connect(target).exposed__enforce(notOwnerAddress, [validEncodedNFTId], 0) ).to.be.revertedWithCustomError(policyHarness, "UnsuccessfulCheck") }) @@ -786,7 +786,7 @@ describe("Advanced", () => { const tx = await policyHarness .connect(target) - .exposed__enforce(subjectAddress, validEncodedNFTId, 0) + .exposed__enforce(subjectAddress, [validEncodedNFTId], 0) const receipt = await tx.wait() const event = AdvancedERC721PolicyFactory.interface.parseLog( receipt?.logs[0] as unknown as { topics: string[]; data: string } @@ -801,7 +801,7 @@ describe("Advanced", () => { expect(receipt?.status).to.eq(1) expect(event.args.subject).to.eq(subjectAddress) expect(event.args.target).to.eq(targetAddress) - expect(event.args.evidence).to.eq(validEncodedNFTId) + expect(event.args.evidence[0]).to.eq(validEncodedNFTId) expect((await policyHarness.enforced(targetAddress, subjectAddress))[0]).to.be.equal(true) }) @@ -811,10 +811,10 @@ describe("Advanced", () => { await policyHarness.setTarget(await target.getAddress()) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 0) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) await expect( - policyHarness.connect(target).enforce(subjectAddress, validEncodedNFTId, 0) + policyHarness.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) ).to.be.revertedWithCustomError(policyHarness, "AlreadyEnforced") }) }) @@ -827,7 +827,7 @@ describe("Advanced", () => { await policyHarness.setTarget(await target.getAddress()) expect( - policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 1) + policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 1) ).to.be.revertedWithCustomError(policyHarness, "PreCheckNotEnforced") }) @@ -836,10 +836,10 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policyHarness.setTarget(await target.getAddress()) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 0) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) expect( - policyHarness.connect(target).exposed__enforce(notOwnerAddress, validEncodedNFTId, 1) + policyHarness.connect(target).exposed__enforce(notOwnerAddress, [validEncodedNFTId], 1) ).to.be.revertedWithCustomError(policyHarness, "UnsuccessfulCheck") }) @@ -849,11 +849,11 @@ describe("Advanced", () => { const targetAddress = await target.getAddress() await policyHarness.setTarget(await target.getAddress()) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 0) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) const tx = await policyHarness .connect(target) - .exposed__enforce(subjectAddress, validEncodedNFTId, 1) + .exposed__enforce(subjectAddress, [validEncodedNFTId], 1) const receipt = await tx.wait() const event = AdvancedERC721PolicyFactory.interface.parseLog( receipt?.logs[0] as unknown as { topics: string[]; data: string } @@ -868,7 +868,7 @@ describe("Advanced", () => { expect(receipt?.status).to.eq(1) expect(event.args.subject).to.eq(subjectAddress) expect(event.args.target).to.eq(targetAddress) - expect(event.args.evidence).to.eq(validEncodedNFTId) + expect(event.args.evidence[0]).to.eq(validEncodedNFTId) expect((await policyHarness.enforced(targetAddress, subjectAddress))[1]).to.be.equal(1) }) @@ -878,12 +878,12 @@ describe("Advanced", () => { const targetAddress = await target.getAddress() await policyHarness.setTarget(targetAddress) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 0) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 1) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 1) const tx = await policyHarness .connect(target) - .exposed__enforce(subjectAddress, validEncodedNFTId, 1) + .exposed__enforce(subjectAddress, [validEncodedNFTId], 1) const receipt = await tx.wait() const event = AdvancedERC721PolicyFactory.interface.parseLog( receipt?.logs[0] as unknown as { topics: string[]; data: string } @@ -898,7 +898,7 @@ describe("Advanced", () => { expect(receipt?.status).to.eq(1) expect(event.args.subject).to.eq(subjectAddress) expect(event.args.target).to.eq(targetAddress) - expect(event.args.evidence).to.eq(validEncodedNFTId) + expect(event.args.evidence[0]).to.eq(validEncodedNFTId) expect((await policyHarness.enforced(targetAddress, subjectAddress))[1]).to.be.equal(2) }) @@ -907,13 +907,13 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policyHarnessSkipped.setTarget(await target.getAddress()) - await policyHarnessSkipped.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 1) + await policyHarnessSkipped.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 1) expect( - policyHarnessSkipped.connect(target).exposed__enforce(notOwnerAddress, validEncodedNFTId, 1) + policyHarnessSkipped.connect(target).exposed__enforce(notOwnerAddress, [validEncodedNFTId], 1) ).to.be.revertedWithCustomError(policyHarnessSkipped, "MainCheckAlreadyEnforced") expect( - policyHarnessSkipped.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 1) + policyHarnessSkipped.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 1) ).to.be.revertedWithCustomError(policyHarnessSkipped, "MainCheckAlreadyEnforced") }) }) @@ -926,13 +926,13 @@ describe("Advanced", () => { await policyHarness.setTarget(await target.getAddress()) expect( - policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 2) + policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 2) ).to.be.revertedWithCustomError(policyHarness, "PreCheckNotEnforced") - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 0) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) expect( - policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 2) + policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 2) ).to.be.revertedWithCustomError(policyHarness, "MainCheckNotEnforced") }) @@ -941,11 +941,11 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policyHarness.setTarget(await target.getAddress()) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 0) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 1) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 1) await expect( - policyHarness.connect(subject).exposed__enforce(subjectAddress, ZeroHash, 2) + policyHarness.connect(subject).exposed__enforce(subjectAddress, [ZeroHash], 2) ).to.be.revertedWithCustomError(policyHarness, "TargetOnly") }) @@ -960,11 +960,11 @@ describe("Advanced", () => { } = await loadFixture(deployAdvancedPolicyFixture) await policyHarness.setTarget(await target.getAddress()) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 0) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 1) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 1) await expect( - policyHarness.connect(target).exposed__enforce(subjectAddress, invalidEncodedNFTId, 2) + policyHarness.connect(target).exposed__enforce(subjectAddress, [invalidEncodedNFTId], 2) ).to.be.revertedWithCustomError(iERC721Errors, "ERC721NonexistentToken") }) @@ -973,10 +973,10 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policyHarnessSkipped.setTarget(await target.getAddress()) - await policyHarnessSkipped.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 1) + await policyHarnessSkipped.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 1) await expect( - policyHarnessSkipped.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 2) + policyHarnessSkipped.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 2) ).to.be.revertedWithCustomError(policyHarnessSkipped, "CannotPostCheckWhenSkipped") }) @@ -985,11 +985,11 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policyHarness.setTarget(await target.getAddress()) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 0) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 1) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 1) expect( - policyHarness.connect(target).exposed__enforce(notOwnerAddress, validEncodedNFTId, 2) + policyHarness.connect(target).exposed__enforce(notOwnerAddress, [validEncodedNFTId], 2) ).to.be.revertedWithCustomError(policyHarness, "UnsuccessfulCheck") }) @@ -999,12 +999,12 @@ describe("Advanced", () => { const targetAddress = await target.getAddress() await policyHarness.setTarget(targetAddress) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 0) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 1) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 1) const tx = await policyHarness .connect(target) - .exposed__enforce(subjectAddress, validEncodedNFTId, 2) + .exposed__enforce(subjectAddress, [validEncodedNFTId], 2) const receipt = await tx.wait() const event = AdvancedERC721PolicyFactory.interface.parseLog( receipt?.logs[0] as unknown as { topics: string[]; data: string } @@ -1019,7 +1019,7 @@ describe("Advanced", () => { expect(receipt?.status).to.eq(1) expect(event.args.subject).to.eq(subjectAddress) expect(event.args.target).to.eq(targetAddress) - expect(event.args.evidence).to.eq(validEncodedNFTId) + expect(event.args.evidence[0]).to.eq(validEncodedNFTId) expect((await policyHarness.enforced(targetAddress, subjectAddress))[2]).to.be.equal(true) }) @@ -1028,12 +1028,12 @@ describe("Advanced", () => { await loadFixture(deployAdvancedPolicyFixture) await policyHarness.setTarget(await target.getAddress()) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 0) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 1) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 2) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 1) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 2) await expect( - policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId, 2) + policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 2) ).to.be.revertedWithCustomError(policyHarness, "AlreadyEnforced") }) }) @@ -1057,7 +1057,7 @@ describe("Advanced", () => { const iERC721Errors: IERC721Errors = await ethers.getContractAt("IERC721Errors", await nft.getAddress()) const checker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect(deployer).deploy( - await nft.getAddress(), + [await nft.getAddress()], 1, 0, 10 @@ -1384,7 +1384,7 @@ describe("Advanced", () => { const nft: NFT = await NFTFactory.deploy() const checker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect(deployer).deploy( - await nft.getAddress(), + [await nft.getAddress()], 1, 0, 20 diff --git a/packages/contracts/test/Base.test.ts b/packages/contracts/test/Base.test.ts index bcf7cb3..53143e7 100644 --- a/packages/contracts/test/Base.test.ts +++ b/packages/contracts/test/Base.test.ts @@ -32,12 +32,12 @@ describe("Base", () => { await ethers.getContractFactory("BaseERC721CheckerHarness") const nft: NFT = await NFTFactory.deploy() - const checker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy( + const checker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy([ await nft.getAddress() - ) + ]) const checkerHarness: BaseERC721CheckerHarness = await BaseERC721CheckerHarnessFactory.connect( deployer - ).deploy(await nft.getAddress()) + ).deploy([await nft.getAddress()]) // mint 0 for subject. await nft.connect(deployer).mint(subjectAddress) @@ -71,22 +71,21 @@ describe("Base", () => { const { nft, checker, target, subjectAddress, invalidNFTId } = await loadFixture(deployBaseCheckerFixture) - await expect(checker.connect(target).check(subjectAddress, invalidNFTId)).to.be.revertedWithCustomError( - nft, - "ERC721NonexistentToken" - ) + await expect( + checker.connect(target).check(subjectAddress, [invalidNFTId]) + ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") }) it("returns false when subject not owner", async () => { const { checker, target, notOwnerAddress, validNFTId } = await loadFixture(deployBaseCheckerFixture) - expect(await checker.connect(target).check(notOwnerAddress, validNFTId)).to.be.equal(false) + expect(await checker.connect(target).check(notOwnerAddress, [validNFTId])).to.be.equal(false) }) it("succeeds when valid", async () => { const { checker, target, subjectAddress, validNFTId } = await loadFixture(deployBaseCheckerFixture) - expect(await checker.connect(target).check(subjectAddress, validNFTId)).to.be.equal(true) + expect(await checker.connect(target).check(subjectAddress, [validNFTId])).to.be.equal(true) }) }) @@ -96,7 +95,7 @@ describe("Base", () => { await loadFixture(deployBaseCheckerFixture) await expect( - checkerHarness.connect(target).exposed__check(subjectAddress, invalidNFTId) + checkerHarness.connect(target).exposed__check(subjectAddress, [invalidNFTId]) ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") }) @@ -104,7 +103,7 @@ describe("Base", () => { const { checkerHarness, target, notOwnerAddress, validNFTId } = await loadFixture(deployBaseCheckerFixture) - expect(await checkerHarness.connect(target).exposed__check(notOwnerAddress, validNFTId)).to.be.equal( + expect(await checkerHarness.connect(target).exposed__check(notOwnerAddress, [validNFTId])).to.be.equal( false ) }) @@ -113,7 +112,7 @@ describe("Base", () => { const { checkerHarness, target, subjectAddress, validNFTId } = await loadFixture(deployBaseCheckerFixture) - expect(await checkerHarness.connect(target).exposed__check(subjectAddress, validNFTId)).to.be.equal( + expect(await checkerHarness.connect(target).exposed__check(subjectAddress, [validNFTId])).to.be.equal( true ) }) @@ -137,9 +136,9 @@ describe("Base", () => { const nft: NFT = await NFTFactory.deploy() const iERC721Errors: IERC721Errors = await ethers.getContractAt("IERC721Errors", await nft.getAddress()) - const checker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy( + const checker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy([ await nft.getAddress() - ) + ]) const policy: BaseERC721Policy = await BaseERC721PolicyFactory.connect(deployer).deploy( await checker.getAddress() ) @@ -240,7 +239,7 @@ describe("Base", () => { await policy.setTarget(await target.getAddress()) - await expect(policy.connect(subject).enforce(subjectAddress, ZeroHash)).to.be.revertedWithCustomError( + await expect(policy.connect(subject).enforce(subjectAddress, [ZeroHash])).to.be.revertedWithCustomError( policy, "TargetOnly" ) @@ -253,7 +252,7 @@ describe("Base", () => { await policy.setTarget(await target.getAddress()) await expect( - policy.connect(target).enforce(subjectAddress, invalidEncodedNFTId) + policy.connect(target).enforce(subjectAddress, [invalidEncodedNFTId]) ).to.be.revertedWithCustomError(iERC721Errors, "ERC721NonexistentToken") }) @@ -264,7 +263,7 @@ describe("Base", () => { await policy.setTarget(await target.getAddress()) expect( - policy.connect(target).enforce(notOwnerAddress, validEncodedNFTId) + policy.connect(target).enforce(notOwnerAddress, [validEncodedNFTId]) ).to.be.revertedWithCustomError(policy, "UnsuccessfulCheck") }) @@ -275,7 +274,7 @@ describe("Base", () => { await policy.setTarget(await target.getAddress()) - const tx = await policy.connect(target).enforce(subjectAddress, validEncodedNFTId) + const tx = await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId]) const receipt = await tx.wait() const event = BaseERC721PolicyFactory.interface.parseLog( receipt?.logs[0] as unknown as { topics: string[]; data: string } @@ -290,7 +289,7 @@ describe("Base", () => { expect(receipt?.status).to.eq(1) expect(event.args.subject).to.eq(subjectAddress) expect(event.args.target).to.eq(targetAddress) - expect(event.args.evidence).to.eq(validEncodedNFTId) + expect(event.args.evidence[0]).to.eq(validEncodedNFTId) expect(await policy.enforced(targetAddress, subjectAddress)).to.be.equal(true) }) @@ -299,10 +298,10 @@ describe("Base", () => { await policy.setTarget(await target.getAddress()) - await policy.connect(target).enforce(subjectAddress, validEncodedNFTId) + await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId]) await expect( - policy.connect(target).enforce(subjectAddress, validEncodedNFTId) + policy.connect(target).enforce(subjectAddress, [validEncodedNFTId]) ).to.be.revertedWithCustomError(policy, "AlreadyEnforced") }) }) @@ -314,7 +313,7 @@ describe("Base", () => { await policyHarness.setTarget(await target.getAddress()) await expect( - policyHarness.connect(subject).exposed__enforce(subjectAddress, ZeroHash) + policyHarness.connect(subject).exposed__enforce(subjectAddress, [ZeroHash]) ).to.be.revertedWithCustomError(policyHarness, "TargetOnly") }) @@ -325,7 +324,7 @@ describe("Base", () => { await policyHarness.setTarget(await target.getAddress()) await expect( - policyHarness.connect(target).exposed__enforce(subjectAddress, invalidEncodedNFTId) + policyHarness.connect(target).exposed__enforce(subjectAddress, [invalidEncodedNFTId]) ).to.be.revertedWithCustomError(iERC721Errors, "ERC721NonexistentToken") }) @@ -336,7 +335,7 @@ describe("Base", () => { await policyHarness.setTarget(await target.getAddress()) expect( - policyHarness.connect(target).exposed__enforce(notOwnerAddress, validEncodedNFTId) + policyHarness.connect(target).exposed__enforce(notOwnerAddress, [validEncodedNFTId]) ).to.be.revertedWithCustomError(policyHarness, "UnsuccessfulCheck") }) @@ -347,7 +346,7 @@ describe("Base", () => { await policyHarness.setTarget(await target.getAddress()) - const tx = await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId) + const tx = await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId]) const receipt = await tx.wait() const event = BaseERC721PolicyFactory.interface.parseLog( receipt?.logs[0] as unknown as { topics: string[]; data: string } @@ -362,7 +361,7 @@ describe("Base", () => { expect(receipt?.status).to.eq(1) expect(event.args.subject).to.eq(subjectAddress) expect(event.args.target).to.eq(targetAddress) - expect(event.args.evidence).to.eq(validEncodedNFTId) + expect(event.args.evidence[0]).to.eq(validEncodedNFTId) expect(await policyHarness.enforced(targetAddress, subjectAddress)).to.be.equal(true) }) @@ -372,10 +371,10 @@ describe("Base", () => { await policyHarness.setTarget(await target.getAddress()) - await policyHarness.connect(target).exposed__enforce(subjectAddress, validEncodedNFTId) + await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId]) await expect( - policyHarness.connect(target).enforce(subjectAddress, validEncodedNFTId) + policyHarness.connect(target).enforce(subjectAddress, [validEncodedNFTId]) ).to.be.revertedWithCustomError(policyHarness, "AlreadyEnforced") }) }) @@ -397,9 +396,9 @@ describe("Base", () => { const nft: NFT = await NFTFactory.deploy() const iERC721Errors: IERC721Errors = await ethers.getContractAt("IERC721Errors", await nft.getAddress()) - const checker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy( + const checker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy([ await nft.getAddress() - ) + ]) const policy: BaseERC721Policy = await BaseERC721PolicyFactory.connect(deployer).deploy( await checker.getAddress() ) @@ -586,9 +585,9 @@ describe("Base", () => { const nft: NFT = await NFTFactory.deploy() - const checker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy( + const checker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy([ await nft.getAddress() - ) + ]) const policy: BaseERC721Policy = await BaseERC721PolicyFactory.connect(deployer).deploy( await checker.getAddress() ) From fd66efc260155d9c664a68ef15f246b4371e0efb Mon Sep 17 00:00:00 2001 From: 0xjei Date: Fri, 17 Jan 2025 15:51:11 +0100 Subject: [PATCH 2/2] refactor(contracts): core contracts optimization, reflect on tests --- packages/contracts/contracts/src/Checker.sol | 14 +- .../contracts/src/interfaces/IChecker.sol | 6 + .../contracts/src/test/Advanced.t.sol | 400 +++++++++--------- .../contracts/contracts/src/test/Base.t.sol | 19 + .../test/advanced/AdvancedERC721Checker.sol | 65 +-- .../src/test/advanced/AdvancedVoting.sol | 98 ++--- .../src/test/base/BaseERC721Checker.sol | 2 +- .../wrappers/AdvancedERC721CheckerHarness.sol | 8 + .../wrappers/BaseERC721CheckerHarness.sol | 8 + packages/contracts/test/Advanced.test.ts | 392 ++++++++++------- packages/contracts/test/Base.test.ts | 27 ++ 11 files changed, 589 insertions(+), 450 deletions(-) diff --git a/packages/contracts/contracts/src/Checker.sol b/packages/contracts/contracts/src/Checker.sol index d149fd6..83cc4a6 100644 --- a/packages/contracts/contracts/src/Checker.sol +++ b/packages/contracts/contracts/src/Checker.sol @@ -20,17 +20,19 @@ abstract contract Checker is IChecker { verifiers = _verifiers; } - /// @notice Retrieves the list of third-party verifiers' addresses. - /// @return Array of addresses for the necessary verification contracts. - function getVerifiers() internal view returns (address[] memory) { - return verifiers; + /// @notice Retrieves the verifier address at a specific index. + /// @param index The index of the verifier in the array. + /// @return The address of the verifier at the specified index. + /// @custom:throws VerifierNotFound if no address have been specified at given index. + function getVerifierAtIndex(uint256 index) external view returns (address) { + return _getVerifierAtIndex(index); } - /// @notice Retrieves the verifier address at a specific index. + /// @notice Internal implementation of verifier address retrieval at a specific index. /// @param index The index of the verifier in the array. /// @return The address of the verifier at the specified index. /// @custom:throws VerifierNotFound if no address have been specified at given index. - function getVerifierAtIndex(uint256 index) internal view returns (address) { + function _getVerifierAtIndex(uint256 index) internal view returns (address) { if (index >= verifiers.length) revert VerifierNotFound(); return verifiers[index]; diff --git a/packages/contracts/contracts/src/interfaces/IChecker.sol b/packages/contracts/contracts/src/interfaces/IChecker.sol index 3b1b847..f8898a9 100644 --- a/packages/contracts/contracts/src/interfaces/IChecker.sol +++ b/packages/contracts/contracts/src/interfaces/IChecker.sol @@ -6,4 +6,10 @@ pragma solidity ^0.8.20; interface IChecker { /// @notice Core error conditions. error VerifierNotFound(); + + /// @notice Retrieves the verifier address at a specific index. + /// @param index The index of the verifier in the array. + /// @return The address of the verifier at the specified index. + /// @custom:throws VerifierNotFound if no address have been specified at given index. + function getVerifierAtIndex(uint256 index) external view returns (address); } diff --git a/packages/contracts/contracts/src/test/Advanced.t.sol b/packages/contracts/contracts/src/test/Advanced.t.sol index 78902a0..f84fb3f 100644 --- a/packages/contracts/contracts/src/test/Advanced.t.sol +++ b/packages/contracts/contracts/src/test/Advanced.t.sol @@ -3,11 +3,13 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/src/Test.sol"; import {NFT} from "./utils/NFT.sol"; +import {BaseERC721Checker} from "./base/BaseERC721Checker.sol"; import {AdvancedERC721Checker} from "./advanced/AdvancedERC721Checker.sol"; import {AdvancedERC721Policy} from "./advanced/AdvancedERC721Policy.sol"; import {AdvancedVoting} from "./advanced/AdvancedVoting.sol"; import {AdvancedERC721CheckerHarness} from "./wrappers/AdvancedERC721CheckerHarness.sol"; import {AdvancedERC721PolicyHarness} from "./wrappers/AdvancedERC721PolicyHarness.sol"; +import {IChecker} from "../interfaces/IChecker.sol"; import {IPolicy} from "../interfaces/IPolicy.sol"; import {IAdvancedPolicy} from "../interfaces/IAdvancedPolicy.sol"; import {IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; @@ -15,28 +17,39 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Check} from "../interfaces/IAdvancedChecker.sol"; contract AdvancedChecker is Test { - NFT internal nft; - AdvancedERC721Checker internal checker; - AdvancedERC721CheckerHarness internal checkerHarness; + NFT internal signupNft; + NFT internal rewardNft; + BaseERC721Checker internal baseChecker; + AdvancedERC721Checker internal advancedChecker; + AdvancedERC721CheckerHarness internal advancedCheckerHarness; address public deployer = vm.addr(0x1); address public target = vm.addr(0x2); address public subject = vm.addr(0x3); address public notOwner = vm.addr(0x4); - address[] internal verifiers; + address[] internal baseVerifiers; + address[] internal advancedVerifiers; bytes[] public evidence = new bytes[](1); bytes[] public wrongEvidence = new bytes[](1); function setUp() public virtual { vm.startPrank(deployer); - nft = new NFT(); - verifiers = new address[](1); - verifiers[0] = address(nft); + signupNft = new NFT(); + rewardNft = new NFT(); - checker = new AdvancedERC721Checker(verifiers, 1, 0, 10); - checkerHarness = new AdvancedERC721CheckerHarness(verifiers, 1, 0, 10); + baseVerifiers = new address[](1); + baseVerifiers[0] = address(signupNft); + baseChecker = new BaseERC721Checker(baseVerifiers); + + advancedVerifiers = new address[](3); + advancedVerifiers[0] = address(signupNft); + advancedVerifiers[1] = address(rewardNft); + advancedVerifiers[2] = address(baseChecker); + + advancedChecker = new AdvancedERC721Checker(advancedVerifiers, 1, 0, 10); + advancedCheckerHarness = new AdvancedERC721CheckerHarness(advancedVerifiers, 1, 0, 10); evidence[0] = abi.encode(0); wrongEvidence[0] = abi.encode(1); @@ -44,11 +57,29 @@ contract AdvancedChecker is Test { vm.stopPrank(); } + function test_getVerifierAtIndex_ReturnsCorrectAddress() public view { + assertEq(advancedChecker.getVerifierAtIndex(0), address(signupNft)); + } + + function test_getVerifierAtIndex_RevertWhen_VerifierNotFound() public { + vm.expectRevert(abi.encodeWithSelector(IChecker.VerifierNotFound.selector)); + advancedChecker.getVerifierAtIndex(5); + } + + function test_getVerifierAtIndex_internal_ReturnsCorrectAddress() public view { + assertEq(advancedCheckerHarness.exposed__getVerifierAtIndex(0), address(signupNft)); + } + + function test_getVerifierAtIndex_internal_RevertWhen_VerifierNotFound() public { + vm.expectRevert(abi.encodeWithSelector(IChecker.VerifierNotFound.selector)); + advancedCheckerHarness.exposed__getVerifierAtIndex(5); + } + function test_checkPre_whenTokenDoesNotExist_reverts() public { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(0))); - checker.check(subject, evidence, Check.PRE); + advancedChecker.check(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -56,9 +87,9 @@ contract AdvancedChecker is Test { function test_checkPre_whenCallerNotOwner_returnsFalse() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(!checker.check(notOwner, evidence, Check.PRE)); + assert(!advancedChecker.check(notOwner, evidence, Check.PRE)); vm.stopPrank(); } @@ -66,9 +97,9 @@ contract AdvancedChecker is Test { function test_checkPre_whenValid_succeeds() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(checker.check(subject, evidence, Check.PRE)); + assert(advancedChecker.check(subject, evidence, Check.PRE)); vm.stopPrank(); } @@ -76,9 +107,9 @@ contract AdvancedChecker is Test { function test_checkMain_whenCallerHasNoTokens_returnsFalse() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(!checker.check(notOwner, evidence, Check.MAIN)); + assert(!advancedChecker.check(notOwner, evidence, Check.MAIN)); vm.stopPrank(); } @@ -86,28 +117,19 @@ contract AdvancedChecker is Test { function test_checkMain_whenCallerHasTokens_succeeds() public { vm.startPrank(target); - nft.mint(subject); - - assert(checker.check(subject, evidence, Check.MAIN)); + signupNft.mint(subject); - vm.stopPrank(); - } - - function test_checkPost_whenTokenDoesNotExist_reverts() public { - vm.startPrank(target); - - vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - checker.check(subject, wrongEvidence, Check.POST); + assert(advancedChecker.check(subject, evidence, Check.MAIN)); vm.stopPrank(); } - function test_checkPost_whenCallerNotOwner_returnsFalse() public { + function test_checkPost_whenCallerBalanceGreaterThanZero_returnsFalse() public { vm.startPrank(target); - nft.mint(subject); + rewardNft.mint(subject); - assert(!checker.check(notOwner, evidence, Check.POST)); + assert(!advancedChecker.check(subject, evidence, Check.POST)); vm.stopPrank(); } @@ -115,9 +137,9 @@ contract AdvancedChecker is Test { function test_checkPost_whenValid_succeeds() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(checker.check(subject, evidence, Check.POST)); + assert(advancedChecker.check(subject, evidence, Check.POST)); vm.stopPrank(); } @@ -126,7 +148,7 @@ contract AdvancedChecker is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(0))); - checkerHarness.exposed__check(subject, evidence, Check.PRE); + advancedCheckerHarness.exposed__check(subject, evidence, Check.PRE); vm.stopPrank(); } @@ -134,9 +156,9 @@ contract AdvancedChecker is Test { function test_checkerPre_whenCallerNotOwner_returnsFalse() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(!checkerHarness.exposed__check(notOwner, evidence, Check.PRE)); + assert(!advancedCheckerHarness.exposed__check(notOwner, evidence, Check.PRE)); vm.stopPrank(); } @@ -144,9 +166,9 @@ contract AdvancedChecker is Test { function test_checkerPre_whenValid_succeeds() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(checkerHarness.exposed__check(subject, evidence, Check.PRE)); + assert(advancedCheckerHarness.exposed__check(subject, evidence, Check.PRE)); vm.stopPrank(); } @@ -154,9 +176,9 @@ contract AdvancedChecker is Test { function test_checkerMain_whenCallerHasNoTokens_returnsFalse() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(!checkerHarness.exposed__check(notOwner, evidence, Check.MAIN)); + assert(!advancedCheckerHarness.exposed__check(notOwner, evidence, Check.MAIN)); vm.stopPrank(); } @@ -164,28 +186,19 @@ contract AdvancedChecker is Test { function test_checkerMain_whenCallerHasTokens_succeeds() public { vm.startPrank(target); - nft.mint(subject); - - assert(checkerHarness.exposed__check(subject, evidence, Check.MAIN)); - - vm.stopPrank(); - } - - function test_checkerPost_whenTokenDoesNotExist_reverts() public { - vm.startPrank(target); + signupNft.mint(subject); - vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - checkerHarness.exposed__check(subject, wrongEvidence, Check.POST); + assert(advancedCheckerHarness.exposed__check(subject, evidence, Check.MAIN)); vm.stopPrank(); } - function test_checkerPost_whenCallerNotOwner_returnsFalse() public { + function test_checkerPost_whenCallerBalanceGreaterThanZero_returnsFalse() public { vm.startPrank(target); - nft.mint(subject); + rewardNft.mint(subject); - assert(!checkerHarness.exposed__check(notOwner, evidence, Check.POST)); + assert(!advancedCheckerHarness.check(subject, evidence, Check.POST)); vm.stopPrank(); } @@ -193,9 +206,9 @@ contract AdvancedChecker is Test { function test_checkerPost_whenValid_succeeds() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(checkerHarness.exposed__check(subject, evidence, Check.POST)); + assert(advancedCheckerHarness.exposed__check(subject, evidence, Check.POST)); vm.stopPrank(); } @@ -204,7 +217,7 @@ contract AdvancedChecker is Test { vm.startPrank(target); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - checkerHarness.exposed__checkPre(subject, wrongEvidence); + advancedCheckerHarness.exposed__checkPre(subject, wrongEvidence); vm.stopPrank(); } @@ -212,9 +225,9 @@ contract AdvancedChecker is Test { function test_internalPre_whenCallerNotOwner_returnsFalse() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(!checkerHarness.exposed__checkPre(notOwner, evidence)); + assert(!advancedCheckerHarness.exposed__checkPre(notOwner, evidence)); vm.stopPrank(); } @@ -222,9 +235,9 @@ contract AdvancedChecker is Test { function test_internalPre_whenValid_succeeds() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(checkerHarness.exposed__checkPre(subject, evidence)); + assert(advancedCheckerHarness.exposed__checkPre(subject, evidence)); vm.stopPrank(); } @@ -232,9 +245,9 @@ contract AdvancedChecker is Test { function test_internalMain_whenCallerHasNoTokens_returnsFalse() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(!checkerHarness.exposed__checkMain(notOwner, evidence)); + assert(!advancedCheckerHarness.exposed__checkMain(notOwner, evidence)); vm.stopPrank(); } @@ -242,28 +255,19 @@ contract AdvancedChecker is Test { function test_internalMain_whenCallerHasTokens_succeeds() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(checkerHarness.exposed__checkMain(subject, evidence)); + assert(advancedCheckerHarness.exposed__checkMain(subject, evidence)); vm.stopPrank(); } - function test_internalPost_whenTokenDoesNotExist_reverts() public { + function test_internalPost_whenCallerBalanceGreaterThanZero_returnsFalse() public { vm.startPrank(target); - vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - checkerHarness.exposed__checkPost(subject, wrongEvidence); + rewardNft.mint(subject); - vm.stopPrank(); - } - - function test_internalPost_whenCallerNotOwner_returnsFalse() public { - vm.startPrank(target); - - nft.mint(subject); - - assert(!checkerHarness.exposed__checkPost(notOwner, evidence)); + assert(!advancedCheckerHarness.exposed__checkPost(subject, evidence)); vm.stopPrank(); } @@ -271,9 +275,9 @@ contract AdvancedChecker is Test { function test_internalPost_whenValid_succeeds() public { vm.startPrank(target); - nft.mint(subject); + signupNft.mint(subject); - assert(checkerHarness.exposed__checkPost(subject, evidence)); + assert(advancedCheckerHarness.exposed__checkPost(subject, evidence)); vm.stopPrank(); } @@ -283,9 +287,11 @@ contract AdvancedPolicy is Test { event TargetSet(address indexed target); event Enforced(address indexed subject, address indexed target, bytes[] evidence, Check checkType); - NFT internal nft; - AdvancedERC721Checker internal checker; - AdvancedERC721Checker internal checkerSkipped; + NFT internal signupNft; + NFT internal rewardNft; + BaseERC721Checker internal baseChecker; + AdvancedERC721Checker internal advancedChecker; + AdvancedERC721Checker internal advancedCheckerSkipped; AdvancedERC721Policy internal policy; AdvancedERC721Policy internal policySkipped; AdvancedERC721PolicyHarness internal policyHarness; @@ -296,23 +302,32 @@ contract AdvancedPolicy is Test { address public subject = vm.addr(0x3); address public notOwner = vm.addr(0x4); - address[] internal verifiers; + address[] internal baseVerifiers; + address[] internal advancedVerifiers; bytes[] public evidence = new bytes[](1); bytes[] public wrongEvidence = new bytes[](1); function setUp() public virtual { vm.startPrank(deployer); - nft = new NFT(); - verifiers = new address[](1); - verifiers[0] = address(nft); + signupNft = new NFT(); + rewardNft = new NFT(); + + baseVerifiers = new address[](1); + baseVerifiers[0] = address(signupNft); + baseChecker = new BaseERC721Checker(baseVerifiers); + + advancedVerifiers = new address[](3); + advancedVerifiers[0] = address(signupNft); + advancedVerifiers[1] = address(rewardNft); + advancedVerifiers[2] = address(baseChecker); - checker = new AdvancedERC721Checker(verifiers, 1, 0, 10); - checkerSkipped = new AdvancedERC721Checker(verifiers, 1, 0, 10); - policy = new AdvancedERC721Policy(checker, false, false, true); - policyHarness = new AdvancedERC721PolicyHarness(checker, false, false, true); - policySkipped = new AdvancedERC721Policy(checkerSkipped, true, true, false); - policyHarnessSkipped = new AdvancedERC721PolicyHarness(checkerSkipped, true, true, false); + advancedChecker = new AdvancedERC721Checker(advancedVerifiers, 1, 0, 10); + advancedCheckerSkipped = new AdvancedERC721Checker(advancedVerifiers, 1, 0, 10); + policy = new AdvancedERC721Policy(advancedChecker, false, false, true); + policyHarness = new AdvancedERC721PolicyHarness(advancedChecker, false, false, true); + policySkipped = new AdvancedERC721Policy(advancedCheckerSkipped, true, true, false); + policyHarnessSkipped = new AdvancedERC721PolicyHarness(advancedCheckerSkipped, true, true, false); evidence[0] = abi.encode(0); wrongEvidence[0] = abi.encode(1); @@ -398,7 +413,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policySkipped.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -414,7 +429,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policy.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -430,7 +445,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policy.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -448,7 +463,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policy.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -496,7 +511,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policy.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -512,7 +527,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policy.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -532,7 +547,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policy.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -557,7 +572,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policySkipped.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -575,7 +590,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policy.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -603,29 +618,11 @@ contract AdvancedPolicy is Test { vm.stopPrank(); } - function test_enforcePost_whenTokenDoesNotExist_reverts() public { - vm.startPrank(deployer); - - policy.setTarget(target); - nft.mint(subject); - - vm.stopPrank(); - - vm.startPrank(target); - policy.enforce(subject, evidence, Check.PRE); - policy.enforce(subject, evidence, Check.MAIN); - - vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - policy.enforce(subject, wrongEvidence, Check.POST); - - vm.stopPrank(); - } - function test_enforcePost_whenChecksSkipped_reverts() public { vm.startPrank(deployer); policySkipped.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -643,7 +640,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policy.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -652,8 +649,10 @@ contract AdvancedPolicy is Test { policy.enforce(subject, evidence, Check.PRE); policy.enforce(subject, evidence, Check.MAIN); + rewardNft.mint(subject); + vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector)); - policy.enforce(notOwner, evidence, Check.POST); + policy.enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -662,7 +661,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policy.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -683,7 +682,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policy.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -733,7 +732,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarnessSkipped.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -749,7 +748,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarness.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -765,7 +764,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarness.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -783,7 +782,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarness.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -831,7 +830,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarness.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -847,7 +846,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarness.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -867,7 +866,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarness.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -892,7 +891,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarnessSkipped.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -910,7 +909,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarness.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -938,29 +937,11 @@ contract AdvancedPolicy is Test { vm.stopPrank(); } - function test_enforcePostInternal_whenTokenDoesNotExist_reverts() public { - vm.startPrank(deployer); - - policyHarness.setTarget(target); - nft.mint(subject); - - vm.stopPrank(); - - vm.startPrank(target); - policyHarness.exposed__enforce(subject, evidence, Check.PRE); - policyHarness.exposed__enforce(subject, evidence, Check.MAIN); - - vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - policyHarness.exposed__enforce(subject, wrongEvidence, Check.POST); - - vm.stopPrank(); - } - function test_enforcePostInternal_whenChecksSkipped_reverts() public { vm.startPrank(deployer); policyHarnessSkipped.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -978,7 +959,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarness.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -987,8 +968,10 @@ contract AdvancedPolicy is Test { policyHarness.exposed__enforce(subject, evidence, Check.PRE); policyHarness.exposed__enforce(subject, evidence, Check.MAIN); + rewardNft.mint(subject); + vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector)); - policyHarness.exposed__enforce(notOwner, evidence, Check.POST); + policyHarness.exposed__enforce(subject, evidence, Check.POST); vm.stopPrank(); } @@ -997,7 +980,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarness.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1018,7 +1001,7 @@ contract AdvancedPolicy is Test { vm.startPrank(deployer); policyHarness.setTarget(target); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1038,27 +1021,39 @@ contract AdvancedPolicy is Test { contract Voting is Test { event Registered(address voter); event Voted(address voter, uint8 option); - event RewardClaimed(address voter, uint256 rewardId); + event Eligible(address voter); - NFT internal nft; - AdvancedERC721Checker internal checker; + NFT internal signupNft; + NFT internal rewardNft; + BaseERC721Checker internal baseChecker; + AdvancedERC721Checker internal advancedChecker; AdvancedERC721Policy internal policy; AdvancedVoting internal voting; - address[] internal verifiers; address public deployer = vm.addr(0x1); address public subject = vm.addr(0x2); address public notOwner = vm.addr(0x3); + address[] internal baseVerifiers; + address[] internal advancedVerifiers; + function setUp() public virtual { vm.startPrank(deployer); - nft = new NFT(); - verifiers = new address[](1); - verifiers[0] = address(nft); + signupNft = new NFT(); + rewardNft = new NFT(); + + baseVerifiers = new address[](1); + baseVerifiers[0] = address(signupNft); + baseChecker = new BaseERC721Checker(baseVerifiers); - checker = new AdvancedERC721Checker(verifiers, 1, 0, 10); - policy = new AdvancedERC721Policy(checker, false, false, true); + advancedVerifiers = new address[](3); + advancedVerifiers[0] = address(signupNft); + advancedVerifiers[1] = address(rewardNft); + advancedVerifiers[2] = address(baseChecker); + + advancedChecker = new AdvancedERC721Checker(advancedVerifiers, 1, 0, 10); + policy = new AdvancedERC721Policy(advancedChecker, false, false, true); voting = new AdvancedVoting(policy); vm.stopPrank(); @@ -1068,7 +1063,7 @@ contract Voting is Test { vm.startPrank(deployer); policy.setTarget(deployer); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1084,7 +1079,7 @@ contract Voting is Test { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1100,7 +1095,7 @@ contract Voting is Test { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1116,7 +1111,7 @@ contract Voting is Test { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1134,7 +1129,7 @@ contract Voting is Test { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1152,7 +1147,7 @@ contract Voting is Test { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1168,7 +1163,7 @@ contract Voting is Test { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1185,7 +1180,7 @@ contract Voting is Test { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1204,7 +1199,7 @@ contract Voting is Test { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1220,31 +1215,12 @@ contract Voting is Test { vm.stopPrank(); } - function test_reward_whenTokenDoesNotExist_reverts() public { + function test_eligible_whenCheckFails_reverts() public { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); - - vm.stopPrank(); - - vm.startPrank(subject); - - voting.register(0); - voting.vote(0); - - vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, uint256(1))); - voting.reward(1); - - vm.stopPrank(); - } - - function test_reward_whenCheckFails_reverts() public { - vm.startPrank(deployer); - - policy.setTarget(address(voting)); - nft.mint(subject); - nft.mint(notOwner); + signupNft.mint(subject); + signupNft.mint(notOwner); vm.stopPrank(); @@ -1258,33 +1234,35 @@ contract Voting is Test { voting.register(0); voting.vote(0); + rewardNft.mint(subject); + vm.expectRevert(abi.encodeWithSelector(IPolicy.UnsuccessfulCheck.selector)); - voting.reward(1); + voting.eligible(); vm.stopPrank(); } - function test_reward_whenNotRegistered_reverts() public { + function test_eligible_whenNotRegistered_reverts() public { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); vm.startPrank(subject); vm.expectRevert(abi.encodeWithSelector(AdvancedVoting.NotRegistered.selector)); - voting.reward(0); + voting.eligible(); vm.stopPrank(); } - function test_reward_whenNotVoted_reverts() public { + function test_eligible_whenNotVoted_reverts() public { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1292,16 +1270,16 @@ contract Voting is Test { voting.register(0); vm.expectRevert(abi.encodeWithSelector(AdvancedVoting.NotVoted.selector)); - voting.reward(0); + voting.eligible(); vm.stopPrank(); } - function test_reward_whenValid_succeeds() public { + function test_eligible_whenValid_succeeds() public { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1311,18 +1289,18 @@ contract Voting is Test { voting.vote(0); vm.expectEmit(true, true, true, true); - emit RewardClaimed(subject, 0); + emit Eligible(subject); - voting.reward(0); + voting.eligible(); vm.stopPrank(); } - function test_reward_whenAlreadyClaimed_reverts() public { + function test_eligible_whenAlreadyEligible_reverts() public { vm.startPrank(deployer); policy.setTarget(address(voting)); - nft.mint(subject); + signupNft.mint(subject); vm.stopPrank(); @@ -1330,10 +1308,10 @@ contract Voting is Test { voting.register(0); voting.vote(0); - voting.reward(0); + voting.eligible(); - vm.expectRevert(abi.encodeWithSelector(AdvancedVoting.AlreadyClaimed.selector)); - voting.reward(0); + vm.expectRevert(abi.encodeWithSelector(AdvancedVoting.AlreadyEligible.selector)); + voting.eligible(); vm.stopPrank(); } diff --git a/packages/contracts/contracts/src/test/Base.t.sol b/packages/contracts/contracts/src/test/Base.t.sol index eef8978..60f9abc 100644 --- a/packages/contracts/contracts/src/test/Base.t.sol +++ b/packages/contracts/contracts/src/test/Base.t.sol @@ -9,6 +9,7 @@ import {BaseVoting} from "./base/BaseVoting.sol"; import {BaseERC721CheckerHarness} from "./wrappers/BaseERC721CheckerHarness.sol"; import {BaseERC721PolicyHarness} from "./wrappers/BaseERC721PolicyHarness.sol"; import {IPolicy} from "../interfaces/IPolicy.sol"; +import {IChecker} from "../interfaces/IChecker.sol"; import {IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; @@ -40,6 +41,24 @@ contract BaseChecker is Test { vm.stopPrank(); } + function test_getVerifierAtIndex_ReturnsCorrectAddress() public view { + assertEq(checker.getVerifierAtIndex(0), address(nft)); + } + + function test_getVerifierAtIndex_RevertWhen_VerifierNotFound() public { + vm.expectRevert(abi.encodeWithSelector(IChecker.VerifierNotFound.selector)); + checker.getVerifierAtIndex(1); + } + + function test_getVerifierAtIndex_internal_ReturnsCorrectAddress() public view { + assertEq(checkerHarness.exposed__getVerifierAtIndex(0), address(nft)); + } + + function test_getVerifierAtIndex_internal_RevertWhen_VerifierNotFound() public { + vm.expectRevert(abi.encodeWithSelector(IChecker.VerifierNotFound.selector)); + checkerHarness.exposed__getVerifierAtIndex(1); + } + function test_checker_whenTokenDoesNotExist_reverts() public { vm.startPrank(target); diff --git a/packages/contracts/contracts/src/test/advanced/AdvancedERC721Checker.sol b/packages/contracts/contracts/src/test/advanced/AdvancedERC721Checker.sol index 309959f..644b944 100644 --- a/packages/contracts/contracts/src/test/advanced/AdvancedERC721Checker.sol +++ b/packages/contracts/contracts/src/test/advanced/AdvancedERC721Checker.sol @@ -2,61 +2,78 @@ pragma solidity ^0.8.20; import {AdvancedChecker} from "../../AdvancedChecker.sol"; +import {BaseERC721Checker} from "../base/BaseERC721Checker.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; /// @title AdvancedERC721Checker. -/// @notice Multi-phase ERC721 token validation. -/// @dev Implements pre, main, and post checks for NFTs. +/// @notice Multi-phase NFT validation with aggregated verification contracts. +/// @dev Implements three-phase validation using multiple NFT contracts and external verifiers: +/// - Pre-check: Basic signup token validation using BaseERC721Checker. +/// - Main-check: Balance threshold validation for signup token. +/// - Post-check: Reward eligibility verification for reward token. contract AdvancedERC721Checker is AdvancedChecker { - /// @notice Contract references and thresholds. - IERC721 public immutable NFT; + /// @notice External contracts used for verification. + /// @dev Immutable references derived from verifier array positions: + /// - Index 0: Signup NFT contract. + /// - Index 1: Reward NFT contract. + /// - Index 2: Base ERC721 checker contract. + IERC721 public immutable SIGNUP_NFT; + IERC721 public immutable REWARD_NFT; + BaseERC721Checker public immutable BASE_ERC721_CHECKER; + + /// @notice Validation thresholds. uint256 public immutable MIN_BALANCE; uint256 public immutable MIN_TOKEN_ID; uint256 public immutable MAX_TOKEN_ID; - /// @notice Initializes checker with validation parameters. - /// @param _verifiers Array of addresses for existing verification contracts. - /// @param _minBalance Required token balance. - /// @param _minTokenId Minimum valid token ID. - /// @param _maxTokenId Maximum valid token ID. + /// @notice Initializes checker with verification chain. + /// @dev Orders of verifiers array is crucial: + /// [signupNFT, rewardNFT, baseChecker] + /// @param _verifiers Ordered array of verification contract addresses. + /// @param _minBalance Required signup token balance. + /// @param _minTokenId Lower bound for valid token IDs. + /// @param _maxTokenId Upper bound for valid token IDs. constructor( address[] memory _verifiers, uint256 _minBalance, uint256 _minTokenId, uint256 _maxTokenId ) AdvancedChecker(_verifiers) { - NFT = IERC721(getVerifierAtIndex(0)); + SIGNUP_NFT = IERC721(_getVerifierAtIndex(0)); + REWARD_NFT = IERC721(_getVerifierAtIndex(1)); + BASE_ERC721_CHECKER = BaseERC721Checker(_getVerifierAtIndex(2)); MIN_BALANCE = _minBalance; MIN_TOKEN_ID = _minTokenId; MAX_TOKEN_ID = _maxTokenId; } - /// @notice Validates basic token ownership. + /// @notice Pre-check: Validates initial NFT ownership. + /// @dev Delegates basic ownership check to BaseERC721Checker. /// @param subject Address to validate. - /// @param evidence Encoded tokenId. - /// @return Token ownership status. + /// @param evidence Array containing encoded tokenId. + /// @return Validation status from base checker. function _checkPre(address subject, bytes[] calldata evidence) internal view override returns (bool) { super._checkPre(subject, evidence); - uint256 tokenId = abi.decode(evidence[0], (uint256)); - return NFT.ownerOf(tokenId) == subject; + return BASE_ERC721_CHECKER.check(subject, evidence); } - /// @notice Validates minimum token balance. + /// @notice Main-check: Validates token balance requirements. + /// @dev Ensures subject has exactly MIN_BALANCE tokens. /// @param subject Address to validate. - /// @param evidence Unused parameter. - /// @return Balance threshold status. + /// @param evidence Not used in balance check. + /// @return True if balance meets requirements. function _checkMain(address subject, bytes[] calldata evidence) internal view override returns (bool) { super._checkMain(subject, evidence); - return NFT.balanceOf(subject) >= MIN_BALANCE; + return SIGNUP_NFT.balanceOf(subject) >= MIN_BALANCE && SIGNUP_NFT.balanceOf(subject) <= MIN_BALANCE; } - /// @notice Validates token ID range ownership. + /// @notice Post-check: Validates reward eligibility. + /// @dev Ensures subject doesn't already have reward tokens. /// @param subject Address to validate. - /// @param evidence Encoded tokenId. - /// @return Token range validation status. + /// @param evidence Not used in reward check. + /// @return True if subject eligible for rewards. function _checkPost(address subject, bytes[] calldata evidence) internal view override returns (bool) { super._checkPost(subject, evidence); - uint256 tokenId = abi.decode(evidence[0], (uint256)); - return tokenId >= MIN_TOKEN_ID && tokenId <= MAX_TOKEN_ID && NFT.ownerOf(tokenId) == subject; + return REWARD_NFT.balanceOf(subject) == 0; } } diff --git a/packages/contracts/contracts/src/test/advanced/AdvancedVoting.sol b/packages/contracts/contracts/src/test/advanced/AdvancedVoting.sol index c182f0c..8d69c78 100644 --- a/packages/contracts/contracts/src/test/advanced/AdvancedVoting.sol +++ b/packages/contracts/contracts/src/test/advanced/AdvancedVoting.sol @@ -5,73 +5,77 @@ import {AdvancedPolicy} from "../../AdvancedPolicy.sol"; import {Check} from "../../interfaces/IAdvancedPolicy.sol"; /// @title AdvancedVoting. -/// @notice Multi-phase voting system with NFT validation and rewards. -/// @dev Implements a three-phase voting process: -/// 1. Registration (PRE): Validates initial NFT ownership. -/// 2. Voting (MAIN): Validates voting power and records vote. -/// 3. Rewards (POST): Validates and distributes NFT rewards. +/// @notice Advanced voting system with NFT-based phases and eligibility verification. +/// @dev Implements a three-phase governance process using NFT validation: +/// 1. Registration: Validates ownership of signup NFT (under-the-hood uses the BaseERC721Checker). +/// 2. Voting: Validates token balances and records votes (single token = single vote). +/// 3. Eligibility: Validates criteria for governance participation benefits. contract AdvancedVoting { - /// @notice Events for tracking system state changes. + /// @notice Emitted on successful phase completion. + /// @param voter Address that completed the phase. event Registered(address voter); + /// @param option Selected voting option (0 or 1). event Voted(address voter, uint8 option); - event RewardClaimed(address voter, uint256 rewardId); - - /// @notice System error conditions. - error NotRegistered(); - error NotVoted(); - error AlreadyClaimed(); - error InvalidOption(); - error NotOwnerOfReward(); - - /// @notice Policy contract for validation checks. + /// @param voter Address that met eligibility criteria. + event Eligible(address voter); + + /// @notice Validation error states. + /// @dev Thrown when phase requirements not met. + error NotRegistered(); // Pre-check (registration) not completed. + error NotVoted(); // Main check (voting) not completed. + error AlreadyEligible(); // Post check (eligibility) already verified. + error InvalidOption(); // Vote option out of valid range. + error NotEligible(); // Eligibility criteria not met. + + /// @notice Policy contract managing multi-phase validation. + /// @dev Handles all NFT-based checks through aggregated verifiers. AdvancedPolicy public immutable POLICY; - /// @notice Tracks total votes per option. - /// @dev Maps option ID => vote count. + /// @notice Vote tracking per option. + /// @dev Maps option ID (0 or 1) to total votes received. mapping(uint8 => uint256) public voteCounts; - /// @notice Sets up voting system with policy contract. - /// @param _policy Contract handling validation logic. + /// @notice Initializes voting system. + /// @param _policy Advanced policy contract with configured verifiers. constructor(AdvancedPolicy _policy) { POLICY = _policy; } - /// @notice First phase - Register voter with NFT ownership proof. - /// @dev Enforces PRE check through policy contract. - /// @param tokenId NFT used for registration. - /// @custom:requirements Caller must own the NFT with tokenId. - /// @custom:emits Registered on successful registration. + /// @notice Registration phase handler. + /// @dev Validates signup NFT ownership using BaseERC721Checker. + /// @param tokenId ID of the signup NFT to validate. + /// @custom:requirements + /// - Token must exist. + /// - Caller must be token owner. + /// - Token ID must be within valid range. + /// @custom:emits Registered when registration succeeds. function register(uint256 tokenId) external { - // Encode token ID for policy verification. bytes[] memory _evidence = new bytes[](1); _evidence[0] = abi.encode(tokenId); - // Verify NFT ownership through policy's PRE check. POLICY.enforce(msg.sender, _evidence, Check.PRE); emit Registered(msg.sender); } - /// @notice Second phase - Cast vote after registration. - /// @dev Enforces MAIN check and updates vote counts. - /// @param option Vote choice (0 or 1). + /// @notice Voting phase handler. + /// @dev Validates voting power and records vote choice. + /// @param option Binary choice (0 or 1). /// @custom:requirements - /// - Caller must be registered (passed PRE check). + /// - Registration must be completed. /// - Option must be valid (0 or 1). - /// @custom:emits Voted on successful vote cast. + /// - Token balance must meet requirements. + /// @custom:emits Voted when vote is recorded. function vote(uint8 option) external { - // Check registration status (PRE check completion). (bool pre, , ) = POLICY.enforced(address(this), msg.sender); - if (!pre) revert NotRegistered(); if (option >= 2) revert InvalidOption(); - // Verify voting power through policy's MAIN check. bytes[] memory _evidence = new bytes[](1); _evidence[0] = abi.encode(option); + POLICY.enforce(msg.sender, _evidence, Check.MAIN); - // Increment vote count safely. unchecked { voteCounts[option]++; } @@ -79,27 +83,23 @@ contract AdvancedVoting { emit Voted(msg.sender, option); } - /// @notice Final phase - Claim NFT reward after voting. - /// @dev Enforces POST check for reward distribution. - /// @param rewardId Identifier of NFT reward to claim. + /// @notice Eligibility verification phase. + /// @dev Validates completion of governance process and checks eligibility criteria. /// @custom:requirements /// - Caller must be registered (passed PRE check). /// - Caller must have voted (passed MAIN check). - /// - Caller must not have claimed before (no POST check). - /// @custom:emits RewardClaimed on successful claim. - function reward(uint256 rewardId) external { - // Verify completion of previous phases. + /// - Caller must not be already verified (no POST check). + /// - Caller must meet eligibility criteria (no existing benefits). + /// @custom:emits Eligible when verification succeeds. + function eligible() external { (bool pre, uint8 main, bool post) = POLICY.enforced(address(this), msg.sender); if (!pre) revert NotRegistered(); if (main == 0) revert NotVoted(); - if (post) revert AlreadyClaimed(); + if (post) revert AlreadyEligible(); - // Verify reward eligibility through policy's POST check. - bytes[] memory _evidence = new bytes[](1); - _evidence[0] = abi.encode(rewardId); - POLICY.enforce(msg.sender, _evidence, Check.POST); + POLICY.enforce(msg.sender, new bytes[](1), Check.POST); - emit RewardClaimed(msg.sender, rewardId); + emit Eligible(msg.sender); } } diff --git a/packages/contracts/contracts/src/test/base/BaseERC721Checker.sol b/packages/contracts/contracts/src/test/base/BaseERC721Checker.sol index b8cc57d..759fc02 100644 --- a/packages/contracts/contracts/src/test/base/BaseERC721Checker.sol +++ b/packages/contracts/contracts/src/test/base/BaseERC721Checker.sol @@ -14,7 +14,7 @@ contract BaseERC721Checker is BaseChecker { /// @notice Initializes with ERC721 contract. /// @param _verifiers Array of addresses for existing verification contracts. constructor(address[] memory _verifiers) BaseChecker(_verifiers) { - NFT = IERC721(getVerifierAtIndex(0)); + NFT = IERC721(_getVerifierAtIndex(0)); } /// @notice Validates token ownership. diff --git a/packages/contracts/contracts/src/test/wrappers/AdvancedERC721CheckerHarness.sol b/packages/contracts/contracts/src/test/wrappers/AdvancedERC721CheckerHarness.sol index 1d0511d..a48995e 100644 --- a/packages/contracts/contracts/src/test/wrappers/AdvancedERC721CheckerHarness.sol +++ b/packages/contracts/contracts/src/test/wrappers/AdvancedERC721CheckerHarness.sol @@ -52,4 +52,12 @@ contract AdvancedERC721CheckerHarness is AdvancedERC721Checker { function exposed__checkPost(address subject, bytes[] calldata evidence) public view returns (bool) { return _checkPost(subject, evidence); } + + /// @notice Test exposure for _getVerifierAtIndex method. + /// @param index The index of the verifier in the array. + /// @return The address of the verifier at the specified index. + /// @custom:throws VerifierNotFound if no address have been specified at given index. + function exposed__getVerifierAtIndex(uint256 index) public view returns (address) { + return _getVerifierAtIndex(index); + } } diff --git a/packages/contracts/contracts/src/test/wrappers/BaseERC721CheckerHarness.sol b/packages/contracts/contracts/src/test/wrappers/BaseERC721CheckerHarness.sol index d97448d..f5458bb 100644 --- a/packages/contracts/contracts/src/test/wrappers/BaseERC721CheckerHarness.sol +++ b/packages/contracts/contracts/src/test/wrappers/BaseERC721CheckerHarness.sol @@ -17,4 +17,12 @@ contract BaseERC721CheckerHarness is BaseERC721Checker { function exposed__check(address subject, bytes[] calldata evidence) public view returns (bool) { return _check(subject, evidence); } + + /// @notice Test exposure for _getVerifierAtIndex method. + /// @param index The index of the verifier in the array. + /// @return The address of the verifier at the specified index. + /// @custom:throws VerifierNotFound if no address have been specified at given index. + function exposed__getVerifierAtIndex(uint256 index) public view returns (address) { + return _getVerifierAtIndex(index); + } } diff --git a/packages/contracts/test/Advanced.test.ts b/packages/contracts/test/Advanced.test.ts index 55c816b..ce76a40 100644 --- a/packages/contracts/test/Advanced.test.ts +++ b/packages/contracts/test/Advanced.test.ts @@ -3,6 +3,8 @@ import { ethers } from "hardhat" import { AbiCoder, Signer, ZeroAddress, ZeroHash } from "ethers" import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers" import { + BaseERC721Checker, + BaseERC721Checker__factory, AdvancedERC721Checker, AdvancedERC721Checker__factory, AdvancedERC721CheckerHarness, @@ -26,36 +28,47 @@ describe("Advanced", () => { const notOwnerAddress: string = await notOwner.getAddress() const NFTFactory: NFT__factory = await ethers.getContractFactory("NFT") + const BaseERC721CheckerFactory: BaseERC721Checker__factory = + await ethers.getContractFactory("BaseERC721Checker") const AdvancedERC721CheckerFactory: AdvancedERC721Checker__factory = await ethers.getContractFactory("AdvancedERC721Checker") const AdvancedERC721CheckerHarnessFactory: AdvancedERC721CheckerHarness__factory = await ethers.getContractFactory("AdvancedERC721CheckerHarness") - const nft: NFT = await NFTFactory.deploy() - - const checker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect(deployer).deploy( - [await nft.getAddress()], + const signupNft: NFT = await NFTFactory.deploy() + const rewardNft: NFT = await NFTFactory.deploy() + const baseChecker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy([ + await signupNft.getAddress() + ]) + const advancedChecker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect(deployer).deploy( + [await signupNft.getAddress(), await rewardNft.getAddress(), await baseChecker.getAddress()], 1, 0, 10 ) - const checkerHarness: AdvancedERC721CheckerHarness = await AdvancedERC721CheckerHarnessFactory.connect( - deployer - ).deploy([await nft.getAddress()], 1, 0, 10) + const advancedCheckerHarness: AdvancedERC721CheckerHarness = + await AdvancedERC721CheckerHarnessFactory.connect(deployer).deploy( + [await signupNft.getAddress(), await rewardNft.getAddress(), await baseChecker.getAddress()], + 1, + 0, + 10 + ) // mint 0 for subject. - await nft.connect(deployer).mint(subjectAddress) + await signupNft.connect(deployer).mint(subjectAddress) // encoded token ids. const validNFTId = AbiCoder.defaultAbiCoder().encode(["uint256"], [0]) const invalidNFTId = AbiCoder.defaultAbiCoder().encode(["uint256"], [1]) return { - nft, - checker, + signupNft, + rewardNft, + baseChecker, + advancedChecker, + advancedCheckerHarness, deployer, - checkerHarness, target, subject, subjectAddress, @@ -67,151 +80,181 @@ describe("Advanced", () => { describe("constructor", () => { it("deploys correctly", async () => { - const { checker } = await loadFixture(deployAdvancedCheckerFixture) + const { advancedChecker } = await loadFixture(deployAdvancedCheckerFixture) - expect(checker).to.not.eq(undefined) + expect(advancedChecker).to.not.eq(undefined) }) }) describe("check", () => { describe("pre check", () => { it("reverts when evidence invalid", async () => { - const { nft, checker, target, subjectAddress, invalidNFTId } = + const { rewardNft, advancedChecker, target, subjectAddress, invalidNFTId } = await loadFixture(deployAdvancedCheckerFixture) await expect( - checker.connect(target).check(subjectAddress, [invalidNFTId], 0) - ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") + advancedChecker.connect(target).check(subjectAddress, [invalidNFTId], 0) + ).to.be.revertedWithCustomError(rewardNft, "ERC721NonexistentToken") }) it("returns false when not owner", async () => { - const { checker, target, notOwnerAddress, validNFTId } = + const { advancedChecker, target, notOwnerAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checker.connect(target).check(notOwnerAddress, [validNFTId], 0)).to.be.equal(false) + expect(await advancedChecker.connect(target).check(notOwnerAddress, [validNFTId], 0)).to.be.equal( + false + ) }) it("succeeds when valid", async () => { - const { checker, target, subjectAddress, validNFTId } = + const { advancedChecker, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checker.connect(target).check(subjectAddress, [validNFTId], 0)).to.be.equal(true) + expect(await advancedChecker.connect(target).check(subjectAddress, [validNFTId], 0)).to.be.equal( + true + ) }) }) describe("main check", () => { it("returns false when balance insufficient", async () => { - const { checker, target, notOwnerAddress, validNFTId } = + const { advancedChecker, target, notOwnerAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checker.connect(target).check(notOwnerAddress, [validNFTId], 1)).to.be.equal(false) + expect(await advancedChecker.connect(target).check(notOwnerAddress, [validNFTId], 1)).to.be.equal( + false + ) }) it("succeeds when balance sufficient", async () => { - const { checker, target, subjectAddress, validNFTId } = + const { advancedChecker, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checker.connect(target).check(subjectAddress, [validNFTId], 1)).to.be.equal(true) + expect(await advancedChecker.connect(target).check(subjectAddress, [validNFTId], 1)).to.be.equal( + true + ) }) }) describe("post check", () => { - it("reverts when evidence invalid", async () => { - const { nft, checker, target, subjectAddress, invalidNFTId } = + it("reverts when already rewarded", async () => { + const { rewardNft, advancedChecker, target, subjectAddress, invalidNFTId } = await loadFixture(deployAdvancedCheckerFixture) - await expect( - checker.connect(target).check(subjectAddress, [invalidNFTId], 2) - ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") - }) + await rewardNft.mint(subjectAddress) - it("returns false when not in range", async () => { - const { checker, target, notOwnerAddress, validNFTId } = - await loadFixture(deployAdvancedCheckerFixture) - - expect(await checker.connect(target).check(notOwnerAddress, [validNFTId], 2)).to.be.equal(false) + expect(await advancedChecker.connect(target).check(subjectAddress, [invalidNFTId], 2)).to.be.equal( + false + ) }) it("succeeds when in valid range", async () => { - const { checker, target, subjectAddress, validNFTId } = + const { advancedChecker, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) - expect(await checker.connect(target).check(subjectAddress, [validNFTId], 2)).to.be.equal(true) + expect(await advancedChecker.connect(target).check(subjectAddress, [validNFTId], 2)).to.be.equal( + true + ) }) }) }) + describe("getVerifierAtIndex", () => { + it("returns correct verifier address", async () => { + const { advancedChecker, signupNft } = await loadFixture(deployAdvancedCheckerFixture) + expect(await advancedChecker.getVerifierAtIndex(0)).to.equal(await signupNft.getAddress()) + }) + + it("reverts when index out of bounds", async () => { + const { advancedChecker } = await loadFixture(deployAdvancedCheckerFixture) + await expect(advancedChecker.getVerifierAtIndex(5)).to.be.revertedWithCustomError( + advancedChecker, + "VerifierNotFound" + ) + }) + }) + + describe("internal getVerifierAtIndex", () => { + it("returns correct verifier address", async () => { + const { advancedCheckerHarness, signupNft } = await loadFixture(deployAdvancedCheckerFixture) + expect(await advancedCheckerHarness.exposed__getVerifierAtIndex(0)).to.equal( + await signupNft.getAddress() + ) + }) + + it("reverts when index out of bounds", async () => { + const { advancedCheckerHarness } = await loadFixture(deployAdvancedCheckerFixture) + await expect(advancedCheckerHarness.exposed__getVerifierAtIndex(5)).to.be.revertedWithCustomError( + advancedCheckerHarness, + "VerifierNotFound" + ) + }) + }) + describe("internal checks", () => { describe("pre check", () => { it("reverts when evidence invalid", async () => { - const { nft, checkerHarness, target, subjectAddress, invalidNFTId } = + const { signupNft, advancedCheckerHarness, target, subjectAddress, invalidNFTId } = await loadFixture(deployAdvancedCheckerFixture) await expect( - checkerHarness.connect(target).exposed__check(subjectAddress, [invalidNFTId], 0) - ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") + advancedCheckerHarness.connect(target).exposed__check(subjectAddress, [invalidNFTId], 0) + ).to.be.revertedWithCustomError(signupNft, "ERC721NonexistentToken") }) it("returns false when not owner", async () => { - const { checkerHarness, target, notOwnerAddress, validNFTId } = + const { advancedCheckerHarness, target, notOwnerAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__check(notOwnerAddress, [validNFTId], 0) + await advancedCheckerHarness.connect(target).exposed__check(notOwnerAddress, [validNFTId], 0) ).to.be.equal(false) }) it("succeeds when valid", async () => { - const { checkerHarness, target, subjectAddress, validNFTId } = + const { advancedCheckerHarness, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__check(subjectAddress, [validNFTId], 0) + await advancedCheckerHarness.connect(target).exposed__check(subjectAddress, [validNFTId], 0) ).to.be.equal(true) }) }) describe("main check", () => { it("returns false when balance insufficient", async () => { - const { checkerHarness, target, notOwnerAddress, validNFTId } = + const { advancedCheckerHarness, target, notOwnerAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__check(notOwnerAddress, [validNFTId], 1) + await advancedCheckerHarness.connect(target).exposed__check(notOwnerAddress, [validNFTId], 1) ).to.be.equal(false) }) it("succeeds when balance sufficient", async () => { - const { checkerHarness, target, subjectAddress, validNFTId } = + const { advancedCheckerHarness, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__check(subjectAddress, [validNFTId], 1) + await advancedCheckerHarness.connect(target).exposed__check(subjectAddress, [validNFTId], 1) ).to.be.equal(true) }) }) describe("post check", () => { it("reverts when evidence invalid", async () => { - const { nft, checkerHarness, target, subjectAddress, invalidNFTId } = + const { rewardNft, advancedCheckerHarness, target, subjectAddress, invalidNFTId } = await loadFixture(deployAdvancedCheckerFixture) - await expect( - checkerHarness.connect(target).exposed__check(subjectAddress, [invalidNFTId], 2) - ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") - }) - - it("returns false when not in range", async () => { - const { checkerHarness, target, notOwnerAddress, validNFTId } = - await loadFixture(deployAdvancedCheckerFixture) + await rewardNft.mint(subjectAddress) expect( - await checkerHarness.connect(target).exposed__check(notOwnerAddress, [validNFTId], 2) + await advancedCheckerHarness.connect(target).check(subjectAddress, [invalidNFTId], 2) ).to.be.equal(false) }) it("succeeds when in valid range", async () => { - const { checkerHarness, target, subjectAddress, validNFTId } = + const { advancedCheckerHarness, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__check(subjectAddress, [validNFTId], 2) + await advancedCheckerHarness.connect(target).exposed__check(subjectAddress, [validNFTId], 2) ).to.be.equal(true) }) }) @@ -219,78 +262,71 @@ describe("Advanced", () => { describe("internal checkPre", () => { it("reverts when evidence invalid", async () => { - const { nft, checkerHarness, target, subjectAddress, invalidNFTId } = + const { signupNft, advancedCheckerHarness, target, subjectAddress, invalidNFTId } = await loadFixture(deployAdvancedCheckerFixture) await expect( - checkerHarness.connect(target).exposed__checkPre(subjectAddress, [invalidNFTId]) - ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") + advancedCheckerHarness.connect(target).exposed__checkPre(subjectAddress, [invalidNFTId]) + ).to.be.revertedWithCustomError(signupNft, "ERC721NonexistentToken") }) it("returns false when not owner", async () => { - const { checkerHarness, target, notOwnerAddress, validNFTId } = + const { advancedCheckerHarness, target, notOwnerAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__checkPre(notOwnerAddress, [validNFTId]) + await advancedCheckerHarness.connect(target).exposed__checkPre(notOwnerAddress, [validNFTId]) ).to.be.equal(false) }) it("succeeds when valid", async () => { - const { checkerHarness, target, subjectAddress, validNFTId } = + const { advancedCheckerHarness, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__checkPre(subjectAddress, [validNFTId]) + await advancedCheckerHarness.connect(target).exposed__checkPre(subjectAddress, [validNFTId]) ).to.be.equal(true) }) }) describe("internal checkMain", () => { it("returns false when balance insufficient", async () => { - const { checkerHarness, target, notOwnerAddress, validNFTId } = + const { advancedCheckerHarness, target, notOwnerAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__checkMain(notOwnerAddress, [validNFTId]) + await advancedCheckerHarness.connect(target).exposed__checkMain(notOwnerAddress, [validNFTId]) ).to.be.equal(false) }) it("succeeds when balance sufficient", async () => { - const { checkerHarness, target, subjectAddress, validNFTId } = + const { advancedCheckerHarness, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__checkMain(subjectAddress, [validNFTId]) + await advancedCheckerHarness.connect(target).exposed__checkMain(subjectAddress, [validNFTId]) ).to.be.equal(true) }) }) describe("internal checkPost", () => { it("reverts when evidence invalid", async () => { - const { nft, checkerHarness, target, subjectAddress, invalidNFTId } = + const { rewardNft, advancedCheckerHarness, target, subjectAddress, invalidNFTId } = await loadFixture(deployAdvancedCheckerFixture) - await expect( - checkerHarness.connect(target).exposed__checkPost(subjectAddress, [invalidNFTId]) - ).to.be.revertedWithCustomError(nft, "ERC721NonexistentToken") - }) - - it("returns false when not in range", async () => { - const { checkerHarness, target, notOwnerAddress, validNFTId } = - await loadFixture(deployAdvancedCheckerFixture) + await rewardNft.mint(subjectAddress) expect( - await checkerHarness.connect(target).exposed__checkPost(notOwnerAddress, [validNFTId]) + await advancedCheckerHarness.connect(target).exposed__checkPost(subjectAddress, [invalidNFTId]) ).to.be.equal(false) }) it("succeeds when in valid range", async () => { - const { checkerHarness, target, subjectAddress, validNFTId } = + const { advancedCheckerHarness, target, subjectAddress, validNFTId } = await loadFixture(deployAdvancedCheckerFixture) expect( - await checkerHarness.connect(target).exposed__checkPost(subjectAddress, [validNFTId]) + await advancedCheckerHarness.connect(target).exposed__checkPost(subjectAddress, [validNFTId]) ).to.be.equal(true) }) }) @@ -303,6 +339,8 @@ describe("Advanced", () => { const notOwnerAddress: string = await notOwner.getAddress() const NFTFactory: NFT__factory = await ethers.getContractFactory("NFT") + const BaseERC721CheckerFactory: BaseERC721Checker__factory = + await ethers.getContractFactory("BaseERC721Checker") const AdvancedERC721CheckerFactory: AdvancedERC721Checker__factory = await ethers.getContractFactory("AdvancedERC721Checker") const AdvancedERC721PolicyFactory: AdvancedERC721Policy__factory = @@ -310,51 +348,68 @@ describe("Advanced", () => { const AdvancedERC721PolicyHarnessFactory: AdvancedERC721PolicyHarness__factory = await ethers.getContractFactory("AdvancedERC721PolicyHarness") - const nft: NFT = await NFTFactory.deploy() - const iERC721Errors: IERC721Errors = await ethers.getContractAt("IERC721Errors", await nft.getAddress()) - - const checker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect(deployer).deploy( - [await nft.getAddress()], + const signupNft: NFT = await NFTFactory.deploy() + const rewardNft: NFT = await NFTFactory.deploy() + const signupIERC721Errors: IERC721Errors = await ethers.getContractAt( + "IERC721Errors", + await signupNft.getAddress() + ) + const rewardIERC721Errors: IERC721Errors = await ethers.getContractAt( + "IERC721Errors", + await rewardNft.getAddress() + ) + const baseChecker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy([ + await signupNft.getAddress() + ]) + const advancedChecker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect(deployer).deploy( + [await signupNft.getAddress(), await rewardNft.getAddress(), await baseChecker.getAddress()], 1, 0, 10 ) - const checkerSkippedPrePostNoMultMain: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect( - deployer - ).deploy([await nft.getAddress()], 1, 0, 10) + const advancedCheckerSkippedPrePostNoMultMain: AdvancedERC721Checker = + await AdvancedERC721CheckerFactory.connect(deployer).deploy( + [await signupNft.getAddress(), await rewardNft.getAddress(), await baseChecker.getAddress()], + 1, + 0, + 10 + ) const policy: AdvancedERC721Policy = await AdvancedERC721PolicyFactory.connect(deployer).deploy( - await checker.getAddress(), + await advancedChecker.getAddress(), false, false, true ) const policySkipped: AdvancedERC721Policy = await AdvancedERC721PolicyFactory.connect(deployer).deploy( - await checkerSkippedPrePostNoMultMain.getAddress(), + await advancedCheckerSkippedPrePostNoMultMain.getAddress(), true, true, false ) const policyHarness: AdvancedERC721PolicyHarness = await AdvancedERC721PolicyHarnessFactory.connect( deployer - ).deploy(await checker.getAddress(), false, false, true) + ).deploy(await advancedChecker.getAddress(), false, false, true) const policyHarnessSkipped: AdvancedERC721PolicyHarness = await AdvancedERC721PolicyHarnessFactory.connect( deployer - ).deploy(await checkerSkippedPrePostNoMultMain.getAddress(), true, true, false) + ).deploy(await advancedCheckerSkippedPrePostNoMultMain.getAddress(), true, true, false) // mint 0 for subject. - await nft.connect(deployer).mint(subjectAddress) + await signupNft.connect(deployer).mint(subjectAddress) // encoded token ids. const validEncodedNFTId = AbiCoder.defaultAbiCoder().encode(["uint256"], [0]) const invalidEncodedNFTId = AbiCoder.defaultAbiCoder().encode(["uint256"], [1]) return { - iERC721Errors, + signupIERC721Errors, + rewardIERC721Errors, AdvancedERC721PolicyFactory, - nft, - checker, + signupNft, + rewardNft, + advancedChecker, + advancedCheckerSkippedPrePostNoMultMain, policyHarness, policyHarnessSkipped, policy, @@ -446,14 +501,14 @@ describe("Advanced", () => { }) it("reverts when evidence invalid", async () => { - const { iERC721Errors, policy, target, subjectAddress, invalidEncodedNFTId } = + const { rewardIERC721Errors, policy, target, subjectAddress, invalidEncodedNFTId } = await loadFixture(deployAdvancedPolicyFixture) await policy.setTarget(await target.getAddress()) await expect( policy.connect(target).enforce(subjectAddress, [invalidEncodedNFTId], 0) - ).to.be.revertedWithCustomError(iERC721Errors, "ERC721NonexistentToken") + ).to.be.revertedWithCustomError(rewardIERC721Errors, "ERC721NonexistentToken") }) it("reverts when pre-check skipped", async () => { @@ -647,17 +702,19 @@ describe("Advanced", () => { ).to.be.revertedWithCustomError(policy, "TargetOnly") }) - it("reverts when evidence invalid", async () => { - const { iERC721Errors, policy, target, subjectAddress, validEncodedNFTId, invalidEncodedNFTId } = + it("reverts when already rewarded", async () => { + const { rewardNft, policy, target, subjectAddress, validEncodedNFTId, invalidEncodedNFTId } = await loadFixture(deployAdvancedPolicyFixture) await policy.setTarget(await target.getAddress()) await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 0) await policy.connect(target).enforce(subjectAddress, [validEncodedNFTId], 1) + await rewardNft.mint(subjectAddress) + await expect( policy.connect(target).enforce(subjectAddress, [invalidEncodedNFTId], 2) - ).to.be.revertedWithCustomError(iERC721Errors, "ERC721NonexistentToken") + ).to.be.revertedWithCustomError(policy, "UnsuccessfulCheck") }) it("reverts when post-check skipped", async () => { @@ -745,14 +802,14 @@ describe("Advanced", () => { }) it("reverts when evidence invalid", async () => { - const { iERC721Errors, policyHarness, target, subjectAddress, invalidEncodedNFTId } = + const { rewardIERC721Errors, policyHarness, target, subjectAddress, invalidEncodedNFTId } = await loadFixture(deployAdvancedPolicyFixture) await policyHarness.setTarget(await target.getAddress()) await expect( policyHarness.connect(target).exposed__enforce(subjectAddress, [invalidEncodedNFTId], 0) - ).to.be.revertedWithCustomError(iERC721Errors, "ERC721NonexistentToken") + ).to.be.revertedWithCustomError(rewardIERC721Errors, "ERC721NonexistentToken") }) it("reverts when pre-check skipped", async () => { @@ -950,22 +1007,18 @@ describe("Advanced", () => { }) it("reverts when evidence invalid", async () => { - const { - iERC721Errors, - policyHarness, - target, - subjectAddress, - validEncodedNFTId, - invalidEncodedNFTId - } = await loadFixture(deployAdvancedPolicyFixture) + const { rewardNft, policyHarness, target, subjectAddress, validEncodedNFTId, invalidEncodedNFTId } = + await loadFixture(deployAdvancedPolicyFixture) await policyHarness.setTarget(await target.getAddress()) await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 0) await policyHarness.connect(target).exposed__enforce(subjectAddress, [validEncodedNFTId], 1) + await rewardNft.mint(subjectAddress) + await expect( - policyHarness.connect(target).exposed__enforce(subjectAddress, [invalidEncodedNFTId], 2) - ).to.be.revertedWithCustomError(iERC721Errors, "ERC721NonexistentToken") + policyHarness.connect(target).enforce(subjectAddress, [invalidEncodedNFTId], 2) + ).to.be.revertedWithCustomError(policyHarness, "UnsuccessfulCheck") }) it("reverts when post-check skipped", async () => { @@ -1047,24 +1100,36 @@ describe("Advanced", () => { const notOwnerAddress: string = await notOwner.getAddress() const NFTFactory: NFT__factory = await ethers.getContractFactory("NFT") + const BaseERC721CheckerFactory: BaseERC721Checker__factory = + await ethers.getContractFactory("BaseERC721Checker") const AdvancedERC721CheckerFactory: AdvancedERC721Checker__factory = await ethers.getContractFactory("AdvancedERC721Checker") const AdvancedERC721PolicyFactory: AdvancedERC721Policy__factory = await ethers.getContractFactory("AdvancedERC721Policy") const AdvancedVotingFactory: AdvancedVoting__factory = await ethers.getContractFactory("AdvancedVoting") - const nft: NFT = await NFTFactory.deploy() - const iERC721Errors: IERC721Errors = await ethers.getContractAt("IERC721Errors", await nft.getAddress()) - - const checker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect(deployer).deploy( - [await nft.getAddress()], + const signupNft: NFT = await NFTFactory.deploy() + const rewardNft: NFT = await NFTFactory.deploy() + const signupIERC721Errors: IERC721Errors = await ethers.getContractAt( + "IERC721Errors", + await signupNft.getAddress() + ) + const rewardIERC721Errors: IERC721Errors = await ethers.getContractAt( + "IERC721Errors", + await rewardNft.getAddress() + ) + const baseChecker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy([ + await signupNft.getAddress() + ]) + const advancedChecker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect(deployer).deploy( + [await signupNft.getAddress(), await rewardNft.getAddress(), await baseChecker.getAddress()], 1, 0, 10 ) const policy: AdvancedERC721Policy = await AdvancedERC721PolicyFactory.connect(deployer).deploy( - await checker.getAddress(), + await advancedChecker.getAddress(), false, false, true @@ -1075,7 +1140,7 @@ describe("Advanced", () => { ) // mint 0 for subject. - await nft.connect(deployer).mint(subjectAddress) + await signupNft.connect(deployer).mint(subjectAddress) // encoded token ids. const validNFTId = 0 @@ -1084,9 +1149,13 @@ describe("Advanced", () => { const invalidEncodedNFTId = AbiCoder.defaultAbiCoder().encode(["uint256"], [invalidNFTId]) return { - iERC721Errors, + signupIERC721Errors, + rewardIERC721Errors, AdvancedVotingFactory, - nft, + AdvancedERC721PolicyFactory, + signupNft, + rewardNft, + advancedChecker, voting, policy, subject, @@ -1122,13 +1191,13 @@ describe("Advanced", () => { }) it("reverts when evidence invalid", async () => { - const { iERC721Errors, voting, policy, subject, invalidNFTId } = + const { signupIERC721Errors, voting, policy, subject, invalidNFTId } = await loadFixture(deployAdvancedVotingFixture) await policy.setTarget(await voting.getAddress()) await expect(voting.connect(subject).register(invalidNFTId)).to.be.revertedWithCustomError( - iERC721Errors, + signupIERC721Errors, "ERC721NonexistentToken" ) }) @@ -1262,7 +1331,7 @@ describe("Advanced", () => { }) }) - describe("reward", () => { + describe("eligibility", () => { it("reverts when caller not target", async () => { const { voting, policy, subject, notOwner, validNFTId } = await loadFixture(deployAdvancedVotingFixture) @@ -1274,46 +1343,47 @@ describe("Advanced", () => { ) }) - it("reverts when evidence invalid", async () => { - const { iERC721Errors, voting, policy, subject, validNFTId, invalidNFTId } = + it("reverts when already owns reward token", async () => { + const { rewardNft, voting, policy, subject, validNFTId } = await loadFixture(deployAdvancedVotingFixture) await policy.setTarget(await voting.getAddress()) await voting.connect(subject).register(validNFTId) await voting.connect(subject).vote(0) - await expect(voting.connect(subject).reward(invalidNFTId)).to.be.revertedWithCustomError( - iERC721Errors, - "ERC721NonexistentToken" + await rewardNft.mint(subject) + + await expect(voting.connect(subject).eligible()).to.be.revertedWithCustomError( + policy, + "UnsuccessfulCheck" ) }) it("reverts when check fails", async () => { - const { nft, deployer, voting, policy, notOwner, subject, validNFTId } = + const { signupNft, rewardNft, deployer, voting, policy, notOwner, subject, validNFTId } = await loadFixture(deployAdvancedVotingFixture) await policy.setTarget(await voting.getAddress()) - await nft.connect(deployer).mint(notOwner) + await signupNft.connect(deployer).mint(notOwner) await voting.connect(subject).register(validNFTId) await voting.connect(subject).vote(0) await voting.connect(notOwner).register(1) await voting.connect(notOwner).vote(0) - await expect(voting.connect(subject).reward(1)).to.be.revertedWithCustomError( + await rewardNft.connect(deployer).mint(subject) + + await expect(voting.connect(subject).eligible()).to.be.revertedWithCustomError( policy, "UnsuccessfulCheck" ) }) it("reverts when not registered", async () => { - const { voting, policy, notOwner, validNFTId } = await loadFixture(deployAdvancedVotingFixture) + const { voting, policy, notOwner } = await loadFixture(deployAdvancedVotingFixture) await policy.setTarget(await notOwner.getAddress()) - await expect(voting.connect(notOwner).reward(validNFTId)).to.be.revertedWithCustomError( - voting, - "NotRegistered" - ) + await expect(voting.connect(notOwner).eligible()).to.be.revertedWithCustomError(voting, "NotRegistered") }) it("reverts when not voted", async () => { @@ -1322,13 +1392,10 @@ describe("Advanced", () => { await policy.setTarget(await voting.getAddress()) await voting.connect(subject).register(validNFTId) - await expect(voting.connect(subject).reward(validNFTId)).to.be.revertedWithCustomError( - voting, - "NotVoted" - ) + await expect(voting.connect(subject).eligible()).to.be.revertedWithCustomError(voting, "NotVoted") }) - it("claims reward successfully", async () => { + it("verifies eligibility successfully", async () => { const { AdvancedVotingFactory, voting, policy, subject, subjectAddress, validNFTId } = await loadFixture(deployAdvancedVotingFixture) const targetAddress = await voting.getAddress() @@ -1337,7 +1404,7 @@ describe("Advanced", () => { await voting.connect(subject).register(validNFTId) await voting.connect(subject).vote(0) - const tx = await voting.connect(subject).reward(validNFTId) + const tx = await voting.connect(subject).eligible() const receipt = await tx.wait() const event = AdvancedVotingFactory.interface.parseLog( receipt?.logs[1] as unknown as { topics: string[]; data: string } @@ -1356,17 +1423,17 @@ describe("Advanced", () => { expect(await voting.voteCounts(1)).to.be.equal(0) }) - it("reverts when already claimed", async () => { + it("reverts when already eligible", async () => { const { voting, policy, subject, validNFTId } = await loadFixture(deployAdvancedVotingFixture) await policy.setTarget(await voting.getAddress()) await voting.connect(subject).register(validNFTId) await voting.connect(subject).vote(0) - await voting.connect(subject).reward(validNFTId) + await voting.connect(subject).eligible() - await expect(voting.connect(subject).reward(validNFTId)).to.be.revertedWithCustomError( + await expect(voting.connect(subject).eligible()).to.be.revertedWithCustomError( voting, - "AlreadyClaimed" + "AlreadyEligible" ) }) }) @@ -1375,23 +1442,30 @@ describe("Advanced", () => { const [deployer]: Signer[] = await ethers.getSigners() const NFTFactory: NFT__factory = await ethers.getContractFactory("NFT") + const BaseERC721CheckerFactory: BaseERC721Checker__factory = + await ethers.getContractFactory("BaseERC721Checker") const AdvancedERC721CheckerFactory: AdvancedERC721Checker__factory = await ethers.getContractFactory("AdvancedERC721Checker") const AdvancedERC721PolicyFactory: AdvancedERC721Policy__factory = await ethers.getContractFactory("AdvancedERC721Policy") const AdvancedVotingFactory: AdvancedVoting__factory = await ethers.getContractFactory("AdvancedVoting") - const nft: NFT = await NFTFactory.deploy() - - const checker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect(deployer).deploy( - [await nft.getAddress()], + const signupNft: NFT = await NFTFactory.deploy() + const rewardNft: NFT = await NFTFactory.deploy() + const baseChecker: BaseERC721Checker = await BaseERC721CheckerFactory.connect(deployer).deploy([ + await signupNft.getAddress() + ]) + const advancedChecker: AdvancedERC721Checker = await AdvancedERC721CheckerFactory.connect( + deployer + ).deploy( + [await signupNft.getAddress(), await rewardNft.getAddress(), await baseChecker.getAddress()], 1, 0, - 20 + 10 ) const policy: AdvancedERC721Policy = await AdvancedERC721PolicyFactory.connect(deployer).deploy( - await checker.getAddress(), + await advancedChecker.getAddress(), false, false, true @@ -1409,7 +1483,7 @@ describe("Advanced", () => { const voterAddress = await voter.getAddress() // mint for voter. - await nft.connect(deployer).mint(voterAddress) + await signupNft.connect(deployer).mint(voterAddress) // register. await voting.connect(voter).register(tokenId) @@ -1418,7 +1492,7 @@ describe("Advanced", () => { await voting.connect(voter).vote(tokenId % 2) // reward. - await voting.connect(voter).reward(tokenId) + await voting.connect(voter).eligible() expect((await policy.enforced(targetAddress, voterAddress))[0]).to.be.equal(true) expect((await policy.enforced(targetAddress, voterAddress))[1]).to.be.equal(1) diff --git a/packages/contracts/test/Base.test.ts b/packages/contracts/test/Base.test.ts index 53143e7..21f6fdc 100644 --- a/packages/contracts/test/Base.test.ts +++ b/packages/contracts/test/Base.test.ts @@ -66,6 +66,33 @@ describe("Base", () => { }) }) + describe("getVerifierAtIndex", () => { + it("returns correct verifier address", async () => { + const { checker, nft } = await loadFixture(deployBaseCheckerFixture) + expect(await checker.getVerifierAtIndex(0)).to.equal(await nft.getAddress()) + }) + + it("reverts when index out of bounds", async () => { + const { checker } = await loadFixture(deployBaseCheckerFixture) + await expect(checker.getVerifierAtIndex(1)).to.be.revertedWithCustomError(checker, "VerifierNotFound") + }) + }) + + describe("internal getVerifierAtIndex", () => { + it("returns correct verifier address", async () => { + const { checkerHarness, nft } = await loadFixture(deployBaseCheckerFixture) + expect(await checkerHarness.exposed__getVerifierAtIndex(0)).to.equal(await nft.getAddress()) + }) + + it("reverts when index out of bounds", async () => { + const { checkerHarness } = await loadFixture(deployBaseCheckerFixture) + await expect(checkerHarness.exposed__getVerifierAtIndex(1)).to.be.revertedWithCustomError( + checkerHarness, + "VerifierNotFound" + ) + }) + }) + describe("check", () => { it("reverts when evidence is invalid", async () => { const { nft, checker, target, subjectAddress, invalidNFTId } =