Skip to content

Commit

Permalink
Merge pull request #5 from blockful-io/feat#10multiAttest
Browse files Browse the repository at this point in the history
Feat#10multi attest
  • Loading branch information
LeonardoVieira1630 authored Nov 7, 2024
2 parents 9c52e94 + 1dd414f commit 37bc13e
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 25 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"lint:sol": "forge fmt --check && bun solhint {script,src,test}/**/*.sol",
"prettier:check": "prettier --check \"**/*.{json,md,yml}\" --ignore-path \".prettierignore\"",
"prettier:write": "prettier --write \"**/*.{json,md,yml}\" --ignore-path \".prettierignore\"",
"test": "forge test --fork-url $RPC_OP -vvv --via-ir",
"test": "forge test --fork-url $RPC_OP -vvvv --via-ir",
"test:registry": "forge test --match-test registry --fork-url $RPC_OP -vvv --via-ir",
"test:resolver": "forge test --match-test access_control --fork-url $RPC_OP -vvv --via-ir",
"test:attest": "forge test --match-test attestations --fork-url $RPC_OP -vvv --via-ir",
Expand Down
6 changes: 6 additions & 0 deletions src/interfaces/IResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ interface IResolver {
/// @param action The action that the role can perform on the schema.
function setSchema(bytes32 uid, uint256 action) external;

function multiAttest(
Attestation[] calldata attestations,
uint256[] calldata values
) external payable returns (bool);

/// @notice Creates a new session with a specified duration and title.
/// @param duration The duration of the session in seconds.
/// @param sessionTitle The title of the session.
Expand All @@ -92,4 +97,5 @@ interface IResolver {
/// @notice Closes an existing session.
/// @param sessionId The id of the session to be closed.
function closeSession(bytes32 sessionId) external;

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


error AlreadyHasResponse();
error InsufficientValue();
error InvalidAttestationTitle();
Expand Down Expand Up @@ -135,29 +136,7 @@ contract Resolver is IResolver, AccessControl {

/// @inheritdoc IResolver
function attest(Attestation calldata attestation) external payable onlyEAS returns (bool) {
// Prohibits the attestation expiration to be finite
if (attestation.expirationTime != NO_EXPIRATION_TIME) revert InvalidExpiration();

// Schema to assign managers
if (isActionAllowed(attestation.schema, Action.ASSIGN_MANAGER))
return assignManager(attestation);

// Schema to checkIn / checkOut villagers
if (isActionAllowed(attestation.schema, Action.ASSIGN_VILLAGER)) {
return assignVillager(attestation);
}

// Schema to create event attestations (Attestations)
if (isActionAllowed(attestation.schema, Action.ATTEST)) {
return attestEvent(attestation);
}

// Schema to create a response ( true / false )
if (isActionAllowed(attestation.schema, Action.REPLY)) {
return attestResponse(attestation);
}

return false;
return onAttest(attestation);
}

/// @inheritdoc IResolver
Expand Down Expand Up @@ -323,6 +302,46 @@ contract Resolver is IResolver, AccessControl {
_allowedSchemas[uid] = Action(action);
}

/// @inheritdoc IResolver
function multiAttest(
Attestation[] calldata attestations,
uint256[] calldata values
) external payable onlyEAS returns (bool) {
for (uint256 i = 0; i < attestations.length; i = uncheckedInc(i)) {
if (!onAttest(attestations[i])) {
revert("Attestation failed");
}
}
return true;
}

/// @dev Internal function to handle attestation logic
function onAttest(Attestation calldata attestation) internal returns (bool) {
// Prohibits the attestation expiration to be finite
if (attestation.expirationTime != NO_EXPIRATION_TIME) revert InvalidExpiration();

// Schema to assign managers
if (isActionAllowed(attestation.schema, Action.ASSIGN_MANAGER))
return assignManager(attestation);

// Schema to checkIn / checkOut villagers
if (isActionAllowed(attestation.schema, Action.ASSIGN_VILLAGER)) {
return assignVillager(attestation);
}

// Schema to create event attestations (Attestations)
if (isActionAllowed(attestation.schema, Action.ATTEST)) {
return attestEvent(attestation);
}

// Schema to create a response ( true / false )
if (isActionAllowed(attestation.schema, Action.REPLY)) {
return attestResponse(attestation);
}

return false;
}

/// @dev creates a new session
function createSession(
uint256 duration,
Expand Down Expand Up @@ -402,4 +421,5 @@ contract Resolver is IResolver, AccessControl {
revert NotPayable();
}
}

}
131 changes: 130 additions & 1 deletion test/EAS.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Test, console2 } from "forge-std/src/Test.sol";
import { Resolver } from "../src/resolver/Resolver.sol";
import { IResolver } from "../src/interfaces/IResolver.sol";
import { ISchemaRegistry } from "../src/interfaces/ISchemaRegistry.sol";
import { IEAS, AttestationRequest, AttestationRequestData, RevocationRequest, RevocationRequestData } from "../src/interfaces/IEAS.sol";
import { IEAS, AttestationRequest, AttestationRequestData, RevocationRequest, RevocationRequestData, Attestation, MultiAttestationRequest } from "../src/interfaces/IEAS.sol";
import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";

contract ResolverTest is Test {
Expand Down Expand Up @@ -393,4 +393,133 @@ contract ResolverTest is Test {
return false;
}
}

function test_multi_attest_villager() public {
bytes32[] memory uids = register_allowed_schemas();

// Assign manager role to be able to check in villagers
vm.startPrank(deployer);
attest_manager(uids[0], manager, "Manager");

address villager1 = address(0x1111);
address villager2 = address(0x2222);

vm.deal(manager, 1 ether);
vm.startPrank(manager);

// Create an array of MultiAttestationRequest
MultiAttestationRequest[] memory requests = new MultiAttestationRequest[](1);

// Create an array of AttestationRequestData for your two attestations
AttestationRequestData[] memory attestationData = new AttestationRequestData[](2);

attestationData[0] = AttestationRequestData({
recipient: villager1,
expirationTime: 0,
revocable: false,
refUID: bytes32(0),
data: abi.encode("Check-in"),
value: 0
});

attestationData[1] = AttestationRequestData({
recipient: villager2,
expirationTime: 0,
revocable: false,
refUID: bytes32(0),
data: abi.encode("Check-in"),
value: 0
});

// Create the MultiAttestationRequest
requests[0] = MultiAttestationRequest({ schema: uids[1], data: attestationData });

// Call multiAttest
uint256 amountInWei = 0.1 ether;
bytes32[] memory attestationUIDs = eas.multiAttest{ value: amountInWei }(requests);

// Verify that both villagers have been assigned the VILLAGER_ROLE
assert(IAccessControl(address(resolver)).hasRole(VILLAGER_ROLE, villager1));
assert(IAccessControl(address(resolver)).hasRole(VILLAGER_ROLE, villager2));
}

function test_multi_attest_unauthorized() public {
bytes32[] memory uids = register_allowed_schemas();

// Assign manager role to be able to check in villagers
vm.startPrank(deployer);
attest_manager(uids[0], manager, "Manager");

address villager1 = address(0x1111);
address villager2 = address(0x2222);

vm.deal(manager, 1 ether);
vm.startPrank(manager);

// Create an array of MultiAttestationRequest
MultiAttestationRequest[] memory requests = new MultiAttestationRequest[](1);

// Create an array of AttestationRequestData for your two attestations
AttestationRequestData[] memory attestationData = new AttestationRequestData[](2);

attestationData[0] = AttestationRequestData({
recipient: villager1,
expirationTime: 0,
revocable: false,
refUID: bytes32(0),
data: abi.encode("Check-in"),
value: 0
});

attestationData[1] = AttestationRequestData({
recipient: villager2,
expirationTime: 0,
revocable: false,
refUID: bytes32(0),
data: abi.encode("Changed My Mind"),
value: 0
});

// Create the MultiAttestationRequest
vm.expectRevert();
eas.multiAttest{ value: 0.1 ether }(requests);
}

function test_multi_attest_without_manager_role() public {
bytes32[] memory uids = register_allowed_schemas();

address villager1 = address(0x1111);
address villager2 = address(0x2222);

vm.deal(manager, 1 ether);
vm.startPrank(manager);

// Create an array of MultiAttestationRequest
MultiAttestationRequest[] memory requests = new MultiAttestationRequest[](1);

// Create an array of AttestationRequestData for your two attestations
AttestationRequestData[] memory attestationData = new AttestationRequestData[](2);

attestationData[0] = AttestationRequestData({
recipient: villager1,
expirationTime: 0,
revocable: false,
refUID: bytes32(0),
data: abi.encode("Check-in"),
value: 0
});

attestationData[1] = AttestationRequestData({
recipient: villager2,
expirationTime: 0,
revocable: false,
refUID: bytes32(0),
data: abi.encode("Check-in"),
value: 0
});

// Create the MultiAttestationRequest
vm.expectRevert();
eas.multiAttest{ value: 0.1 ether }(requests);
}
}

0 comments on commit 37bc13e

Please sign in to comment.