// File: @openzeppelin/contracts/utils/Address.sol



// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

// File: contracts/messaging/connectors/Connector.sol



// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

import {Address} from "@openzeppelin/contracts/utils/Address.sol";

import {ProposedOwnable} from "../../shared/ProposedOwnable.sol";
import {IConnector} from "../interfaces/IConnector.sol";

/**
 * @title Connector
 * @author Connext Labs, Inc.
 * @notice This contract has the messaging interface functions used by all connectors.
 *
 * @dev This contract stores information about mirror connectors, but can be used as a
 * base for contracts that do not have a mirror (i.e. the connector handling messaging on
 * mainnet). In this case, the `mirrorConnector` and `MIRROR_DOMAIN`
 * will be empty
 *
 * @dev If ownership is renounced, this contract will be unable to update its `mirrorConnector`
 * or `mirrorGas`
 */
abstract contract Connector is ProposedOwnable, IConnector {
  // ========== Custom Errors ===========

  error Connector__processMessage_notUsed();

  // ============ Events ============

  event NewConnector(
    uint32 indexed domain,
    uint32 indexed mirrorDomain,
    address amb,
    address rootManager,
    address mirrorConnector
  );

  event MirrorConnectorUpdated(address previous, address current);

  /**
   * @notice Emitted when funds are withdrawn by the admin
   * @dev See comments in `withdrawFunds`
   * @param to The recipient of the funds
   * @param amount The amount withdrawn
   */
  event FundsWithdrawn(address indexed to, uint256 amount);

  // ============ Public Storage ============

  /**
   * @notice The domain of this Messaging (i.e. Connector) contract.
   */
  uint32 public immutable DOMAIN;

  /**
   * @notice Address of the AMB on this domain.
   */
  address public immutable AMB;

  /**
   * @notice RootManager contract address.
   */
  address public immutable ROOT_MANAGER;

  /**
   * @notice The domain of the corresponding messaging (i.e. Connector) contract.
   */
  uint32 public immutable MIRROR_DOMAIN;

  /**
   * @notice Connector on L2 for L1 connectors, and vice versa.
   */
  address public mirrorConnector;

  // ============ Modifiers ============

  /**
   * @notice Errors if the msg.sender is not the registered AMB
   */
  modifier onlyAMB() {
    require(msg.sender == AMB, "!AMB");
    _;
  }

  /**
   * @notice Errors if the msg.sender is not the registered ROOT_MANAGER
   */
  modifier onlyRootManager() {
    // NOTE: RootManager will be zero address for spoke connectors.
    // Only root manager can dispatch a message to spokes/L2s via the hub connector.
    require(msg.sender == ROOT_MANAGER, "!rootManager");
    _;
  }

  // ============ Constructor ============

  /**
   * @notice Creates a new HubConnector instance
   * @dev The connectors are deployed such that there is one on each side of an AMB (i.e.
   * for optimism, there is one connector on optimism and one connector on mainnet)
   * @param _domain The domain this connector lives on
   * @param _mirrorDomain The spoke domain
   * @param _amb The address of the amb on the domain this connector lives on
   * @param _rootManager The address of the RootManager on mainnet
   * @param _mirrorConnector The address of the spoke connector
   */
  constructor(
    uint32 _domain,
    uint32 _mirrorDomain,
    address _amb,
    address _rootManager,
    address _mirrorConnector
  ) ProposedOwnable() {
    // set the owner
    _setOwner(msg.sender);

    // sanity checks on values
    require(_domain != 0, "empty domain");
    require(_rootManager != address(0), "empty rootManager");
    // see note at top of contract on why the mirror values are not sanity checked

    // set immutables
    DOMAIN = _domain;
    AMB = _amb;
    ROOT_MANAGER = _rootManager;
    MIRROR_DOMAIN = _mirrorDomain;
    // set mutables if defined
    if (_mirrorConnector != address(0)) {
      _setMirrorConnector(_mirrorConnector);
    }

    emit NewConnector(_domain, _mirrorDomain, _amb, _rootManager, _mirrorConnector);
  }

  // ============ Receivable ============
  /**
   * @notice Connectors may need to receive native asset to handle fees when sending a
   * message
   */
  receive() external payable {}

  // ============ Admin Functions ============

  /**
   * @notice Sets the address of the l2Connector for this domain
   */
  function setMirrorConnector(address _mirrorConnector) public onlyOwner {
    _setMirrorConnector(_mirrorConnector);
  }

  /**
   * @notice This function should be callable by owner, and send funds trapped on
   * a connector to the provided recipient.
   * @dev Withdraws the entire balance of the contract.
   *
   * @param _to The recipient of the funds withdrawn
   */
  function withdrawFunds(address _to) public onlyOwner {
    uint256 amount = address(this).balance;
    Address.sendValue(payable(_to), amount);
    emit FundsWithdrawn(_to, amount);
  }

  // ============ Public Functions ============

  /**
   * @notice Processes a message received by an AMB
   * @dev This is called by AMBs to process messages originating from mirror connector
   */
  function processMessage(bytes memory _data) external virtual onlyAMB {
    _processMessage(_data);
    emit MessageProcessed(_data, msg.sender);
  }

  /**
   * @notice Checks the cross domain sender for a given address
   */
  function verifySender(address _expected) external returns (bool) {
    return _verifySender(_expected);
  }

  // ============ Virtual Functions ============

  /**
   * @notice This function is used by the Connext contract on the l2 domain to send a message to the
   * l1 domain (i.e. called by Connext on optimism to send a message to mainnet with roots)
   * @param _data The contents of the message
   * @param _encodedData Data used to send the message; specific to connector
   */
  function _sendMessage(bytes memory _data, bytes memory _encodedData) internal virtual;

  /**
   * @notice This function is used by the AMBs to handle incoming messages. Should store the latest
   * root generated on the l2 domain.
   */
  function _processMessage(
    bytes memory /* _data */
  ) internal virtual {
    // By default, reverts. This is to ensure the call path is not used unless this function is
    // overridden by the inheriting class
    revert Connector__processMessage_notUsed();
  }

  /**
   * @notice Verify that the msg.sender is the correct AMB contract, and that the message's origin sender
   * is the expected address.
   * @dev Should be overridden by the implementing Connector contract.
   */
  function _verifySender(address _expected) internal virtual returns (bool);

  // ============ Private Functions ============

  function _setMirrorConnector(address _mirrorConnector) internal virtual {
    emit MirrorConnectorUpdated(mirrorConnector, _mirrorConnector);
    mirrorConnector = _mirrorConnector;
  }
}

// File: contracts/messaging/connectors/GasCap.sol



// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ProposedOwnable} from "../../shared/ProposedOwnable.sol";

/**
 * @notice This contract is used to enforce upper bounds on the amount of fees
 * forwarded along. This caps the amount relayers could charge for the service
 */
abstract contract GasCap is ProposedOwnable {
  // ============ Storage ============
  /**
   * @notice The gnosis amb requires destination gas to be specified on the origin.
   * The gas used will be passed in by the relayer to allow for real-time estimates,
   * but will be capped at the admin-set cap.
   */
  uint256 public gasCap;

  // ============ Events ============

  /**
   * @notice Emitted when admin updates the gas cap
   * @param _previous The starting value
   * @param _updated The final value
   */
  event GasCapUpdated(uint256 _previous, uint256 _updated);

  // ============ Constructor ============
  constructor(uint256 _gasCap) {
    _setGasCap(_gasCap);
  }

  // ============ Admin Fns ============
  function setGasCap(uint256 _gasCap) public onlyOwner {
    _setGasCap(_gasCap);
  }

  // ============ Internal Fns ============

  /**
   * @notice Used (by admin) to update the gas cap
   * @param _gasCap The new value
   */
  function _setGasCap(uint256 _gasCap) internal {
    emit GasCapUpdated(gasCap, _gasCap);
    gasCap = _gasCap;
  }

  /**
   * @notice Used to get the gas to use. Will be the original value IFF it
   * is less than the cap
   * @param _gas The proposed gas value
   */
  function _getGas(uint256 _gas) internal view returns (uint256) {
    if (_gas > gasCap) {
      _gas = gasCap;
    }
    return _gas;
  }
}

// File: contracts/messaging/connectors/HubConnector.sol



// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

import {Connector} from "./Connector.sol";

/**
 * @title HubConnector
 * @author Connext Labs, Inc.
 * @notice This contract implements the messaging functions needed on the hub-side of a given AMB.
 * The HubConnector has a limited set of functionality compared to the SpokeConnector, namely that
 * it contains no logic to store or prove messages.
 *
 * @dev This contract should be deployed on the hub-side of an AMB (i.e. on L1), and contracts
 * which extend this should implement the virtual functions defined in the BaseConnector class
 */
abstract contract HubConnector is Connector {
  /**
   * @notice Creates a new HubConnector instance
   * @dev The connectors are deployed such that there is one on each side of an AMB (i.e.
   * for optimism, there is one connector on optimism and one connector on mainnet)
   * @param _domain The domain this connector lives on
   * @param _mirrorDomain The spoke domain
   * @param _amb The address of the amb on the domain this connector lives on
   * @param _rootManager The address of the RootManager on mainnet
   * @param _mirrorConnector The address of the spoke connector
   */
  constructor(
    uint32 _domain,
    uint32 _mirrorDomain,
    address _amb,
    address _rootManager,
    address _mirrorConnector
  ) Connector(_domain, _mirrorDomain, _amb, _rootManager, _mirrorConnector) {}

  // ============ Public fns ============
  /**
   * @notice Sends a message over the amb
   * @dev This is called by the root manager *only* on mainnet to propagate the aggregate root
   */
  function sendMessage(bytes memory _data, bytes memory _encodedData) external payable onlyRootManager {
    _sendMessage(_data, _encodedData);
    emit MessageSent(_data, _encodedData, msg.sender);
  }
}

// File: contracts/messaging/connectors/wormhole/BaseWormhole.sol



// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

import {IWormholeRelayer} from "../../interfaces/ambs/wormhole/IWormholeRelayer.sol";

import {GasCap} from "../GasCap.sol";

abstract contract BaseWormhole is GasCap {
  // ============ Events ============

  event RefundAddressUpdated(address indexed previous, address indexed updated);

  // ============ Storage ============
  /**
   * @notice The wormhole id for the mirror network
   */
  uint16 public immutable MIRROR_WORMHOLE_ID;

  /**
   * @notice The address on this chain any refunds from wormhole fees will be
   * sent to
   */
  address public refundAddress;

  /**
   * @notice Mapping of processed messages from wormhole.
   * @dev Used for replay protection.
   */
  mapping(bytes32 => bool) public processedWhMessages;

  // ============ Constructor ============
  constructor(uint256 _gasCap, uint16 _mirrorWormholeChainId) GasCap(_gasCap) {
    MIRROR_WORMHOLE_ID = _mirrorWormholeChainId;
    _setRefundAddress(msg.sender);
  }

  // ============ Admin fns ============
  /**
   * @notice Allows the owner to set a new address to collect excess wormhole fees.
   * @param _updated The updated refund address
   */
  function setRefundAddress(address _updated) public onlyOwner {
    _setRefundAddress(_updated);
  }

  // ============ Public fns ============

  /**
   * @dev calculcate gas to call `receiveWormholeMessages` on target chain
   * https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/relayer/deliveryProvider/DeliveryProvider.sol
   */
  function quoteEVMDeliveryPrice(uint256 _gasLimit, address _amb) public view returns (uint256 _cost) {
    // First Get the gas, if it is more than the cap use the cap
    // And calculcate delievery price with gasCap
    (_cost, ) = IWormholeRelayer(_amb).quoteEVMDeliveryPrice(MIRROR_WORMHOLE_ID, 0, _getGas(_gasLimit));
  }

  // ============ Private fns ============

  function _setRefundAddress(address _updated) internal {
    require(_updated != refundAddress, "!changed");
    emit RefundAddressUpdated(refundAddress, _updated);
    refundAddress = _updated;
  }

  /**
   * @dev Asserts the sender of a cross domain message
   */
  function _verifySender(address _mirrorConnector, address _expected) internal pure returns (bool) {
    return _mirrorConnector == _expected;
  }

  // DO NOT override _processMessage, should revert from `Connector` class. All messages must use the _processMessageFrom function
  /**
   * @notice This function is called to handle incoming messages. Should store the latest
   * root generated on the l2 domain.
   */
  function _processMessageFrom(address _sender, bytes memory _data) internal virtual;

  /**
   * @notice Performs sanity checks specific to receiving wormhole messages.
   * @dev Checks the sender is the AMB, the chain is the mirror, and replay.
   */
  function _wormholeSanityChecks(uint16 _sourceChain, address _amb, bytes32 _deliveryHash) internal {
    require(_sourceChain == MIRROR_WORMHOLE_ID, "!source chain");
    require(msg.sender == _amb, "!relayer");

    // Check that the VAA hasn't already been processed (replay protection)
    require(!processedWhMessages[_deliveryHash], "already processed");

    // Add the VAA to processed messages so it can't be replayed
    // you can alternatively rely on the replay protection
    // of something like transferWithPayload from the Token Bridge module
    processedWhMessages[_deliveryHash] = true;
  }

  /**
   * @dev send message via wormhole.
   * https://book.wormhole.com/technical/evm/relayer.html#sending-messages
   */
  function _sendMessage(
    address _amb,
    address _mirrorConnector,
    bytes memory _data,
    bytes memory _encodedData
  ) internal {
    // Should always be sending a merkle root
    require(_data.length == 32, "!data length");

    // Should include gas limit info in specialized calldata
    require(_encodedData.length == 32, "!encoded data length");

    //calculate cost to deliver message
    uint256 gasLimit = abi.decode(_encodedData, (uint256));
    uint256 deliveryCost = quoteEVMDeliveryPrice(gasLimit, _amb);
    require(deliveryCost == msg.value, "!msg.value");

    // publish delivery request
    IWormholeRelayer(_amb).sendPayloadToEvm{value: deliveryCost}(
      MIRROR_WORMHOLE_ID,
      _mirrorConnector,
      _data,
      0,
      gasLimit,
      MIRROR_WORMHOLE_ID, // refundChain
      refundAddress // refundAddress
    );
  }

  /**
   * @notice Converts from wormhole 32 byte identifier format to evm address
   */
  function _fromWormholeFormat(bytes32 _whFormatAddress) internal pure returns (address) {
    require(uint256(_whFormatAddress) >> 160 == 0, "!evm address");
    return address(uint160(uint256(_whFormatAddress)));
  }
}

