Skip to content

Commit 9c310e9

Browse files
committed
chore: sync repo with latest changes
1 parent c6da6a1 commit 9c310e9

20 files changed

+800
-329
lines changed

src/common/relay/GasRelayBase.sol

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ contract GasRelayBase is GasRelayHelper {
197197
}
198198

199199
// Set the transaction sender context
200-
_storeAbstractedMsgSender(owner, false);
200+
_storeUnderlyingMsgSender(false);
201201

202202
// Execute the decorated function
203203
_;
@@ -211,21 +211,18 @@ contract GasRelayBase is GasRelayHelper {
211211
}
212212

213213
// Clean up the transaction context
214-
_clearAbstractedMsgSender();
214+
_unlock(false);
215215
}
216216

217217
/// @notice Modifier for gas abstraction via session keys
218218
/// @dev Handles detection of session keys, gas reimbursement, and task execution
219219
modifier GasAbstracted() {
220220
_checkForReentrancy();
221-
_lock();
221+
// NOTE: Locking is handled inside the _startShMonadGasAbstraction method.
222222

223223
// Initialize gas abstraction tracking and identify session key
224224
GasAbstractionTracker memory gasAbstractionTracker = _startShMonadGasAbstraction(msg.sender);
225225

226-
// Set caller context for the duration of the transaction
227-
_storeAbstractedMsgSender(gasAbstractionTracker.owner, gasAbstractionTracker.usingSessionKey);
228-
229226
// Execute the intended function
230227
_;
231228

@@ -236,7 +233,7 @@ contract GasRelayBase is GasRelayHelper {
236233
_finishShMonadGasAbstraction(gasAbstractionTracker);
237234

238235
// Clean up the transaction context
239-
_clearAbstractedMsgSender();
236+
_unlock(false);
240237
}
241238

242239
/// @notice Modifier that provides reentrancy protection
@@ -247,7 +244,7 @@ contract GasRelayBase is GasRelayHelper {
247244

248245
_;
249246

250-
_clearAbstractedMsgSender();
247+
_unlock(false);
251248
}
252249

253250
/// @notice Get the abstracted msg.sender
@@ -258,12 +255,18 @@ contract GasRelayBase is GasRelayHelper {
258255
// which is a useful pattern if they still want to handle the gas reimbursement of a gas abstracted
259256
// transaction in scenarios in which the users' call would revert.
260257

261-
(address _msgSender, bool _isCallerSessionKey, bool _inUse) = _loadAbstractedMsgSenderData();
258+
(address _underlyingMsgSender, bool _isCallerSessionKey, bool _inUse) = _loadUnderlyingMsgSenderData();
262259

263-
if (_isCallerSessionKey && _inUse && _msgSender != address(0)) {
264-
return _msgSender;
260+
if (!_isCallerSessionKey || !_inUse) {
261+
return msg.sender;
265262
}
266263

264+
if (msg.sender == address(this) || msg.sender == _underlyingMsgSender) {
265+
(address _owner, bool _valid) = _loadAbstractedMsgSenderData(_underlyingMsgSender);
266+
if (_valid) {
267+
return _owner;
268+
}
269+
}
267270
return msg.sender;
268271
}
269272

@@ -280,7 +283,7 @@ contract GasRelayBase is GasRelayHelper {
280283
/// @notice Check if the current caller is a session key
281284
/// @return isSessionKey True if the caller is a session key
282285
function _isSessionKey() internal view returns (bool isSessionKey) {
283-
(, isSessionKey,) = _loadAbstractedMsgSenderData();
286+
(, isSessionKey,) = _loadUnderlyingMsgSenderData();
284287
}
285288

286289
/// @notice Handles unused gas by executing tasks
@@ -321,7 +324,6 @@ contract GasRelayBase is GasRelayHelper {
321324
/// @return gasAbstractionTracker The gas abstraction tracker with initial data
322325
function _startShMonadGasAbstraction(address caller)
323326
internal
324-
view
325327
returns (GasAbstractionTracker memory gasAbstractionTracker)
326328
{
327329
// NOTE: Assumes msg.sender is session key
@@ -335,6 +337,7 @@ contract GasRelayBase is GasRelayHelper {
335337
startingGasLeft: gasleft() + _BASE_TX_GAS_USAGE + (msg.data.length * 16),
336338
credits: 0
337339
});
340+
_storeUnderlyingMsgSender(true);
338341
} else {
339342
gasAbstractionTracker = GasAbstractionTracker({
340343
usingSessionKey: false,
@@ -344,6 +347,7 @@ contract GasRelayBase is GasRelayHelper {
344347
startingGasLeft: gasleft() + _BASE_TX_GAS_USAGE + (msg.data.length * 16),
345348
credits: 0
346349
});
350+
_storeUnderlyingMsgSender(false);
347351
}
348352
return gasAbstractionTracker;
349353
}

src/common/relay/GasRelayHelper.sol

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ contract GasRelayHelper is GasRelayErrors {
4343
/// @notice Namespace for key owner storage
4444
bytes32 private immutable KEY_OWNER_NAMESPACE;
4545

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;
4848

4949
/// @notice Minimum gas required for task execution
5050
uint256 internal constant _MIN_TASK_EXECUTION_GAS = 110_000;
@@ -70,6 +70,9 @@ contract GasRelayHelper is GasRelayErrors {
7070
/// @notice Transient storage bit for tracking usage lock
7171
bytes32 private constant _IN_USE_BIT = 0x0000000000000000000000020000000000000000000000000000000000000000;
7272

73+
/// @notice Transient storage bit for modifying usage lock
74+
bytes32 private constant _NOT_IN_USE_BITMASK = 0xfffffffffffffffffffffffdffffffffffffffffffffffffffffffffffffffff;
75+
7376
/// @notice Transient storage bit for identifying session keys
7477
bytes32 private constant _IS_SESSION_KEY_BIT = 0x0000000000000000000000040000000000000000000000000000000000000000;
7578

@@ -139,10 +142,11 @@ contract GasRelayHelper is GasRelayErrors {
139142
block.chainid
140143
)
141144
);
142-
ABSTRACTED_CALLER_NAMESPACE = keccak256(
145+
146+
UNDERLYING_CALLER_NAMESPACE = keccak256(
143147
abi.encode(
144148
"ShMonad GasRelayHelper 1.0",
145-
"Abstracted Caller Transient Namespace",
149+
"Underlying Caller Transient Namespace",
146150
taskManager,
147151
shMonad,
148152
policyIDLocal,
@@ -180,12 +184,12 @@ contract GasRelayHelper is GasRelayErrors {
180184
/// @return inUse True if the contract is in use
181185
function _inUse() internal view returns (bool inUse) {
182186
// 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;
185189
assembly {
186-
_packedAbstractedCaller := tload(_abstractedCallerTransientSlot)
190+
_packedUnderlyingCaller := tload(_underlyingCallerTransientSlot)
187191
}
188-
inUse = _packedAbstractedCaller & _IN_USE_BIT != 0;
192+
inUse = _packedUnderlyingCaller & _IN_USE_BIT != 0;
189193
}
190194

191195
/// @notice Check for reentrancy and revert if detected
@@ -198,49 +202,83 @@ contract GasRelayHelper is GasRelayErrors {
198202

199203
/// @notice Lock the contract against reentrancy
200204
function _lock() internal {
201-
bytes32 _abstractedCallerTransientSlot = ABSTRACTED_CALLER_NAMESPACE;
205+
bytes32 _underlyingCallerTransientSlot = UNDERLYING_CALLER_NAMESPACE;
202206
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+
}
204229
}
205230
}
206231

207232
/// @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)
212237
internal
213238
view
214-
returns (address abstractedMsgSender, bool isSessionKey, bool inUse)
239+
returns (address abstractedMsgSender, bool valid)
215240
{
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);
222243
}
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;
225247
}
226248

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;
233259
assembly {
234-
tstore(_abstractedCallerTransientSlot, or(_packedAbstractedCaller, abstractedMsgSender))
260+
tstore(_underlyingCallerTransientSlot, or(_packedUnderlyingCaller, _underlyingCaller))
235261
}
236262
}
237263

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;
241275
assembly {
242-
tstore(_abstractedCallerTransientSlot, 0x0000000000000000000000000000000000000000000000000000000000000000)
276+
_packedUnderlyingCaller := tload(_underlyingCallerTransientSlot)
277+
underlyingMsgSender :=
278+
and(_packedUnderlyingCaller, 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff)
243279
}
280+
isSessionKey = _packedUnderlyingCaller & _IS_SESSION_KEY_BIT != 0;
281+
inUse = _packedUnderlyingCaller & _IN_USE_BIT != 0;
244282
}
245283

246284
/// @notice Update a session key's data

0 commit comments

Comments
 (0)