From d48b0e149a0c8b61dc78d9fd32774c5563db6d4c Mon Sep 17 00:00:00 2001 From: Satyajeet Kolhapure Date: Tue, 26 Sep 2023 12:36:58 +0100 Subject: [PATCH 1/5] feat: implemented ERC-1155 --- src/AttestationRegistry.sol | 48 ++++++++++++++++++++++++-- test/AttestationRegistry.t.sol | 63 ++++++++++++++++++++++++++++++---- 2 files changed, 103 insertions(+), 8 deletions(-) diff --git a/src/AttestationRegistry.sol b/src/AttestationRegistry.sol index f0a922f2..4fb788a1 100644 --- a/src/AttestationRegistry.sol +++ b/src/AttestationRegistry.sol @@ -2,6 +2,9 @@ pragma solidity 0.8.21; import { OwnableUpgradeable } from "openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol"; +import { ContextUpgradeable } from "openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol"; +import { ERC1155 } from "openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol"; +import { Context } from "openzeppelin-contracts/contracts/utils/Context.sol"; import { Attestation, AttestationPayload } from "./types/Structs.sol"; import { PortalRegistry } from "./PortalRegistry.sol"; import { SchemaRegistry } from "./SchemaRegistry.sol"; @@ -12,7 +15,7 @@ import { IRouter } from "./interface/IRouter.sol"; * @author Consensys * @notice This contract stores a registry of all attestations */ -contract AttestationRegistry is OwnableUpgradeable { +contract AttestationRegistry is OwnableUpgradeable, ERC1155 { IRouter public router; uint16 private version; @@ -61,7 +64,7 @@ contract AttestationRegistry is OwnableUpgradeable { } /// @custom:oz-upgrades-unsafe-allow constructor - constructor() { + constructor() ERC1155("NA") { _disableInitializers(); } @@ -262,4 +265,45 @@ contract AttestationRegistry is OwnableUpgradeable { function getAttestationIdCounter() public view returns (uint32) { return attestationIdCounter; } + + /** + * @notice Get the balance of an account's attestations for a given attestation ID. + * @param account The address of the token holder + * @param id ID of the attestation + * @return The _owner's balance of the attestations on a given attestation ID + */ + function balanceOf(address account, uint256 id) public view override returns (uint256) { + bytes32 attestationId = bytes32(abi.encode(id)); + Attestation memory attestation = attestations[attestationId]; + if (keccak256(attestation.subject) == keccak256(abi.encode(account))) return 1; + return 0; + } + + /** + * @notice Get the balance of multiple account/attestation pairs + * @param accounts The addresses of the attestation holders + * @param ids ID of the attestations + * @return The _owner's balance of the attestation for a given address (i.e. balance for each (owner, id) pair) + */ + function balanceOfBatch( + address[] memory accounts, + uint256[] memory ids + ) public view override returns (uint256[] memory) { + if (accounts.length != ids.length) revert ArrayLengthMismatch(); + uint256[] memory result = new uint256[](accounts.length); + for (uint256 i = 0; i < accounts.length; i++) { + bytes32 attestationId = bytes32(abi.encode(ids[i])); + Attestation memory attestation = attestations[attestationId]; + if (keccak256(attestation.subject) == keccak256(abi.encode(accounts[i]))) result[i] = 1; + } + return result; + } + + function _msgSender() internal view override(Context, ContextUpgradeable) returns (address sender) { + sender = ContextUpgradeable._msgSender(); + } + + function _msgData() internal view override(Context, ContextUpgradeable) returns (bytes calldata) { + return ContextUpgradeable._msgData(); + } } diff --git a/test/AttestationRegistry.t.sol b/test/AttestationRegistry.t.sol index f6d3f1b2..88ac3085 100644 --- a/test/AttestationRegistry.t.sol +++ b/test/AttestationRegistry.t.sol @@ -484,25 +484,76 @@ contract AttestationRegistryTest is Test { SchemaRegistryMock schemaRegistryMock = SchemaRegistryMock(router.getSchemaRegistry()); attestationPayload.schemaId = schemaRegistryMock.getIdFromSchemaString("schemaString"); schemaRegistryMock.createSchema("name", "description", "context", "schemaString"); - uint32 version = attestationRegistry.getAttestationIdCounter(); + uint32 attestationIdCounter = attestationRegistry.getAttestationIdCounter(); - assertEq(version, 0); + assertEq(attestationIdCounter, 0); vm.startPrank(portal); attestationRegistry.attest(attestationPayload, attester); - version = attestationRegistry.getAttestationIdCounter(); - assertEq(version, 1); + attestationIdCounter = attestationRegistry.getAttestationIdCounter(); + assertEq(attestationIdCounter, 1); attestationRegistry.attest(attestationPayload, attester); - version = attestationRegistry.getAttestationIdCounter(); - assertEq(version, 2); + attestationIdCounter = attestationRegistry.getAttestationIdCounter(); + assertEq(attestationIdCounter, 2); vm.stopPrank(); } + function test_balanceOf(AttestationPayload memory attestationPayload) public { + vm.assume(attestationPayload.subject.length != 0); + vm.assume(attestationPayload.attestationData.length != 0); + SchemaRegistryMock schemaRegistryMock = SchemaRegistryMock(router.getSchemaRegistry()); + attestationPayload.schemaId = schemaRegistryMock.getIdFromSchemaString("schemaString"); + schemaRegistryMock.createSchema("name", "description", "context", "schemaString"); + + vm.startPrank(portal); + attestationPayload.subject = abi.encode(address(1)); + attestationRegistry.attest(attestationPayload, attester); + + uint256 balance = attestationRegistry.balanceOf(address(1), 1); + assertEq(balance, 1); + } + + function test_balanceOfBatch(AttestationPayload memory attestationPayload) public { + vm.assume(attestationPayload.subject.length != 0); + vm.assume(attestationPayload.attestationData.length != 0); + SchemaRegistryMock schemaRegistryMock = SchemaRegistryMock(router.getSchemaRegistry()); + attestationPayload.schemaId = schemaRegistryMock.getIdFromSchemaString("schemaString"); + schemaRegistryMock.createSchema("name", "description", "context", "schemaString"); + + address[] memory owners = new address[](2); + owners[0] = address(1); + owners[1] = address(2); + + vm.startPrank(portal); + attestationPayload.subject = abi.encode(owners[0]); + attestationRegistry.attest(attestationPayload, attester); + + attestationPayload.subject = abi.encode(owners[1]); + attestationRegistry.attest(attestationPayload, attester); + + uint256[] memory ids = new uint256[](2); + ids[0] = 1; + ids[1] = 2; + uint256[] memory balance = attestationRegistry.balanceOfBatch(owners, ids); + assertEq(balance[0], 1); + assertEq(balance[1], 1); + } + + function test_balanceOfBatch_ArrayLengthMismatch() public { + address[] memory owners = new address[](2); + owners[0] = address(1); + owners[1] = address(2); + uint256[] memory ids = new uint256[](1); + ids[0] = 1; + vm.expectRevert(AttestationRegistry.ArrayLengthMismatch.selector); + attestationRegistry.balanceOfBatch(owners, ids); + } + function _createAttestation( AttestationPayload memory attestationPayload, uint256 id From e96e08fc09d1c747ae8b79387bbefd47982acb3f Mon Sep 17 00:00:00 2001 From: Satyajeet Kolhapure <77279246+satyajeetkolhapure@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:44:13 +0100 Subject: [PATCH 2/5] Update src/AttestationRegistry.sol Co-authored-by: Alain Nicolas --- src/AttestationRegistry.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AttestationRegistry.sol b/src/AttestationRegistry.sol index 4fb788a1..9577ca6f 100644 --- a/src/AttestationRegistry.sol +++ b/src/AttestationRegistry.sol @@ -267,7 +267,7 @@ contract AttestationRegistry is OwnableUpgradeable, ERC1155 { } /** - * @notice Get the balance of an account's attestations for a given attestation ID. + * @notice Checks if an address owns a given attestation * @param account The address of the token holder * @param id ID of the attestation * @return The _owner's balance of the attestations on a given attestation ID From 3c7d5ff32b94b95581290e6686a3d3b123ebe42c Mon Sep 17 00:00:00 2001 From: Satyajeet Kolhapure Date: Tue, 26 Sep 2023 13:51:23 +0100 Subject: [PATCH 3/5] fix: used ERC1155Upgradeable --- src/AttestationRegistry.sol | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/AttestationRegistry.sol b/src/AttestationRegistry.sol index 9577ca6f..399f38f5 100644 --- a/src/AttestationRegistry.sol +++ b/src/AttestationRegistry.sol @@ -3,8 +3,7 @@ pragma solidity 0.8.21; import { OwnableUpgradeable } from "openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol"; import { ContextUpgradeable } from "openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol"; -import { ERC1155 } from "openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol"; -import { Context } from "openzeppelin-contracts/contracts/utils/Context.sol"; +import { ERC1155Upgradeable } from "openzeppelin-contracts-upgradeable/contracts/token/ERC1155/ERC1155Upgradeable.sol"; import { Attestation, AttestationPayload } from "./types/Structs.sol"; import { PortalRegistry } from "./PortalRegistry.sol"; import { SchemaRegistry } from "./SchemaRegistry.sol"; @@ -15,7 +14,7 @@ import { IRouter } from "./interface/IRouter.sol"; * @author Consensys * @notice This contract stores a registry of all attestations */ -contract AttestationRegistry is OwnableUpgradeable, ERC1155 { +contract AttestationRegistry is OwnableUpgradeable, ERC1155Upgradeable { IRouter public router; uint16 private version; @@ -64,7 +63,7 @@ contract AttestationRegistry is OwnableUpgradeable, ERC1155 { } /// @custom:oz-upgrades-unsafe-allow constructor - constructor() ERC1155("NA") { + constructor() { _disableInitializers(); } @@ -299,11 +298,11 @@ contract AttestationRegistry is OwnableUpgradeable, ERC1155 { return result; } - function _msgSender() internal view override(Context, ContextUpgradeable) returns (address sender) { - sender = ContextUpgradeable._msgSender(); - } + // function _msgSender() internal view override(Context, ContextUpgradeable) returns (address sender) { + // sender = ContextUpgradeable._msgSender(); + // } - function _msgData() internal view override(Context, ContextUpgradeable) returns (bytes calldata) { - return ContextUpgradeable._msgData(); - } + // function _msgData() internal view override(Context, ContextUpgradeable) returns (bytes calldata) { + // return ContextUpgradeable._msgData(); + // } } From 07fdf5529d2286deae3c4389ed44aa2306f9acce Mon Sep 17 00:00:00 2001 From: Satyajeet Kolhapure Date: Tue, 26 Sep 2023 13:53:03 +0100 Subject: [PATCH 4/5] fix: lint issues --- src/AttestationRegistry.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AttestationRegistry.sol b/src/AttestationRegistry.sol index 399f38f5..1a6cb0d4 100644 --- a/src/AttestationRegistry.sol +++ b/src/AttestationRegistry.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.21; import { OwnableUpgradeable } from "openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol"; -import { ContextUpgradeable } from "openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol"; import { ERC1155Upgradeable } from "openzeppelin-contracts-upgradeable/contracts/token/ERC1155/ERC1155Upgradeable.sol"; import { Attestation, AttestationPayload } from "./types/Structs.sol"; import { PortalRegistry } from "./PortalRegistry.sol"; From c60560e818f0dde98bc49934d9b9a9647e9cfd96 Mon Sep 17 00:00:00 2001 From: Satyajeet Kolhapure Date: Tue, 26 Sep 2023 13:58:59 +0100 Subject: [PATCH 5/5] fix: removed the commented functions --- src/AttestationRegistry.sol | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/AttestationRegistry.sol b/src/AttestationRegistry.sol index 1a6cb0d4..57176b7e 100644 --- a/src/AttestationRegistry.sol +++ b/src/AttestationRegistry.sol @@ -296,12 +296,4 @@ contract AttestationRegistry is OwnableUpgradeable, ERC1155Upgradeable { } return result; } - - // function _msgSender() internal view override(Context, ContextUpgradeable) returns (address sender) { - // sender = ContextUpgradeable._msgSender(); - // } - - // function _msgData() internal view override(Context, ContextUpgradeable) returns (bytes calldata) { - // return ContextUpgradeable._msgData(); - // } }