// File: contracts/messaging/connectors/wormhole/WormholeHubConnector.sol



// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

import {IRootManager} from "../../interfaces/IRootManager.sol";
import {IWormholeReceiver} from "../../interfaces/ambs/wormhole/IWormholeReceiver.sol";

import {HubConnector, Connector} from "../HubConnector.sol";

import {BaseWormhole} from "./BaseWormhole.sol";

contract WormholeHubConnector is HubConnector, BaseWormhole, IWormholeReceiver {
  // ============ Constructor ============
  constructor(
    uint32 _domain,
    uint32 _mirrorDomain,
    address _amb,
    address _rootManager,
    address _mirrorConnector,
    uint256 _gasCap,
    uint16 _mirrorWormholeChainId
  )
    HubConnector(_domain, _mirrorDomain, _amb, _rootManager, _mirrorConnector)
    BaseWormhole(_gasCap, _mirrorWormholeChainId)
  {}

  // ============ Override Fns ============
  function _verifySender(address _expected) internal view override returns (bool) {
    return _verifySender(mirrorConnector, _expected);
  }

  // ============ Public fns ============
  /**
   * @notice This function is called to receive messages through the wormhole relayer module
   * https://book.wormhole.com/technical/evm/relayer.html
   * @dev This is defined here instead of the `BaseWormhole` to avoid storing AMB values twice.
   */
  function receiveWormholeMessages(
    bytes memory _payload,
    bytes[] memory, // additionalVaas,
    bytes32 _sourceAddress,
    uint16 _sourceChain,
    bytes32 _deliveryHash
  ) public payable override {
    _wormholeSanityChecks(_sourceChain, AMB, _deliveryHash);

    _processMessageFrom(_fromWormholeFormat(_sourceAddress), _payload);
  }

  // ============ Private fns ============
  /**
   * @dev Handles an incoming `outboundRoot`
   */
  function _processMessageFrom(address _sender, bytes memory _data) internal override(BaseWormhole) {
    // enforce this came from connector on l2
    require(_verifySender(_sender), "!l2Connector");

    // get the data (should be the outbound root)
    require(_data.length == 32, "!length");

    // set the outbound root for BSC domain
    IRootManager(ROOT_MANAGER).aggregate(MIRROR_DOMAIN, bytes32(_data));

    emit MessageProcessed(_data, msg.sender);
  }

  function _sendMessage(bytes memory _data, bytes memory _encodedData) internal override {
    _sendMessage(AMB, mirrorConnector, _data, _encodedData);
  }
}

// File: contracts/messaging/interfaces/IConnector.sol



// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

import {IProposedOwnable} from "../../shared/interfaces/IProposedOwnable.sol";

/**
 * @notice This interface is what the Connext contract will send and receive messages through.
 * The messaging layer should conform to this interface, and should be interchangeable (i.e.
 * could be Nomad or a generic AMB under the hood).
 *
 * @dev This uses the nomad format to ensure nomad can be added in as it comes back online.
 *
 * Flow from transfer from polygon to optimism:
 * 1. User calls `xcall` with destination specified
 * 2. This will swap in to the bridge assets
 * 3. The swapped assets will get burned
 * 4. The Connext contract will call `dispatch` on the messaging contract to add the transfer
 *    to the root
 * 5. [At some time interval] Relayers call `send` to send the current root from polygon to
 *    mainnet. This is done on all "spoke" domains.
 * 6. [At some time interval] Relayers call `propagate` [better name] on mainnet, this generates a new merkle
 *    root from all of the AMBs
 *    - This function must be able to read root data from all AMBs and aggregate them into a single merkle
 *      tree root
 *    - Will send the mixed root from all chains back through the respective AMBs to all other chains
 * 7. AMB will call `update` to update the latest root on the messaging contract on spoke domains
 * 8. [At any point] Relayers can call `proveAndProcess` to prove inclusion of dispatched message, and call
 *    process on the `Connext` contract
 * 9. Takes minted bridge tokens and credits the LP
 *
 * AMB requirements:
 * - Access `msg.sender` both from mainnet -> spoke and vice versa
 * - Ability to read *our root* from the AMB
 *
 * AMBs:
 * - PoS bridge from polygon
 * - arbitrum bridge
 * - optimism bridge
 * - gnosis chain
 * - bsc (use multichain for messaging)
 */
interface IConnector is IProposedOwnable {
  // ============ Events ============
  /**
   * @notice Emitted whenever a message is successfully sent over an AMB
   * @param data The contents of the message
   * @param encodedData Data used to send the message; specific to connector
   * @param caller Who called the function (sent the message)
   */
  event MessageSent(bytes data, bytes encodedData, address caller);

  /**
   * @notice Emitted whenever a message is successfully received over an AMB
   * @param data The contents of the message
   * @param caller Who called the function
   */
  event MessageProcessed(bytes data, address caller);

  // ============ Public fns ============

  function processMessage(bytes memory _data) external;

  function verifySender(address _expected) external returns (bool);
}

// File: contracts/messaging/interfaces/IRootManager.sol



// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

