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 563c09b..88b164f 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, IERC7484} 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; @@ -64,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( @@ -118,6 +129,7 @@ contract MMSAFacet is override onlyWhenUnlocked withHook + withRegistry(msg.sender, EXECUTOR_MODULE_TYPE) returns (bytes[] memory returnData) { if (!_isExecutorInstalled(msg.sender)) { @@ -175,7 +187,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/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, diff --git a/contracts/facets/mmsa/utils/RegistryAdapter.sol b/contracts/facets/mmsa/utils/RegistryAdapter.sol new file mode 100644 index 0000000..1dbc119 --- /dev/null +++ b/contracts/facets/mmsa/utils/RegistryAdapter.sol @@ -0,0 +1,50 @@ +// 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(address(this), 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 + if (address(registry) != address(0)) { + 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 {