From c57c89a0bcc49aa47e2126910ed78c501942fb90 Mon Sep 17 00:00:00 2001 From: Welliton Gervickas Date: Fri, 10 Nov 2023 11:24:18 -0300 Subject: [PATCH] feat: simplifying code base --- contracts/AccessManagement.sol | 10 +- contracts/Hub.sol | 72 ++++--- contracts/Registry.sol | 33 --- contracts/interfaces/IAdapter.sol | 7 - contracts/interfaces/IApp.sol | 9 - contracts/interfaces/IHub.sol | 14 -- contracts/interfaces/IRegistry.sol | 14 -- .../fixtures.ts | 3 - test/hub/Hub.spec.ts | 201 ++---------------- test/hub/fixture.ts | 8 +- test/registry/Registry.spec.ts | 121 ----------- test/registry/fixture.ts | 13 -- 12 files changed, 72 insertions(+), 433 deletions(-) delete mode 100644 contracts/Registry.sol delete mode 100644 contracts/interfaces/IAdapter.sol delete mode 100644 contracts/interfaces/IApp.sol delete mode 100644 contracts/interfaces/IHub.sol delete mode 100644 contracts/interfaces/IRegistry.sol rename test/{access-management => accessManagement}/fixtures.ts (87%) delete mode 100644 test/registry/Registry.spec.ts delete mode 100644 test/registry/fixture.ts diff --git a/contracts/AccessManagement.sol b/contracts/AccessManagement.sol index 568d04c..ae13649 100644 --- a/contracts/AccessManagement.sol +++ b/contracts/AccessManagement.sol @@ -3,6 +3,14 @@ pragma solidity 0.8.21; import "@openzeppelin/contracts/access/manager/AccessManager.sol"; +uint64 constant ADMIN_ROLE = type(uint64).min; +uint64 constant PUBLIC_ROLE = type(uint64).max; + +/** + * @title AccessManagement + * @notice This contract is used to manage access to the protocol + */ + contract AccessManagement is AccessManager { - constructor(address initiaAdmin_) AccessManager(initiaAdmin_) {} + constructor(address admin) AccessManager(admin) {} } diff --git a/contracts/Hub.sol b/contracts/Hub.sol index f89e1cf..48d5b73 100644 --- a/contracts/Hub.sol +++ b/contracts/Hub.sol @@ -1,49 +1,65 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.21; -import {IHub} from "./interfaces/IHub.sol"; -import {IRegistry} from "./interfaces/IRegistry.sol"; -import {App} from "./interfaces/IApp.sol"; -import {Adapter} from "./interfaces/IAdapter.sol"; import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; -contract Hub is IHub, AccessManaged { - IRegistry public immutable registryAddress; - uint256 private _appIdSalt; +/** + * @title Hub + * @notice This contract is used to manage apps in the protocol + */ - mapping(bytes32 => App) private _apps; - - constructor(IRegistry registryAddress_, address accessManagement_) AccessManaged(accessManagement_) { - registryAddress = registryAddress_; +contract Hub is AccessManaged { + struct App { + address appAddress; } - modifier checkIsRegistryAdapter(bytes32 adapterId_) { - if (!registryAddress.isAdapter(adapterId_)) { - revert IHub.Hub_AdapterNotFound(adapterId_); - } - _; - } + /// @notice The salt used to generate appIds + uint256 private s_appIdSalt; + + mapping(bytes32 => App) private s_apps; - function createApp( - bytes32 adapterId_, - address appAddress_ - ) external checkIsRegistryAdapter(adapterId_) restricted returns (bytes32) { - App memory app = App({adapter: _getRegistryAdapter(adapterId_), appAddress: appAddress_}); + /// @notice Emitted when an app is added to the hub + event Hub_AppAdded(bytes32 indexed appId_); - bytes32 appId = keccak256(abi.encodePacked(_appIdSalt++, adapterId_, appAddress_, msg.sender)); + constructor(address accessManagement_) AccessManaged(accessManagement_) {} - _apps[appId] = app; + /** + * @notice Adds an app to the hub + * @param appAddress_ The address of the app contract + * @return The id of the app + */ + function addApp(address appAddress_) external restricted returns (bytes32) { + bytes32 appId = _getNextAppId(appAddress_); + s_apps[appId] = App({appAddress: appAddress_}); - emit IHub.Hub_AppCreated(appId); + emit Hub_AppAdded(appId); return appId; } - function _getRegistryAdapter(bytes32 adapterId_) internal view returns (Adapter memory) { - return registryAddress.getAdapter(adapterId_); + /** + * @notice Gets the next app id + * @param appAddress_ The address of the app contract + * @return The id of the app + */ + function _getNextAppId(address appAddress_) private returns (bytes32) { + return keccak256(abi.encodePacked(_getNextAppIdSalt(), msg.sender, appAddress_)); + } + + /** + * @notice Gets the next app id salt + * @return The next app id salt + */ + function _getNextAppIdSalt() private returns (uint256) { + return s_appIdSalt++; } + /** + * @notice Gets an app from the hub + * @param appId_ The id of the app + * @return The app + */ function getApp(bytes32 appId_) external view returns (App memory) { - return _apps[appId_]; + return s_apps[appId_]; } } diff --git a/contracts/Registry.sol b/contracts/Registry.sol deleted file mode 100644 index c65bddd..0000000 --- a/contracts/Registry.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.21; - -import {IRegistry, Adapter} from "./interfaces/IRegistry.sol"; -import {Adapter} from "./interfaces/IAdapter.sol"; -import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; - -contract Registry is IRegistry, AccessManaged { - uint256 private _adapterIdSalt; - - mapping(bytes32 => Adapter) private _adapters; - - constructor(address accessManagement_) AccessManaged(accessManagement_) {} - - function createAdapter(bytes32 adapterType_, address adapterAddress_) external restricted returns (bytes32) { - Adapter memory adapter = Adapter({adapterType: adapterType_, adapterAddress: adapterAddress_}); - - bytes32 adapterId = keccak256(abi.encodePacked(_adapterIdSalt++, adapterType_, adapterAddress_, msg.sender)); - _adapters[adapterId] = adapter; - - emit IRegistry.Registry_AdapterCreated(adapterId); - - return adapterId; - } - - function getAdapter(bytes32 adapterId) external view returns (Adapter memory) { - return _adapters[adapterId]; - } - - function isAdapter(bytes32 adapterId) external view returns (bool) { - return _adapters[adapterId].adapterAddress != address(0); - } -} diff --git a/contracts/interfaces/IAdapter.sol b/contracts/interfaces/IAdapter.sol deleted file mode 100644 index 885836e..0000000 --- a/contracts/interfaces/IAdapter.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.21; - -struct Adapter { - bytes32 adapterType; - address adapterAddress; -} diff --git a/contracts/interfaces/IApp.sol b/contracts/interfaces/IApp.sol deleted file mode 100644 index 170e6d6..0000000 --- a/contracts/interfaces/IApp.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.21; - -import {Adapter} from "./IAdapter.sol"; - -struct App { - address appAddress; - Adapter adapter; -} diff --git a/contracts/interfaces/IHub.sol b/contracts/interfaces/IHub.sol deleted file mode 100644 index 3bfab87..0000000 --- a/contracts/interfaces/IHub.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.21; - -import {App} from "./IApp.sol"; - -interface IHub { - event Hub_AppCreated(bytes32 indexed appId_); - - error Hub_AdapterNotFound(bytes32 adapterId_); - - function createApp(bytes32 adapterId_, address adapterAddress_) external returns (bytes32); - - function getApp(bytes32 appId_) external view returns (App memory); -} diff --git a/contracts/interfaces/IRegistry.sol b/contracts/interfaces/IRegistry.sol deleted file mode 100644 index c837da1..0000000 --- a/contracts/interfaces/IRegistry.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.21; - -import {Adapter} from "./IAdapter.sol"; - -interface IRegistry { - event Registry_AdapterCreated(bytes32 indexed adapterId); - - function createAdapter(bytes32 adapterType_, address adapterAddress_) external returns (bytes32); - - function getAdapter(bytes32 adapterId) external view returns (Adapter memory); - - function isAdapter(bytes32 adapterId) external view returns (bool); -} diff --git a/test/access-management/fixtures.ts b/test/accessManagement/fixtures.ts similarity index 87% rename from test/access-management/fixtures.ts rename to test/accessManagement/fixtures.ts index 904b6ec..14a4459 100644 --- a/test/access-management/fixtures.ts +++ b/test/accessManagement/fixtures.ts @@ -1,8 +1,5 @@ import { ethers } from 'hardhat' -export const ADMIN_ROLE = 0n -export const DEVELOPER_ROLE = 1n - export async function deployAccessManagementFixture() { const [owner] = await ethers.getSigners() diff --git a/test/hub/Hub.spec.ts b/test/hub/Hub.spec.ts index ae20223..0fdd560 100644 --- a/test/hub/Hub.spec.ts +++ b/test/hub/Hub.spec.ts @@ -3,218 +3,51 @@ import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' import { expect } from 'chai' import { ethers } from 'hardhat' -import { - deployAccessManagementFixture, - DEVELOPER_ROLE -} from '@/test/access-management/fixtures' +import { deployAccessManagementFixture } from '@/test/accessManagement/fixtures' import { deployHubFixture } from './fixture' -import { VAULT_V1 } from '../registry/fixture' -import { deployRegistryFixture } from '../registry/fixture' +// import { VAULT_V1 } from '../registry/fixture' +// import { deployRegistryFixture } from '../registry/fixture' describe('Hub', function () { - it('should set app data on create', async function () { + it('should add app by app address', async function () { + const [, developer] = await ethers.getSigners() + const { accessManagementAddress, accessManagement } = await loadFixture( deployAccessManagementFixture ) - const { registry, registryAddress, developer } = await loadFixture( - deployRegistryFixture.bind(this, accessManagementAddress) - ) - - // grant role to developer - await accessManagement.grantRole(DEVELOPER_ROLE, developer.address, 0n) + const DEVELOPER_ROLE = 1n + const DELAY = 0n - // grant role to developer to create adapter - await accessManagement.setTargetFunctionRole( - registryAddress, - [registry.interface.getFunction('createAdapter').selector], - DEVELOPER_ROLE - ) + // grant developer role to address + await accessManagement.grantRole(DEVELOPER_ROLE, developer.address, DELAY) const { hub, hubAddress } = await loadFixture( - deployHubFixture.bind(this, registryAddress, accessManagementAddress) + deployHubFixture.bind(this, accessManagementAddress) ) - // grant role to developer to create app + // grant role to developer to add app await accessManagement.setTargetFunctionRole( hubAddress, - [hub.interface.getFunction('createApp').selector], + [hub.interface.getFunction('addApp').selector], DEVELOPER_ROLE ) - // create adapter - const adapterType = VAULT_V1 - const adapterAddress = '0x0000000000000000000000000000000000000001' - const tx = await registry - .connect(developer) - .createAdapter(adapterType, adapterAddress) - - const receipt = await tx.wait() - const filter = registry.filters.Registry_AdapterCreated - const logs = await registry.queryFilter(filter, receipt?.blockHash) - const [adapterId] = logs[0].args - - const adapter = await registry.getAdapter(adapterId) - // create app const appAddress = '0x0000000000000000000000000000000000000001' - const tx2 = await hub.connect(developer).createApp(adapterId, appAddress) + const tx2 = await hub.connect(developer).addApp(appAddress) const receipt2 = await tx2.wait() - const filter2 = hub.filters.Hub_AppCreated + const filter2 = hub.filters.Hub_AppAdded const logs2 = await hub.queryFilter(filter2, receipt2?.blockHash) const [appId] = logs2[0].args const app = await hub.getApp(appId) expect({ - appAddress: app.appAddress, - adapter: app.adapter + appAddress: app.appAddress }).to.deep.equal({ - appAddress, - adapter + appAddress }) }) - - it('should revert if adapter id does not exist', async function () { - const { accessManagementAddress, accessManagement } = await loadFixture( - deployAccessManagementFixture - ) - - const { registryAddress, developer } = await loadFixture( - deployRegistryFixture.bind(this, accessManagementAddress) - ) - - // grant role to developer - await accessManagement.grantRole(DEVELOPER_ROLE, developer.address, 0n) - - const { hub, hubAddress } = await loadFixture( - deployHubFixture.bind(this, registryAddress, accessManagementAddress) - ) - - // grant role to developer to create app - await accessManagement.setTargetFunctionRole( - hubAddress, - [hub.interface.getFunction('createApp').selector], - DEVELOPER_ROLE - ) - - const nonExistentAdapterId = ethers.keccak256(ethers.toUtf8Bytes('foo')) - - // create app - const appAddress = '0x0000000000000000000000000000000000000001' - - await expect( - hub.connect(developer).createApp(nonExistentAdapterId, appAddress) - ).to.be.revertedWithCustomError(hub, 'Hub_AdapterNotFound') - }) - - it('should not repeat app id', async function () { - const { accessManagementAddress, accessManagement } = await loadFixture( - deployAccessManagementFixture - ) - - const { registry, registryAddress, developer } = await loadFixture( - deployRegistryFixture.bind(this, accessManagementAddress) - ) - - // grant role to developer - await accessManagement.grantRole(DEVELOPER_ROLE, developer.address, 0n) - - // grant role to developer to create adapter - await accessManagement.setTargetFunctionRole( - registryAddress, - [registry.interface.getFunction('createAdapter').selector], - DEVELOPER_ROLE - ) - - const { hub, hubAddress } = await loadFixture( - deployHubFixture.bind(this, registryAddress, accessManagementAddress) - ) - - // grant role to developer to create app - await accessManagement.setTargetFunctionRole( - hubAddress, - [hub.interface.getFunction('createApp').selector], - DEVELOPER_ROLE - ) - - // create adapter - const adapterType = VAULT_V1 - const adapterAddress = '0x0000000000000000000000000000000000000001' - const tx = await registry - .connect(developer) - .createAdapter(adapterType, adapterAddress) - - const receipt = await tx.wait() - const filter = registry.filters.Registry_AdapterCreated - const logs = await registry.queryFilter(filter, receipt?.blockHash) - const [adapterId] = logs[0].args - - // create app 1 - const appAddress = '0x0000000000000000000000000000000000000001' - const tx2 = await hub.connect(developer).createApp(adapterId, appAddress) - const receipt2 = await tx2.wait() - const filter2 = hub.filters.Hub_AppCreated - const logs2 = await hub.queryFilter(filter2, receipt2?.blockHash) - const [appId] = logs2[0].args - - //create app 2 - const tx3 = await hub.connect(developer).createApp(adapterId, appAddress) - const receipt3 = await tx3.wait() - const logs3 = await hub.queryFilter(filter2, receipt3?.blockHash) - const [appId2] = logs3[0].args - - expect(appId).to.not.equal(appId2) - }) - - it('should revert if not authorized', async function () { - const [, developer, otherAccount] = await ethers.getSigners() - const { accessManagementAddress, accessManagement } = await loadFixture( - deployAccessManagementFixture - ) - - const { registry, registryAddress } = await loadFixture( - deployRegistryFixture.bind(this, accessManagementAddress) - ) - - // grant role to developer - await accessManagement.grantRole(DEVELOPER_ROLE, developer.address, 0n) - - // grant role to developer to create adapter - await accessManagement.setTargetFunctionRole( - registryAddress, - [registry.interface.getFunction('createAdapter').selector], - DEVELOPER_ROLE - ) - - const { hub, hubAddress } = await loadFixture( - deployHubFixture.bind(this, registryAddress, accessManagementAddress) - ) - - // grant role to developer to create app - await accessManagement.setTargetFunctionRole( - hubAddress, - [hub.interface.getFunction('createApp').selector], - DEVELOPER_ROLE - ) - - // create adapter - const adapterType = VAULT_V1 - const adapterAddress = '0x0000000000000000000000000000000000000001' - const tx = await registry - .connect(developer) - .createAdapter(adapterType, adapterAddress) - - const receipt = await tx.wait() - const filter = registry.filters.Registry_AdapterCreated - const logs = await registry.queryFilter(filter, receipt?.blockHash) - const [adapterId] = logs[0].args - - // create app - const appAddress = '0x0000000000000000000000000000000000000001' - await expect( - hub.connect(otherAccount).createApp(adapterId, appAddress) - ).to.be.revertedWithCustomError(hub, 'AccessManagedUnauthorized') - }) }) diff --git a/test/hub/fixture.ts b/test/hub/fixture.ts index 71038cf..5d19b13 100644 --- a/test/hub/fixture.ts +++ b/test/hub/fixture.ts @@ -1,13 +1,9 @@ import { ethers } from 'hardhat' -export async function deployHubFixture( - registryAddress: string, - accessManagementAddress: string -) { +export async function deployHubFixture(accessManagementAddress: string) { const [owner] = await ethers.getSigners() const Hub = await ethers.getContractFactory('Hub') - const hub = await Hub.deploy(registryAddress, accessManagementAddress) - + const hub = await Hub.deploy(accessManagementAddress) const hubAddress = await hub.getAddress() return { hub, owner, hubAddress } diff --git a/test/registry/Registry.spec.ts b/test/registry/Registry.spec.ts deleted file mode 100644 index f178bb3..0000000 --- a/test/registry/Registry.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers' - -import { expect } from 'chai' -import { ethers } from 'hardhat' - -import { - deployAccessManagementFixture, - DEVELOPER_ROLE -} from '@/test/access-management/fixtures' - -import { deployRegistryFixture, VAULT_V1 } from './fixture' - -describe('Registry', function () { - it('should set adapter data on create', async function () { - const { accessManagementAddress, accessManagement } = await loadFixture( - deployAccessManagementFixture - ) - - const { registry, registryAddress, developer } = await loadFixture( - deployRegistryFixture.bind(this, accessManagementAddress) - ) - - // grant role to developer - await accessManagement.grantRole(DEVELOPER_ROLE, developer.address, 0n) - - // grant role to developer to create adapter - await accessManagement.setTargetFunctionRole( - registryAddress, - [registry.interface.getFunction('createAdapter').selector], - DEVELOPER_ROLE - ) - - // create adapter - const adapterType = VAULT_V1 - const adapterAddress = ethers.ZeroAddress - const tx = await registry - .connect(developer) - .createAdapter(adapterType, adapterAddress) - const receipt = await tx.wait() - const filter = registry.filters.Registry_AdapterCreated - const logs = await registry.queryFilter(filter, receipt?.blockHash) - const [adapterId] = logs[0].args - const adapter = await registry.getAdapter(adapterId) - - expect({ - adapterType: adapter.adapterType, - adapterAddress: adapter.adapterAddress - }).to.deep.equal({ - adapterType, - adapterAddress - }) - }) - - it('should not repeat adapter id', async function () { - const { accessManagementAddress, accessManagement } = await loadFixture( - deployAccessManagementFixture - ) - - const { registry, registryAddress, developer } = await loadFixture( - deployRegistryFixture.bind(this, accessManagementAddress) - ) - - await accessManagement.grantRole(DEVELOPER_ROLE, developer.address, 0n) - await accessManagement.setTargetFunctionRole( - registryAddress, - [registry.interface.getFunction('createAdapter').selector], - DEVELOPER_ROLE - ) - - const adapterType = VAULT_V1 - const adapterAddress = ethers.ZeroAddress - - const tx = await registry - .connect(developer) - .createAdapter(adapterType, adapterAddress) - - const receipt = await tx.wait() - const filter = registry.filters.Registry_AdapterCreated - const logs = await registry.queryFilter(filter, receipt?.blockHash) - const [adapterId1] = logs[0].args - - const tx2 = await registry - .connect(developer) - .createAdapter(adapterType, adapterAddress) - - const receipt2 = await tx2.wait() - const logs2 = await registry.queryFilter(filter, receipt2?.blockHash) - const [adapterId2] = logs2[0].args - - expect(adapterId1).to.not.equal(adapterId2) - }) - - it('should revert if not authorized', async function () { - const [, developer, otherAccount] = await ethers.getSigners() - - const { accessManagementAddress, accessManagement } = await loadFixture( - deployAccessManagementFixture - ) - - const { registry, registryAddress } = await loadFixture( - deployRegistryFixture.bind(this, accessManagementAddress) - ) - - // grant role to developer - await accessManagement.grantRole(DEVELOPER_ROLE, developer.address, 0n) - - // grant role to developer to create adapter - await accessManagement.setTargetFunctionRole( - registryAddress, - [registry.interface.getFunction('createAdapter').selector], - DEVELOPER_ROLE - ) - - // create adapter - const adapterType = VAULT_V1 - const adapterAddress = ethers.ZeroAddress - await expect( - registry.connect(otherAccount).createAdapter(adapterType, adapterAddress) - ).to.be.revertedWithCustomError(registry, 'AccessManagedUnauthorized') - }) -}) diff --git a/test/registry/fixture.ts b/test/registry/fixture.ts deleted file mode 100644 index 49074fe..0000000 --- a/test/registry/fixture.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ethers } from 'hardhat' - -export const VAULT_V1 = ethers.keccak256(ethers.toUtf8Bytes('VAULT.V1')) - -export async function deployRegistryFixture(accessManagementAddress: string) { - const [owner, developer] = await ethers.getSigners() - - const Registry = await ethers.getContractFactory('Registry') - const registry = await Registry.deploy(accessManagementAddress) - const registryAddress = await registry.getAddress() - - return { registry, owner, developer, registryAddress } -}