diff --git a/contracts/src/examples/modules/SchemaCheckerModule.sol b/contracts/src/examples/modules/SchemaCheckerModule.sol new file mode 100644 index 00000000..2e1a308a --- /dev/null +++ b/contracts/src/examples/modules/SchemaCheckerModule.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +import { AbstractModule } from "../../interface/AbstractModule.sol"; +import { AttestationPayload } from "../../types/Structs.sol"; + +/** + * @title Schema checker Module + * @notice This contract illustrates a valid Module that is used to check the schema that an attestation is based on + */ +contract SchemaCheckerModule is AbstractModule { + error InvalidSchemaId(); + /* + * @notice This is an example of how to check the attestation payload encoding/decoding, based on a "Profile Schema" + */ + struct Profile { + address issuer; + bytes32 schemaId; + uint64 issueDate; + } + + /** + * @inheritdoc AbstractModule + * @notice This method is used to run the module's validation logic + * @param attestationPayload - AttestationPayload containing the user address as `subject` and nonce as `attestationData` + */ + function run( + AttestationPayload memory attestationPayload, + bytes memory /*validationPayload*/, + address /*txSender*/, + uint256 /*value*/ + ) public view override { + if (keccak256(abi.encodePacked(attestationPayload.schemaId)) != keccak256(abi.encode(bytes32("12345678")))) { + revert InvalidSchemaId(); + } + abi.decode(attestationPayload.attestationData, (address, bytes32, uint64)); + } +} diff --git a/contracts/test/example/SchemaCheckerModule.t.sol b/contracts/test/example/SchemaCheckerModule.t.sol new file mode 100644 index 00000000..dbfd1887 --- /dev/null +++ b/contracts/test/example/SchemaCheckerModule.t.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +import { Test } from "forge-std/Test.sol"; +import { AbstractModule } from "../../src/interface/AbstractModule.sol"; +import { SchemaCheckerModule } from "../../src/examples/modules/SchemaCheckerModule.sol"; +import { AttestationPayload } from "../../src/types/Structs.sol"; + +contract SchemaCheckerModuleTest is Test { + SchemaCheckerModule private schemaCheckerModule; + address internal issuer; + + event ModuleRegistered(string name, string description, address moduleAddress); + + function setUp() public { + issuer = makeAddr("issuer"); + schemaCheckerModule = new SchemaCheckerModule(); + vm.deal(issuer, 1 ether); + } + + function test_SchemaCheckerModule_matchSchemaId() public { + address user = makeAddr("user"); + uint64 issueDate = 0; + AttestationPayload memory attestationPayload = AttestationPayload( + bytes32("12345678"), + 0, + abi.encode(user), + abi.encode(issuer, "112334", issueDate) + ); + + schemaCheckerModule.run(attestationPayload, bytes("0000"), user, 0); + } + + function test_SchemaCheckerModule_InvalidSchemaId() public { + address user = makeAddr("user"); + bytes32 schemaId = bytes32(uint256(1234)); + uint64 issueDate = 0; + AttestationPayload memory attestationPayload = AttestationPayload( + schemaId, + 0, + abi.encode(user), + abi.encode(issuer, bytes32(uint256(4321)), issueDate) + ); + + vm.expectRevert(SchemaCheckerModule.InvalidSchemaId.selector); + schemaCheckerModule.run(attestationPayload, bytes("0000"), user, 0); + } + + function test_SchemaCheckerModule_supportsInterface() public { + bool isAbstractModuleSupported = schemaCheckerModule.supportsInterface(type(AbstractModule).interfaceId); + assertEq(isAbstractModuleSupported, true); + } +}