@@ -3,61 +3,129 @@ pragma solidity ^0.8.0;
3
3
4
4
import "../interface/plugin/IMap.sol " ;
5
5
6
- import "../Multicall.sol " ;
7
6
import "../../openzeppelin-presets/utils/EnumerableSet.sol " ;
8
7
9
- /**
10
- * TODO:
11
- * - Remove OZ EnumerableSet external dependency.
12
- */
13
-
14
- contract Map is IMap , Multicall {
8
+ abstract contract Map is IMap {
15
9
using EnumerableSet for EnumerableSet.Bytes32Set;
16
10
17
11
EnumerableSet.Bytes32Set private allSelectors;
18
12
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
+ //////////////////////////////////////////////////////////////*/
21
19
22
- constructor (ExtensionMap [] memory _extensionsToRegister ) {
23
- uint256 len = _extensionsToRegister .length ;
20
+ constructor (Plugin [] memory _pluginsToAdd ) {
21
+ uint256 len = _pluginsToAdd .length ;
24
22
for (uint256 i = 0 ; i < len; i += 1 ) {
25
- _setExtensions (_extensionsToRegister [i]. selector , _extensionsToRegister[i].extension );
23
+ _addPlugin (_pluginsToAdd [i]);
26
24
}
27
25
}
28
26
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 " );
31
41
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 " );
34
48
35
- emit ExtensionRegistered (_selector, _extension );
49
+ _removePlugin (_selector);
36
50
}
37
51
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 " );
41
60
42
- return ext ;
61
+ return _pluginAddress ;
43
62
}
44
63
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 ();
47
67
registered = new bytes4 [](len);
48
68
49
69
for (uint256 i = 0 ; i < len; i += 1 ) {
50
- registered[i] = bytes4 (selectorsForExtension[_extension ].at (i));
70
+ registered[i] = bytes4 (selectorsForPlugin[_pluginAddress ].at (i));
51
71
}
52
72
}
53
73
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 ) {
55
76
uint256 len = allSelectors.length ();
56
- functionExtensionPairs = new ExtensionMap [](len);
77
+ _plugins = new Plugin [](len);
57
78
58
79
for (uint256 i = 0 ; i < len; i += 1 ) {
59
80
bytes4 selector = bytes4 (allSelectors.at (i));
60
- functionExtensionPairs [i] = ExtensionMap (selector, extension [selector]) ;
81
+ _plugins [i] = pluginForSelector [selector];
61
82
}
62
83
}
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 );
63
131
}
0 commit comments