ETH Price: $2,925.38 (-9.74%)
Gas: 15 Gwei

Contract

0xFaf539a73659fEAEC96ec7242f075Be0445526A8
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Propose New Owne...166728992023-02-20 23:02:47500 days ago1676934167IN
0xFaf539a7...0445526A8
0 ETH0.0019314527.70229116
Set Gas Cap166019952023-02-11 0:39:11510 days ago1676075951IN
0xFaf539a7...0445526A8
0 ETH0.0006369921.22122574
Set Mirror Conne...162337302022-12-21 14:40:11561 days ago1671633611IN
0xFaf539a7...0445526A8
0 ETH0.0007744716.28001254
0x61014060162329762022-12-21 12:08:23561 days ago1671624503IN
 Contract Creation
0 ETH0.013558512.3819391

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
175712392023-06-27 14:20:11373 days ago1687875611
0xFaf539a7...0445526A8
0.0006108 ETH
175712392023-06-27 14:20:11373 days ago1687875611
0xFaf539a7...0445526A8
0.0006108 ETH
175710892023-06-27 13:49:59373 days ago1687873799
0xFaf539a7...0445526A8
0.0006108 ETH
175710892023-06-27 13:49:59373 days ago1687873799
0xFaf539a7...0445526A8
0.0006108 ETH
175709402023-06-27 13:19:47373 days ago1687871987
0xFaf539a7...0445526A8
0.0006108 ETH
175709402023-06-27 13:19:47373 days ago1687871987
0xFaf539a7...0445526A8
0.0006108 ETH
175707922023-06-27 12:49:35373 days ago1687870175
0xFaf539a7...0445526A8
0.0006108 ETH
175707922023-06-27 12:49:35373 days ago1687870175
0xFaf539a7...0445526A8
0.0006108 ETH
175706492023-06-27 12:19:23373 days ago1687868363
0xFaf539a7...0445526A8
0.0006108 ETH
175706492023-06-27 12:19:23373 days ago1687868363
0xFaf539a7...0445526A8
0.0006108 ETH
175705012023-06-27 11:49:11373 days ago1687866551
0xFaf539a7...0445526A8
0.0006108 ETH
175705012023-06-27 11:49:11373 days ago1687866551
0xFaf539a7...0445526A8
0.0006108 ETH
175703602023-06-27 11:18:59373 days ago1687864739
0xFaf539a7...0445526A8
0.0006108 ETH
175703602023-06-27 11:18:59373 days ago1687864739
0xFaf539a7...0445526A8
0.0006108 ETH
175702132023-06-27 10:48:23373 days ago1687862903
0xFaf539a7...0445526A8
0.0006108 ETH
175702132023-06-27 10:48:23373 days ago1687862903
0xFaf539a7...0445526A8
0.0006108 ETH
175700622023-06-27 10:18:11373 days ago1687861091
0xFaf539a7...0445526A8
0.0006108 ETH
175700622023-06-27 10:18:11373 days ago1687861091
0xFaf539a7...0445526A8
0.0006108 ETH
175699142023-06-27 9:47:47373 days ago1687859267
0xFaf539a7...0445526A8
0.0006108 ETH
175699142023-06-27 9:47:47373 days ago1687859267
0xFaf539a7...0445526A8
0.0006108 ETH
175697672023-06-27 9:17:35373 days ago1687857455
0xFaf539a7...0445526A8
0.0006108 ETH
175697672023-06-27 9:17:35373 days ago1687857455
0xFaf539a7...0445526A8
0.0006108 ETH
175696192023-06-27 8:47:11373 days ago1687855631
0xFaf539a7...0445526A8
0.0006108 ETH
175696192023-06-27 8:47:11373 days ago1687855631
0xFaf539a7...0445526A8
0.0006108 ETH
175694702023-06-27 8:16:59373 days ago1687853819
0xFaf539a7...0445526A8
0.0006108 ETH
View All Internal Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x677bD3A4...9Bb624630
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
MultichainHubConnector

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license
File 1 of 10 : MultichainHubConnector.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

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

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

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

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

  // ============ Private fns ============
  /**
   * @dev Handles an incoming `outboundRoot`
   */
  function _processMessage(bytes memory _data) internal override(Connector, BaseMultichain) {
    // enforce this came from connector on l2
    require(_verifySender(mirrorConnector), "!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));
  }

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

  function _verifySender(address _expected) internal view override returns (bool) {
    return _verifySender(AMB, _expected);
  }
}

File 2 of 10 : Connector.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

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

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

  error Connector__processMessage_notUsed();

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

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

  event MirrorConnectorUpdated(address previous, address current);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 3 of 10 : GasCap.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

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

