ETH Price: $2,074.66 (+9.90%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Mirror Conne...187743152023-12-13 2:36:35806 days ago1702434995IN
0xae6B9cDE...2B78a99DA
0 ETH0.0028932260.72582571
Propose New Owne...187379252023-12-08 0:19:35811 days ago1701994775IN
0xae6B9cDE...2B78a99DA
0 ETH0.0031458245.14416986

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Send Payload To ...206346722024-08-29 13:55:59545 days ago1724939759
0xae6B9cDE...2B78a99DA
0.00010873 ETH
Send Message206346722024-08-29 13:55:59545 days ago1724939759
0xae6B9cDE...2B78a99DA
0.00010873 ETH
Send Payload To ...206340792024-08-29 11:56:11545 days ago1724932571
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Message206340792024-08-29 11:56:11545 days ago1724932571
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Payload To ...206334842024-08-29 9:55:59545 days ago1724925359
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Message206334842024-08-29 9:55:59545 days ago1724925359
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Payload To ...206328862024-08-29 7:55:59545 days ago1724918159
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Message206328862024-08-29 7:55:59545 days ago1724918159
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Payload To ...206322912024-08-29 5:55:59545 days ago1724910959
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Message206322912024-08-29 5:55:59545 days ago1724910959
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Payload To ...206316992024-08-29 3:55:59546 days ago1724903759
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Message206316992024-08-29 3:55:59546 days ago1724903759
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Payload To ...206311042024-08-29 1:55:59546 days ago1724896559
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Message206311042024-08-29 1:55:59546 days ago1724896559
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Payload To ...206305052024-08-28 23:55:47546 days ago1724889347
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Message206305052024-08-28 23:55:47546 days ago1724889347
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Payload To ...206303072024-08-28 23:15:59546 days ago1724886959
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Message206303072024-08-28 23:15:59546 days ago1724886959
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Payload To ...206299092024-08-28 21:55:47546 days ago1724882147
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Message206299092024-08-28 21:55:47546 days ago1724882147
0xae6B9cDE...2B78a99DA
0.00011103 ETH
Send Payload To ...206293152024-08-28 19:55:59546 days ago1724874959
0xae6B9cDE...2B78a99DA
0.00010867 ETH
Send Message206293152024-08-28 19:55:59546 days ago1724874959
0xae6B9cDE...2B78a99DA
0.00010867 ETH
Send Payload To ...206287152024-08-28 17:55:59546 days ago1724867759
0xae6B9cDE...2B78a99DA
0.00010867 ETH
Send Message206287152024-08-28 17:55:59546 days ago1724867759
0xae6B9cDE...2B78a99DA
0.00010867 ETH
Send Payload To ...206281202024-08-28 15:55:59546 days ago1724860559
0xae6B9cDE...2B78a99DA
0.00011234 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
WormholeHubConnector

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
london EvmVersion, MIT license
// 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);
  }
}

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

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

// 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 5 of 12 : 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);
  }
}

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

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

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

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

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

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

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

