Skip to content

Commit

Permalink
feat: users can be checked in once more
Browse files Browse the repository at this point in the history
  • Loading branch information
0xneves committed Jul 17, 2024
1 parent b08128c commit e4d8ccd
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 23 deletions.
3 changes: 0 additions & 3 deletions src/interfaces/IResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ interface IResolver {
/// @return Whether the resolver supports ETH transfers.
function isPayable() external pure returns (bool);

/// @dev Checks if a villager is checkedOut.
function checkedOutVillagers(address villager) external view returns (bool);

/// @dev Checks if a title is allowed to be attested.
function allowedAttestationTitles(string memory title) external view returns (bool);

Expand Down
17 changes: 3 additions & 14 deletions src/resolver/Resolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { IResolver } from "../interfaces/IResolver.sol";
import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";
import { AccessDenied, InvalidEAS, InvalidLength, uncheckedInc, EMPTY_UID, NO_EXPIRATION_TIME } from "../Common.sol";

error AlreadyCheckedOut();
error AlreadyHasResponse();
error InsufficientValue();
error InvalidAttestationTitle();
Expand All @@ -30,9 +29,6 @@ contract Resolver is IResolver, AccessControl {
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
bytes32 public constant VILLAGER_ROLE = keccak256("VILLAGER_ROLE");

// Maps addresses to booleans to check if a Villager has checked out
mapping(address => bool) private _checkedOutVillagers;

// Maps addresses to booleans to check if a Manager has been revoked
mapping(address => bool) private _receivedManagerBadge;

Expand Down Expand Up @@ -76,11 +72,6 @@ contract Resolver is IResolver, AccessControl {
return false;
}

/// @inheritdoc IResolver
function checkedOutVillagers(address villager) public view returns (bool) {
return _checkedOutVillagers[villager];
}

/// @inheritdoc IResolver
function allowedAttestationTitles(string memory title) public view returns (bool) {
return _allowedAttestationTitles[keccak256(abi.encode(title))];
Expand Down Expand Up @@ -173,21 +164,19 @@ contract Resolver is IResolver, AccessControl {

string memory status = abi.decode(attestation.data, (string));

// Check if recipient doesn't have Villager Role and it's not checked out (haven't been checked in yet)
// Check if recipient doesn't have Villager Role (check-in)
if (
!hasRole(VILLAGER_ROLE, attestation.recipient) &&
!_checkedOutVillagers[attestation.recipient] &&
keccak256(abi.encode(status)) == keccak256(abi.encode("Check-in"))
) {
_checkRole(MANAGER_ROLE, attestation.attester);
_grantRole(VILLAGER_ROLE, attestation.recipient);
return true;
}

// Check if recipient has Villager Role and it's not checked out (is checked in)
// Check if recipient has Villager Role (check-out)
if (
hasRole(VILLAGER_ROLE, attestation.recipient) &&
!_checkedOutVillagers[attestation.recipient] &&
keccak256(abi.encode(status)) == keccak256(abi.encode("Check-out")) &&
(attestation.recipient == attestation.attester || hasRole(MANAGER_ROLE, attestation.attester))
) {
Expand All @@ -199,7 +188,6 @@ contract Resolver is IResolver, AccessControl {
if (attesterRef.recipient != attestation.recipient) revert InvalidRefUID();

_revokeRole(VILLAGER_ROLE, attestation.recipient);
_checkedOutVillagers[attestation.recipient] = true;
return true;
}

Expand All @@ -210,6 +198,7 @@ contract Resolver is IResolver, AccessControl {
function attestEvent(Attestation calldata attestation) internal view returns (bool) {
if (attestation.revocable) revert InvalidRevocability();
_checkRole(VILLAGER_ROLE, attestation.attester);
_checkRole(VILLAGER_ROLE, attestation.recipient);

// Titles for attestations must be included in this contract by the managers
// via the {setAttestationTitle} function
Expand Down
48 changes: 42 additions & 6 deletions test/EAS.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,31 @@ contract ResolverTest is Test {
vm.startPrank(villager);
attest_villager_checkout(uids[1], villager, "Check-out", attestVillagerUID);
assert(!IAccessControl(address(resolver)).hasRole(VILLAGER_ROLE, villager));
assert(resolver.checkedOutVillagers(villager));
// Should fail to check-out again
assert(!try_attest_villager_checkout(uids[1], villager, "Check-out", attestVillagerUID));
// Should fail to check-in again
assert(!try_attest_villager(uids[1], villager, "Check-in"));

// Check-Out Villager as Manager
vm.startPrank(manager);
bytes32 attestVillager2UID = attest_villager_checkin(uids[1], villager2, "Check-in");
attest_villager_checkout(uids[1], villager2, "Check-out", attestVillager2UID);
assert(!IAccessControl(address(resolver)).hasRole(VILLAGER_ROLE, villager2));
assert(resolver.checkedOutVillagers(villager2));
// Should fail to check-out again
assert(!try_attest_villager_checkout(uids[1], villager2, "Check-out", attestVillager2UID));
// Should fail to check-in again
assert(!try_attest_villager(uids[1], villager2, "Check-in"));

// Villager cannot receive event badges after checkout
vm.startPrank(manager);
assert(!try_attest_event(uids[2], villager2, titles[1], "This address is a good person"));

// Villager can be checked-in again
vm.startPrank(manager);
bytes32 attestVillagerUIDSecondTime = attest_villager_checkin(uids[1], villager, "Check-in");
// Should have the VILLAGER_ROLE
assert(IAccessControl(address(resolver)).hasRole(VILLAGER_ROLE, villager));
// Should be able to attest events again
vm.startPrank(villager);
attest_event(uids[2], manager, titles[2], "This address has a brilliant mind");
// Should be able to check-out once more
attest_villager_checkout(uids[1], villager, "Check-out", attestVillagerUIDSecondTime);

// Revoke Manager
vm.startPrank(deployer);
Expand Down Expand Up @@ -295,6 +304,33 @@ contract ResolverTest is Test {
}
}

function try_attest_event(
bytes32 schemaUID,
address recipient,
string memory title,
string memory comment
) public returns (bool) {
try
eas.attest(
AttestationRequest({
schema: schemaUID,
data: AttestationRequestData({
recipient: recipient,
expirationTime: 0,
revocable: false,
refUID: 0,
data: abi.encode(title, comment),
value: 0
})
})
)
{
return true;
} catch {
return false;
}
}

function try_attest_response(
bytes32 schemaUID,
address recipient,
Expand Down

0 comments on commit e4d8ccd

Please sign in to comment.