@@ -3,61 +3,129 @@ pragma solidity ^0.8.0;
33
44import "../interface/plugin/IMap.sol " ;
55
6- import "../Multicall.sol " ;
76import "../../openzeppelin-presets/utils/EnumerableSet.sol " ;
87
9- /**
10- * TODO:
11- * - Remove OZ EnumerableSet external dependency.
12- */
13-
14- contract Map is IMap , Multicall {
8+ abstract contract Map is IMap {
159 using EnumerableSet for EnumerableSet.Bytes32Set;
1610
1711 EnumerableSet.Bytes32Set private allSelectors;
1812
19- mapping (address => EnumerableSet.Bytes32Set) private selectorsForExtension;
20- mapping (bytes4 => address ) private extension;
13+ mapping (address => EnumerableSet.Bytes32Set) private selectorsForPlugin;
14+ mapping (bytes4 => Plugin) private pluginForSelector;
15+
16+ /*///////////////////////////////////////////////////////////////
17+ Constructor + initializer logic
18+ //////////////////////////////////////////////////////////////*/
2119
22- constructor (ExtensionMap [] memory _extensionsToRegister ) {
23- uint256 len = _extensionsToRegister .length ;
20+ constructor (Plugin [] memory _pluginsToAdd ) {
21+ uint256 len = _pluginsToAdd .length ;
2422 for (uint256 i = 0 ; i < len; i += 1 ) {
25- _setExtensions (_extensionsToRegister [i]. selector , _extensionsToRegister[i].extension );
23+ _addPlugin (_pluginsToAdd [i]);
2624 }
2725 }
2826
29- function _setExtensions (bytes4 _selector , address _extension ) internal {
30- require (allSelectors.add (bytes32 (_selector)), "REGISTERED " );
27+ /*///////////////////////////////////////////////////////////////
28+ External functions
29+ //////////////////////////////////////////////////////////////*/
30+
31+ /// @dev Add functionality to the contract.
32+ function addPlugin (Plugin memory _plugin ) external {
33+ require (_canSetPlugin (), "Map: Not authorized " );
34+
35+ _addPlugin (_plugin);
36+ }
37+
38+ /// @dev Update or override existing functionality.
39+ function updatePlugin (Plugin memory _plugin ) external {
40+ require (_canSetPlugin (), "Map: Not authorized " );
3141
32- extension[_selector] = _extension;
33- selectorsForExtension[_extension].add (bytes32 (_selector));
42+ _updatePlugin (_plugin);
43+ }
44+
45+ /// @dev Remove existing functionality from the contract.
46+ function removePlugin (bytes4 _selector ) external {
47+ require (_canSetPlugin (), "Map: Not authorized " );
3448
35- emit ExtensionRegistered (_selector, _extension );
49+ _removePlugin (_selector);
3650 }
3751
38- function getExtensionForFunction (bytes4 _selector ) external view returns (address ) {
39- address ext = extension[_selector];
40- require (ext != address (0 ), "No extension available for selector. " );
52+ /*///////////////////////////////////////////////////////////////
53+ View functions
54+ //////////////////////////////////////////////////////////////*/
55+
56+ /// @dev View address of the plugged-in functionality contract for a given function signature.
57+ function getPluginForFunction (bytes4 _selector ) public view returns (address ) {
58+ address _pluginAddress = pluginForSelector[_selector].pluginAddress;
59+ require (_pluginAddress != address (0 ), "Map: No plugin available for selector " );
4160
42- return ext ;
61+ return _pluginAddress ;
4362 }
4463
45- function getAllFunctionsOfExtension (address _extension ) external view returns (bytes4 [] memory registered ) {
46- uint256 len = selectorsForExtension[_extension].length ();
64+ /// @dev View all funtionality as list of function signatures.
65+ function getAllFunctionsOfPlugin (address _pluginAddress ) external view returns (bytes4 [] memory registered ) {
66+ uint256 len = selectorsForPlugin[_pluginAddress].length ();
4767 registered = new bytes4 [](len);
4868
4969 for (uint256 i = 0 ; i < len; i += 1 ) {
50- registered[i] = bytes4 (selectorsForExtension[_extension ].at (i));
70+ registered[i] = bytes4 (selectorsForPlugin[_pluginAddress ].at (i));
5171 }
5272 }
5373
54- function getAllRegistered () external view returns (ExtensionMap[] memory functionExtensionPairs ) {
74+ /// @dev View all funtionality existing on the contract.
75+ function getAllPlugins () external view returns (Plugin[] memory _plugins ) {
5576 uint256 len = allSelectors.length ();
56- functionExtensionPairs = new ExtensionMap [](len);
77+ _plugins = new Plugin [](len);
5778
5879 for (uint256 i = 0 ; i < len; i += 1 ) {
5980 bytes4 selector = bytes4 (allSelectors.at (i));
60- functionExtensionPairs [i] = ExtensionMap (selector, extension [selector]) ;
81+ _plugins [i] = pluginForSelector [selector];
6182 }
6283 }
84+
85+ /*///////////////////////////////////////////////////////////////
86+ Internal functions
87+ //////////////////////////////////////////////////////////////*/
88+
89+ /// @dev Add functionality to the contract.
90+ function _addPlugin (Plugin memory _plugin ) internal {
91+ require (allSelectors.add (bytes32 (_plugin.selector )), "Map: Selector exists " );
92+ require (
93+ _plugin.selector == bytes4 (keccak256 (abi.encodePacked (_plugin.functionString))),
94+ "Map: Incorrect selector "
95+ );
96+
97+ pluginForSelector[_plugin.selector ] = _plugin;
98+ selectorsForPlugin[_plugin.pluginAddress].add (bytes32 (_plugin.selector ));
99+
100+ emit PluginAdded (_plugin.selector , _plugin.pluginAddress);
101+ }
102+
103+ /// @dev Update or override existing functionality.
104+ function _updatePlugin (Plugin memory _plugin ) internal {
105+ address currentPlugin = getPluginForFunction (_plugin.selector );
106+ require (
107+ _plugin.selector == bytes4 (keccak256 (abi.encodePacked (_plugin.functionString))),
108+ "Map: Incorrect selector "
109+ );
110+
111+ pluginForSelector[_plugin.selector ] = _plugin;
112+ selectorsForPlugin[currentPlugin].remove (bytes32 (_plugin.selector ));
113+ selectorsForPlugin[_plugin.pluginAddress].add (bytes32 (_plugin.selector ));
114+
115+ emit PluginUpdated (_plugin.selector , currentPlugin, _plugin.pluginAddress);
116+ }
117+
118+ /// @dev Remove existing functionality from the contract.
119+ function _removePlugin (bytes4 _selector ) internal {
120+ address currentPlugin = getPluginForFunction (_selector);
121+
122+ delete pluginForSelector[_selector];
123+ allSelectors.remove (_selector);
124+ selectorsForPlugin[currentPlugin].remove (bytes32 (_selector));
125+
126+ emit PluginRemoved (_selector, currentPlugin);
127+ }
128+
129+ /// @dev Returns whether plug-in can be set in the given execution context.
130+ function _canSetPlugin () internal view virtual returns (bool );
63131}
0 commit comments