From 64129014d77403199a3502441b494040619707c9 Mon Sep 17 00:00:00 2001 From: kopy-kat Date: Wed, 4 Sep 2024 17:04:43 +0200 Subject: [PATCH 1/3] feat: implement registry adapter --- contracts/facets/mmsa/MMSAFacet.sol | 13 ++++- .../facets/mmsa/utils/RegistryAdapter.sol | 47 ++++++++++++++++ contracts/interfaces/ERC/IERC7484.sol | 54 +++++++++++++++++++ contracts/libraries/LibMMSAStorage.sol | 8 ++- 4 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 contracts/facets/mmsa/utils/RegistryAdapter.sol create mode 100644 contracts/interfaces/ERC/IERC7484.sol diff --git a/contracts/facets/mmsa/MMSAFacet.sol b/contracts/facets/mmsa/MMSAFacet.sol index 563c09b..94d36ab 100644 --- a/contracts/facets/mmsa/MMSAFacet.sol +++ b/contracts/facets/mmsa/MMSAFacet.sol @@ -17,6 +17,7 @@ import {IValidator} from "./interfaces/IValidator.sol"; import {IModule} from "./interfaces/IModule.sol"; import {IHook} from "./interfaces/IHook.sol"; import {IMMSAFacet} from "./interfaces/IMMSAFacet.sol"; +import {RegistryAdapter} from "./utils/RegistryAdapter.sol"; /** * @title MMSA(Minimal Modular Smart Account) Facet @@ -29,6 +30,7 @@ contract MMSAFacet is ModuleManager, ValidationManager, Executor, + RegistryAdapter, BarzStorage { using LibSentinelList for LibSentinelList.SentinelList; @@ -118,6 +120,7 @@ contract MMSAFacet is override onlyWhenUnlocked withHook + withRegistry(msg.sender, EXECUTOR_MODULE_TYPE) returns (bytes[] memory returnData) { if (!_isExecutorInstalled(msg.sender)) { @@ -175,7 +178,15 @@ contract MMSAFacet is uint256 _moduleTypeId, address _module, bytes calldata _initData - ) external payable override onlyEntryPointOrSelf onlyWhenUnlocked withHook { + ) + external + payable + override + onlyEntryPointOrSelf + onlyWhenUnlocked + withHook + withRegistry(_module, _moduleTypeId) + { if (!IModule(_module).isModuleType(_moduleTypeId)) { revert MMSAFacet__InvalidModule(_moduleTypeId, _module); } diff --git a/contracts/facets/mmsa/utils/RegistryAdapter.sol b/contracts/facets/mmsa/utils/RegistryAdapter.sol new file mode 100644 index 0000000..ee79bbd --- /dev/null +++ b/contracts/facets/mmsa/utils/RegistryAdapter.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IERC7484} from "../../../interfaces/ERC/IERC7484.sol"; +import {LibMMSAStorage} from "../../../libraries/LibMMSAStorage.sol"; + +/** + * IERC7484 Registry adapter. + * this feature is opt-in. The smart account owner can choose to use the registry and which + * attesters to trust. + * @author zeroknots.eth | rhinestone.wtf + */ +abstract contract RegistryAdapter { + event ERC7484RegistryConfigured(address registry); + + modifier withRegistry(address module, uint256 moduleType) { + _checkRegistry(module, moduleType); + _; + } + + /** + * Check on ERC7484 Registry, if suffcient attestations were made + * This will revert, if not succicient valid attestations are on the registry + */ + function _checkRegistry(address module, uint256 moduleType) internal view { + IERC7484 registry = LibMMSAStorage.mmsaStorage().registry; + if (address(registry) != address(0)) { + // this will revert if attestations / threshold are not met + registry.checkForAccount(msg.sender, module, moduleType); + } + } + + /** + * Configure ERC7484 Registry for Safe + */ + function _configureRegistry( + IERC7484 registry, + address[] calldata attesters, + uint8 threshold + ) internal { + // sstore value in any case, as this function may be used to disable the use of registry + LibMMSAStorage.mmsaStorage().registry = registry; + // registry is an opt in feature for barz. if set, configure trusted attesters + registry.trustAttesters(threshold, attesters); + emit ERC7484RegistryConfigured(address(registry)); + } +} diff --git a/contracts/interfaces/ERC/IERC7484.sol b/contracts/interfaces/ERC/IERC7484.sol new file mode 100644 index 0000000..e304253 --- /dev/null +++ b/contracts/interfaces/ERC/IERC7484.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IERC7484 { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with Registry internal attesters */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function check(address module) external view; + + function checkForAccount( + address smartAccount, + address module + ) external view; + + function check(address module, uint256 moduleType) external view; + + function checkForAccount( + address smartAccount, + address module, + uint256 moduleType + ) external view; + + /** + * Allows Smart Accounts - the end users of the registry - to appoint + * one or many attesters as trusted. + * @dev this function reverts, if address(0), or duplicates are provided in attesters[] + * + * @param threshold The minimum number of attestations required for a module + * to be considered secure. + * @param attesters The addresses of the attesters to be trusted. + */ + function trustAttesters( + uint8 threshold, + address[] calldata attesters + ) external; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* Check with external attester(s) */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function check( + address module, + address[] calldata attesters, + uint256 threshold + ) external view; + + function check( + address module, + uint256 moduleType, + address[] calldata attesters, + uint256 threshold + ) external view; +} diff --git a/contracts/libraries/LibMMSAStorage.sol b/contracts/libraries/LibMMSAStorage.sol index 55217cd..3196f27 100644 --- a/contracts/libraries/LibMMSAStorage.sol +++ b/contracts/libraries/LibMMSAStorage.sol @@ -2,14 +2,17 @@ pragma solidity 0.8.26; import {LibSentinelList} from "./LibSentinelList.sol"; +import {IERC7484} from "../interfaces/ERC/IERC7484.sol"; import {IHook} from "../facets/mmsa/interfaces/IHook.sol"; import {ISigner} from "../facets/mmsa/interfaces/ISigner.sol"; import {CallType, PermissionId, PassFlag, PolicyData} from "../facets/mmsa/utils/Types.sol"; struct FallbackHandler { - address handler; ///< The address of the fallback function handler. - CallType calltype; ///< The type of call this handler supports (e.g., static or delegatecall). + address handler; + ///< The address of the fallback function handler. + CallType calltype; } +///< The type of call this handler supports (e.g., static or delegatecall). struct PermissionConfig { PassFlag permissionFlag; @@ -24,6 +27,7 @@ struct MMSAStorage { mapping(PermissionId => PermissionConfig) permissionConfig; IHook hook; bool isInitialized; + IERC7484 registry; } library LibMMSAStorage { From 30aa8c803935822ba10983e5e7068c874f75bc50 Mon Sep 17 00:00:00 2001 From: kopy-kat Date: Wed, 4 Sep 2024 21:17:56 +0200 Subject: [PATCH 2/3] fix: account address and conditional trust attesters --- contracts/facets/mmsa/utils/RegistryAdapter.sol | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contracts/facets/mmsa/utils/RegistryAdapter.sol b/contracts/facets/mmsa/utils/RegistryAdapter.sol index ee79bbd..1dbc119 100644 --- a/contracts/facets/mmsa/utils/RegistryAdapter.sol +++ b/contracts/facets/mmsa/utils/RegistryAdapter.sol @@ -26,7 +26,7 @@ abstract contract RegistryAdapter { IERC7484 registry = LibMMSAStorage.mmsaStorage().registry; if (address(registry) != address(0)) { // this will revert if attestations / threshold are not met - registry.checkForAccount(msg.sender, module, moduleType); + registry.checkForAccount(address(this), module, moduleType); } } @@ -40,8 +40,11 @@ abstract contract RegistryAdapter { ) internal { // sstore value in any case, as this function may be used to disable the use of registry LibMMSAStorage.mmsaStorage().registry = registry; + // registry is an opt in feature for barz. if set, configure trusted attesters - registry.trustAttesters(threshold, attesters); + if (address(registry) != address(0)) { + registry.trustAttesters(threshold, attesters); + } emit ERC7484RegistryConfigured(address(registry)); } } From 17fca6a849f27e230a6e5a793385aed2a525a7ef Mon Sep 17 00:00:00 2001 From: kopy-kat Date: Mon, 9 Sep 2024 21:09:34 +0200 Subject: [PATCH 3/3] feat: add default registry and attesters --- contracts/facets/V2MigrationFacet.sol | 10 +++++++++- contracts/facets/mmsa/MMSAFacet.sol | 13 +++++++++++-- contracts/facets/mmsa/interfaces/IMMSAFacet.sol | 6 +++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/contracts/facets/V2MigrationFacet.sol b/contracts/facets/V2MigrationFacet.sol index d6497f1..0d8cf68 100644 --- a/contracts/facets/V2MigrationFacet.sol +++ b/contracts/facets/V2MigrationFacet.sol @@ -67,7 +67,15 @@ contract V2MigrationFacet is BarzStorage { }); IDiamondCut(address(this)).diamondCut(cut, address(0), ""); - IMMSAFacet(address(this)).initMMSA(); + + address[] memory attesters = new address[](2); + attesters[0] = 0x0000000000000000000000000000000000000000; // Todo: Trust attester + attesters[1] = 0x000000333034E9f539ce08819E12c1b8Cb29084d; // Rhinestone attester + IMMSAFacet(address(this)).initMMSA({ + registry: address(0x000000000069E2a187AEFFb852bF3cCdC95151B2), + attesters: attesters, + threshold: 1 + }); emit V2MigrationComplete(); } diff --git a/contracts/facets/mmsa/MMSAFacet.sol b/contracts/facets/mmsa/MMSAFacet.sol index 94d36ab..88b164f 100644 --- a/contracts/facets/mmsa/MMSAFacet.sol +++ b/contracts/facets/mmsa/MMSAFacet.sol @@ -17,7 +17,7 @@ import {IValidator} from "./interfaces/IValidator.sol"; import {IModule} from "./interfaces/IModule.sol"; import {IHook} from "./interfaces/IHook.sol"; import {IMMSAFacet} from "./interfaces/IMMSAFacet.sol"; -import {RegistryAdapter} from "./utils/RegistryAdapter.sol"; +import {RegistryAdapter, IERC7484} from "./utils/RegistryAdapter.sol"; /** * @title MMSA(Minimal Modular Smart Account) Facet @@ -66,8 +66,17 @@ contract MMSAFacet is } } - function initMMSA() external onlyEntryPointOrSelf { + function initMMSA( + address registry, + address[] calldata attesters, + uint8 threshold + ) external onlyEntryPointOrSelf { _initialize(); + _configureRegistry({ + registry: IERC7484(registry), + attesters: attesters, + threshold: threshold + }); } function validateUserOp( diff --git a/contracts/facets/mmsa/interfaces/IMMSAFacet.sol b/contracts/facets/mmsa/interfaces/IMMSAFacet.sol index bfd2d5b..06ddc4e 100644 --- a/contracts/facets/mmsa/interfaces/IMMSAFacet.sol +++ b/contracts/facets/mmsa/interfaces/IMMSAFacet.sol @@ -19,7 +19,11 @@ interface IMMSAFacet { event ModuleInstalled(uint256 moduleTypeId, address module); event ModuleUninstalled(uint256 moduleTypeId, address module); - function initMMSA() external; + function initMMSA( + address registry, + address[] memory attesters, + uint8 threshold + ) external; function installModule( uint256 moduleTypeId,