Settings
{
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"uint32","name":"_domain","type":"uint32"},{"internalType":"uint32","name":"_mirrorDomain","type":"uint32"},{"internalType":"address","name":"_amb","type":"address"},{"internalType":"address","name":"_rootManager","type":"address"},{"internalType":"address","name":"_mirrorConnector","type":"address"},{"internalType":"uint256","name":"_gasCap","type":"uint256"},{"internalType":"uint16","name":"_mirrorWormholeChainId","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Connector__processMessage_notUsed","type":"error"},{"inputs":[],"name":"ProposedOwnable__onlyOwner_notOwner","type":"error"},{"inputs":[],"name":"ProposedOwnable__onlyProposed_notProposedOwner","type":"error"},{"inputs":[],"name":"ProposedOwnable__ownershipDelayElapsed_delayNotElapsed","type":"error"},{"inputs":[],"name":"ProposedOwnable__proposeNewOwner_invalidProposal","type":"error"},{"inputs":[],"name":"ProposedOwnable__proposeNewOwner_noOwnershipChange","type":"error"},{"inputs":[],"name":"ProposedOwnable__renounceOwnership_invalidProposal","type":"error"},{"inputs":[],"name":"ProposedOwnable__renounceOwnership_noProposal","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_previous","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_updated","type":"uint256"}],"name":"GasCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"MessageProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"encodedData","type":"bytes"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"MessageSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previous","type":"address"},{"indexed":false,"internalType":"address","name":"current","type":"address"}],"name":"MirrorConnectorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"mirrorDomain","type":"uint32"},{"indexed":false,"internalType":"address","name":"amb","type":"address"},{"indexed":false,"internalType":"address","name":"rootManager","type":"address"},{"indexed":false,"internalType":"address","name":"mirrorConnector","type":"address"}],"name":"NewConnector","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proposedOwner","type":"address"}],"name":"OwnershipProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previous","type":"address"},{"indexed":true,"internalType":"address","name":"updated","type":"address"}],"name":"RefundAddressUpdated","type":"event"},{"inputs":[],"name":"AMB","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIRROR_DOMAIN","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIRROR_WORMHOLE_ID","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROOT_MANAGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptProposedOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mirrorConnector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"processMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"processedWhMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newlyProposed","type":"address"}],"name":"proposeNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proposed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposedTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasLimit","type":"uint256"},{"internalType":"address","name":"_amb","type":"address"}],"name":"quoteEVMDeliveryPrice","outputs":[{"internalType":"uint256","name":"_cost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_payload","type":"bytes"},{"internalType":"bytes[]","name":"","type":"bytes[]"},{"internalType":"bytes32","name":"_sourceAddress","type":"bytes32"},{"internalType":"uint16","name":"_sourceChain","type":"uint16"},{"internalType":"bytes32","name":"_deliveryHash","type":"bytes32"}],"name":"receiveWormholeMessages","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounced","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_encodedData","type":"bytes"}],"name":"sendMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasCap","type":"uint256"}],"name":"setGasCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_mirrorConnector","type":"address"}],"name":"setMirrorConnector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_updated","type":"address"}],"name":"setRefundAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_expected","type":"address"}],"name":"verifySender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101206040523480156200001257600080fd5b5060405162001c2b38038062001c2b83398101604081905262000035916200039b565b818181898989898984848484846200004d33620001b3565b8463ffffffff16600003620000985760405162461bcd60e51b815260206004820152600c60248201526b32b6b83a3c903237b6b0b4b760a11b60448201526064015b60405180910390fd5b6001600160a01b038216620000e45760405162461bcd60e51b815260206004820152601160248201527032b6b83a3c903937b7ba26b0b730b3b2b960791b60448201526064016200008f565b63ffffffff8086166080526001600160a01b0380851660a05283811660c05290851660e0528116156200011c576200011c8162000218565b604080516001600160a01b0385811682528481166020830152831681830152905163ffffffff86811692908816917f4f9c27c2fe3f84576ea469d367d044da53c45e951617e8389f2b5ed8db9d25f09181900360600190a3505050505050505050506200018f816200028160201b60201c565b5061ffff811661010052620001a433620002c2565b50505050505050505062000431565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b039092166001600160a01b0319928316178155600255600180549091169055565b600354604080516001600160a01b03928316815291831660208301527fc77bec288fc88f168427f2f7da682eadb26cac89d8d591af6e443da98dff2bbc910160405180910390a1600380546001600160a01b0319166001600160a01b0392909216919091179055565b60045460408051918252602082018390527f877a02cb809da0364d23adca3cd50c451b53f279d3df632e1fc11eb66335bce5910160405180910390a1600455565b6005546001600160a01b03908116908216036200030d5760405162461bcd60e51b81526020600482015260086024820152670858da185b99d95960c21b60448201526064016200008f565b6005546040516001600160a01b038084169216907f57b5839c3435f5b2eb2d2e286fb44ca7303d01d9b25a5d9c05c489523474285990600090a3600580546001600160a01b0319166001600160a01b0392909216919091179055565b805163ffffffff811681146200037e57600080fd5b919050565b80516001600160a01b03811681146200037e57600080fd5b600080600080600080600060e0888a031215620003b757600080fd5b620003c28862000369565b9650620003d26020890162000369565b9550620003e26040890162000383565b9450620003f26060890162000383565b9350620004026080890162000383565b925060a0880151915060c088015161ffff811681146200042157600080fd5b8091505092959891949750929550565b60805160a05160c05160e05161010051611776620004b5600039600081816102af0152818161065501528181610bab01526112130152600081816102040152610db60152600081816103c5015281816105980152610d8f01526000818161051401528181610701015281816107a20152610b460152600061037101526117766000f3fe6080604052600436106101855760003560e01c80635f61e3ec116100d1578063b1f8100d1161008a578063d1851c9211610064578063d1851c92146104c5578063d232c220146104e3578063d69f9d6114610502578063db1b76591461053657600080fd5b8063b1f8100d14610470578063c5b350df14610490578063cc394283146104a557600080fd5b80635f61e3ec146103b357806368742da6146103e75780636a42b8f814610407578063715018a61461041d5780637850b020146104325780638da5cb5b1461045257600080fd5b80633cf52ffb1161013e5780634ff746f6116101185780634ff746f61461032c578063529dca321461034c57806352a9674b1461035f5780635bd11efc1461039357600080fd5b80633cf52ffb146102e457806348e6fa23146102f95780634d93538b1461030c57600080fd5b8063047dbeb8146101915780630cb61f6c146101ba57806314168416146101f257806315b75bea1461023b57806318c817091461025d578063194ea9961461029d57600080fd5b3661018c57005b600080fd5b34801561019d57600080fd5b506101a760045481565b6040519081526020015b60405180910390f35b3480156101c657600080fd5b506005546101da906001600160a01b031681565b6040516001600160a01b0390911681526020016101b1565b3480156101fe57600080fd5b506102267f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016101b1565b34801561024757600080fd5b5061025b6102563660046112b0565b610556565b005b34801561026957600080fd5b5061028d6102783660046112d2565b60066020526000908152604090205460ff1681565b60405190151581526020016101b1565b3480156102a957600080fd5b506102d17f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff90911681526020016101b1565b3480156102f057600080fd5b506002546101a7565b61025b6103073660046113a2565b61058d565b34801561031857600080fd5b506101a7610327366004611406565b610642565b34801561033857600080fd5b5061025b610347366004611432565b6106f6565b61025b61035a366004611481565b61079c565b34801561036b57600080fd5b506102267f000000000000000000000000000000000000000000000000000000000000000081565b34801561039f57600080fd5b5061025b6103ae3660046112b0565b6107e0565b3480156103bf57600080fd5b506101da7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103f357600080fd5b5061025b6104023660046112b0565b610814565b34801561041357600080fd5b5062093a806101a7565b34801561042957600080fd5b5061025b610891565b34801561043e57600080fd5b5061025b61044d3660046112d2565b610945565b34801561045e57600080fd5b506000546001600160a01b03166101da565b34801561047c57600080fd5b5061025b61048b3660046112b0565b610979565b34801561049c57600080fd5b5061025b610a17565b3480156104b157600080fd5b506003546101da906001600160a01b031681565b3480156104d157600080fd5b506001546001600160a01b03166101da565b3480156104ef57600080fd5b506000546001600160a01b03161561028d565b34801561050e57600080fd5b506101da7f000000000000000000000000000000000000000000000000000000000000000081565b34801561054257600080fd5b5061028d6105513660046112b0565b610a87565b6000546001600160a01b03163314610581576040516311a8a1bb60e31b815260040160405180910390fd5b61058a81610a98565b50565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105f95760405162461bcd60e51b815260206004820152600c60248201526b10b937b7ba26b0b730b3b2b960a11b60448201526064015b60405180910390fd5b6106038282610b3d565b7fdcaa37a042a0087de79018c629bbd29cee82ca80bd9be394e1696bf9e9355077828233604051610636939291906115d0565b60405180910390a15050565b6000816001600160a01b031663c23ee3c37f0000000000000000000000000000000000000000000000000000000000000000600061067f87610b7a565b6040516001600160e01b031960e086901b16815261ffff9093166004840152602483019190915260448201526064016040805180830381865afa1580156106ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ee919061160e565b509392505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107575760405162461bcd60e51b81526004016105f09060208082526004908201526310a0a6a160e11b604082015260600190565b61076081610b90565b7fb3abc57bfeebd2cac918901db582f71972a8e628bccf19f5ae3e3482b98a5ced8133604051610791929190611632565b60405180910390a150565b6107c7827f000000000000000000000000000000000000000000000000000000000000000083610ba9565b6107d96107d384610cc3565b86610d06565b5050505050565b6000546001600160a01b0316331461080b576040516311a8a1bb60e31b815260040160405180910390fd5b61058a81610e6b565b6000546001600160a01b0316331461083f576040516311a8a1bb60e31b815260040160405180910390fd5b4761084a8282610ed4565b816001600160a01b03167feaff4b37086828766ad3268786972c0cd24259d4c87a80f9d3963a3c3d999b0d8260405161088591815260200190565b60405180910390a25050565b6000546001600160a01b031633146108bc576040516311a8a1bb60e31b815260040160405180910390fd5b62093a80600254426108ce919061165c565b116108ec576040516324e0285f60e21b815260040160405180910390fd5b60025460000361090f57604051630e4b303f60e21b815260040160405180910390fd5b6001546001600160a01b031615610939576040516323295ef960e01b815260040160405180910390fd5b6109436000610ff2565b565b6000546001600160a01b03163314610970576040516311a8a1bb60e31b815260040160405180910390fd5b61058a81611057565b6000546001600160a01b031633146109a4576040516311a8a1bb60e31b815260040160405180910390fd5b6001546001600160a01b0382811691161480156109c2575060025415155b156109e0576040516311bc066560e11b815260040160405180910390fd5b6000546001600160a01b03808316911603610a0e57604051634a2fb73f60e11b815260040160405180910390fd5b61058a81611098565b6001546001600160a01b03163314610a42576040516311a7f27160e11b815260040160405180910390fd5b62093a8060025442610a54919061165c565b11610a72576040516324e0285f60e21b815260040160405180910390fd5b600154610943906001600160a01b0316610ff2565b6000610a92826110e6565b92915050565b6005546001600160a01b0390811690821603610ae15760405162461bcd60e51b81526020600482015260086024820152670858da185b99d95960c21b60448201526064016105f0565b6005546040516001600160a01b038084169216907f57b5839c3435f5b2eb2d2e286fb44ca7303d01d9b25a5d9c05c489523474285990600090a3600580546001600160a01b0319166001600160a01b0392909216919091179055565b600354610b76907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b031684846110ff565b5050565b6000600454821115610b8c5760045491505b5090565b6040516316c2fdb560e21b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000061ffff168361ffff1614610c105760405162461bcd60e51b815260206004820152600d60248201526c10b9b7bab931b29031b430b4b760991b60448201526064016105f0565b336001600160a01b03831614610c535760405162461bcd60e51b815260206004820152600860248201526710b932b630bcb2b960c11b60448201526064016105f0565b60008181526006602052604090205460ff1615610ca65760405162461bcd60e51b8152602060048201526011602482015270185b1c9958591e481c1c9bd8d95cdcd959607a1b60448201526064016105f0565b6000908152600660205260409020805460ff191660011790555050565b600060a082901c15610b8c5760405162461bcd60e51b815260206004820152600c60248201526b2165766d206164647265737360a01b60448201526064016105f0565b610d0f826110e6565b610d4a5760405162461bcd60e51b815260206004820152600c60248201526b10b61921b7b73732b1ba37b960a11b60448201526064016105f0565b8051602014610d855760405162461bcd60e51b8152602060048201526007602482015266042d8cadccee8d60cb1b60448201526064016105f0565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016638e7d93fa7f0000000000000000000000000000000000000000000000000000000000000000610dde8461167d565b6040516001600160e01b031960e085901b16815263ffffffff9290921660048301526024820152604401600060405180830381600087803b158015610e2257600080fd5b505af1158015610e36573d6000803e3d6000fd5b505050507fb3abc57bfeebd2cac918901db582f71972a8e628bccf19f5ae3e3482b98a5ced8133604051610636929190611632565b600354604080516001600160a01b03928316815291831660208301527fc77bec288fc88f168427f2f7da682eadb26cac89d8d591af6e443da98dff2bbc910160405180910390a1600380546001600160a01b0319166001600160a01b0392909216919091179055565b80471015610f245760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016105f0565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610f71576040519150601f19603f3d011682016040523d82523d6000602084013e610f76565b606091505b5050905080610fed5760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105f0565b505050565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b039092166001600160a01b0319928316178155600255600180549091169055565b60045460408051918252602082018390527f877a02cb809da0364d23adca3cd50c451b53f279d3df632e1fc11eb66335bce5910160405180910390a1600455565b42600255600180546001600160a01b0319166001600160a01b0383169081179091556040517f6ab4d119f23076e8ad491bc65ce85f017fb0591dce08755ba8591059cc51737a90600090a250565b6003546000906001600160a01b03838116911614610a92565b815160201461113f5760405162461bcd60e51b815260206004820152600c60248201526b042c8c2e8c240d8cadccee8d60a31b60448201526064016105f0565b80516020146111875760405162461bcd60e51b8152602060048201526014602482015273042cadcc6dec8cac840c8c2e8c240d8cadccee8d60631b60448201526064016105f0565b60008180602001905181019061119d91906116a4565b905060006111ab8287610642565b90503481146111e95760405162461bcd60e51b815260206004820152600a602482015269216d73672e76616c756560b01b60448201526064016105f0565b6005546040516312d729bd60e21b81526001600160a01b0380891692634b5ca6f4928592611248927f0000000000000000000000000000000000000000000000000000000000000000928c928c926000928c92879216906004016116bd565b60206040518083038185885af1158015611266573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061128b9190611716565b50505050505050565b80356001600160a01b03811681146112ab57600080fd5b919050565b6000602082840312156112c257600080fd5b6112cb82611294565b9392505050565b6000602082840312156112e457600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561132a5761132a6112eb565b604052919050565b600082601f83011261134357600080fd5b813567ffffffffffffffff81111561135d5761135d6112eb565b611370601f8201601f1916602001611301565b81815284602083860101111561138557600080fd5b816020850160208301376000918101602001919091529392505050565b600080604083850312156113b557600080fd5b823567ffffffffffffffff808211156113cd57600080fd5b6113d986838701611332565b935060208501359150808211156113ef57600080fd5b506113fc85828601611332565b9150509250929050565b6000806040838503121561141957600080fd5b8235915061142960208401611294565b90509250929050565b60006020828403121561144457600080fd5b813567ffffffffffffffff81111561145b57600080fd5b61146784828501611332565b949350505050565b803561ffff811681146112ab57600080fd5b600080600080600060a0868803121561149957600080fd5b853567ffffffffffffffff808211156114b157600080fd5b6114bd89838a01611332565b96506020915081880135818111156114d457600080fd5b8801601f81018a136114e557600080fd5b8035828111156114f7576114f76112eb565b8060051b611506858201611301565b918252828101850191858101908d84111561152057600080fd5b86850192505b8383101561155c5782358681111561153e5760008081fd5b61154c8f8983890101611332565b8352509186019190860190611526565b809a5050505050505050604086013592506115796060870161146f565b949793965091946080013592915050565b6000815180845260005b818110156115b057602081850181015186830182015201611594565b506000602082860101526020601f19601f83011685010191505092915050565b6060815260006115e3606083018661158a565b82810360208401526115f5818661158a565b91505060018060a01b0383166040830152949350505050565b6000806040838503121561162157600080fd5b505080516020909101519092909150565b604081526000611645604083018561158a565b905060018060a01b03831660208301529392505050565b81810381811115610a9257634e487b7160e01b600052601160045260246000fd5b8051602080830151919081101561169e576000198160200360031b1b821691505b50919050565b6000602082840312156116b657600080fd5b5051919050565b600061ffff808a16835260018060a01b03808a16602085015260e060408501526116ea60e085018a61158a565b925087606085015286608085015281861660a085015280851660c0850152505098975050505050505050565b60006020828403121561172857600080fd5b815167ffffffffffffffff811681146112cb57600080fdfea264697066735822122077ef5ddd4f84658dcd6f5d78758dafb44d91461cf057c309b77b296faf446eec64736f6c6343000811003300000000000000000000000000000000000000000000000000000000006574680000000000000000000000000000000000000000000000000000000000626e6200000000000000000000000027428dd2d3dd32a4d7f7c497eaaa23130d894911000000000000000000000000523ab7424ad126809b1d7a134eb6e0ee414c9b3a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000493e00000000000000000000000000000000000000000000000000000000000000004

