@@ -9,6 +9,32 @@ import { ResolverRecord, ModuleRecord, ResolverUID } from "../DataTypes.sol";
9
9
import { ResolverManager } from "./ResolverManager.sol " ;
10
10
import { IRegistry } from "../IRegistry.sol " ;
11
11
12
+ /**
13
+ * In order to separate msg.sender context from registry,
14
+ * interactions with external Factories are done with this Trampoline contract.
15
+ */
16
+ contract FactoryTrampoline {
17
+ error FactoryCallFailed (address factory );
18
+
19
+ /**
20
+ * @param factory the address of the factory to call
21
+ * @param callOnFactory the call data to send to the factory
22
+ * @return moduleAddress the moduleAddress that was returned by the
23
+ */
24
+ function deployViaFactory (address factory , bytes memory callOnFactory ) external payable returns (address moduleAddress ) {
25
+ // call external factory to deploy module
26
+ bool success;
27
+ /* solhint-disable no-inline-assembly */
28
+ assembly ("memory-safe" ) {
29
+ success := call (gas (), factory, callvalue (), add (callOnFactory, 0x20 ), mload (callOnFactory), 0 , 32 )
30
+ moduleAddress := mload (0 )
31
+ }
32
+ if (! success) {
33
+ revert FactoryCallFailed (factory);
34
+ }
35
+ }
36
+ }
37
+
12
38
/**
13
39
* In order for Attesters to be able to make statements about a Module, the Module first needs to be registered on the Registry.
14
40
* This can be done as part of or after Module deployment. On registration, every module is tied to a
@@ -34,29 +60,40 @@ abstract contract ModuleManager is IRegistry, ResolverManager {
34
60
35
61
mapping (address moduleAddress = > ModuleRecord moduleRecord ) internal $moduleAddrToRecords;
36
62
63
+ FactoryTrampoline private immutable FACTORY_TRAMPOLINE;
64
+
65
+ constructor () {
66
+ FACTORY_TRAMPOLINE = new FactoryTrampoline ();
67
+ }
68
+
37
69
/**
38
70
* @inheritdoc IRegistry
39
71
*/
40
72
function deployModule (
41
73
bytes32 salt ,
42
74
ResolverUID resolverUID ,
43
75
bytes calldata initCode ,
44
- bytes calldata metadata
76
+ bytes calldata metadata ,
77
+ bytes calldata resolverContext
45
78
)
46
79
external
47
80
payable
48
81
returns (address moduleAddress )
49
82
{
50
83
ResolverRecord storage $resolver = $resolvers[resolverUID];
51
- if ($resolver.resolverOwner == ZERO_ADDRESS) revert InvalidResolver ($resolver.resolver );
84
+ if ($resolver.resolverOwner == ZERO_ADDRESS) revert InvalidResolverUID (resolverUID );
52
85
53
86
moduleAddress = initCode.deploy (salt);
54
87
// _storeModuleRecord() will check if module is already registered,
55
88
// which should prevent reentry to any deploy function
56
89
ModuleRecord memory record =
57
90
_storeModuleRecord ({ moduleAddress: moduleAddress, sender: msg .sender , resolverUID: resolverUID, metadata: metadata });
58
91
59
- record.requireExternalResolverOnModuleRegistration ({ moduleAddress: moduleAddress, $resolver: $resolver });
92
+ record.requireExternalResolverOnModuleRegistration ({
93
+ moduleAddress: moduleAddress,
94
+ $resolver: $resolver,
95
+ resolverContext: resolverContext
96
+ });
60
97
}
61
98
62
99
/**
@@ -69,11 +106,18 @@ abstract contract ModuleManager is IRegistry, ResolverManager {
69
106
/**
70
107
* @inheritdoc IRegistry
71
108
*/
72
- function registerModule (ResolverUID resolverUID , address moduleAddress , bytes calldata metadata ) external {
109
+ function registerModule (
110
+ ResolverUID resolverUID ,
111
+ address moduleAddress ,
112
+ bytes calldata metadata ,
113
+ bytes calldata resolverContext
114
+ )
115
+ external
116
+ {
73
117
ResolverRecord storage $resolver = $resolvers[resolverUID];
74
118
75
119
// ensure that non-zero resolverUID was provided
76
- if ($resolver.resolverOwner == ZERO_ADDRESS) revert InvalidResolver ($resolver.resolver );
120
+ if ($resolver.resolverOwner == ZERO_ADDRESS) revert InvalidResolverUID (resolverUID );
77
121
78
122
ModuleRecord memory record = _storeModuleRecord ({
79
123
moduleAddress: moduleAddress,
@@ -83,7 +127,11 @@ abstract contract ModuleManager is IRegistry, ResolverManager {
83
127
});
84
128
85
129
// resolve module registration
86
- record.requireExternalResolverOnModuleRegistration ({ moduleAddress: moduleAddress, $resolver: $resolver });
130
+ record.requireExternalResolverOnModuleRegistration ({
131
+ moduleAddress: moduleAddress,
132
+ $resolver: $resolver,
133
+ resolverContext: resolverContext
134
+ });
87
135
}
88
136
89
137
/**
@@ -93,7 +141,8 @@ abstract contract ModuleManager is IRegistry, ResolverManager {
93
141
address factory ,
94
142
bytes calldata callOnFactory ,
95
143
bytes calldata metadata ,
96
- ResolverUID resolverUID
144
+ ResolverUID resolverUID ,
145
+ bytes calldata resolverContext
97
146
)
98
147
external
99
148
payable
@@ -105,11 +154,9 @@ abstract contract ModuleManager is IRegistry, ResolverManager {
105
154
// prevent someone from calling a registry function pretending its a factory
106
155
if (factory == address (this )) revert FactoryCallFailed (factory);
107
156
108
- // call external factory to deploy module
109
- (bool ok , bytes memory returnData ) = factory.call { value: msg .value }(callOnFactory);
110
- if (! ok) revert FactoryCallFailed (factory);
111
-
112
- moduleAddress = abi.decode (returnData, (address ));
157
+ // Call the factory via the trampoline contract. This will make sure that there is msg.sender separation
158
+ // Making "raw" calls to user supplied addresses could create security issues.
159
+ moduleAddress = FACTORY_TRAMPOLINE.deployViaFactory { value: msg .value }({ factory: factory, callOnFactory: callOnFactory });
113
160
114
161
ModuleRecord memory record = _storeModuleRecord ({
115
162
moduleAddress: moduleAddress,
@@ -118,7 +165,11 @@ abstract contract ModuleManager is IRegistry, ResolverManager {
118
165
metadata: metadata
119
166
});
120
167
121
- record.requireExternalResolverOnModuleRegistration ({ moduleAddress: moduleAddress, $resolver: $resolver });
168
+ record.requireExternalResolverOnModuleRegistration ({
169
+ moduleAddress: moduleAddress,
170
+ $resolver: $resolver,
171
+ resolverContext: resolverContext
172
+ });
122
173
}
123
174
124
175
/**
0 commit comments