interface IRootManager {
  /**
   * @notice This is called by relayers to generate + send the mixed root from mainnet via AMB to
   * spoke domains.
   * @dev This must read information for the root from the registered AMBs.
   */
  function propagate(
    address[] calldata _connectors,
    uint256[] calldata _fees,
    bytes[] memory _encodedData
  ) external payable;

  /**
   * @notice Called by the connectors for various domains on the hub to aggregate their latest
   * inbound root.
   * @dev This must read information for the root from the registered AMBs
   */
  function aggregate(uint32 _domain, bytes32 _outbound) external;
}

// File: contracts/messaging/interfaces/ambs/wormhole/IWormholeReceiver.sol



// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

/**
 * @notice Interface for a contract which can receive Wormhole messages.
 */
interface IWormholeReceiver {
  /**
   * @notice When a `send` is performed with this contract as the target, this function will be
   *     invoked by the WormholeRelayer contract
   *
   * NOTE: This function should be restricted such that only the Wormhole Relayer contract can call it.
   *
   * We also recommend that this function:
   *   - Stores all received `deliveryHash`s in a mapping `(bytes32 => bool)`, and
   *       on every call, checks that deliveryHash has not already been stored in the
   *       map (This is to prevent other users maliciously trying to relay the same message)
   *   - Checks that `sourceChain` and `sourceAddress` are indeed who
   *       you expect to have requested the calling of `send` or `forward` on the source chain
   *
   * The invocation of this function corresponding to the `send` request will have msg.value equal
   *   to the receiverValue specified in the send request.
   *
   * If the invocation of this function reverts or exceeds the gas limit
   *   specified by the send requester, this delivery will result in a `ReceiverFailure`.
   *
   * @param payload - an arbitrary message which was included in the delivery by the
   *     requester.
   * @param additionalVaas - Additional VAAs which were requested to be included in this delivery.
   *   They are guaranteed to all be included and in the same order as was specified in the
   *     delivery request.
   * @param sourceAddress - the (wormhole format) address on the sending chain which requested
   *     this delivery.
   * @param sourceChain - the wormhole chain ID where this delivery was requested.
   * @param deliveryHash - the VAA hash of the deliveryVAA.
   *
   * NOTE: These signedVaas are NOT verified by the Wormhole core contract prior to being provided
   *     to this call. Always make sure `parseAndVerify()` is called on the Wormhole core contract
   *     before trusting the content of a raw VAA, otherwise the VAA may be invalid or malicious.
   */
  function receiveWormholeMessages(
    bytes memory payload,
    bytes[] memory additionalVaas,
    bytes32 sourceAddress,
    uint16 sourceChain,
    bytes32 deliveryHash
  ) external payable;
}

// File: contracts/messaging/interfaces/ambs/wormhole/IWormholeRelayer.sol



// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

/**
 * @title WormholeRelayer
 * @author
 * @notice This project allows developers to build cross-chain applications powered by Wormhole without needing to
 * write and run their own relaying infrastructure
 *
 * We implement the IWormholeRelayer interface that allows users to request a delivery provider to relay a payload (and/or additional VAAs)
 * to a chain and address of their choice.
 */

/**
 * @notice VaaKey identifies a wormhole message
 *
 * @custom:member chainId Wormhole chain ID of the chain where this VAA was emitted from
 * @custom:member emitterAddress Address of the emitter of the VAA, in Wormhole bytes32 format
 * @custom:member sequence Sequence number of the VAA
 */
struct VaaKey {
  uint16 chainId;
  bytes32 emitterAddress;
  uint64 sequence;
}

interface IWormholeRelayerBase {
  event SendEvent(uint64 indexed sequence, uint256 deliveryQuote, uint256 paymentForExtraReceiverValue);

  function getRegisteredWormholeRelayerContract(uint16 chainId) external view returns (bytes32);
}

/**
 * @title IWormholeRelayerSend
 * @notice The interface to request deliveries
 */
interface IWormholeRelayerSend is IWormholeRelayerBase {
  /**
   * @notice Publishes an instruction for the default delivery provider
   * to relay a payload to the address `targetAddress` on chain `targetChain`
   * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
   *
   * `targetAddress` must implement the IWormholeReceiver interface
   *
   * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
   *
   * Any refunds (from leftover gas) will be paid to the delivery provider. In order to receive the refunds, use the `sendPayloadToEvm` function
   * with `refundChain` and `refundAddress` as parameters
   *
   * @param targetChain in Wormhole Chain ID format
   * @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
   * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param gasLimit gas limit with which to call `targetAddress`.
   * @return sequence sequence number of published VAA containing delivery instructions
   */
  function sendPayloadToEvm(
    uint16 targetChain,
    address targetAddress,
    bytes memory payload,
    uint256 receiverValue,
    uint256 gasLimit
  ) external payable returns (uint64 sequence);

  /**
   * @notice Publishes an instruction for the default delivery provider
   * to relay a payload to the address `targetAddress` on chain `targetChain`
   * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
   *
   * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
   * `targetAddress` must implement the IWormholeReceiver interface
   *
   * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
   *
   * @param targetChain in Wormhole Chain ID format
   * @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
   * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
   *        `targetChainRefundPerGasUnused` rate quoted by the delivery provider
   * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
   * @param refundAddress The address on `refundChain` to deliver any refund to
   * @return sequence sequence number of published VAA containing delivery instructions
   */
  function sendPayloadToEvm(
    uint16 targetChain,
    address targetAddress,
    bytes memory payload,
    uint256 receiverValue,
    uint256 gasLimit,
    uint16 refundChain,
    address refundAddress
  ) external payable returns (uint64 sequence);

  /**
   * @notice Publishes an instruction for the default delivery provider
   * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
   * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
   *
   * `targetAddress` must implement the IWormholeReceiver interface
   *
   * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
   *
   * Any refunds (from leftover gas) will be paid to the delivery provider. In order to receive the refunds, use the `sendVaasToEvm` function
   * with `refundChain` and `refundAddress` as parameters
   *
   * @param targetChain in Wormhole Chain ID format
   * @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
   * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param gasLimit gas limit with which to call `targetAddress`.
   * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
   * @return sequence sequence number of published VAA containing delivery instructions
   */
  function sendVaasToEvm(
    uint16 targetChain,
    address targetAddress,
    bytes memory payload,
    uint256 receiverValue,
    uint256 gasLimit,
    VaaKey[] memory vaaKeys
  ) external payable returns (uint64 sequence);

