@@ -43,8 +43,8 @@ contract GasRelayHelper is GasRelayErrors {
43
43
/// @notice Namespace for key owner storage
44
44
bytes32 private immutable KEY_OWNER_NAMESPACE;
45
45
46
- /// @notice Namespace for abstracted caller transient storage
47
- bytes32 private immutable ABSTRACTED_CALLER_NAMESPACE ;
46
+ /// @notice Namespace for underlying caller transient storage
47
+ bytes32 private immutable UNDERLYING_CALLER_NAMESPACE ;
48
48
49
49
/// @notice Minimum gas required for task execution
50
50
uint256 internal constant _MIN_TASK_EXECUTION_GAS = 110_000 ;
@@ -70,6 +70,9 @@ contract GasRelayHelper is GasRelayErrors {
70
70
/// @notice Transient storage bit for tracking usage lock
71
71
bytes32 private constant _IN_USE_BIT = 0x0000000000000000000000020000000000000000000000000000000000000000 ;
72
72
73
+ /// @notice Transient storage bit for modifying usage lock
74
+ bytes32 private constant _NOT_IN_USE_BITMASK = 0xfffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffff ;
75
+
73
76
/// @notice Transient storage bit for identifying session keys
74
77
bytes32 private constant _IS_SESSION_KEY_BIT = 0x0000000000000000000000040000000000000000000000000000000000000000 ;
75
78
@@ -139,10 +142,11 @@ contract GasRelayHelper is GasRelayErrors {
139
142
block .chainid
140
143
)
141
144
);
142
- ABSTRACTED_CALLER_NAMESPACE = keccak256 (
145
+
146
+ UNDERLYING_CALLER_NAMESPACE = keccak256 (
143
147
abi.encode (
144
148
"ShMonad GasRelayHelper 1.0 " ,
145
- "Abstracted Caller Transient Namespace " ,
149
+ "Underlying Caller Transient Namespace " ,
146
150
taskManager,
147
151
shMonad,
148
152
policyIDLocal,
@@ -180,12 +184,12 @@ contract GasRelayHelper is GasRelayErrors {
180
184
/// @return inUse True if the contract is in use
181
185
function _inUse () internal view returns (bool inUse ) {
182
186
// Check if the transient storage has the IN_USE_BIT set
183
- bytes32 _abstractedCallerTransientSlot = ABSTRACTED_CALLER_NAMESPACE ;
184
- bytes32 _packedAbstractedCaller ;
187
+ bytes32 _underlyingCallerTransientSlot = UNDERLYING_CALLER_NAMESPACE ;
188
+ bytes32 _packedUnderlyingCaller ;
185
189
assembly {
186
- _packedAbstractedCaller := tload (_abstractedCallerTransientSlot )
190
+ _packedUnderlyingCaller := tload (_underlyingCallerTransientSlot )
187
191
}
188
- inUse = _packedAbstractedCaller & _IN_USE_BIT != 0 ;
192
+ inUse = _packedUnderlyingCaller & _IN_USE_BIT != 0 ;
189
193
}
190
194
191
195
/// @notice Check for reentrancy and revert if detected
@@ -198,49 +202,83 @@ contract GasRelayHelper is GasRelayErrors {
198
202
199
203
/// @notice Lock the contract against reentrancy
200
204
function _lock () internal {
201
- bytes32 _abstractedCallerTransientSlot = ABSTRACTED_CALLER_NAMESPACE ;
205
+ bytes32 _underlyingCallerTransientSlot = UNDERLYING_CALLER_NAMESPACE ;
202
206
assembly {
203
- tstore (_abstractedCallerTransientSlot, _IN_USE_BIT)
207
+ tstore (_underlyingCallerTransientSlot, _IN_USE_BIT)
208
+ }
209
+ }
210
+
211
+ /// @notice Lock the contract against reentrancy
212
+ /// @param preserveUnderlyingCaller bool that determines whether the packed caller data is preserved when unlocking
213
+ /// @dev Set preserveUnderlyingCaller to false unless you are 100% confident that you need to access the data again
214
+ /// later
215
+ // and you either dont need reentrancy protection or you are using another mechanism that protects from reentrancy.
216
+ function _unlock (bool preserveUnderlyingCaller ) internal {
217
+ bytes32 _underlyingCallerTransientSlot = UNDERLYING_CALLER_NAMESPACE;
218
+ if (! preserveUnderlyingCaller) {
219
+ assembly {
220
+ tstore (
221
+ _underlyingCallerTransientSlot, 0x0000000000000000000000000000000000000000000000000000000000000000
222
+ )
223
+ }
224
+ } else {
225
+ assembly {
226
+ let _packedUnderlyingCaller := tload (_underlyingCallerTransientSlot)
227
+ tstore (_underlyingCallerTransientSlot, and (_packedUnderlyingCaller, _NOT_IN_USE_BITMASK))
228
+ }
204
229
}
205
230
}
206
231
207
232
/// @notice Load abstracted msg sender data from transient storage
208
- /// @return abstractedMsgSender Address of the abstracted msg sender
209
- /// @return isSessionKey Whether the caller is a session key
210
- /// @return inUse Whether the contract is in use
211
- function _loadAbstractedMsgSenderData ()
233
+ /// @param underlyingMsgSender Address of the underlying msg sender
234
+ /// @return abstractedMsgSender Address of the session key's owner
235
+ /// @return valid Bool indicating if the session key is valid
236
+ function _loadAbstractedMsgSenderData (address underlyingMsgSender )
212
237
internal
213
238
view
214
- returns (address abstractedMsgSender , bool isSessionKey , bool inUse )
239
+ returns (address abstractedMsgSender , bool valid )
215
240
{
216
- bytes32 _abstractedCallerTransientSlot = ABSTRACTED_CALLER_NAMESPACE;
217
- bytes32 _packedAbstractedCaller;
218
- assembly {
219
- _packedAbstractedCaller := tload (_abstractedCallerTransientSlot)
220
- abstractedMsgSender :=
221
- and (_packedAbstractedCaller, 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff )
241
+ if (underlyingMsgSender == address (0 ) || underlyingMsgSender == address (this )) {
242
+ return (address (0 ), false );
222
243
}
223
- isSessionKey = _packedAbstractedCaller & _IS_SESSION_KEY_BIT != 0 ;
224
- inUse = _packedAbstractedCaller & _IN_USE_BIT != 0 ;
244
+ SessionKey memory _sessionKey = _loadSessionKey (underlyingMsgSender);
245
+ abstractedMsgSender = _sessionKey.owner;
246
+ valid = abstractedMsgSender != address (0 ) && uint256 (_sessionKey.expiration) > block .number ;
225
247
}
226
248
227
- /// @notice Store abstracted msg sender in transient storage
228
- /// @param abstractedMsgSender Address of the abstracted msg sender
229
- /// @param isSessionKey Whether the caller is a session key
230
- function _storeAbstractedMsgSender (address abstractedMsgSender , bool isSessionKey ) internal {
231
- bytes32 _abstractedCallerTransientSlot = ABSTRACTED_CALLER_NAMESPACE;
232
- bytes32 _packedAbstractedCaller = isSessionKey ? _IN_USE_AS_SESSION_KEY_BITS : _IN_USE_BIT;
249
+ /// @notice Store underlying msg sender in transient storage
250
+ function _storeUnderlyingMsgSender (bool isSessionKey ) internal {
251
+ // NOTE: We do not let smart contracts use session keys. EIP-7702-enabled wallets
252
+ // should already benefit from "session key" usage and will get treated as a
253
+ // default owner, which results in the same UX.
254
+ if (msg .sender == address (this ) || address (msg .sender ).code.length != 0 ) return ;
255
+
256
+ bytes32 _underlyingCallerTransientSlot = UNDERLYING_CALLER_NAMESPACE;
257
+ address _underlyingCaller = address (msg .sender );
258
+ bytes32 _packedUnderlyingCaller = isSessionKey ? _IN_USE_AS_SESSION_KEY_BITS : _IN_USE_BIT;
233
259
assembly {
234
- tstore (_abstractedCallerTransientSlot , or (_packedAbstractedCaller, abstractedMsgSender ))
260
+ tstore (_underlyingCallerTransientSlot , or (_packedUnderlyingCaller, _underlyingCaller ))
235
261
}
236
262
}
237
263
238
- /// @notice Clear abstracted msg sender from transient storage
239
- function _clearAbstractedMsgSender () internal {
240
- bytes32 _abstractedCallerTransientSlot = ABSTRACTED_CALLER_NAMESPACE;
264
+ /// @notice Load underlying msg sender data from transient storage
265
+ /// @return underlyingMsgSender Address of the underlying msg sender (embedded wallet / bundler)
266
+ /// @return isSessionKey Whether the caller is using a session key
267
+ /// @return inUse Whether the contract is in use
268
+ function _loadUnderlyingMsgSenderData ()
269
+ internal
270
+ view
271
+ returns (address underlyingMsgSender , bool isSessionKey , bool inUse )
272
+ {
273
+ bytes32 _underlyingCallerTransientSlot = UNDERLYING_CALLER_NAMESPACE;
274
+ bytes32 _packedUnderlyingCaller;
241
275
assembly {
242
- tstore (_abstractedCallerTransientSlot, 0x0000000000000000000000000000000000000000000000000000000000000000 )
276
+ _packedUnderlyingCaller := tload (_underlyingCallerTransientSlot)
277
+ underlyingMsgSender :=
278
+ and (_packedUnderlyingCaller, 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff )
243
279
}
280
+ isSessionKey = _packedUnderlyingCaller & _IS_SESSION_KEY_BIT != 0 ;
281
+ inUse = _packedUnderlyingCaller & _IN_USE_BIT != 0 ;
244
282
}
245
283
246
284
/// @notice Update a session key's data
0 commit comments