Skip to content

Commit 267383e

Browse files
authored
Add EntrypointOverrideable: opt-in override an extension for a function. (#293)
1 parent 4a7c7fa commit 267383e

File tree

6 files changed

+407
-0
lines changed

6 files changed

+407
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
interface IEntrypointOverrideable {
5+
struct ExtensionMap {
6+
bytes4 selector;
7+
address extension;
8+
}
9+
10+
function overrideExtensionForFunction(bytes4 _selector, address _extension) external;
11+
12+
function getAllOverriden() external view returns (ExtensionMap[] memory functionExtensionPairs);
13+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import "../interface/plugin/IMap.sol";
5+
import "../interface/plugin/IEntrypointOverrideable.sol";
6+
import "../../extension/Multicall.sol";
7+
import "../../openzeppelin-presets/utils/EnumerableSet.sol";
8+
9+
library EntrypointOverrideableStorage {
10+
bytes32 public constant ENTRYPOINT_OVERRIDEABLE_STORAGE_POSITION = keccak256("entrypoint.overrideable.storage");
11+
12+
struct Data {
13+
EnumerableSet.Bytes32Set functions;
14+
mapping(bytes4 => address) extensionOverride;
15+
}
16+
17+
function entrypointStorage() internal pure returns (Data storage entrypointData) {
18+
bytes32 position = ENTRYPOINT_OVERRIDEABLE_STORAGE_POSITION;
19+
assembly {
20+
entrypointData.slot := position
21+
}
22+
}
23+
}
24+
25+
abstract contract EntrypointOverrideable is Multicall, IEntrypointOverrideable {
26+
using EnumerableSet for EnumerableSet.Bytes32Set;
27+
28+
/*///////////////////////////////////////////////////////////////
29+
State variables
30+
//////////////////////////////////////////////////////////////*/
31+
32+
address public immutable functionMap;
33+
34+
/*///////////////////////////////////////////////////////////////
35+
Constructor + initializer logic
36+
//////////////////////////////////////////////////////////////*/
37+
38+
constructor(address _functionMap) {
39+
functionMap = _functionMap;
40+
}
41+
42+
/*///////////////////////////////////////////////////////////////
43+
Generic contract logic
44+
//////////////////////////////////////////////////////////////*/
45+
46+
fallback() external payable virtual {
47+
address extension = _getExtensionOverride(msg.sig);
48+
if (extension == address(0)) {
49+
extension = IMap(functionMap).getExtensionForFunction(msg.sig);
50+
}
51+
52+
_delegate(extension);
53+
}
54+
55+
receive() external payable {}
56+
57+
function _delegate(address implementation) internal virtual {
58+
assembly {
59+
// Copy msg.data. We take full control of memory in this inline assembly
60+
// block because it will not return to Solidity code. We overwrite the
61+
// Solidity scratch pad at memory position 0.
62+
calldatacopy(0, 0, calldatasize())
63+
64+
// Call the implementation.
65+
// out and outsize are 0 because we don't know the size yet.
66+
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
67+
68+
// Copy the returned data.
69+
returndatacopy(0, 0, returndatasize())
70+
71+
switch result
72+
// delegatecall returns 0 on error.
73+
case 0 {
74+
revert(0, returndatasize())
75+
}
76+
default {
77+
return(0, returndatasize())
78+
}
79+
}
80+
}
81+
82+
/*///////////////////////////////////////////////////////////////
83+
External functions
84+
//////////////////////////////////////////////////////////////*/
85+
86+
function overrideExtensionForFunction(bytes4 _selector, address _extension) external {
87+
require(_canOverrideExtensions(), "Entrypoint: cannot override extensions.");
88+
89+
EntrypointOverrideableStorage.Data storage data = EntrypointOverrideableStorage.entrypointStorage();
90+
data.extensionOverride[_selector] = _extension;
91+
92+
if (_extension != address(0)) {
93+
data.functions.add(bytes32(_selector));
94+
} else {
95+
data.functions.remove(bytes32(_selector));
96+
}
97+
}
98+
99+
function getAllOverriden() external view returns (ExtensionMap[] memory functionExtensionPairs) {
100+
EntrypointOverrideableStorage.Data storage data = EntrypointOverrideableStorage.entrypointStorage();
101+
uint256 len = data.functions.length();
102+
functionExtensionPairs = new ExtensionMap[](len);
103+
104+
for (uint256 i = 0; i < len; i += 1) {
105+
bytes4 selector = bytes4(data.functions.at(i));
106+
functionExtensionPairs[i] = ExtensionMap(selector, data.extensionOverride[selector]);
107+
}
108+
}
109+
110+
/*///////////////////////////////////////////////////////////////
111+
Internal functions
112+
//////////////////////////////////////////////////////////////*/
113+
114+
function _getExtensionOverride(bytes4 _selector) internal view returns (address) {
115+
EntrypointOverrideableStorage.Data storage data = EntrypointOverrideableStorage.entrypointStorage();
116+
return data.extensionOverride[_selector];
117+
}
118+
119+
function _canOverrideExtensions() internal view virtual returns (bool);
120+
}

docs/EntrypointOverrideable.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# EntrypointOverrideable
2+
3+
4+
5+
6+
7+
8+
9+
10+
11+
## Methods
12+
13+
### functionMap
14+
15+
```solidity
16+
function functionMap() external view returns (address)
17+
```
18+
19+
20+
21+
22+
23+
24+
#### Returns
25+
26+
| Name | Type | Description |
27+
|---|---|---|
28+
| _0 | address | undefined |
29+
30+
### getAllOverriden
31+
32+
```solidity
33+
function getAllOverriden() external view returns (struct IEntrypointOverrideable.ExtensionMap[] functionExtensionPairs)
34+
```
35+
36+
37+
38+
39+
40+
41+
#### Returns
42+
43+
| Name | Type | Description |
44+
|---|---|---|
45+
| functionExtensionPairs | IEntrypointOverrideable.ExtensionMap[] | undefined |
46+
47+
### multicall
48+
49+
```solidity
50+
function multicall(bytes[] data) external nonpayable returns (bytes[] results)
51+
```
52+
53+
Receives and executes a batch of function calls on this contract.
54+
55+
*Receives and executes a batch of function calls on this contract.*
56+
57+
#### Parameters
58+
59+
| Name | Type | Description |
60+
|---|---|---|
61+
| data | bytes[] | The bytes data that makes up the batch of function calls to execute. |
62+
63+
#### Returns
64+
65+
| Name | Type | Description |
66+
|---|---|---|
67+
| results | bytes[] | The bytes data that makes up the result of the batch of function calls executed. |
68+
69+
### overrideExtensionForFunction
70+
71+
```solidity
72+
function overrideExtensionForFunction(bytes4 _selector, address _extension) external nonpayable
73+
```
74+
75+
76+
77+
78+
79+
#### Parameters
80+
81+
| Name | Type | Description |
82+
|---|---|---|
83+
| _selector | bytes4 | undefined |
84+
| _extension | address | undefined |
85+
86+
87+
88+

docs/EntrypointOverrideableStorage.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# EntrypointOverrideableStorage
2+
3+
4+
5+
6+
7+
8+
9+
10+
11+
## Methods
12+
13+
### ENTRYPOINT_OVERRIDEABLE_STORAGE_POSITION
14+
15+
```solidity
16+
function ENTRYPOINT_OVERRIDEABLE_STORAGE_POSITION() external view returns (bytes32)
17+
```
18+
19+
20+
21+
22+
23+
24+
#### Returns
25+
26+
| Name | Type | Description |
27+
|---|---|---|
28+
| _0 | bytes32 | undefined |
29+
30+
31+
32+

docs/IEntrypointOverrideable.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# IEntrypointOverrideable
2+
3+
4+
5+
6+
7+
8+
9+
10+
11+
## Methods
12+
13+
### getAllOverriden
14+
15+
```solidity
16+
function getAllOverriden() external view returns (struct IEntrypointOverrideable.ExtensionMap[] functionExtensionPairs)
17+
```
18+
19+
20+
21+
22+
23+
24+
#### Returns
25+
26+
| Name | Type | Description |
27+
|---|---|---|
28+
| functionExtensionPairs | IEntrypointOverrideable.ExtensionMap[] | undefined |
29+
30+
### overrideExtensionForFunction
31+
32+
```solidity
33+
function overrideExtensionForFunction(bytes4 _selector, address _extension) external nonpayable
34+
```
35+
36+
37+
38+
39+
40+
#### Parameters
41+
42+
| Name | Type | Description |
43+
|---|---|---|
44+
| _selector | bytes4 | undefined |
45+
| _extension | address | undefined |
46+
47+
48+
49+

0 commit comments

Comments
 (0)