abstract contract GasCap is ProposedOwnable {
  // ============ Storage ============
  /**
   * @notice The gnosis amb requires destination gas to be specified on the origin.
   * The gas used will be passed in by the relayer to allow for real-time estimates,
   * but will be capped at the admin-set cap.
   */
  uint256 gasCap;

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

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

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

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

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

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

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

File 4 of 10 : HubConnector.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

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

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

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

File 5 of 10 : BaseMultichain.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

import {Multichain} from "../../interfaces/ambs/Multichain.sol";

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

abstract contract BaseMultichain is GasCap {
  // ============ Internal Storage ============
  address internal immutable EXECUTOR; // Is != amb, used only to retrieve sender context

  // Mirror chain id
  uint256 internal immutable MIRROR_CHAIN_ID;

  // ============ Constructor ============
  constructor(
    address _amb,
    uint256 _mirrorChainId,
    uint256 _gasCap // max fee on destination chain
  ) GasCap(_gasCap) {
    // sanity checks
    require(_mirrorChainId != 0, "!mirrorChainId");

    // set immutable propertioes
    EXECUTOR = Multichain(_amb).executor();
    require(EXECUTOR != address(0), "!executor");
    MIRROR_CHAIN_ID = _mirrorChainId;
  }

  // ============ Public Fns ============
  function anyExecute(bytes memory _data) external returns (bool success, bytes memory result) {
    _processMessage(_data);
  }

  // ============ Private fns ============
  /**
   * @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;

  /**
   * @dev Sends `outboundRoot` to root manager on the mirror chain
   */
  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 not include any gas info
    require(_encodedData.length == 0, "!data length");

    // Get the max fee supplied
    uint256 supplied = _getGas(msg.value); // fee paid on origin chain, up to cap
    // NOTE: fee will always be <= msg.value

    // Get the min fees
    uint256 required = Multichain(_amb).calcSrcFees(
      "", // app id
      MIRROR_CHAIN_ID, // destination chain
      32 // data length: selector + root
    );
    // Should have at least the min fees
    require(required < supplied + 1, "!fees");

    Multichain(_amb).anyCall{value: supplied}(
      _mirrorConnector, // Target contract on destination
      _data, // Call data for interaction
      address(0), // fallback address on origin chain
      MIRROR_CHAIN_ID,
      2 // fees paid on source chain
    );
  }

  function _verifySender(address _amb, address _expected) internal view returns (bool) {
    require(msg.sender == EXECUTOR, "!executor");

    (address from, uint256 fromChainId, ) = Multichain(EXECUTOR).context();
    return from == _expected && fromChainId == MIRROR_CHAIN_ID;
  }
}

File 6 of 10 : IConnector.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

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

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

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

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

  function processMessage(bytes memory _data) external;

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

File 7 of 10 : IRootManager.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

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

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

File 8 of 10 : Multichain.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;

/**
 * @dev interface to interact with multicall (prev anyswap) anycall proxy
 *     see https://github.com/anyswap/multichain-smart-contracts/blob/main/contracts/anycall/AnyswapV6CallProxy.sol
 */
interface Multichain {
  function anyCall(
    address _to,
    bytes calldata _data,
    address _fallback,
    uint256 _toChainID,
    uint256 _flags
  ) external payable;

  function context()
    external
    view
    returns (
      address from,
      uint256 fromChainID,
      uint256 nonce
    );

  function executor() external view returns (address executor);

  function calcSrcFees(
    string calldata _appID,
    uint256 _toChainID,
    uint256 _dataLength
  ) external view returns (uint256);
}

File 9 of 10 : ProposedOwnable.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;

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

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

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

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

  address private _owner;

  address private _proposed;
  uint256 private _proposedOwnershipTimestamp;

  uint256 private constant _delay = 7 days;

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

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

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

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

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

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

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

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

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

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

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

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

    _setProposed(newlyProposed);
  }

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

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

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

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

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

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

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

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

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

File 10 of 10 : IProposedOwnable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

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

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

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

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

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

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

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

[{"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":"_mirrorChainId","type":"uint256"},{"internalType":"uint256","name":"_gasCap","type":"uint256"}],"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":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"},{"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":"ROOT_MANAGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptProposedOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"anyExecute","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delay","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":"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":[],"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":"_expected","type":"address"}],"name":"verifySender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

Deployed Bytecode