  /**
   * @notice Publishes an instruction for the default delivery provider
   * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
   * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
   *
   * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
   * `targetAddress` must implement the IWormholeReceiver interface
   *
   * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
   *
   * @param targetChain in Wormhole Chain ID format
   * @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
   * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
   *        `targetChainRefundPerGasUnused` rate quoted by the delivery provider
   * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
   * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
   * @param refundAddress The address on `refundChain` to deliver any refund to
   * @return sequence sequence number of published VAA containing delivery instructions
   */
  function sendVaasToEvm(
    uint16 targetChain,
    address targetAddress,
    bytes memory payload,
    uint256 receiverValue,
    uint256 gasLimit,
    VaaKey[] memory vaaKeys,
    uint16 refundChain,
    address refundAddress
  ) external payable returns (uint64 sequence);

  /**
   * @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress`
   * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
   * with gas limit `gasLimit` and `msg.value` equal to
   * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
   *
   * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
   * `targetAddress` must implement the IWormholeReceiver interface
   *
   * This function must be called with `msg.value` equal to
   * quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit, deliveryProviderAddress) + paymentForExtraReceiverValue
   *
   * @param targetChain in Wormhole Chain ID format
   * @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
   * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
   *        (in addition to the `receiverValue` specified)
   * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
   *        `targetChainRefundPerGasUnused` rate quoted by the delivery provider
   * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
   * @param refundAddress The address on `refundChain` to deliver any refund to
   * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
   * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
   * @param consistencyLevel Consistency level with which to publish the delivery instructions - see
   *        https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
   * @return sequence sequence number of published VAA containing delivery instructions
   */
  function sendToEvm(
    uint16 targetChain,
    address targetAddress,
    bytes memory payload,
    uint256 receiverValue,
    uint256 paymentForExtraReceiverValue,
    uint256 gasLimit,
    uint16 refundChain,
    address refundAddress,
    address deliveryProviderAddress,
    VaaKey[] memory vaaKeys,
    uint8 consistencyLevel
  ) external payable returns (uint64 sequence);

  /**
   * @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress`
   * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
   * with `msg.value` equal to
   * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
   *
   * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
   * `targetAddress` must implement the IWormholeReceiver interface
   *
   * This function must be called with `msg.value` equal to
   * quoteDeliveryPrice(targetChain, receiverValue, encodedExecutionParameters, deliveryProviderAddress) + paymentForExtraReceiverValue
   *
   * @param targetChain in Wormhole Chain ID format
   * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format
   * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
   *        (in addition to the `receiverValue` specified)
   * @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
   *        e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
   * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
   * @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format
   * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
   * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
   * @param consistencyLevel Consistency level with which to publish the delivery instructions - see
   *        https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
   * @return sequence sequence number of published VAA containing delivery instructions
   */
  function send(
    uint16 targetChain,
    bytes32 targetAddress,
    bytes memory payload,
    uint256 receiverValue,
    uint256 paymentForExtraReceiverValue,
    bytes memory encodedExecutionParameters,
    uint16 refundChain,
    bytes32 refundAddress,
    address deliveryProviderAddress,
    VaaKey[] memory vaaKeys,
    uint8 consistencyLevel
  ) external payable returns (uint64 sequence);

  /**
   * @notice Performs the same function as a `send`, except:
   * 1)  Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`)
   * 2)  Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery)
   * 3)  Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number)
   *
   * The refund from the delivery currently in progress will not be sent to the user; it will instead
   * be paid to the delivery provider to perform the instruction specified here
   *
   * Publishes an instruction for the same delivery provider (or default, if the same one doesn't support the new target chain)
   * to relay a payload to the address `targetAddress` on chain `targetChain`
   * with gas limit `gasLimit` and with `msg.value` equal to `receiverValue`
   *
   * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`):
   * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f]
   * >= sum_f [quoteEVMDeliveryPrice(targetChain_f, receiverValue_f, gasLimit_f)]
   *
   * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested
   *
   * Any refunds (from leftover gas) from this forward will be paid to the same refundChain and refundAddress specified for the current delivery.
   *
   * @param targetChain in Wormhole Chain ID format
   * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format
   * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param gasLimit gas limit with which to call `targetAddress`.
   */
  function forwardPayloadToEvm(
    uint16 targetChain,
    address targetAddress,
    bytes memory payload,
    uint256 receiverValue,
    uint256 gasLimit
  ) external payable;

  /**
   * @notice Performs the same function as a `send`, except:
   * 1)  Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`)
   * 2)  Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery)
   * 3)  Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number)
   *
   * The refund from the delivery currently in progress will not be sent to the user; it will instead
   * be paid to the delivery provider to perform the instruction specified here
   *
   * Publishes an instruction for the same delivery provider (or default, if the same one doesn't support the new target chain)
   * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
   * with gas limit `gasLimit` and with `msg.value` equal to `receiverValue`
   *
   * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`):
   * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f]
   * >= sum_f [quoteEVMDeliveryPrice(targetChain_f, receiverValue_f, gasLimit_f)]
   *
   * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested
   *
   * Any refunds (from leftover gas) from this forward will be paid to the same refundChain and refundAddress specified for the current delivery.
   *
   * @param targetChain in Wormhole Chain ID format
   * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format
   * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param gasLimit gas limit with which to call `targetAddress`.
   * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
   */
  function forwardVaasToEvm(
    uint16 targetChain,
    address targetAddress,
    bytes memory payload,
    uint256 receiverValue,
    uint256 gasLimit,
    VaaKey[] memory vaaKeys
  ) external payable;

  /**
   * @notice Performs the same function as a `send`, except:
   * 1)  Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`)
   * 2)  Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery)
   * 3)  Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number)
   *
   * The refund from the delivery currently in progress will not be sent to the user; it will instead
   * be paid to the delivery provider to perform the instruction specified here
   *
   * Publishes an instruction for the delivery provider at `deliveryProviderAddress`
   * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
   * with gas limit `gasLimit` and with `msg.value` equal to
   * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
   *
   * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
   * `targetAddress` must implement the IWormholeReceiver interface
   *
   * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`):
   * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f]
   * >= sum_f [quoteEVMDeliveryPrice(targetChain_f, receiverValue_f, gasLimit_f, deliveryProviderAddress_f) + paymentForExtraReceiverValue_f]
   *
   * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested
   *
   * @param targetChain in Wormhole Chain ID format
   * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format
   * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
   *        (in addition to the `receiverValue` specified)
   * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
   *        `targetChainRefundPerGasUnused` rate quoted by the delivery provider
   * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
   * @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format
   * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
   * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
   * @param consistencyLevel Consistency level with which to publish the delivery instructions - see
   *        https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
   */
  function forwardToEvm(
    uint16 targetChain,
    address targetAddress,
    bytes memory payload,
    uint256 receiverValue,
    uint256 paymentForExtraReceiverValue,
    uint256 gasLimit,
    uint16 refundChain,
    address refundAddress,
    address deliveryProviderAddress,
    VaaKey[] memory vaaKeys,
    uint8 consistencyLevel
  ) external payable;

