From 7b02860330fe7b6e946ed1701e21ee9de9c2d5f8 Mon Sep 17 00:00:00 2001 From: Jay Paik Date: Sat, 27 Jan 2024 01:15:36 -0500 Subject: [PATCH] fix: enable hooks for token receiver callbacks --- src/account/TokenReceiver.sol | 64 ---------------------- src/account/UpgradeableModularAccount.sol | 67 ++++++++++++++++++++++- src/helpers/KnownSelectors.sol | 2 +- 3 files changed, 65 insertions(+), 68 deletions(-) delete mode 100644 src/account/TokenReceiver.sol diff --git a/src/account/TokenReceiver.sol b/src/account/TokenReceiver.sol deleted file mode 100644 index 844ab4393..000000000 --- a/src/account/TokenReceiver.sol +++ /dev/null @@ -1,64 +0,0 @@ -// This file is part of Modular Account. -// -// Copyright 2024 Alchemy Insights, Inc. -// -// SPDX-License-Identifier: GPL-3.0-or-later -// -// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General -// Public License as published by the Free Software Foundation, either version 3 of the License, or (at your -// option) any later version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the -// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -// more details. -// -// You should have received a copy of the GNU General Public License along with this program. If not, see -// . - -pragma solidity ^0.8.22; - -import {IERC1155Receiver} from "@openzeppelin/contracts/interfaces/IERC1155Receiver.sol"; -import {IERC777Recipient} from "@openzeppelin/contracts/interfaces/IERC777Recipient.sol"; -import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; - -abstract contract TokenReceiver is IERC165, IERC721Receiver, IERC777Recipient, IERC1155Receiver { - /// @inheritdoc IERC777Recipient - function tokensReceived(address, address, address, uint256, bytes calldata, bytes calldata) - external - pure - override - // solhint-disable-next-line no-empty-blocks - {} - - /// @inheritdoc IERC721Receiver - function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) { - return IERC721Receiver.onERC721Received.selector; - } - - /// @inheritdoc IERC1155Receiver - function onERC1155Received(address, address, uint256, uint256, bytes calldata) - external - pure - override - returns (bytes4) - { - return IERC1155Receiver.onERC1155Received.selector; - } - - /// @inheritdoc IERC1155Receiver - function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) - external - pure - override - returns (bytes4) - { - return IERC1155Receiver.onERC1155BatchReceived.selector; - } - - /// @inheritdoc IERC165 - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - return interfaceId == type(IERC721Receiver).interfaceId - || interfaceId == type(IERC777Recipient).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId; - } -} diff --git a/src/account/UpgradeableModularAccount.sol b/src/account/UpgradeableModularAccount.sol index 93b0fe6d9..042fe3ad8 100644 --- a/src/account/UpgradeableModularAccount.sol +++ b/src/account/UpgradeableModularAccount.sol @@ -17,6 +17,9 @@ pragma solidity ^0.8.22; +import {IERC1155Receiver} from "@openzeppelin/contracts/interfaces/IERC1155Receiver.sol"; +import {IERC777Recipient} from "@openzeppelin/contracts/interfaces/IERC777Recipient.sol"; +import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {UUPSUpgradeable} from "../../ext/UUPSUpgradeable.sol"; @@ -38,7 +41,6 @@ import {AccountExecutor} from "./AccountExecutor.sol"; import {AccountLoupe} from "./AccountLoupe.sol"; import {AccountStorageInitializable} from "./AccountStorageInitializable.sol"; import {PluginManagerInternals} from "./PluginManagerInternals.sol"; -import {TokenReceiver} from "./TokenReceiver.sol"; /// @title Upgradeable Modular Account /// @author Alchemy @@ -48,10 +50,13 @@ contract UpgradeableModularAccount is AccountLoupe, AccountStorageInitializable, PluginManagerInternals, - TokenReceiver, IAccount, IAccountInitializable, IAccountView, + IERC165, + IERC721Receiver, + IERC777Recipient, + IERC1155Receiver, IPluginExecutor, IStandardExecutor, UUPSUpgradeable @@ -371,6 +376,61 @@ contract UpgradeableModularAccount is _postNativeFunction(postExecHooks, postHookArgs); } + /// @inheritdoc IERC777Recipient + /// @dev Runtime validation is bypassed for this callback, but we still allow pre and post exec hooks to be + /// assigned and run. + function tokensReceived(address, address, address, uint256, bytes calldata, bytes calldata) + external + override + // solhint-disable-next-line no-empty-blocks + { + (FunctionReference[][] memory postExecHooks, bytes[] memory postHookArgs) = + _doPreExecHooks(_getAccountStorage().selectorData[msg.sig], ""); + _postNativeFunction(postExecHooks, postHookArgs); + } + + /// @inheritdoc IERC721Receiver + /// @dev Runtime validation is bypassed for this callback, but we still allow pre and post exec hooks to be + /// assigned and run. + function onERC721Received(address, address, uint256, bytes calldata) + external + override + returns (bytes4 selector) + { + (FunctionReference[][] memory postExecHooks, bytes[] memory postHookArgs) = + _doPreExecHooks(_getAccountStorage().selectorData[msg.sig], ""); + selector = IERC721Receiver.onERC721Received.selector; + _postNativeFunction(postExecHooks, postHookArgs); + } + + /// @inheritdoc IERC1155Receiver + /// @dev Runtime validation is bypassed for this callback, but we still allow pre and post exec hooks to be + /// assigned and run. + function onERC1155Received(address, address, uint256, uint256, bytes calldata) + external + override + returns (bytes4 selector) + { + (FunctionReference[][] memory postExecHooks, bytes[] memory postHookArgs) = + _doPreExecHooks(_getAccountStorage().selectorData[msg.sig], ""); + selector = IERC1155Receiver.onERC1155Received.selector; + _postNativeFunction(postExecHooks, postHookArgs); + } + + /// @inheritdoc IERC1155Receiver + /// @dev Runtime validation is bypassed for this callback, but we still allow pre and post exec hooks to be + /// assigned and run. + function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) + external + override + returns (bytes4 selector) + { + (FunctionReference[][] memory postExecHooks, bytes[] memory postHookArgs) = + _doPreExecHooks(_getAccountStorage().selectorData[msg.sig], ""); + selector = IERC1155Receiver.onERC1155BatchReceived.selector; + _postNativeFunction(postExecHooks, postHookArgs); + } + /// @inheritdoc UUPSUpgradeable function upgradeToAndCall(address newImplementation, bytes calldata data) public payable override onlyProxy { (FunctionReference[][] memory postExecHooks, bytes[] memory postHookArgs) = _preNativeFunction(); @@ -383,7 +443,8 @@ contract UpgradeableModularAccount is if (interfaceId == _INTERFACE_ID_INVALID) { return false; } - return interfaceId == _IERC165_INTERFACE_ID || super.supportsInterface(interfaceId) + return interfaceId == _IERC165_INTERFACE_ID || interfaceId == type(IERC721Receiver).interfaceId + || interfaceId == type(IERC777Recipient).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId || _getAccountStorage().supportedInterfaces[interfaceId] > 0; } diff --git a/src/helpers/KnownSelectors.sol b/src/helpers/KnownSelectors.sol index 3689edf74..ba6774867 100644 --- a/src/helpers/KnownSelectors.sol +++ b/src/helpers/KnownSelectors.sol @@ -64,7 +64,7 @@ library KnownSelectors { || selector == IAccountLoupe.getExecutionHooks.selector || selector == IAccountLoupe.getPreValidationHooks.selector || selector == IAccountLoupe.getInstalledPlugins.selector - // check against TokenReceiver methods + // check against token receiver methods || selector == IERC777Recipient.tokensReceived.selector || selector == IERC721Receiver.onERC721Received.selector || selector == IERC1155Receiver.onERC1155Received.selector