diff --git a/contracts/SafeL2.sol b/contracts/SafeL2.sol index de3320c..56f6cb0 100644 --- a/contracts/SafeL2.sol +++ b/contracts/SafeL2.sol @@ -71,7 +71,13 @@ contract SafeL2 is Safe { * @inheritdoc ModuleManager */ - function onBeforeExecTransactionFromModule(address to, uint256 value, bytes memory data, Enum.Operation operation) internal override { + function onBeforeExecTransactionFromModule( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + bytes memory /* context */ + ) internal override { emit SafeModuleTransaction(msg.sender, to, value, data, operation); } diff --git a/contracts/base/ModuleManager.sol b/contracts/base/ModuleManager.sol index b123270..cfaeaf5 100644 --- a/contracts/base/ModuleManager.sol +++ b/contracts/base/ModuleManager.sol @@ -26,6 +26,7 @@ interface IModuleGuard is IERC165 { uint256 value, bytes memory data, Enum.Operation operation, + bytes memory context, address module ) external returns (bytes32 moduleTxHash); @@ -88,6 +89,7 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager { * @param value Ether value of module transaction. * @param data Data payload of module transaction. * @param operation Operation type of module transaction. + * @param context Context of the module transaction. * @return guard Guard to be used for checking. * @return guardHash Hash returned from the guard tx check. */ @@ -95,16 +97,17 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager { address to, uint256 value, bytes memory data, - Enum.Operation operation + Enum.Operation operation, + bytes calldata context ) internal returns (address guard, bytes32 guardHash) { - onBeforeExecTransactionFromModule(to, value, data, operation); + onBeforeExecTransactionFromModule(to, value, data, operation, context); guard = getModuleGuard(); // Only whitelisted modules are allowed. require(msg.sender != SENTINEL_MODULES && modules[msg.sender] != address(0), "GS104"); if (guard != address(0)) { - guardHash = IModuleGuard(guard).checkModuleTransaction(to, value, data, operation, msg.sender); + guardHash = IModuleGuard(guard).checkModuleTransaction(to, value, data, operation, context, msg.sender); } } @@ -148,6 +151,19 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager { emit DisabledModule(module); } + /** + * @inheritdoc IModuleManager + */ + function execTransactionFromModule( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + bytes calldata context + ) external override returns (bool success) { + success = _execTransactionFromModule(to, value, data, operation, context); + } + /** * @inheritdoc IModuleManager */ @@ -157,7 +173,17 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager { bytes memory data, Enum.Operation operation ) external override returns (bool success) { - (address guard, bytes32 guardHash) = preModuleExecution(to, value, data, operation); + success = _execTransactionFromModule(to, value, data, operation, ""); + } + + function _execTransactionFromModule( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + bytes calldata context + ) internal returns (bool success) { + (address guard, bytes32 guardHash) = preModuleExecution(to, value, data, operation, context); success = execute(to, value, data, operation, type(uint256).max); postModuleExecution(guard, guardHash, success); @@ -172,7 +198,30 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager { bytes memory data, Enum.Operation operation ) external override returns (bool success, bytes memory returnData) { - (address guard, bytes32 guardHash) = preModuleExecution(to, value, data, operation); + (success, returnData) = _execTransactionFromModuleReturnData(to, value, data, operation, ""); + } + + /** + * @inheritdoc IModuleManager + */ + function execTransactionFromModuleReturnData( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + bytes calldata context + ) external override returns (bool success, bytes memory returnData) { + (success, returnData) = _execTransactionFromModuleReturnData(to, value, data, operation, context); + } + + function _execTransactionFromModuleReturnData( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + bytes calldata context + ) internal returns (bool success, bytes memory returnData) { + (address guard, bytes32 guardHash) = preModuleExecution(to, value, data, operation, context); success = execute(to, value, data, operation, type(uint256).max); /* solhint-disable no-inline-assembly */ /// @solidity memory-safe-assembly @@ -288,5 +337,11 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager { * @param data Data payload of module transaction. * @param operation Operation type of module transaction. */ - function onBeforeExecTransactionFromModule(address to, uint256 value, bytes memory data, Enum.Operation operation) internal virtual {} + function onBeforeExecTransactionFromModule( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + bytes calldata context + ) internal virtual {} } diff --git a/contracts/examples/guards/DebugTransactionGuard.sol b/contracts/examples/guards/DebugTransactionGuard.sol index 9f55574..2ec9622 100644 --- a/contracts/examples/guards/DebugTransactionGuard.sol +++ b/contracts/examples/guards/DebugTransactionGuard.sol @@ -101,6 +101,7 @@ contract DebugTransactionGuard is BaseGuard { uint256 value, bytes memory data, Enum.Operation operation, + bytes memory /* context */, address module ) external override returns (bytes32 moduleTxHash) { moduleTxHash = keccak256(abi.encodePacked(to, value, data, operation, module)); diff --git a/contracts/examples/guards/DelegateCallTransactionGuard.sol b/contracts/examples/guards/DelegateCallTransactionGuard.sol index 3590d90..99e12c1 100644 --- a/contracts/examples/guards/DelegateCallTransactionGuard.sol +++ b/contracts/examples/guards/DelegateCallTransactionGuard.sol @@ -63,6 +63,7 @@ contract DelegateCallTransactionGuard is BaseGuard { uint256 value, bytes memory data, Enum.Operation operation, + bytes memory /* context */, address module ) external view override returns (bytes32 moduleTxHash) { require(operation != Enum.Operation.DelegateCall || to == ALLOWED_TARGET, "This call is restricted"); diff --git a/contracts/examples/guards/ReentrancyTransactionGuard.sol b/contracts/examples/guards/ReentrancyTransactionGuard.sol index c779a17..a7ce1ab 100644 --- a/contracts/examples/guards/ReentrancyTransactionGuard.sol +++ b/contracts/examples/guards/ReentrancyTransactionGuard.sol @@ -80,6 +80,7 @@ contract ReentrancyTransactionGuard is BaseGuard { uint256 value, bytes memory data, Enum.Operation operation, + bytes memory /* context */, address module ) external override returns (bytes32 moduleTxHash) { moduleTxHash = keccak256(abi.encodePacked(to, value, data, operation, module)); diff --git a/contracts/interfaces/IModuleManager.sol b/contracts/interfaces/IModuleManager.sol index 86bc89c..90cda05 100644 --- a/contracts/interfaces/IModuleManager.sol +++ b/contracts/interfaces/IModuleManager.sol @@ -48,6 +48,24 @@ interface IModuleManager { Enum.Operation operation ) external returns (bool success); + /** + * @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token) + * @dev Function is virtual to allow overriding for L2 singleton to emit an event for indexing. + * @param to Destination address of module transaction. + * @param value Ether value of module transaction. + * @param data Data payload of module transaction. + * @param operation Operation type of module transaction. + * @param context Additional context information for the module transaction. + * @return success Boolean flag indicating if the call succeeded. + */ + function execTransactionFromModule( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + bytes calldata context + ) external returns (bool success); + /** * @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token) and return data * @param to Destination address of module transaction. @@ -64,6 +82,24 @@ interface IModuleManager { Enum.Operation operation ) external returns (bool success, bytes memory returnData); + /** + * @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token) and return data + * @param to Destination address of module transaction. + * @param value Ether value of module transaction. + * @param data Data payload of module transaction. + * @param operation Operation type of module transaction. + * @param context Additional context information for the module transaction. + * @return success Boolean flag indicating if the call succeeded. + * @return returnData Data returned by the call. + */ + function execTransactionFromModuleReturnData( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + bytes calldata context + ) external returns (bool success, bytes memory returnData); + /** * @notice Returns if an module is enabled * @return True if the module is enabled