Skip to content

Commit 4709d1e

Browse files
authored
Plugin updates (#297)
* plugin updates * fix issue, code cleanup
1 parent 6179287 commit 4709d1e

File tree

11 files changed

+278
-280
lines changed

11 files changed

+278
-280
lines changed

contracts/extension/interface/plugin/IEntrypointOverrideable.sol

-13
This file was deleted.

contracts/extension/interface/plugin/IMap.sol

+33-6
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,43 @@
22
pragma solidity ^0.8.11;
33

44
interface IMap {
5-
struct ExtensionMap {
5+
/**
6+
* @notice An interface to describe a plug-in functionality.
7+
*
8+
* @param selector 4-byte function signature.
9+
* @param pluginAddress Address of the contract containing the function.
10+
* @param functionString Function representation as a string. E.g. "transfer(address,address,uint256)"
11+
*/
12+
struct Plugin {
613
bytes4 selector;
7-
address extension;
14+
address pluginAddress;
15+
string functionString;
816
}
917

10-
event ExtensionRegistered(bytes4 indexed selector, address indexed extension);
18+
/// @dev Emitted when a functionality is added, or plugged-in.
19+
event PluginAdded(bytes4 indexed selector, address indexed pluginAddress);
1120

12-
function getExtensionForFunction(bytes4 _selector) external view returns (address);
21+
/// @dev Emitted when a functionality is updated or overridden.
22+
event PluginUpdated(bytes4 indexed selector, address indexed oldPluginAddress, address indexed newPluginAddress);
1323

14-
function getAllFunctionsOfExtension(address _extension) external view returns (bytes4[] memory registered);
24+
/// @dev Emitted when a functionality is removed.
25+
event PluginRemoved(bytes4 indexed selector, address indexed pluginAddress);
1526

16-
function getAllRegistered() external view returns (ExtensionMap[] memory registered);
27+
/// @dev Add functionality to the contract.
28+
function addPlugin(Plugin memory _plugin) external;
29+
30+
/// @dev Update or override existing functionality.
31+
function updatePlugin(Plugin memory _plugin) external;
32+
33+
/// @dev Remove existing functionality from the contract.
34+
function removePlugin(bytes4 _selector) external;
35+
36+
/// @dev View address of the plugged-in functionality contract for a given function signature.
37+
function getPluginForFunction(bytes4 _selector) external view returns (address);
38+
39+
/// @dev View all funtionality as list of function signatures.
40+
function getAllFunctionsOfPlugin(address _pluginAddress) external view returns (bytes4[] memory);
41+
42+
/// @dev View all funtionality existing on the contract.
43+
function getAllPlugins() external view returns (Plugin[] memory);
1744
}

contracts/extension/plugin/EntrypointOverrideable.sol

-120
This file was deleted.

contracts/extension/plugin/Map.sol

+95-27
Original file line numberDiff line numberDiff line change
@@ -3,61 +3,129 @@ pragma solidity ^0.8.0;
33

44
import "../interface/plugin/IMap.sol";
55

6-
import "../Multicall.sol";
76
import "../../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
}

contracts/extension/plugin/Entrypoint.sol contracts/extension/plugin/Router.sol

+13-8
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,34 @@ pragma solidity ^0.8.0;
33

44
import "../interface/plugin/IMap.sol";
55
import "../../extension/Multicall.sol";
6+
import "../../eip/ERC165.sol";
7+
import "./Map.sol";
68

7-
contract Entrypoint is Multicall {
9+
abstract contract Router is Multicall, Map, ERC165 {
810
/*///////////////////////////////////////////////////////////////
9-
State variables
11+
Constructor + initializer logic
1012
//////////////////////////////////////////////////////////////*/
1113

12-
address public immutable functionMap;
14+
constructor(Plugin[] memory _pluginsToAdd) Map(_pluginsToAdd) {}
1315

1416
/*///////////////////////////////////////////////////////////////
15-
Constructor + initializer logic
17+
ERC 165
1618
//////////////////////////////////////////////////////////////*/
1719

18-
constructor(address _functionMap) {
19-
functionMap = _functionMap;
20+
/**
21+
* @dev See {IERC165-supportsInterface}.
22+
*/
23+
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
24+
return interfaceId == type(IMap).interfaceId || super.supportsInterface(interfaceId);
2025
}
2126

2227
/*///////////////////////////////////////////////////////////////
2328
Generic contract logic
2429
//////////////////////////////////////////////////////////////*/
2530

2631
fallback() external payable virtual {
27-
address extension = IMap(functionMap).getExtensionForFunction(msg.sig);
28-
_delegate(extension);
32+
address _pluginAddress = getPluginForFunction(msg.sig);
33+
_delegate(_pluginAddress);
2934
}
3035

3136
receive() external payable {}

0 commit comments

Comments
 (0)