  /**
   * @notice Performs the same function as a `send`, except:
   * 1)  Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`)
   * 2)  Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery)
   * 3)  Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number)
   *
   * The refund from the delivery currently in progress will not be sent to the user; it will instead
   * be paid to the delivery provider to perform the instruction specified here
   *
   * Publishes an instruction for the delivery provider at `deliveryProviderAddress`
   * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
   * with `msg.value` equal to
   * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
   *
   * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
   * `targetAddress` must implement the IWormholeReceiver interface
   *
   * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`):
   * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f]
   * >= sum_f [quoteDeliveryPrice(targetChain_f, receiverValue_f, encodedExecutionParameters_f, deliveryProviderAddress_f) + paymentForExtraReceiverValue_f]
   *
   * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested
   *
   * @param targetChain in Wormhole Chain ID format
   * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format
   * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
   *        (in addition to the `receiverValue` specified)
   * @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
   *        e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
   * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
   * @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format
   * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
   * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
   * @param consistencyLevel Consistency level with which to publish the delivery instructions - see
   *        https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
   */
  function forward(
    uint16 targetChain,
    bytes32 targetAddress,
    bytes memory payload,
    uint256 receiverValue,
    uint256 paymentForExtraReceiverValue,
    bytes memory encodedExecutionParameters,
    uint16 refundChain,
    bytes32 refundAddress,
    address deliveryProviderAddress,
    VaaKey[] memory vaaKeys,
    uint8 consistencyLevel
  ) external payable;

  /**
   * @notice Requests a previously published delivery instruction to be redelivered
   * (e.g. with a different delivery provider)
   *
   * This function must be called with `msg.value` equal to
   * quoteEVMDeliveryPrice(targetChain, newReceiverValue, newGasLimit, newDeliveryProviderAddress)
   *
   * @param deliveryVaaKey VaaKey identifying the wormhole message containing the
   *        previously published delivery instructions
   * @param targetChain The target chain that the original delivery targeted. Must match targetChain from original delivery instructions
   * @param newReceiverValue new msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param newGasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
   *        `targetChainRefundPerGasUnused` rate quoted by the delivery provider, to the refund chain and address specified in the original request
   * @param newDeliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
   * @return sequence sequence number of published VAA containing redelivery instructions
   */
  function resendToEvm(
    VaaKey memory deliveryVaaKey,
    uint16 targetChain,
    uint256 newReceiverValue,
    uint256 newGasLimit,
    address newDeliveryProviderAddress
  ) external payable returns (uint64 sequence);

  /**
   * @notice Requests a previously published delivery instruction to be redelivered
   *
   *
   * This function must be called with `msg.value` equal to
   * quoteDeliveryPrice(targetChain, newReceiverValue, newEncodedExecutionParameters, newDeliveryProviderAddress)
   *
   * @param deliveryVaaKey VaaKey identifying the wormhole message containing the
   *        previously published delivery instructions
   * @param targetChain The target chain that the original delivery targeted. Must match targetChain from original delivery instructions
   * @param newReceiverValue new msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param newEncodedExecutionParameters new encoded information on how to execute delivery that may impact pricing
   *        e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
   * @param newDeliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
   * @return sequence sequence number of published VAA containing redelivery instructions
   */
  function resend(
    VaaKey memory deliveryVaaKey,
    uint16 targetChain,
    uint256 newReceiverValue,
    bytes memory newEncodedExecutionParameters,
    address newDeliveryProviderAddress
  ) external payable returns (uint64 sequence);

  /**
   * @notice Returns the price to request a relay to chain `targetChain`, using the default delivery provider
   *
   * @param targetChain in Wormhole Chain ID format
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param gasLimit gas limit with which to call `targetAddress`.
   * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
   * @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas unused,
   *         if a refundAddress is specified
   */
  function quoteEVMDeliveryPrice(
    uint16 targetChain,
    uint256 receiverValue,
    uint256 gasLimit
  ) external view returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused);

  /**
   * @notice Returns the price to request a relay to chain `targetChain`, using delivery provider `deliveryProviderAddress`
   *
   * @param targetChain in Wormhole Chain ID format
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param gasLimit gas limit with which to call `targetAddress`.
   * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
   * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
   * @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas unused,
   *         if a refundAddress is specified
   */
  function quoteEVMDeliveryPrice(
    uint16 targetChain,
    uint256 receiverValue,
    uint256 gasLimit,
    address deliveryProviderAddress
  ) external view returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused);

  /**
   * @notice Returns the price to request a relay to chain `targetChain`, using delivery provider `deliveryProviderAddress`
   *
   * @param targetChain in Wormhole Chain ID format
   * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
   * @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
   *        e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
   * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
   * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
   * @return encodedExecutionInfo encoded information on how the delivery will be executed
   *        e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` and `targetChainRefundPerGasUnused`
   *             (which is the amount of target chain currency that will be refunded per unit of gas unused,
   *              if a refundAddress is specified)
   */
  function quoteDeliveryPrice(
    uint16 targetChain,
    uint256 receiverValue,
    bytes memory encodedExecutionParameters,
    address deliveryProviderAddress
  ) external view returns (uint256 nativePriceQuote, bytes memory encodedExecutionInfo);

  /**
   * @notice Returns the (extra) amount of target chain currency that `targetAddress`
   * will be called with, if the `paymentForExtraReceiverValue` field is set to `currentChainAmount`
   *
   * @param targetChain in Wormhole Chain ID format
   * @param currentChainAmount The value that `paymentForExtraReceiverValue` will be set to
   * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
   * @return targetChainAmount The amount such that if `targetAddress` will be called with `msg.value` equal to
   *         receiverValue + targetChainAmount
   */
  function quoteNativeForChain(
    uint16 targetChain,
    uint256 currentChainAmount,
    address deliveryProviderAddress
  ) external view returns (uint256 targetChainAmount);

  /**
   * @notice Returns the address of the current default delivery provider
   * @return deliveryProvider The address of (the default delivery provider)'s contract on this source
   *   chain. This must be a contract that implements IDeliveryProvider.
   */
  function getDefaultDeliveryProvider() external view returns (address deliveryProvider);
}

/**
 * @title IWormholeRelayerDelivery
 * @notice The interface to execute deliveries. Only relevant for Delivery Providers
 */
interface IWormholeRelayerDelivery is IWormholeRelayerBase {
  enum DeliveryStatus {
    SUCCESS,
    RECEIVER_FAILURE,
    FORWARD_REQUEST_FAILURE,
    FORWARD_REQUEST_SUCCESS
  }

