Skip to content

Commit ab250a7

Browse files
Plugin refactor (#302)
* refactor plugin extensions * tests * forge updates * Update comments for IMap * Fix hardhat config * Update Plugin struct variable names * docs update * fix tests * rename Map -> PluginMap * revert addPlugin if default plugin exists in PluginMap * include PluginMap in scope of updatePlugin * Reorder Plugin struct vars * rename test getAllRegistered -> getAllPlugins * cleanup Router * update Router tests Co-authored-by: Krishang <[email protected]>
1 parent 52dff99 commit ab250a7

39 files changed

+2312
-1091
lines changed

contracts/extension/interface/plugin/IMap.sol

Lines changed: 0 additions & 44 deletions
This file was deleted.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.11;
3+
4+
interface IPluginMap {
5+
/**
6+
* @notice An interface to describe a plug-in.
7+
*
8+
* @param functionSelector 4-byte function selector.
9+
* @param functionSignature Function representation as a string. E.g. "transfer(address,address,uint256)"
10+
* @param pluginAddress Address of the contract containing the function.
11+
*/
12+
struct Plugin {
13+
bytes4 functionSelector;
14+
string functionSignature;
15+
address pluginAddress;
16+
}
17+
18+
/// @dev Emitted when a function selector is mapped to a particular plug-in smart contract, during construction of Map.
19+
event PluginSet(bytes4 indexed functionSelector, string indexed functionSignature, address indexed pluginAddress);
20+
21+
/// @dev Returns the plug-in contract for a given function.
22+
function getPluginForFunction(bytes4 functionSelector) external view returns (address);
23+
24+
/// @dev Returns all functions that are mapped to the given plug-in contract.
25+
function getAllFunctionsOfPlugin(address pluginAddress) external view returns (bytes4[] memory);
26+
27+
/// @dev Returns all plug-ins known by Map.
28+
function getAllPlugins() external view returns (Plugin[] memory);
29+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.11;
3+
4+
import "./IPluginMap.sol";
5+
6+
interface IRouter is IPluginMap {
7+
/// @dev Emitted when a functionality is added, or plugged-in.
8+
event PluginAdded(bytes4 indexed functionSelector, address indexed pluginAddress);
9+
10+
/// @dev Emitted when a functionality is updated or overridden.
11+
event PluginUpdated(
12+
bytes4 indexed functionSelector,
13+
address indexed oldPluginAddress,
14+
address indexed newPluginAddress
15+
);
16+
17+
/// @dev Emitted when a functionality is removed.
18+
event PluginRemoved(bytes4 indexed functionSelector, address indexed pluginAddress);
19+
20+
/// @dev Add a new plugin to the contract.
21+
function addPlugin(Plugin memory plugin) external;
22+
23+
/// @dev Update / override an existing plugin.
24+
function updatePlugin(Plugin memory plugin) external;
25+
26+
/// @dev Remove an existing plugin from the contract.
27+
function removePlugin(bytes4 functionSelector) external;
28+
}

contracts/extension/plugin/Map.sol

Lines changed: 0 additions & 131 deletions
This file was deleted.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import "../interface/plugin/IPluginMap.sol";
5+
import "../../openzeppelin-presets/utils/EnumerableSet.sol";
6+
7+
contract PluginMap is IPluginMap {
8+
using EnumerableSet for EnumerableSet.Bytes32Set;
9+
10+
EnumerableSet.Bytes32Set private allSelectors;
11+
12+
mapping(address => EnumerableSet.Bytes32Set) private selectorsForPlugin;
13+
mapping(bytes4 => Plugin) private pluginForSelector;
14+
15+
/*///////////////////////////////////////////////////////////////
16+
Constructor + initializer logic
17+
//////////////////////////////////////////////////////////////*/
18+
19+
constructor(Plugin[] memory _pluginsToAdd) {
20+
uint256 len = _pluginsToAdd.length;
21+
for (uint256 i = 0; i < len; i += 1) {
22+
_setPlugin(_pluginsToAdd[i]);
23+
}
24+
}
25+
26+
/*///////////////////////////////////////////////////////////////
27+
View functions
28+
//////////////////////////////////////////////////////////////*/
29+
30+
/// @dev View address of the plugged-in functionality contract for a given function signature.
31+
function getPluginForFunction(bytes4 _selector) public view returns (address) {
32+
address _pluginAddress = pluginForSelector[_selector].pluginAddress;
33+
require(_pluginAddress != address(0), "Map: No plugin available for selector");
34+
35+
return _pluginAddress;
36+
}
37+
38+
/// @dev View all funtionality as list of function signatures.
39+
function getAllFunctionsOfPlugin(address _pluginAddress) external view returns (bytes4[] memory registered) {
40+
uint256 len = selectorsForPlugin[_pluginAddress].length();
41+
registered = new bytes4[](len);
42+
43+
for (uint256 i = 0; i < len; i += 1) {
44+
registered[i] = bytes4(selectorsForPlugin[_pluginAddress].at(i));
45+
}
46+
}
47+
48+
/// @dev View all funtionality existing on the contract.
49+
function getAllPlugins() external view returns (Plugin[] memory _plugins) {
50+
uint256 len = allSelectors.length();
51+
_plugins = new Plugin[](len);
52+
53+
for (uint256 i = 0; i < len; i += 1) {
54+
bytes4 selector = bytes4(allSelectors.at(i));
55+
_plugins[i] = pluginForSelector[selector];
56+
}
57+
}
58+
59+
/*///////////////////////////////////////////////////////////////
60+
Internal functions
61+
//////////////////////////////////////////////////////////////*/
62+
63+
/// @dev Add functionality to the contract.
64+
function _setPlugin(Plugin memory _plugin) internal {
65+
require(allSelectors.add(bytes32(_plugin.functionSelector)), "Map: Selector exists");
66+
require(
67+
_plugin.functionSelector == bytes4(keccak256(abi.encodePacked(_plugin.functionSignature))),
68+
"Map: Incorrect selector"
69+
);
70+
71+
pluginForSelector[_plugin.functionSelector] = _plugin;
72+
selectorsForPlugin[_plugin.pluginAddress].add(bytes32(_plugin.functionSelector));
73+
74+
emit PluginSet(_plugin.functionSelector, _plugin.functionSignature, _plugin.pluginAddress);
75+
}
76+
}

0 commit comments

Comments
 (0)