diff --git a/contracts/src/AttestationReader.sol b/contracts/src/AttestationReader.sol index dcdf38dd..f0a26755 100644 --- a/contracts/src/AttestationReader.sol +++ b/contracts/src/AttestationReader.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.21; -import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { RouterManager } from "./RouterManager.sol"; import { Attestation as EASAttestation, IEAS } from "./interfaces/IEAS.sol"; import { Attestation } from "./types/Structs.sol"; import { AttestationRegistry } from "./AttestationRegistry.sol"; @@ -13,17 +13,13 @@ import { IRouter } from "./interfaces/IRouter.sol"; * @author Consensys * @notice This contract allows to read attestations stored by EAS or Verax */ -contract AttestationReader is OwnableUpgradeable { +contract AttestationReader is RouterManager { IRouter public router; IEAS public easRegistry; - /// @notice Error thrown when an invalid Router address is given - error RouterInvalid(); /// @notice Error thrown when an invalid EAS registry address is given error EASAddressInvalid(); - /// @notice Event emitted when the router is updated - event RouterUpdated(address routerAddress); /// @notice Event emitted when the EAS registry address is updated event EASRegistryAddressUpdated(address easRegistryAddress); @@ -40,13 +36,11 @@ contract AttestationReader is OwnableUpgradeable { } /** - * @notice Changes the address for the Router - * @dev Only the registry owner can call this method + * @dev Changes the address for the Router + * @param _router the new Router address */ - function updateRouter(address _router) public onlyOwner { - if (_router == address(0)) revert RouterInvalid(); + function _setRouter(address _router) internal override { router = IRouter(_router); - emit RouterUpdated(_router); } /** diff --git a/contracts/src/AttestationRegistry.sol b/contracts/src/AttestationRegistry.sol index 89de57b5..be65fa94 100644 --- a/contracts/src/AttestationRegistry.sol +++ b/contracts/src/AttestationRegistry.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.21; -import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { RouterManager } from "./RouterManager.sol"; import { Attestation, AttestationPayload } from "./types/Structs.sol"; import { PortalRegistry } from "./PortalRegistry.sol"; import { SchemaRegistry } from "./SchemaRegistry.sol"; @@ -13,7 +13,7 @@ import { uncheckedInc256 } from "./Common.sol"; * @author Consensys * @notice This contract stores a registry of all attestations */ -contract AttestationRegistry is OwnableUpgradeable { +contract AttestationRegistry is RouterManager { IRouter public router; uint16 private version; @@ -25,8 +25,6 @@ contract AttestationRegistry is OwnableUpgradeable { /// @notice Error thrown when a non-portal tries to call a method that can only be called by a portal error OnlyPortal(); - /// @notice Error thrown when an invalid Router address is given - error RouterInvalid(); /// @notice Error thrown when an attestation is not registered in the AttestationRegistry error AttestationNotAttested(); /// @notice Error thrown when an attempt is made to revoke an attestation by an entity other than the attesting portal @@ -52,8 +50,6 @@ contract AttestationRegistry is OwnableUpgradeable { event AttestationRevoked(bytes32 attestationId); /// @notice Event emitted when the version number is incremented event VersionUpdated(uint16 version); - /// @notice Event emitted when the router is updated - event RouterUpdated(address routerAddress); /// @notice Event emitted when the chain prefix is updated event ChainPrefixUpdated(uint256 chainPrefix); @@ -80,13 +76,11 @@ contract AttestationRegistry is OwnableUpgradeable { } /** - * @notice Changes the address for the Router - * @dev Only the registry owner can call this method + * @dev Changes the address for the Router + * @param _router the new Router address */ - function updateRouter(address _router) public onlyOwner { - if (_router == address(0)) revert RouterInvalid(); + function _setRouter(address _router) internal override { router = IRouter(_router); - emit RouterUpdated(_router); } /** diff --git a/contracts/src/ModuleRegistry.sol b/contracts/src/ModuleRegistry.sol index b7d5132b..c06dcf0e 100644 --- a/contracts/src/ModuleRegistry.sol +++ b/contracts/src/ModuleRegistry.sol @@ -5,7 +5,7 @@ import { OperationType } from "./types/Enums.sol"; import { AttestationPayload, Module } from "./types/Structs.sol"; import { AbstractModule } from "./abstracts/AbstractModule.sol"; import { AbstractModuleV2 } from "./abstracts/AbstractModuleV2.sol"; -import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { RouterManager } from "./RouterManager.sol"; // solhint-disable-next-line max-line-length import { ERC165CheckerUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165CheckerUpgradeable.sol"; import { PortalRegistry } from "./PortalRegistry.sol"; @@ -17,15 +17,13 @@ import { uncheckedInc32 } from "./Common.sol"; * @author Consensys * @notice This contract aims to manage the Modules used by the Portals, including their discoverability */ -contract ModuleRegistry is OwnableUpgradeable { +contract ModuleRegistry is RouterManager { IRouter public router; /// @dev The list of Modules, accessed by their address mapping(address id => Module module) public modules; /// @dev Deprecated: The `moduleAddresses` variable is no longer used. It was used to store the modules addresses. address[] public moduleAddresses; - /// @notice Error thrown when an invalid Router address is given - error RouterInvalid(); /// @notice Error thrown when a non-allowlisted user tries to call a forbidden method error OnlyAllowlisted(); /// @notice Error thrown when an identical Module was already registered @@ -45,8 +43,6 @@ contract ModuleRegistry is OwnableUpgradeable { /// @notice Event emitted when a Module is registered event ModuleRegistered(string name, string description, address moduleAddress); - /// @notice Event emitted when the router is updated - event RouterUpdated(address routerAddress); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { @@ -70,13 +66,11 @@ contract ModuleRegistry is OwnableUpgradeable { } /** - * @notice Changes the address for the Router - * @dev Only the registry owner can call this method + * @dev Changes the address for the Router + * @param _router the new Router address */ - function updateRouter(address _router) public onlyOwner { - if (_router == address(0)) revert RouterInvalid(); + function _setRouter(address _router) internal override { router = IRouter(_router); - emit RouterUpdated(_router); } /** diff --git a/contracts/src/PortalRegistry.sol b/contracts/src/PortalRegistry.sol index 799c6a3f..a9dbd03b 100644 --- a/contracts/src/PortalRegistry.sol +++ b/contracts/src/PortalRegistry.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.21; -import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { RouterManager } from "./RouterManager.sol"; // solhint-disable-next-line max-line-length import { ERC165CheckerUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165CheckerUpgradeable.sol"; import { AbstractPortalV2 } from "./abstracts/AbstractPortalV2.sol"; @@ -15,7 +15,7 @@ import { uncheckedInc256 } from "./Common.sol"; * @author Consensys * @notice This contract aims to manage the Portals used by attestation issuers */ -contract PortalRegistry is OwnableUpgradeable { +contract PortalRegistry is RouterManager { IRouter public router; mapping(address id => Portal portal) private portals; @@ -27,8 +27,6 @@ contract PortalRegistry is OwnableUpgradeable { bool private isTestnet; - /// @notice Error thrown when an invalid Router address is given - error RouterInvalid(); /// @notice Error thrown when a non-allowlisted user tries to call a forbidden method error OnlyAllowlisted(); /// @notice Error thrown when attempting to register a Portal twice @@ -56,8 +54,6 @@ contract PortalRegistry is OwnableUpgradeable { event IssuerRemoved(address issuerAddress); /// @notice Event emitted when a Portal is revoked event PortalRevoked(address portalAddress); - /// @notice Event emitted when the router is updated - event RouterUpdated(address routerAddress); /// @notice Event emitted when the `isTestnet` flag is updated event IsTestnetUpdated(bool isTestnet); @@ -75,13 +71,11 @@ contract PortalRegistry is OwnableUpgradeable { } /** - * @notice Changes the address for the Router - * @dev Only the registry owner can call this method + * @dev Changes the address for the Router + * @param _router the new Router address */ - function updateRouter(address _router) public onlyOwner { - if (_router == address(0)) revert RouterInvalid(); + function _setRouter(address _router) internal override { router = IRouter(_router); - emit RouterUpdated(_router); } /** diff --git a/contracts/src/RouterManager.sol b/contracts/src/RouterManager.sol new file mode 100644 index 00000000..fc91a783 --- /dev/null +++ b/contracts/src/RouterManager.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { IRouter } from "./interfaces/IRouter.sol"; + +/** + * @title RouterManager + * @notice Centralise la gestion du Router + */ +abstract contract RouterManager is OwnableUpgradeable { + /// @notice Error thrown when an invalid Router address is given + error RouterInvalid(); + /// @notice Event emitted when the router is updated + event RouterUpdated(address routerAddress); + + /** + * @notice Change l'adresse du Router + * @dev Seul le propriétaire peut appeler cette méthode + * @param _router La nouvelle adresse du Router + */ + function updateRouter(address _router) public onlyOwner { + if (_router == address(0)) revert RouterInvalid(); + _setRouter(_router); // Appelle une fonction interne pour mettre à jour + emit RouterUpdated(_router); // Émet un événement pour signaler la mise à jour + } + + /** + * @dev Définit l'adresse du Router. Doit être implémentée par les contrats enfants. + * @param _router La nouvelle adresse du Router + */ + function _setRouter(address _router) internal virtual; +} diff --git a/contracts/src/SchemaRegistry.sol b/contracts/src/SchemaRegistry.sol index 42d418dc..da96488b 100644 --- a/contracts/src/SchemaRegistry.sol +++ b/contracts/src/SchemaRegistry.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.21; -import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { RouterManager } from "./RouterManager.sol"; import { Schema } from "./types/Structs.sol"; import { PortalRegistry } from "./PortalRegistry.sol"; import { IRouter } from "./interfaces/IRouter.sol"; @@ -12,7 +12,7 @@ import { uncheckedInc256 } from "./Common.sol"; * @author Consensys * @notice This contract aims to manage the Schemas used by the Portals, including their discoverability */ -contract SchemaRegistry is OwnableUpgradeable { +contract SchemaRegistry is RouterManager { IRouter public router; /// @dev The list of Schemas, accessed by their ID mapping(bytes32 id => Schema schema) private schemas; @@ -21,8 +21,6 @@ contract SchemaRegistry is OwnableUpgradeable { /// @dev Associates a Schema ID with the address of the Issuer who created it mapping(bytes32 id => address issuer) private schemasIssuers; - /// @notice Error thrown when an invalid Router address is given - error RouterInvalid(); /// @notice Error thrown when a non-allowlisted user tries to call a forbidden method error OnlyAllowlisted(); /// @notice Error thrown when any address which is not a portal registry tries to call a method @@ -44,8 +42,6 @@ contract SchemaRegistry is OwnableUpgradeable { event SchemaCreated(bytes32 indexed id, string name, string description, string context, string schemaString); /// @notice Event emitted when a Schema context is updated event SchemaContextUpdated(bytes32 indexed id); - /// @notice Event emitted when the router is updated - event RouterUpdated(address routerAddress); /// @notice Event emitted when the schema issuer is updated event SchemaIssuerUpdated(bytes32 schemaId, address schemaIssuerAddress); @@ -81,13 +77,11 @@ contract SchemaRegistry is OwnableUpgradeable { } /** - * @notice Changes the address for the Router - * @dev Only the registry owner can call this method + * @dev Changes the address for the Router + * @param _router the new Router address */ - function updateRouter(address _router) public onlyOwner { - if (_router == address(0)) revert RouterInvalid(); + function _setRouter(address _router) internal override { router = IRouter(_router); - emit RouterUpdated(_router); } /** diff --git a/contracts/test/AttestationReader.t.sol b/contracts/test/AttestationReader.t.sol index bb1fae98..95637b7c 100644 --- a/contracts/test/AttestationReader.t.sol +++ b/contracts/test/AttestationReader.t.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.21; import { Test } from "forge-std/Test.sol"; +import { RouterManager } from "../src/RouterManager.sol"; import { AttestationReader } from "../src/AttestationReader.sol"; import { AttestationRegistryMock } from "./mocks/AttestationRegistryMock.sol"; import { AttestationRegistry } from "../src/AttestationRegistry.sol"; @@ -60,7 +61,7 @@ contract AttestationReaderTest is Test { function test_updateRouter_RouterInvalid() public { AttestationReader testAttestationReader = new AttestationReader(); - vm.expectRevert(AttestationReader.RouterInvalid.selector); + vm.expectRevert(RouterManager.RouterInvalid.selector); vm.prank(address(0)); testAttestationReader.updateRouter(address(0)); } diff --git a/contracts/test/AttestationRegistry.t.sol b/contracts/test/AttestationRegistry.t.sol index f61f3709..a3f91c9a 100644 --- a/contracts/test/AttestationRegistry.t.sol +++ b/contracts/test/AttestationRegistry.t.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.21; import { Test } from "forge-std/Test.sol"; +import { RouterManager } from "../src/RouterManager.sol"; import { AttestationRegistry } from "../src/AttestationRegistry.sol"; import { PortalRegistryMock } from "./mocks/PortalRegistryMock.sol"; import { PortalRegistry } from "../src/PortalRegistry.sol"; @@ -119,7 +120,7 @@ contract AttestationRegistryTest is Test { function test_updateRouter_InvalidParameter() public { AttestationRegistry testAttestationRegistry = new AttestationRegistry(); - vm.expectRevert(AttestationRegistry.RouterInvalid.selector); + vm.expectRevert(RouterManager.RouterInvalid.selector); vm.prank(address(0)); testAttestationRegistry.updateRouter(address(0)); } diff --git a/contracts/test/ModuleRegistry.t.sol b/contracts/test/ModuleRegistry.t.sol index ece92133..9ab9eba2 100644 --- a/contracts/test/ModuleRegistry.t.sol +++ b/contracts/test/ModuleRegistry.t.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.21; import { Test } from "forge-std/Test.sol"; +import { RouterManager } from "../src/RouterManager.sol"; import { ModuleRegistry } from "../src/ModuleRegistry.sol"; import { OldVersionModule } from "./mocks/OldVersionModuleMock.sol"; import { CorrectModuleV2 } from "./mocks/CorrectModuleV2Mock.sol"; @@ -65,7 +66,7 @@ contract ModuleRegistryTest is Test { function test_updateRouter_InvalidParameter() public { ModuleRegistry testModuleRegistry = new ModuleRegistry(); - vm.expectRevert(ModuleRegistry.RouterInvalid.selector); + vm.expectRevert(RouterManager.RouterInvalid.selector); vm.prank(address(0)); testModuleRegistry.updateRouter(address(0)); } diff --git a/contracts/test/PortalRegistry.t.sol b/contracts/test/PortalRegistry.t.sol index dab4e06a..7436be8d 100644 --- a/contracts/test/PortalRegistry.t.sol +++ b/contracts/test/PortalRegistry.t.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.21; import { Test } from "forge-std/Test.sol"; +import { RouterManager } from "../src/RouterManager.sol"; import { PortalRegistry } from "../src/PortalRegistry.sol"; import { CorrectModuleV2 } from "./mocks/CorrectModuleV2Mock.sol"; import { Portal } from "../src/types/Structs.sol"; @@ -77,7 +78,7 @@ contract PortalRegistryTest is Test { function test_updateRouter_RouterInvalid() public { PortalRegistry testPortalRegistry = new PortalRegistry(false); - vm.expectRevert(PortalRegistry.RouterInvalid.selector); + vm.expectRevert(RouterManager.RouterInvalid.selector); vm.prank(address(0)); testPortalRegistry.updateRouter(address(0)); } diff --git a/contracts/test/RouterManager.t.sol b/contracts/test/RouterManager.t.sol new file mode 100644 index 00000000..d7638d3a --- /dev/null +++ b/contracts/test/RouterManager.t.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +import { Test } from "forge-std/Test.sol"; +import { RouterManager } from "../src/RouterManager.sol"; +import { RouterManagerTestContract } from "./mocks/RouterManagerTestContract.sol"; +import { IRouter } from "../src/interfaces/IRouter.sol"; + +contract RouterManagerTest is Test { + RouterManagerTestContract public routerManager; + + event RouterUpdated(address routerAddress); + + function setUp() public { + routerManager = new RouterManagerTestContract(); + } + + function test_updateRouter() public { + address newRouter = makeAddr("NewRouter"); + + vm.expectEmit(true, true, true, true); + emit RouterUpdated(newRouter); + + vm.prank(address(0)); + routerManager.updateRouter(newRouter); + + assertEq(address(routerManager.router()), newRouter); + } + + function test_updateRouter_RouterInvalid() public { + vm.expectRevert(RouterManager.RouterInvalid.selector); + + vm.prank(address(0)); + routerManager.updateRouter(address(0)); + } + + function test_updateRouter_OnlyOwner() public { + address newRouter = makeAddr("NewRouter"); + + vm.prank(makeAddr("NotOwner")); + vm.expectRevert("Ownable: caller is not the owner"); + routerManager.updateRouter(newRouter); + } +} diff --git a/contracts/test/SchemaRegistry.t.sol b/contracts/test/SchemaRegistry.t.sol index dd4f243d..4e36ac08 100644 --- a/contracts/test/SchemaRegistry.t.sol +++ b/contracts/test/SchemaRegistry.t.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.21; import { Test } from "forge-std/Test.sol"; +import { RouterManager } from "../src/RouterManager.sol"; import { SchemaRegistry } from "../src/SchemaRegistry.sol"; import { PortalRegistryMock } from "./mocks/PortalRegistryMock.sol"; import { PortalRegistryNotAllowlistedMock } from "./mocks/PortalRegistryNotAllowlistedMock.sol"; @@ -61,7 +62,7 @@ contract SchemaRegistryTest is Test { function test_updateRouter_RouterInvalid() public { SchemaRegistry testSchemaRegistry = new SchemaRegistry(); - vm.expectRevert(SchemaRegistry.RouterInvalid.selector); + vm.expectRevert(RouterManager.RouterInvalid.selector); vm.prank(address(0)); testSchemaRegistry.updateRouter(address(0)); } diff --git a/contracts/test/mocks/RouterManagerTestContract.sol b/contracts/test/mocks/RouterManagerTestContract.sol new file mode 100644 index 00000000..73708c22 --- /dev/null +++ b/contracts/test/mocks/RouterManagerTestContract.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +import { RouterManager } from "../../src/RouterManager.sol"; +import { IRouter } from "../../src/interfaces/IRouter.sol"; + +/** + * @title RouterManagerTestContract + * @notice Real contract to test RouterManager + */ +contract RouterManagerTestContract is RouterManager { + IRouter public router; + + function _setRouter(address _router) internal override { + router = IRouter(_router); + } +}