  enum RefundStatus {
    REFUND_SENT,
    REFUND_FAIL,
    CROSS_CHAIN_REFUND_SENT,
    CROSS_CHAIN_REFUND_FAIL_PROVIDER_NOT_SUPPORTED,
    CROSS_CHAIN_REFUND_FAIL_NOT_ENOUGH
  }

  /**
   * @custom:member recipientContract - The target contract address
   * @custom:member sourceChain - The chain which this delivery was requested from (in wormhole
   *     ChainID format)
   * @custom:member sequence - The wormhole sequence number of the delivery VAA on the source chain
   *     corresponding to this delivery request
   * @custom:member deliveryVaaHash - The hash of the delivery VAA corresponding to this delivery
   *     request
   * @custom:member gasUsed - The amount of gas that was used to call your target contract
   * @custom:member status:
   *   - RECEIVER_FAILURE, if the target contract reverts
   *   - SUCCESS, if the target contract doesn't revert and no forwards were requested
   *   - FORWARD_REQUEST_FAILURE, if the target contract doesn't revert, forwards were requested,
   *       but provided/leftover funds were not sufficient to cover them all
   *   - FORWARD_REQUEST_SUCCESS, if the target contract doesn't revert and all forwards are covered
   * @custom:member additionalStatusInfo:
   *   - If status is SUCCESS or FORWARD_REQUEST_SUCCESS, then this is empty.
   *   - If status is RECEIVER_FAILURE, this is `RETURNDATA_TRUNCATION_THRESHOLD` bytes of the
   *       return data (i.e. potentially truncated revert reason information).
   *   - If status is FORWARD_REQUEST_FAILURE, this is also the revert data - the reason the forward failed.
   *     This will be either an encoded Cancelled, DeliveryProviderReverted, or DeliveryProviderPaymentFailed error
   * @custom:member refundStatus - Result of the refund. REFUND_SUCCESS or REFUND_FAIL are for
   *     refunds where targetChain=refundChain; the others are for targetChain!=refundChain,
   *     where a cross chain refund is necessary
   * @custom:member overridesInfo:
   *   - If not an override: empty bytes array
   *   - Otherwise: An encoded `DeliveryOverride`
   */
  event Delivery(
    address indexed recipientContract,
    uint16 indexed sourceChain,
    uint64 indexed sequence,
    bytes32 deliveryVaaHash,
    DeliveryStatus status,
    uint256 gasUsed,
    RefundStatus refundStatus,
    bytes additionalStatusInfo,
    bytes overridesInfo
  );

  /**
   * @notice The delivery provider calls `deliver` to relay messages as described by one delivery instruction
   *
   * The delivery provider must pass in the specified (by VaaKeys[]) signed wormhole messages (VAAs) from the source chain
   * as well as the signed wormhole message with the delivery instructions (the delivery VAA)
   *
   * The messages will be relayed to the target address (with the specified gas limit and receiver value) iff the following checks are met:
   * - the delivery VAA has a valid signature
   * - the delivery VAA's emitter is one of these WormholeRelayer contracts
   * - the delivery provider passed in at least enough of this chain's currency as msg.value (enough meaning the maximum possible refund)
   * - the instruction's target chain is this chain
   * - the relayed signed VAAs match the descriptions in container.messages (the VAA hashes match, or the emitter address, sequence number pair matches, depending on the description given)
   *
   * @param encodedVMs - An array of signed wormhole messages (all from the same source chain
   *     transaction)
   * @param encodedDeliveryVAA - Signed wormhole message from the source chain's WormholeRelayer
   *     contract with payload being the encoded delivery instruction container
   * @param relayerRefundAddress - The address to which any refunds to the delivery provider
   *     should be sent
   * @param deliveryOverrides - Optional overrides field which must be either an empty bytes array or
   *     an encoded DeliveryOverride struct
   */
  function deliver(
    bytes[] memory encodedVMs,
    bytes memory encodedDeliveryVAA,
    address payable relayerRefundAddress,
    bytes memory deliveryOverrides
  ) external payable;
}

interface IWormholeRelayer is IWormholeRelayerDelivery, IWormholeRelayerSend {}

/*
 *  Errors thrown by IWormholeRelayer contract
 */

// Bound chosen by the following formula: `memoryWord * 4 + selectorSize`.
// This means that an error identifier plus four fixed size arguments should be available to developers.
// In the case of a `require` revert with error message, this should provide 2 memory word's worth of data.
uint256 constant RETURNDATA_TRUNCATION_THRESHOLD = 132;

//When msg.value was not equal to `delivery provider's quoted delivery price` + `paymentForExtraReceiverValue`
error InvalidMsgValue(uint256 msgValue, uint256 totalFee);

error RequestedGasLimitTooLow();

error DeliveryProviderDoesNotSupportTargetChain(address relayer, uint16 chainId);
error DeliveryProviderCannotReceivePayment();

//When calling `forward()` on the WormholeRelayer if no delivery is in progress
error NoDeliveryInProgress();
//When calling `delivery()` a second time even though a delivery is already in progress
error ReentrantDelivery(address msgSender, address lockedBy);
//When any other contract but the delivery target calls `forward()` on the WormholeRelayer while a
//  delivery is in progress
error ForwardRequestFromWrongAddress(address msgSender, address deliveryTarget);

error InvalidPayloadId(uint8 parsed, uint8 expected);
error InvalidPayloadLength(uint256 received, uint256 expected);
error InvalidVaaKeyType(uint8 parsed);

error InvalidDeliveryVaa(string reason);
//When the delivery VAA (signed wormhole message with delivery instructions) was not emitted by the
//  registered WormholeRelayer contract
error InvalidEmitter(bytes32 emitter, bytes32 registered, uint16 chainId);
error VaaKeysLengthDoesNotMatchVaasLength(uint256 keys, uint256 vaas);
error VaaKeysDoNotMatchVaas(uint8 index);
//When someone tries to call an external function of the WormholeRelayer that is only intended to be
//  called by the WormholeRelayer itself (to allow retroactive reverts for atomicity)
error RequesterNotWormholeRelayer();

//When trying to relay a `DeliveryInstruction` to any other chain but the one it was specified for
error TargetChainIsNotThisChain(uint16 targetChain);
error ForwardNotSufficientlyFunded(uint256 amountOfFunds, uint256 amountOfFundsNeeded);
//When a `DeliveryOverride` contains a gas limit that's less than the original
error InvalidOverrideGasLimit();
//When a `DeliveryOverride` contains a receiver value that's less than the original
error InvalidOverrideReceiverValue();
//When a `DeliveryOverride` contains a 'refund per unit of gas unused' that's less than the original
error InvalidOverrideRefundPerGasUnused();