0x6080604052600436106101185760003560e01c80637850b020116100a0578063cc39428311610064578063cc39428314610332578063d1851c9214610352578063d232c22014610370578063d69f9d611461039b578063db1b7659146103cf57600080fd5b80637850b020146102915780638da5cb5b146102b15780639abaf479146102cf578063b1f8100d146102fd578063c5b350df1461031d57600080fd5b806352a9674b116100e757806352a9674b146101c65780635bd11efc146101fa5780635f61e3ec1461021a5780636a42b8f814610266578063715018a61461027c57600080fd5b806314168416146101245780633cf52ffb1461017257806348e6fa23146101915780634ff746f6146101a657600080fd5b3661011f57005b600080fd5b34801561013057600080fd5b506101587f0000000000000000000000000000000000000000000000000000000000626e6281565b60405163ffffffff90911681526020015b60405180910390f35b34801561017e57600080fd5b506002545b604051908152602001610169565b6101a461019f366004610e95565b6103ef565b005b3480156101b257600080fd5b506101a46101c1366004610ef9565b6104a4565b3480156101d257600080fd5b506101587f000000000000000000000000000000000000000000000000000000000065746881565b34801561020657600080fd5b506101a4610215366004610f4b565b61054a565b34801561022657600080fd5b5061024e7f000000000000000000000000d5d61e9dfb6680cba8353988ba0337802811c2e181565b6040516001600160a01b039091168152602001610169565b34801561027257600080fd5b5062093a80610183565b34801561028857600080fd5b506101a4610581565b34801561029d57600080fd5b506101a46102ac366004610f6f565b610635565b3480156102bd57600080fd5b506000546001600160a01b031661024e565b3480156102db57600080fd5b506102ef6102ea366004610ef9565b610669565b604051610169929190610fce565b34801561030957600080fd5b506101a4610318366004610f4b565b61067b565b34801561032957600080fd5b506101a4610719565b34801561033e57600080fd5b5060035461024e906001600160a01b031681565b34801561035e57600080fd5b506001546001600160a01b031661024e565b34801561037c57600080fd5b506000546001600160a01b0316155b6040519015158152602001610169565b3480156103a757600080fd5b5061024e7f000000000000000000000000c10ef9f491c9b59f936957026020c321651ac07881565b3480156103db57600080fd5b5061038b6103ea366004610f4b565b610789565b336001600160a01b037f000000000000000000000000d5d61e9dfb6680cba8353988ba0337802811c2e1161461045b5760405162461bcd60e51b815260206004820152600c60248201526b10b937b7ba26b0b730b3b2b960a11b60448201526064015b60405180910390fd5b610465828261079a565b7fdcaa37a042a0087de79018c629bbd29cee82ca80bd9be394e1696bf9e935507782823360405161049893929190610fe9565b60405180910390a15050565b336001600160a01b037f000000000000000000000000c10ef9f491c9b59f936957026020c321651ac07816146105055760405162461bcd60e51b81526004016104529060208082526004908201526310a0a6a160e11b604082015260600190565b61050e816107d7565b7fb3abc57bfeebd2cac918901db582f71972a8e628bccf19f5ae3e3482b98a5ced813360405161053f929190611027565b60405180910390a150565b6000546001600160a01b03163314610575576040516311a8a1bb60e31b815260040160405180910390fd5b61057e8161091a565b50565b6000546001600160a01b031633146105ac576040516311a8a1bb60e31b815260040160405180910390fd5b62093a80600254426105be9190611067565b116105dc576040516324e0285f60e21b815260040160405180910390fd5b6002546000036105ff57604051630e4b303f60e21b815260040160405180910390fd5b6001546001600160a01b031615610629576040516323295ef960e01b815260040160405180910390fd5b6106336000610983565b565b6000546001600160a01b03163314610660576040516311a8a1bb60e31b815260040160405180910390fd5b61057e816109e8565b60006060610676836107d7565b915091565b6000546001600160a01b031633146106a6576040516311a8a1bb60e31b815260040160405180910390fd5b6001546001600160a01b0382811691161480156106c4575060025415155b156106e2576040516311bc066560e11b815260040160405180910390fd5b6000546001600160a01b0380831691160361071057604051634a2fb73f60e11b815260040160405180910390fd5b61057e81610a29565b6001546001600160a01b03163314610744576040516311a7f27160e11b815260040160405180910390fd5b62093a80600254426107569190611067565b11610774576040516324e0285f60e21b815260040160405180910390fd5b600154610633906001600160a01b0316610983565b600061079482610a77565b92915050565b6003546107d3907f000000000000000000000000c10ef9f491c9b59f936957026020c321651ac078906001600160a01b03168484610aa3565b5050565b6003546107ec906001600160a01b0316610a77565b6108275760405162461bcd60e51b815260206004820152600c60248201526b10b61921b7b73732b1ba37b960a11b6044820152606401610452565b80516020146108625760405162461bcd60e51b8152602060048201526007602482015266042d8cadccee8d60cb1b6044820152606401610452565b6001600160a01b037f000000000000000000000000d5d61e9dfb6680cba8353988ba0337802811c2e116638e7d93fa7f0000000000000000000000000000000000000000000000000000000000626e626108bb8461107a565b6040516001600160e01b031960e085901b16815263ffffffff9290921660048301526024820152604401600060405180830381600087803b1580156108ff57600080fd5b505af1158015610913573d6000803e3d6000fd5b5050505050565b600354604080516001600160a01b03928316815291831660208301527fc77bec288fc88f168427f2f7da682eadb26cac89d8d591af6e443da98dff2bbc910160405180910390a1600380546001600160a01b0319166001600160a01b0392909216919091179055565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b039092166001600160a01b0319928316178155600255600180549091169055565b60045460408051918252602082018390527f877a02cb809da0364d23adca3cd50c451b53f279d3df632e1fc11eb66335bce5910160405180910390a1600455565b42600255600180546001600160a01b0319166001600160a01b0383169081179091556040517f6ab4d119f23076e8ad491bc65ce85f017fb0591dce08755ba8591059cc51737a90600090a250565b60006107947f000000000000000000000000c10ef9f491c9b59f936957026020c321651ac07883610ca3565b8151602014610ae35760405162461bcd60e51b815260206004820152600c60248201526b042c8c2e8c240d8cadccee8d60a31b6044820152606401610452565b805115610b215760405162461bcd60e51b815260206004820152600c60248201526b042c8c2e8c240d8cadccee8d60a31b6044820152606401610452565b6000610b2c34610ddc565b6040516366c96b3760e01b8152606060048201526000606482018190527f00000000000000000000000000000000000000000000000000000000000000386024830152602060448301529192506001600160a01b038716906366c96b3790608401602060405180830381865afa158015610baa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bce91906110a1565b9050610bdb8260016110ba565b8110610c115760405162461bcd60e51b8152602060048201526005602482015264216665657360d81b6044820152606401610452565b60405163bd45c4e760e01b81526001600160a01b0387169063bd45c4e7908490610c6990899089906000907f0000000000000000000000000000000000000000000000000000000000000038906002906004016110cd565b6000604051808303818588803b158015610c8257600080fd5b505af1158015610c96573d6000803e3d6000fd5b5050505050505050505050565b6000336001600160a01b037f0000000000000000000000000c9f0ea6317038c9d7180cf4a0aeeb58478d13a41614610d095760405162461bcd60e51b815260206004820152600960248201526810b2bc32b1baba37b960b91b6044820152606401610452565b6000807f0000000000000000000000000c9f0ea6317038c9d7180cf4a0aeeb58478d13a46001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610d6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8e919061110b565b5091509150836001600160a01b0316826001600160a01b0316148015610dd357507f000000000000000000000000000000000000000000000000000000000000003881145b95945050505050565b6000600454821115610dee5760045491505b5090565b634e487b7160e01b600052604160045260246000fd5b600082601f830112610e1957600080fd5b813567ffffffffffffffff80821115610e3457610e34610df2565b604051601f8301601f19908116603f01168101908282118183101715610e5c57610e5c610df2565b81604052838152866020858801011115610e7557600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215610ea857600080fd5b823567ffffffffffffffff80821115610ec057600080fd5b610ecc86838701610e08565b93506020850135915080821115610ee257600080fd5b50610eef85828601610e08565b9150509250929050565b600060208284031215610f0b57600080fd5b813567ffffffffffffffff811115610f2257600080fd5b610f2e84828501610e08565b949350505050565b6001600160a01b038116811461057e57600080fd5b600060208284031215610f5d57600080fd5b8135610f6881610f36565b9392505050565b600060208284031215610f8157600080fd5b5035919050565b6000815180845260005b81811015610fae57602081850181015186830182015201610f92565b506000602082860101526020601f19601f83011685010191505092915050565b8215158152604060208201526000610f2e6040830184610f88565b606081526000610ffc6060830186610f88565b828103602084015261100e8186610f88565b91505060018060a01b0383166040830152949350505050565b60408152600061103a6040830185610f88565b905060018060a01b03831660208301529392505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561079457610794611051565b8051602080830151919081101561109b576000198160200360031b1b821691505b50919050565b6000602082840312156110b357600080fd5b5051919050565b8082018082111561079457610794611051565b600060018060a01b03808816835260a060208401526110ef60a0840188610f88565b9516604083015250606081019290925260809091015292915050565b60008060006060848603121561112057600080fd5b835161112b81610f36565b60208501516040909501519096949550939250505056fea264697066735822122031cfc3cb5a032f137de2cab84c416d16e895165d8b4efd56769ea027c640a62864736f6c63430008110033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.