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



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

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);

  // ============ 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);
  }

  // ============ 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 {ProposedOwnable} from "../../shared/ProposedOwnable.sol";

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 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 {IWormholeReceiver} from "../../interfaces/ambs/wormhole/IWormholeReceiver.sol";

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

abstract contract BaseWormhole is GasCap, IWormholeReceiver {
  // ============ Storage ============
  uint16 public immutable MIRROR_CHAIN_ID;
  mapping(bytes32 => bool) public processedWhMessages;

  // ============ Constructor ============
  constructor(uint256 _gasCap, uint16 _mirrorChainId) GasCap(_gasCap) {
    MIRROR_CHAIN_ID = _mirrorChainId;
  }

  // ============ Public Fns ============
  function receiveWormholeMessages(
    bytes memory payload,
    bytes[] memory additionalVaas,
    bytes32 sourceAddress,
    uint16 sourceChain,
    bytes32 deliveryHash
  ) public payable override {
    require(sourceChain == MIRROR_CHAIN_ID, "!source chain");

    // 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;

    _processMessageFrom(fromWormholeFormat(sourceAddress), payload);
  }

  // ============ Private fns ============
  /**
   * @dev Asserts the sender of a cross domain message
   */
  function _verifySender(address _amb, address _mirrorConnector, address _expected) internal view returns (bool) {
    require(msg.sender == _amb, "!relayer");
    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;

  function _sendMessage(
    address _amb,
    address _mirrorConnector,
    address _refund,
    bytes memory _data,
    bytes memory _encodedData
  ) internal {
    // Should always be sending a merkle root
    require(_data.length == 32, "!data length");

    //calculate cost to deliver message
    uint256 gasLimit = _getGasFromEncoded(_encodedData);
    (uint256 deliveryCost, ) = IWormholeRelayer(_amb).quoteEVMDeliveryPrice(MIRROR_CHAIN_ID, 0, gasLimit);

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

  function fromWormholeFormat(bytes32 whFormatAddress) internal pure returns (address) {
    require(uint256(whFormatAddress) >> 160 == 0, "!evm address");
    return address(uint160(uint256(whFormatAddress)));
  }

  /**
   * @notice Using Wormhole relayer (AMB), the gas is provided to `sendMessage` as an encoded uint
   */
  function _getGasFromEncoded(bytes memory _encodedData) internal view returns (uint256 _gas) {
    // Should include gssas info in specialized calldata
    require(_encodedData.length == 32, "!data length");

    // Get the gas, if it is more than the cap use the cap
    _gas = _getGas(abi.decode(_encodedData, (uint256)));
  }
}

// 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 {HubConnector, Connector} from "../HubConnector.sol";

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

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

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

  // ============ 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, owner(), _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.
   *   To get the address that will invoke this contract, call the `getDeliveryAddress()` function
   *     on this chain (the target chain)'s WormholeRelayer contract
   *
   * NOTE: This function should be restricted such that only `getDeliveryAddress()` can call it.
   *
   * We also recommend that this function:
   *   - Stores all received `deliveryData.deliveryHash`s in a mapping `(bytes32 => bool)`, and
   *       on every call, checks that deliveryData.deliveryHash has not already been stored in the
   *       map (This is to prevent other users maliciously trying to relay the same message)
   *   - Checks that `deliveryData.sourceChain` and `deliveryData.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 (`maxTransactionFee`)
   *   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;
}