//When the delivery provider doesn't pass in sufficient funds (i.e. msg.value does not cover the
// maximum possible refund to the user)
error InsufficientRelayerFunds(uint256 msgValue, uint256 minimum);

//When a bytes32 field can't be converted into a 20 byte EVM address, because the 12 padding bytes
//  are non-zero (duplicated from Utils.sol)
error NotAnEvmAddress(bytes32);

// File: contracts/shared/ProposedOwnable.sol



// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;

import {IProposedOwnable} from "./interfaces/IProposedOwnable.sol";

/**
 * @title ProposedOwnable
 * @notice Contract module which provides a basic access control mechanism,
 * where there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed via a two step process:
 * 1. Call `proposeOwner`
 * 2. Wait out the delay period
 * 3. Call `acceptOwner`
 *
 * @dev This module is used through inheritance. It will make available the
 * modifier `onlyOwner`, which can be applied to your functions to restrict
 * their use to the owner.
 *
 * @dev The majority of this code was taken from the openzeppelin Ownable
 * contract
 *
 */
abstract contract ProposedOwnable is IProposedOwnable {
  // ========== Custom Errors ===========

  error ProposedOwnable__onlyOwner_notOwner();
  error ProposedOwnable__onlyProposed_notProposedOwner();
  error ProposedOwnable__ownershipDelayElapsed_delayNotElapsed();
  error ProposedOwnable__proposeNewOwner_invalidProposal();
  error ProposedOwnable__proposeNewOwner_noOwnershipChange();
  error ProposedOwnable__renounceOwnership_noProposal();
  error ProposedOwnable__renounceOwnership_invalidProposal();

  // ============ Properties ============

  address private _owner;

  address private _proposed;
  uint256 private _proposedOwnershipTimestamp;

  uint256 private constant _delay = 7 days;

  // ======== Getters =========

  /**
   * @notice Returns the address of the current owner.
   */
  function owner() public view virtual returns (address) {
    return _owner;
  }

  /**
   * @notice Returns the address of the proposed owner.
   */
  function proposed() public view virtual returns (address) {
    return _proposed;
  }

  /**
   * @notice Returns the address of the proposed owner.
   */
  function proposedTimestamp() public view virtual returns (uint256) {
    return _proposedOwnershipTimestamp;
  }

  /**
   * @notice Returns the delay period before a new owner can be accepted.
   */
  function delay() public view virtual returns (uint256) {
    return _delay;
  }

  /**
   * @notice Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    if (_owner != msg.sender) revert ProposedOwnable__onlyOwner_notOwner();
    _;
  }

  /**
   * @notice Throws if called by any account other than the proposed owner.
   */
  modifier onlyProposed() {
    if (_proposed != msg.sender) revert ProposedOwnable__onlyProposed_notProposedOwner();
    _;
  }

  /**
   * @notice Throws if the ownership delay has not elapsed
   */
  modifier ownershipDelayElapsed() {
    // Ensure delay has elapsed
    if ((block.timestamp - _proposedOwnershipTimestamp) <= _delay)
      revert ProposedOwnable__ownershipDelayElapsed_delayNotElapsed();
    _;
  }

  /**
   * @notice Indicates if the ownership has been renounced() by
   * checking if current owner is address(0)
   */
  function renounced() public view returns (bool) {
    return _owner == address(0);
  }

  // ======== External =========

  /**
   * @notice Sets the timestamp for an owner to be proposed, and sets the
   * newly proposed owner as step 1 in a 2-step process
   */
  function proposeNewOwner(address newlyProposed) public virtual onlyOwner {
    // Contract as source of truth
    if (_proposed == newlyProposed && _proposedOwnershipTimestamp != 0)
      revert ProposedOwnable__proposeNewOwner_invalidProposal();

    // Sanity check: reasonable proposal
    if (_owner == newlyProposed) revert ProposedOwnable__proposeNewOwner_noOwnershipChange();

    _setProposed(newlyProposed);
  }

  /**
   * @notice Renounces ownership of the contract after a delay
   */
  function renounceOwnership() public virtual onlyOwner ownershipDelayElapsed {
    // Ensure there has been a proposal cycle started
    if (_proposedOwnershipTimestamp == 0) revert ProposedOwnable__renounceOwnership_noProposal();

    // Require proposed is set to 0
    if (_proposed != address(0)) revert ProposedOwnable__renounceOwnership_invalidProposal();

    // Emit event, set new owner, reset timestamp
    _setOwner(address(0));
  }

  /**
   * @notice Transfers ownership of the contract to a new account (`newOwner`).
   * Can only be called by the current owner.
   */
  function acceptProposedOwner() public virtual onlyProposed ownershipDelayElapsed {
    // NOTE: no need to check if _owner == _proposed, because the _proposed
    // is 0-d out and this check is implicitly enforced by modifier

    // NOTE: no need to check if _proposedOwnershipTimestamp > 0 because
    // the only time this would happen is if the _proposed was never
    // set (will fail from modifier) or if the owner == _proposed (checked
    // above)

    // Emit event, set new owner, reset timestamp
    _setOwner(_proposed);
  }

  // ======== Internal =========

  function _setOwner(address newOwner) internal {
    emit OwnershipTransferred(_owner, newOwner);
    _owner = newOwner;
    delete _proposedOwnershipTimestamp;
    delete _proposed;
  }

  function _setProposed(address newlyProposed) private {
    _proposedOwnershipTimestamp = block.timestamp;
    _proposed = newlyProposed;
    emit OwnershipProposed(newlyProposed);
  }
}

// File: contracts/shared/interfaces/IProposedOwnable.sol



// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @title IProposedOwnable
 * @notice Defines a minimal interface for ownership with a two step proposal and acceptance
 * process
 */
interface IProposedOwnable {
  /**
   * @dev This emits when change in ownership of a contract is proposed.
   */
  event OwnershipProposed(address indexed proposedOwner);

  /**
   * @dev This emits when ownership of a contract changes.
   */
  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  /**
   * @notice Get the address of the owner
   * @return owner_ The address of the owner.
   */
  function owner() external view returns (address owner_);

  /**
   * @notice Get the address of the proposed owner
   * @return proposed_ The address of the proposed.
   */
  function proposed() external view returns (address proposed_);

  /**
   * @notice Set the address of the proposed owner of the contract
   * @param newlyProposed The proposed new owner of the contract
   */
  function proposeNewOwner(address newlyProposed) external;

  /**
   * @notice Set the address of the proposed owner of the contract
   */
  function acceptProposedOwner() external;
}