// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.8.0; /*@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@ HYPERLANE @@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@*/ // ============ Internal Imports ============ import {AbstractMessageIdAuthHook} from "./libs/AbstractMessageIdAuthHook.sol"; import {StandardHookMetadata} from "./libs/StandardHookMetadata.sol"; import {TypeCasts} from "../libs/TypeCasts.sol"; import {Message} from "../libs/Message.sol"; import {AbstractMessageIdAuthorizedIsm} from "../isms/hook/AbstractMessageIdAuthorizedIsm.sol"; import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; // ============ External Imports ============ import {ICrossDomainMessenger} from "../interfaces/optimism/ICrossDomainMessenger.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; /** * @title OPStackHook * @notice Message hook to inform the OPStackIsm of messages published through * the native OPStack bridge. * @notice This works only for L1 -> L2 messages. */ contract OPStackHook is AbstractMessageIdAuthHook { using StandardHookMetadata for bytes; using Message for bytes; // ============ Constants ============ /// @notice messenger contract specified by the rollup ICrossDomainMessenger public immutable l1Messenger; // Gas limit for sending messages to L2 // First 1.92e6 gas is provided by Optimism, see more here: // https://community.optimism.io/docs/developers/bridge/messaging/#for-l1-%E2%87%92-l2-transactions uint32 internal constant GAS_LIMIT = 1_920_000; // ============ Constructor ============ constructor( address _mailbox, uint32 _destinationDomain, bytes32 _ism, address _l1Messenger ) AbstractMessageIdAuthHook(_mailbox, _destinationDomain, _ism) { require( Address.isContract(_l1Messenger), "OPStackHook: invalid messenger" ); l1Messenger = ICrossDomainMessenger(_l1Messenger); } // ============ Internal functions ============ function _quoteDispatch( bytes calldata metadata, bytes calldata ) internal pure override returns (uint256) { return metadata.msgValue(0); // gas subsidized by the L2 } /// @inheritdoc AbstractMessageIdAuthHook function _sendMessageId( bytes calldata metadata, bytes calldata message ) internal override { bytes memory payload = abi.encodeCall( AbstractMessageIdAuthorizedIsm.preVerifyMessage, (message.id(), metadata.msgValue(0)) ); l1Messenger.sendMessage{value: metadata.msgValue(0)}( TypeCasts.bytes32ToAddress(ism), payload, GAS_LIMIT ); } }