Deployed Bytecode

0x6080604052600436106101855760003560e01c80635f61e3ec116100d1578063b1f8100d1161008a578063d1851c9211610064578063d1851c92146104c5578063d232c220146104e3578063d69f9d6114610502578063db1b76591461053657600080fd5b8063b1f8100d14610470578063c5b350df14610490578063cc394283146104a557600080fd5b80635f61e3ec146103b357806368742da6146103e75780636a42b8f814610407578063715018a61461041d5780637850b020146104325780638da5cb5b1461045257600080fd5b80633cf52ffb1161013e5780634ff746f6116101185780634ff746f61461032c578063529dca321461034c57806352a9674b1461035f5780635bd11efc1461039357600080fd5b80633cf52ffb146102e457806348e6fa23146102f95780634d93538b1461030c57600080fd5b8063047dbeb8146101915780630cb61f6c146101ba57806314168416146101f257806315b75bea1461023b57806318c817091461025d578063194ea9961461029d57600080fd5b3661018c57005b600080fd5b34801561019d57600080fd5b506101a760045481565b6040519081526020015b60405180910390f35b3480156101c657600080fd5b506005546101da906001600160a01b031681565b6040516001600160a01b0390911681526020016101b1565b3480156101fe57600080fd5b506102267f0000000000000000000000000000000000000000000000000000000000626e6281565b60405163ffffffff90911681526020016101b1565b34801561024757600080fd5b5061025b6102563660046112b0565b610556565b005b34801561026957600080fd5b5061028d6102783660046112d2565b60066020526000908152604090205460ff1681565b60405190151581526020016101b1565b3480156102a957600080fd5b506102d17f000000000000000000000000000000000000000000000000000000000000000481565b60405161ffff90911681526020016101b1565b3480156102f057600080fd5b506002546101a7565b61025b6103073660046113a2565b61058d565b34801561031857600080fd5b506101a7610327366004611406565b610642565b34801561033857600080fd5b5061025b610347366004611432565b6106f6565b61025b61035a366004611481565b61079c565b34801561036b57600080fd5b506102267f000000000000000000000000000000000000000000000000000000000065746881565b34801561039f57600080fd5b5061025b6103ae3660046112b0565b6107e0565b3480156103bf57600080fd5b506101da7f000000000000000000000000523ab7424ad126809b1d7a134eb6e0ee414c9b3a81565b3480156103f357600080fd5b5061025b6104023660046112b0565b610814565b34801561041357600080fd5b5062093a806101a7565b34801561042957600080fd5b5061025b610891565b34801561043e57600080fd5b5061025b61044d3660046112d2565b610945565b34801561045e57600080fd5b506000546001600160a01b03166101da565b34801561047c57600080fd5b5061025b61048b3660046112b0565b610979565b34801561049c57600080fd5b5061025b610a17565b3480156104b157600080fd5b506003546101da906001600160a01b031681565b3480156104d157600080fd5b506001546001600160a01b03166101da565b3480156104ef57600080fd5b506000546001600160a01b03161561028d565b34801561050e57600080fd5b506101da7f00000000000000000000000027428dd2d3dd32a4d7f7c497eaaa23130d89491181565b34801561054257600080fd5b5061028d6105513660046112b0565b610a87565b6000546001600160a01b03163314610581576040516311a8a1bb60e31b815260040160405180910390fd5b61058a81610a98565b50565b336001600160a01b037f000000000000000000000000523ab7424ad126809b1d7a134eb6e0ee414c9b3a16146105f95760405162461bcd60e51b815260206004820152600c60248201526b10b937b7ba26b0b730b3b2b960a11b60448201526064015b60405180910390fd5b6106038282610b3d565b7fdcaa37a042a0087de79018c629bbd29cee82ca80bd9be394e1696bf9e9355077828233604051610636939291906115d0565b60405180910390a15050565b6000816001600160a01b031663c23ee3c37f0000000000000000000000000000000000000000000000000000000000000004600061067f87610b7a565b6040516001600160e01b031960e086901b16815261ffff9093166004840152602483019190915260448201526064016040805180830381865afa1580156106ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ee919061160e565b509392505050565b336001600160a01b037f00000000000000000000000027428dd2d3dd32a4d7f7c497eaaa23130d89491116146107575760405162461bcd60e51b81526004016105f09060208082526004908201526310a0a6a160e11b604082015260600190565b61076081610b90565b7fb3abc57bfeebd2cac918901db582f71972a8e628bccf19f5ae3e3482b98a5ced8133604051610791929190611632565b60405180910390a150565b6107c7827f00000000000000000000000027428dd2d3dd32a4d7f7c497eaaa23130d89491183610ba9565b6107d96107d384610cc3565b86610d06565b5050505050565b6000546001600160a01b0316331461080b576040516311a8a1bb60e31b815260040160405180910390fd5b61058a81610e6b565b6000546001600160a01b0316331461083f576040516311a8a1bb60e31b815260040160405180910390fd5b4761084a8282610ed4565b816001600160a01b03167feaff4b37086828766ad3268786972c0cd24259d4c87a80f9d3963a3c3d999b0d8260405161088591815260200190565b60405180910390a25050565b6000546001600160a01b031633146108bc576040516311a8a1bb60e31b815260040160405180910390fd5b62093a80600254426108ce919061165c565b116108ec576040516324e0285f60e21b815260040160405180910390fd5b60025460000361090f57604051630e4b303f60e21b815260040160405180910390fd5b6001546001600160a01b031615610939576040516323295ef960e01b815260040160405180910390fd5b6109436000610ff2565b565b6000546001600160a01b03163314610970576040516311a8a1bb60e31b815260040160405180910390fd5b61058a81611057565b6000546001600160a01b031633146109a4576040516311a8a1bb60e31b815260040160405180910390fd5b6001546001600160a01b0382811691161480156109c2575060025415155b156109e0576040516311bc066560e11b815260040160405180910390fd5b6000546001600160a01b03808316911603610a0e57604051634a2fb73f60e11b815260040160405180910390fd5b61058a81611098565b6001546001600160a01b03163314610a42576040516311a7f27160e11b815260040160405180910390fd5b62093a8060025442610a54919061165c565b11610a72576040516324e0285f60e21b815260040160405180910390fd5b600154610943906001600160a01b0316610ff2565b6000610a92826110e6565b92915050565b6005546001600160a01b0390811690821603610ae15760405162461bcd60e51b81526020600482015260086024820152670858da185b99d95960c21b60448201526064016105f0565b6005546040516001600160a01b038084169216907f57b5839c3435f5b2eb2d2e286fb44ca7303d01d9b25a5d9c05c489523474285990600090a3600580546001600160a01b0319166001600160a01b0392909216919091179055565b600354610b76907f00000000000000000000000027428dd2d3dd32a4d7f7c497eaaa23130d894911906001600160a01b031684846110ff565b5050565b6000600454821115610b8c5760045491505b5090565b6040516316c2fdb560e21b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000461ffff168361ffff1614610c105760405162461bcd60e51b815260206004820152600d60248201526c10b9b7bab931b29031b430b4b760991b60448201526064016105f0565b336001600160a01b03831614610c535760405162461bcd60e51b815260206004820152600860248201526710b932b630bcb2b960c11b60448201526064016105f0565b60008181526006602052604090205460ff1615610ca65760405162461bcd60e51b8152602060048201526011602482015270185b1c9958591e481c1c9bd8d95cdcd959607a1b60448201526064016105f0565b6000908152600660205260409020805460ff191660011790555050565b600060a082901c15610b8c5760405162461bcd60e51b815260206004820152600c60248201526b2165766d206164647265737360a01b60448201526064016105f0565b610d0f826110e6565b610d4a5760405162461bcd60e51b815260206004820152600c60248201526b10b61921b7b73732b1ba37b960a11b60448201526064016105f0565b8051602014610d855760405162461bcd60e51b8152602060048201526007602482015266042d8cadccee8d60cb1b60448201526064016105f0565b6001600160a01b037f000000000000000000000000523ab7424ad126809b1d7a134eb6e0ee414c9b3a16638e7d93fa7f0000000000000000000000000000000000000000000000000000000000626e62610dde8461167d565b6040516001600160e01b031960e085901b16815263ffffffff9290921660048301526024820152604401600060405180830381600087803b158015610e2257600080fd5b505af1158015610e36573d6000803e3d6000fd5b505050507fb3abc57bfeebd2cac918901db582f71972a8e628bccf19f5ae3e3482b98a5ced8133604051610636929190611632565b600354604080516001600160a01b03928316815291831660208301527fc77bec288fc88f168427f2f7da682eadb26cac89d8d591af6e443da98dff2bbc910160405180910390a1600380546001600160a01b0319166001600160a01b0392909216919091179055565b80471015610f245760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016105f0565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610f71576040519150601f19603f3d011682016040523d82523d6000602084013e610f76565b606091505b5050905080610fed5760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105f0565b505050565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b039092166001600160a01b0319928316178155600255600180549091169055565b60045460408051918252602082018390527f877a02cb809da0364d23adca3cd50c451b53f279d3df632e1fc11eb66335bce5910160405180910390a1600455565b42600255600180546001600160a01b0319166001600160a01b0383169081179091556040517f6ab4d119f23076e8ad491bc65ce85f017fb0591dce08755ba8591059cc51737a90600090a250565b6003546000906001600160a01b03838116911614610a92565b815160201461113f5760405162461bcd60e51b815260206004820152600c60248201526b042c8c2e8c240d8cadccee8d60a31b60448201526064016105f0565b80516020146111875760405162461bcd60e51b8152602060048201526014602482015273042cadcc6dec8cac840c8c2e8c240d8cadccee8d60631b60448201526064016105f0565b60008180602001905181019061119d91906116a4565b905060006111ab8287610642565b90503481146111e95760405162461bcd60e51b815260206004820152600a602482015269216d73672e76616c756560b01b60448201526064016105f0565b6005546040516312d729bd60e21b81526001600160a01b0380891692634b5ca6f4928592611248927f0000000000000000000000000000000000000000000000000000000000000004928c928c926000928c92879216906004016116bd565b60206040518083038185885af1158015611266573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061128b9190611716565b50505050505050565b80356001600160a01b03811681146112ab57600080fd5b919050565b6000602082840312156112c257600080fd5b6112cb82611294565b9392505050565b6000602082840312156112e457600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561132a5761132a6112eb565b604052919050565b600082601f83011261134357600080fd5b813567ffffffffffffffff81111561135d5761135d6112eb565b611370601f8201601f1916602001611301565b81815284602083860101111561138557600080fd5b816020850160208301376000918101602001919091529392505050565b600080604083850312156113b557600080fd5b823567ffffffffffffffff808211156113cd57600080fd5b6113d986838701611332565b935060208501359150808211156113ef57600080fd5b506113fc85828601611332565b9150509250929050565b6000806040838503121561141957600080fd5b8235915061142960208401611294565b90509250929050565b60006020828403121561144457600080fd5b813567ffffffffffffffff81111561145b57600080fd5b61146784828501611332565b949350505050565b803561ffff811681146112ab57600080fd5b600080600080600060a0868803121561149957600080fd5b853567ffffffffffffffff808211156114b157600080fd5b6114bd89838a01611332565b96506020915081880135818111156114d457600080fd5b8801601f81018a136114e557600080fd5b8035828111156114f7576114f76112eb565b8060051b611506858201611301565b918252828101850191858101908d84111561152057600080fd5b86850192505b8383101561155c5782358681111561153e5760008081fd5b61154c8f8983890101611332565b8352509186019190860190611526565b809a5050505050505050604086013592506115796060870161146f565b949793965091946080013592915050565b6000815180845260005b818110156115b057602081850181015186830182015201611594565b506000602082860101526020601f19601f83011685010191505092915050565b6060815260006115e3606083018661158a565b82810360208401526115f5818661158a565b91505060018060a01b0383166040830152949350505050565b6000806040838503121561162157600080fd5b505080516020909101519092909150565b604081526000611645604083018561158a565b905060018060a01b03831660208301529392505050565b81810381811115610a9257634e487b7160e01b600052601160045260246000fd5b8051602080830151919081101561169e576000198160200360031b1b821691505b50919050565b6000602082840312156116b657600080fd5b5051919050565b600061ffff808a16835260018060a01b03808a16602085015260e060408501526116ea60e085018a61158a565b925087606085015286608085015281861660a085015280851660c0850152505098975050505050505050565b60006020828403121561172857600080fd5b815167ffffffffffffffff811681146112cb57600080fdfea264697066735822122077ef5ddd4f84658dcd6f5d78758dafb44d91461cf057c309b77b296faf446eec64736f6c63430008110033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000000000000000000000000000000000000006574680000000000000000000000000000000000000000000000000000000000626e6200000000000000000000000027428dd2d3dd32a4d7f7c497eaaa23130d894911000000000000000000000000523ab7424ad126809b1d7a134eb6e0ee414c9b3a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000493e00000000000000000000000000000000000000000000000000000000000000004

-----Decoded View---------------
Arg [0] : _domain (uint32): 6648936
Arg [1] : _mirrorDomain (uint32): 6450786
Arg [2] : _amb (address): 0x27428DD2d3DD32A4D7f7C497eAaa23130d894911
Arg [3] : _rootManager (address): 0x523AB7424AD126809b1d7A134eb6E0ee414C9B3A
Arg [4] : _mirrorConnector (address): 0x0000000000000000000000000000000000000000
Arg [5] : _gasCap (uint256): 300000
Arg [6] : _mirrorWormholeChainId (uint16): 4

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000657468
Arg [1] : 0000000000000000000000000000000000000000000000000000000000626e62
Arg [2] : 00000000000000000000000027428dd2d3dd32a4d7f7c497eaaa23130d894911
Arg [3] : 000000000000000000000000523ab7424ad126809b1d7a134eb6e0ee414c9b3a
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 00000000000000000000000000000000000000000000000000000000000493e0
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000004


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.