github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/safe-tools/CompatibilityFallbackHandler_1_3_0.sol (about)

     1  // SPDX-License-Identifier: LGPL-3.0-only
     2  pragma solidity >=0.7.0 <0.9.0;
     3  
     4  import "safe-contracts/interfaces/ERC1155TokenReceiver.sol";
     5  import "safe-contracts/interfaces/ERC721TokenReceiver.sol";
     6  import "safe-contracts/interfaces/ERC777TokensRecipient.sol";
     7  import "safe-contracts/interfaces/IERC165.sol";
     8  import "safe-contracts/interfaces/ISignatureValidator.sol";
     9  import { Safe as GnosisSafe } from "safe-contracts/Safe.sol";
    10  
    11  /// author: Colin Nielsen
    12  /// https://github.com/colinnielsen/safe-tools/blob/ce6c654a76d91b619ab7778c77d1a76b3ced6666/src/CompatibilityFallbackHandler_1_3_0.sol
    13  contract DefaultCallbackHandler is ERC1155TokenReceiver, ERC777TokensRecipient, ERC721TokenReceiver, IERC165 {
    14      function onERC1155Received(
    15          address,
    16          address,
    17          uint256,
    18          uint256,
    19          bytes calldata
    20      )
    21          external
    22          pure
    23          override
    24          returns (bytes4)
    25      {
    26          return 0xf23a6e61;
    27      }
    28  
    29      function onERC1155BatchReceived(
    30          address,
    31          address,
    32          uint256[] calldata,
    33          uint256[] calldata,
    34          bytes calldata
    35      )
    36          external
    37          pure
    38          override
    39          returns (bytes4)
    40      {
    41          return 0xbc197c81;
    42      }
    43  
    44      function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {
    45          return 0x150b7a02;
    46      }
    47  
    48      function tokensReceived(
    49          address,
    50          address,
    51          address,
    52          uint256,
    53          bytes calldata,
    54          bytes calldata
    55      )
    56          external
    57          pure
    58          override
    59      {
    60          // We implement this for completeness, doesn't really have any value
    61      }
    62  
    63      function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) {
    64          return interfaceId == type(ERC1155TokenReceiver).interfaceId
    65              || interfaceId == type(ERC721TokenReceiver).interfaceId || interfaceId == type(IERC165).interfaceId;
    66      }
    67  }
    68  
    69  address constant SENTINEL_MODULES = address(0x1);
    70  
    71  /// @title Compatibility Fallback Handler - fallback handler to provider compatibility between pre 1.3.0 and 1.3.0+ Safe
    72  /// contracts
    73  /// @author Richard Meissner - <richard@gnosis.pm>
    74  contract CompatibilityFallbackHandler is DefaultCallbackHandler, ISignatureValidator {
    75      //keccak256(
    76      //    "SafeMessage(bytes message)"
    77      //);
    78      bytes32 private constant SAFE_MSG_TYPEHASH = 0x60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca;
    79  
    80      bytes4 internal constant SIMULATE_SELECTOR = bytes4(keccak256("simulate(address,bytes)"));
    81  
    82      bytes4 internal constant UPDATED_MAGIC_VALUE = 0x1626ba7e;
    83  
    84      /**
    85       * Implementation of ISignatureValidator (see `interfaces/ISignatureValidator.sol`)
    86       * @dev Should return whether the signature provided is valid for the provided data.
    87       * @param _data Arbitrary length data signed on the behalf of address(msg.sender)
    88       * @param _signature Signature byte array associated with _data
    89       * @return a bool upon valid or invalid signature with corresponding _data
    90       */
    91      function isValidSignature(bytes memory _data, bytes memory _signature) public view override returns (bytes4) {
    92          // Caller should be a Safe
    93          GnosisSafe safe = GnosisSafe(payable(msg.sender));
    94          bytes32 messageHash = getMessageHashForSafe(safe, _data);
    95          if (_signature.length == 0) {
    96              require(safe.signedMessages(messageHash) != 0, "Hash not approved");
    97          } else {
    98              safe.checkSignatures(messageHash, _data, _signature);
    99          }
   100          return EIP1271_MAGIC_VALUE;
   101      }
   102  
   103      /// @dev Returns hash of a message that can be signed by owners.
   104      /// @param message Message that should be hashed
   105      /// @return Message hash.
   106      function getMessageHash(bytes memory message) public view returns (bytes32) {
   107          return getMessageHashForSafe(GnosisSafe(payable(msg.sender)), message);
   108      }
   109  
   110      /// @dev Returns hash of a message that can be signed by owners.
   111      /// @param safe Safe to which the message is targeted
   112      /// @param message Message that should be hashed
   113      /// @return Message hash.
   114      function getMessageHashForSafe(GnosisSafe safe, bytes memory message) public view returns (bytes32) {
   115          bytes32 safeMessageHash = keccak256(abi.encode(SAFE_MSG_TYPEHASH, keccak256(message)));
   116          return keccak256(abi.encodePacked(bytes1(0x19), bytes1(0x01), safe.domainSeparator(), safeMessageHash));
   117      }
   118  
   119      /**
   120       * Implementation of updated EIP-1271
   121       * @dev Should return whether the signature provided is valid for the provided data.
   122       *       The save does not implement the interface since `checkSignatures` is not a view method.
   123       *       The method will not perform any state changes (see parameters of `checkSignatures`)
   124       * @param _dataHash Hash of the data signed on the behalf of address(msg.sender)
   125       * @param _signature Signature byte array associated with _dataHash
   126       * @return a bool upon valid or invalid signature with corresponding _dataHash
   127       * @notice See
   128       * https://github.com/gnosis/util-contracts/blob/bb5fe5fb5df6d8400998094fb1b32a178a47c3a1/contracts/StorageAccessible.sol
   129       */
   130      function isValidSignature(bytes32 _dataHash, bytes calldata _signature) external view returns (bytes4) {
   131          ISignatureValidator validator = ISignatureValidator(msg.sender);
   132          bytes4 value = validator.isValidSignature(abi.encode(_dataHash), _signature);
   133          return (value == EIP1271_MAGIC_VALUE) ? UPDATED_MAGIC_VALUE : bytes4(0);
   134      }
   135  
   136      /// @dev Returns array of first 10 modules.
   137      /// @return Array of modules.
   138      function getModules() external view returns (address[] memory) {
   139          // Caller should be a Safe
   140          GnosisSafe safe = GnosisSafe(payable(msg.sender));
   141          (address[] memory array,) = safe.getModulesPaginated(SENTINEL_MODULES, 10);
   142          return array;
   143      }
   144  
   145      /**
   146       * @dev Performs a delegetecall on a targetContract in the context of self.
   147       * Internally reverts execution to avoid side effects (making it static). Catches revert and returns encoded result
   148       * as bytes.
   149       * @param targetContract Address of the contract containing the code to execute.
   150       * @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
   151       */
   152      function simulate(
   153          address targetContract,
   154          bytes calldata calldataPayload
   155      )
   156          external
   157          returns (bytes memory response)
   158      {
   159          // Suppress compiler warnings about not using parameters, while allowing
   160          // parameters to keep names for documentation purposes. This does not
   161          // generate code.
   162          targetContract;
   163          calldataPayload;
   164  
   165          assembly {
   166              let internalCalldata := mload(0x40)
   167              // Store `simulateAndRevert.selector`.
   168              // String representation is used to force right padding
   169              mstore(internalCalldata, "\xb4\xfa\xba\x09")
   170              // Abuse the fact that both this and the internal methods have the
   171              // same signature, and differ only in symbol name (and therefore,
   172              // selector) and copy calldata directly. This saves us approximately
   173              // 250 bytes of code and 300 gas at runtime over the
   174              // `abi.encodeWithSelector` builtin.
   175              calldatacopy(add(internalCalldata, 0x04), 0x04, sub(calldatasize(), 0x04))
   176  
   177              // `pop` is required here by the compiler, as top level expressions
   178              // can't have return values in inline assembly. `call` typically
   179              // returns a 0 or 1 value indicated whether or not it reverted, but
   180              // since we know it will always revert, we can safely ignore it.
   181              pop(
   182                  call(
   183                      gas(),
   184                      // address() has been changed to caller() to use the implementation of the Safe
   185                      caller(),
   186                      0,
   187                      internalCalldata,
   188                      calldatasize(),
   189                      // The `simulateAndRevert` call always reverts, and
   190                      // instead encodes whether or not it was successful in the return
   191                      // data. The first 32-byte word of the return data contains the
   192                      // `success` value, so write it to memory address 0x00 (which is
   193                      // reserved Solidity scratch space and OK to use).
   194                      0x00,
   195                      0x20
   196                  )
   197              )
   198  
   199              // Allocate and copy the response bytes, making sure to increment
   200              // the free memory pointer accordingly (in case this method is
   201              // called as an internal function). The remaining `returndata[0x20:]`
   202              // contains the ABI encoded response bytes, so we can just write it
   203              // as is to memory.
   204              let responseSize := sub(returndatasize(), 0x20)
   205              response := mload(0x40)
   206              mstore(0x40, add(response, responseSize))
   207              returndatacopy(response, 0x20, responseSize)
   208  
   209              if iszero(mload(0x00)) { revert(add(response, 0x20), mload(response)) }
   210          }
   211      }
   212  }