Sepolia Testnet

Contract

0x1c95209C226a2f48f1869c17d6cb0d978B3A7146

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

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

Contract Name:
CrossChainController

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 21 : CrossChainController.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;

import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol';
import {SafeERC20} from 'solidity-utils/contracts/oz-common/SafeERC20.sol';
import {Initializable} from 'solidity-utils/contracts/transparent-proxy/Initializable.sol';
import {OwnableWithGuardian} from 'solidity-utils/contracts/access-control/OwnableWithGuardian.sol';
import {EmergencyConsumer, IEmergencyConsumer} from 'solidity-utils/contracts/emergency/EmergencyConsumer.sol';
import {ICrossChainController} from './interfaces/ICrossChainController.sol';
import {CrossChainReceiver} from './CrossChainReceiver.sol';
import {CrossChainForwarder} from './CrossChainForwarder.sol';
import {Errors} from './libs/Errors.sol';

/**
 * @title CrossChainController
 * @author BGD Labs
 * @notice Contract with the logic to manage sending and receiving messages cross chain.
 * @dev This contract is enabled to receive gas tokens as its the one responsible for bridge services payment.
        It should always be topped up, or no messages will be sent to other chains
 * @dev If an emergency is activated, solveEmergency method should be called with new configurations.
 */
contract CrossChainController is
  ICrossChainController,
  CrossChainForwarder,
  CrossChainReceiver,
  EmergencyConsumer,
  Initializable
{
  using SafeERC20 for IERC20;

  /**
   * @param clEmergencyOracle chainlink emergency oracle address
   * @param initialRequiredConfirmations number of confirmations the messages need to be accepted as valid
   * @param receiverBridgeAdaptersToAllow array of addresses of the bridge adapters that can receive messages
   * @param forwarderBridgeAdaptersToEnable array specifying for every bridgeAdapter, the destinations it can have
   * @param sendersToApprove array of addresses to allow as forwarders
   */
  constructor(
    address clEmergencyOracle,
    uint256 initialRequiredConfirmations,
    address[] memory receiverBridgeAdaptersToAllow,
    BridgeAdapterConfigInput[] memory forwarderBridgeAdaptersToEnable,
    address[] memory sendersToApprove
  )
    CrossChainReceiver(initialRequiredConfirmations, receiverBridgeAdaptersToAllow)
    CrossChainForwarder(forwarderBridgeAdaptersToEnable, sendersToApprove)
    EmergencyConsumer(clEmergencyOracle)
  {}

  /// @inheritdoc ICrossChainController
  function initialize(
    address owner,
    address guardian,
    address clEmergencyOracle,
    uint256 initialRequiredConfirmations,
    address[] memory receiverBridgeAdaptersToAllow,
    BridgeAdapterConfigInput[] memory forwarderBridgeAdaptersToEnable,
    address[] memory sendersToApprove
  ) external initializer {
    _transferOwnership(owner);
    _updateGuardian(guardian);
    _updateCLEmergencyOracle(clEmergencyOracle);

    _updateConfirmations(initialRequiredConfirmations);
    _updateReceiverBridgeAdapters(receiverBridgeAdaptersToAllow, true);

    _enableBridgeAdapters(forwarderBridgeAdaptersToEnable);
    _updateSenders(sendersToApprove, true);
  }

  /// @inheritdoc ICrossChainController
  function solveEmergency(
    uint256 newConfirmations,
    uint120 newValidityTimestamp,
    address[] memory receiverBridgeAdaptersToAllow,
    address[] memory receiverBridgeAdaptersToDisallow,
    address[] memory sendersToApprove,
    address[] memory sendersToRemove,
    BridgeAdapterConfigInput[] memory forwarderBridgeAdaptersToEnable,
    BridgeAdapterToDisable[] memory forwarderBridgeAdaptersToDisable
  ) external onlyGuardian onlyInEmergency {
    // receiver side
    _updateReceiverBridgeAdapters(receiverBridgeAdaptersToAllow, true);
    _updateReceiverBridgeAdapters(receiverBridgeAdaptersToDisallow, false);
    _updateConfirmations(newConfirmations);
    _updateMessagesValidityTimestamp(newValidityTimestamp);

    // forwarder side
    _updateSenders(sendersToApprove, true);
    _updateSenders(sendersToRemove, false);
    _enableBridgeAdapters(forwarderBridgeAdaptersToEnable);
    _disableBridgeAdapters(forwarderBridgeAdaptersToDisable);
  }

  /// @inheritdoc ICrossChainController
  function emergencyTokenTransfer(
    address erc20Token,
    address to,
    uint256 amount
  ) external onlyOwner {
    IERC20(erc20Token).safeTransfer(to, amount);
  }

  /// @inheritdoc ICrossChainController
  function emergencyEtherTransfer(address to, uint256 amount) external onlyOwner {
    _safeTransferETH(to, amount);
  }

  /// @notice enable contract to receive eth
  receive() external payable {}

  /**
   * @notice transfer ETH to an address, revert if it fails.
   * @param to recipient of the transfer
   * @param value the amount to send
   */
  function _safeTransferETH(address to, uint256 value) internal {
    (bool success, ) = to.call{value: value}(new bytes(0));
    require(success, Errors.ETH_TRANSFER_FAILED);
  }

  /// @notice method that ensures access control validation
  function _validateEmergencyAdmin() internal override onlyOwner {}
}

File 2 of 21 : CrossChainForwarder.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;

import {OwnableWithGuardian} from 'solidity-utils/contracts/access-control/OwnableWithGuardian.sol';
import {ICrossChainForwarder} from './interfaces/ICrossChainForwarder.sol';
import {IBaseAdapter} from './adapters/IBaseAdapter.sol';
import {Errors} from './libs/Errors.sol';

/**
 * @title CrossChainForwarder
 * @author BGD Labs
 * @notice this contract contains the methods used to forward messages to different chains
 *         using registered bridge adapters.
 * @dev To be able to forward a message, caller needs to be an approved sender.
 */
contract CrossChainForwarder is OwnableWithGuardian, ICrossChainForwarder {
  // for every message we attach a nonce, that will be unique for the message. It increments by one
  uint256 internal _currentNonce;

  // specifies if an address is approved to forward messages
  mapping(address => bool) internal _approvedSenders;

  // Stores messages sent. hash(chainId, msgId, origin, dest, message) . This is used to check if a message can be retried
  mapping(bytes32 => bool) internal _forwardedMessages;

  // (chainId => chain configuration) list of bridge adapter configurations for a chain
  mapping(uint256 => ChainIdBridgeConfig[]) internal _bridgeAdaptersByChain;

  // checks if caller is an approved sender
  modifier onlyApprovedSenders() {
    require(isSenderApproved(msg.sender), Errors.CALLER_IS_NOT_APPROVED_SENDER);
    _;
  }

  /**
   * @param bridgeAdaptersToEnable list of bridge adapter configurations to enable
   * @param sendersToApprove list of addresses to approve to forward messages
   */
  constructor(
    BridgeAdapterConfigInput[] memory bridgeAdaptersToEnable,
    address[] memory sendersToApprove
  ) {
    _enableBridgeAdapters(bridgeAdaptersToEnable);
    _updateSenders(sendersToApprove, true);
  }

  /// @inheritdoc ICrossChainForwarder
  function getCurrentNonce() external view returns (uint256) {
    return _currentNonce;
  }

  /// @inheritdoc ICrossChainForwarder
  function isSenderApproved(address sender) public view returns (bool) {
    return _approvedSenders[sender];
  }

  /// @inheritdoc ICrossChainForwarder
  function isMessageForwarded(
    uint256 destinationChainId,
    address origin,
    address destination,
    bytes memory message
  ) public view returns (bool) {
    bytes32 hashedMsgId = keccak256(abi.encode(destinationChainId, origin, destination, message));

    return _forwardedMessages[hashedMsgId];
  }

  /// @inheritdoc ICrossChainForwarder
  function forwardMessage(
    uint256 destinationChainId,
    address destination,
    uint256 gasLimit,
    bytes memory message
  ) external onlyApprovedSenders {
    _forwardMessage(destinationChainId, msg.sender, destination, gasLimit, message);
  }

  /// @inheritdoc ICrossChainForwarder
  function retryMessage(
    uint256 destinationChainId,
    address origin,
    address destination,
    uint256 gasLimit,
    bytes memory message
  ) external onlyOwnerOrGuardian {
    // If message not bridged before means that something in the message params has changed
    // and it can not be directly resent.
    require(
      isMessageForwarded(destinationChainId, origin, destination, message) == true,
      Errors.MESSAGE_REQUIRED_TO_HAVE_BEEN_PREVIOUSLY_FORWARDED
    );
    _forwardMessage(destinationChainId, origin, destination, gasLimit, message);
  }

  /// @inheritdoc ICrossChainForwarder
  function getBridgeAdaptersByChain(
    uint256 chainId
  ) external view returns (ChainIdBridgeConfig[] memory) {
    return _bridgeAdaptersByChain[chainId];
  }

  /**
   * @dev method called to initiate message forwarding to other networks.
   * @param destinationChainId id of the destination chain where the message needs to be bridged
   * @param origin address where the message originates from
   * @param destination address where the message is intended for
   * @param message bytes that need to be bridged
   */
  function _forwardMessage(
    uint256 destinationChainId,
    address origin,
    address destination,
    uint256 gasLimit,
    bytes memory message
  ) internal {
    bytes memory encodedMessage = abi.encode(_currentNonce++, origin, destination, message);

    ChainIdBridgeConfig[] memory bridgeAdapters = _bridgeAdaptersByChain[destinationChainId];

    bool someMessageForwarded;
    for (uint256 i = 0; i < bridgeAdapters.length; i++) {
      ChainIdBridgeConfig memory bridgeAdapterConfig = bridgeAdapters[i];

      (bool success, bytes memory returnData) = bridgeAdapterConfig
        .currentChainBridgeAdapter
        .delegatecall(
          abi.encodeWithSelector(
            IBaseAdapter.forwardMessage.selector,
            bridgeAdapterConfig.destinationBridgeAdapter,
            gasLimit,
            destinationChainId,
            encodedMessage
          )
        );

      if (!success) {
        // it doesnt revert as sending to other bridges might succeed
        emit AdapterFailed(
          destinationChainId,
          bridgeAdapterConfig.currentChainBridgeAdapter,
          bridgeAdapterConfig.destinationBridgeAdapter,
          encodedMessage,
          returnData
        );
      } else {
        someMessageForwarded = true;

        emit MessageForwarded(
          destinationChainId,
          bridgeAdapterConfig.currentChainBridgeAdapter,
          bridgeAdapterConfig.destinationBridgeAdapter,
          encodedMessage
        );
      }
    }

    require(someMessageForwarded, Errors.NO_MESSAGE_FORWARDED_SUCCESSFULLY);

    // save sent message for future retries. We save even if one bridge was able to send
    // so this way, if other bridges failed, we can retry.
    bytes32 fullMessageId = keccak256(abi.encode(destinationChainId, origin, destination, message));
    _forwardedMessages[fullMessageId] = true;
  }

  /// @inheritdoc ICrossChainForwarder
  function approveSenders(address[] memory senders) external onlyOwner {
    _updateSenders(senders, true);
  }

  /// @inheritdoc ICrossChainForwarder
  function removeSenders(address[] memory senders) external onlyOwner {
    _updateSenders(senders, false);
  }

  /// @inheritdoc ICrossChainForwarder
  function enableBridgeAdapters(
    BridgeAdapterConfigInput[] memory bridgeAdapters
  ) external onlyOwner {
    _enableBridgeAdapters(bridgeAdapters);
  }

  /// @inheritdoc ICrossChainForwarder
  function disableBridgeAdapters(
    BridgeAdapterToDisable[] memory bridgeAdapters
  ) external onlyOwner {
    _disableBridgeAdapters(bridgeAdapters);
  }

  /**
   * @notice method to enable bridge adapters
   * @param bridgeAdapters array of new bridge adapter configurations
   */
  function _enableBridgeAdapters(BridgeAdapterConfigInput[] memory bridgeAdapters) internal {
    for (uint256 i = 0; i < bridgeAdapters.length; i++) {
      BridgeAdapterConfigInput memory bridgeAdapterConfigInput = bridgeAdapters[i];

      require(
        bridgeAdapterConfigInput.destinationBridgeAdapter != address(0) &&
          bridgeAdapterConfigInput.currentChainBridgeAdapter != address(0),
        Errors.CURRENT_OR_DESTINATION_CHAIN_ADAPTER_NOT_SET
      );
      ChainIdBridgeConfig[] storage bridgeAdapterConfigs = _bridgeAdaptersByChain[
        bridgeAdapterConfigInput.destinationChainId
      ];
      bool configFound;
      // check that we dont push same config twice.
      for (uint256 j = 0; j < bridgeAdapterConfigs.length; j++) {
        ChainIdBridgeConfig storage bridgeAdapterConfig = bridgeAdapterConfigs[j];

        if (
          bridgeAdapterConfig.currentChainBridgeAdapter ==
          bridgeAdapterConfigInput.currentChainBridgeAdapter
        ) {
          if (
            bridgeAdapterConfig.destinationBridgeAdapter !=
            bridgeAdapterConfigInput.destinationBridgeAdapter
          ) {
            bridgeAdapterConfig.destinationBridgeAdapter = bridgeAdapterConfigInput
              .destinationBridgeAdapter;
          }
          configFound = true;
          break;
        }
      }

      if (!configFound) {
        bridgeAdapterConfigs.push(
          ChainIdBridgeConfig({
            destinationBridgeAdapter: bridgeAdapterConfigInput.destinationBridgeAdapter,
            currentChainBridgeAdapter: bridgeAdapterConfigInput.currentChainBridgeAdapter
          })
        );
      }

      emit BridgeAdapterUpdated(
        bridgeAdapterConfigInput.destinationChainId,
        bridgeAdapterConfigInput.currentChainBridgeAdapter,
        bridgeAdapterConfigInput.destinationBridgeAdapter,
        true
      );
    }
  }

  /**
   * @notice method to disable bridge adapters
   * @param bridgeAdaptersToDisable array of bridge adapter addresses to disable
   */
  function _disableBridgeAdapters(
    BridgeAdapterToDisable[] memory bridgeAdaptersToDisable
  ) internal {
    for (uint256 i = 0; i < bridgeAdaptersToDisable.length; i++) {
      for (uint256 j = 0; j < bridgeAdaptersToDisable[i].chainIds.length; j++) {
        ChainIdBridgeConfig[] storage bridgeAdapterConfigs = _bridgeAdaptersByChain[
          bridgeAdaptersToDisable[i].chainIds[j]
        ];

        for (uint256 k = 0; k < bridgeAdapterConfigs.length; k++) {
          if (
            bridgeAdapterConfigs[k].currentChainBridgeAdapter ==
            bridgeAdaptersToDisable[i].bridgeAdapter
          ) {
            address destinationBridgeAdapter = bridgeAdapterConfigs[k].destinationBridgeAdapter;

            if (k != bridgeAdapterConfigs.length) {
              bridgeAdapterConfigs[k] = bridgeAdapterConfigs[bridgeAdapterConfigs.length - 1];
            }

            bridgeAdapterConfigs.pop();

            emit BridgeAdapterUpdated(
              bridgeAdaptersToDisable[i].chainIds[j],
              bridgeAdaptersToDisable[i].bridgeAdapter,
              destinationBridgeAdapter,
              false
            );
            break;
          }
        }
      }
    }
  }

  /**
   * @notice method to approve or disapprove a list of senders
   * @param senders list of addresses to update
   * @param newState indicates if the list of senders will be approved or disapproved
   */
  function _updateSenders(address[] memory senders, bool newState) internal {
    for (uint256 i = 0; i < senders.length; i++) {
      _approvedSenders[senders[i]] = newState;
      emit SenderUpdated(senders[i], newState);
    }
  }
}

File 3 of 21 : CrossChainReceiver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;

import {OwnableWithGuardian} from 'solidity-utils/contracts/access-control/OwnableWithGuardian.sol';
import {ICrossChainReceiver} from './interfaces/ICrossChainReceiver.sol';
import {IBaseReceiverPortal} from './interfaces/IBaseReceiverPortal.sol';
import {Errors} from './libs/Errors.sol';

/**
 * @title CrossChainReceiver
 * @author BGD Labs
 * @notice this contract contains the methods to get bridged messages and route them to their respective recipients.
 * @dev to route a message, this one needs to be bridged correctly n number of confirmations.
 * @dev if at some point, it is detected that some bridge has been hacked, there is a possibility to invalidate
 *      messages by calling updateMessagesValidityTimestamp
 */
contract CrossChainReceiver is OwnableWithGuardian, ICrossChainReceiver {
  // number of bridges that are needed to make a bridged message valid.
  // Depending on the deployment chain, this needs to change, to account for the existing number of bridges
  uint256 internal _requiredConfirmations;

  // all messages originated but not finally confirmed before this timestamp, are invalid
  uint120 internal _validityTimestamp;

  // stores hash(nonce + originChainId + origin + dest + message) => bridged message information and state
  mapping(bytes32 => InternalBridgedMessage) internal _internalReceivedMessages;

  // specifies if an address is allowed to forward messages
  mapping(address => bool) internal _allowedBridgeAdapters;

  // checks if caller is one of the approved bridge adapters
  modifier onlyApprovedBridges() {
    require(isReceiverBridgeAdapterAllowed(msg.sender), Errors.CALLER_NOT_APPROVED_BRIDGE);
    _;
  }

  /**
   * @param initialRequiredConfirmations number of confirmations the messages need to be accepted as valid
   * @param bridgeAdaptersToAllow array of addresses of the bridge adapters that can receive messages
   */
  constructor(uint256 initialRequiredConfirmations, address[] memory bridgeAdaptersToAllow) {
    _updateConfirmations(initialRequiredConfirmations);
    _updateReceiverBridgeAdapters(bridgeAdaptersToAllow, true);
  }

  /// @inheritdoc ICrossChainReceiver
  function getRequiredConfirmations() external view returns (uint256) {
    return _requiredConfirmations;
  }

  /// @inheritdoc ICrossChainReceiver
  function getValidityTimestamp() external view returns (uint120) {
    return _validityTimestamp;
  }

  /// @inheritdoc ICrossChainReceiver
  function isReceiverBridgeAdapterAllowed(address bridgeAdapter) public view returns (bool) {
    return _allowedBridgeAdapters[bridgeAdapter];
  }

  /// @inheritdoc ICrossChainReceiver
  function getInternalMessageState(
    bytes32 internalId
  ) external view returns (InternalBridgedMessageStateWithoutAdapters memory) {
    return
      InternalBridgedMessageStateWithoutAdapters({
        confirmations: _internalReceivedMessages[internalId].confirmations,
        firstBridgedAt: _internalReceivedMessages[internalId].firstBridgedAt,
        delivered: _internalReceivedMessages[internalId].delivered
      });
  }

  /// @inheritdoc ICrossChainReceiver
  function isInternalMessageReceivedByAdapter(
    bytes32 internalId,
    address bridgeAdapter
  ) external view returns (bool) {
    return _internalReceivedMessages[internalId].bridgedByAdapter[bridgeAdapter];
  }

  /// @inheritdoc ICrossChainReceiver
  function updateConfirmations(uint256 newConfirmations) external onlyOwner {
    _updateConfirmations(newConfirmations);
  }

  /// @inheritdoc ICrossChainReceiver
  function updateMessagesValidityTimestamp(uint120 newValidityTimestamp) external onlyOwner {
    _updateMessagesValidityTimestamp(newValidityTimestamp);
  }

  /// @inheritdoc ICrossChainReceiver
  function allowReceiverBridgeAdapters(address[] memory bridgeAdapters) external onlyOwner {
    _updateReceiverBridgeAdapters(bridgeAdapters, true);
  }

  /// @inheritdoc ICrossChainReceiver
  function disallowReceiverBridgeAdapters(address[] memory bridgeAdapters) external onlyOwner {
    _updateReceiverBridgeAdapters(bridgeAdapters, false);
  }

  /// @inheritdoc ICrossChainReceiver
  function receiveCrossChainMessage(
    bytes memory payload,
    uint256 originChainId
  ) external onlyApprovedBridges {
    (, address msgOrigin, address msgDestination, bytes memory message) = abi.decode(
      payload,
      (uint256, address, address, bytes)
    );

    bytes32 internalId = keccak256(abi.encode(originChainId, payload));

    InternalBridgedMessage storage internalMessage = _internalReceivedMessages[internalId];

    // if bridged at is > invalidation means that the first message bridged happened after invalidation
    // which means that invalidation doesnt affect as invalid bridge has already been removed.
    // as nonce is packed in the payload. If message arrives after invalidation from resending, it will pass.
    // if its 0 means that is the first bridge received, meaning that invalidation does not matter for this message
    // checks that bridge adapter has not already bridged this message
    uint120 messageFirstBridgedAt = internalMessage.firstBridgedAt;
    if (
      (messageFirstBridgedAt > _validityTimestamp &&
        !internalMessage.bridgedByAdapter[msg.sender]) || messageFirstBridgedAt == 0
    ) {
      if (messageFirstBridgedAt == 0) {
        internalMessage.firstBridgedAt = uint120(block.timestamp);
      }

      uint256 newConfirmations = ++internalMessage.confirmations;
      internalMessage.bridgedByAdapter[msg.sender] = true;

      emit MessageReceived(
        internalId,
        msg.sender,
        msgDestination,
        msgOrigin,
        message,
        newConfirmations
      );

      // it checks if it has been delivered, so it doesnt deliver again when message arrives from extra bridges
      // (when already reached confirmations) and reverts (because of destination logic)
      // and it saves that these bridges have also correctly bridged the message
      if (newConfirmations == _requiredConfirmations && !internalMessage.delivered) {
        IBaseReceiverPortal(msgDestination).receiveCrossChainMessage(
          msgOrigin,
          originChainId,
          message
        );

        internalMessage.delivered = true;

        emit MessageConfirmed(msgDestination, msgOrigin, message);
      }
    }
  }

  /**
   * @notice method to invalidate messages previous to certain timestamp.
   * @param newValidityTimestamp timestamp where all the previous unconfirmed messages must be invalidated.
   */
  function _updateMessagesValidityTimestamp(uint120 newValidityTimestamp) internal {
    require(newValidityTimestamp > _validityTimestamp, Errors.TIMESTAMP_ALREADY_PASSED);
    _validityTimestamp = newValidityTimestamp;

    emit NewInvalidation(newValidityTimestamp);
  }

  /**
   * @notice updates confirmations needed for a message to be accepted as valid
   * @param newConfirmations number of confirmations
   */
  function _updateConfirmations(uint256 newConfirmations) internal {
    _requiredConfirmations = newConfirmations;
    emit ConfirmationsUpdated(newConfirmations);
  }

  /**
   * @notice method to remove bridge adapters from the allowed list
   * @param bridgeAdapters array of bridge adapter addresses to update
   * @param newState new state, will they be allowed or not
   */
  function _updateReceiverBridgeAdapters(address[] memory bridgeAdapters, bool newState) internal {
    for (uint256 i = 0; i < bridgeAdapters.length; i++) {
      _allowedBridgeAdapters[bridgeAdapters[i]] = newState;

      emit ReceiverBridgeAdaptersUpdated(bridgeAdapters[i], newState);
    }
  }
}

File 4 of 21 : IBaseAdapter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title IBaseAdapter
 * @author BGD Labs
 * @notice interface containing the event and method used in all bridge adapters
 */
interface IBaseAdapter {
  /**
   * @notice method that will bridge the payload to the chain specified
   * @param receiver address of the receiver contract on destination chain
   * @param gasLimit amount of the gas limit in wei to use for bridging on receiver side. Each adapter will manage this
            as needed
   * @param destinationChainId id of the destination chain in the bridge notation
   * @param message to send to the specified chain
   */
  function forwardMessage(
    address receiver, // TODO: this should be renamed as is the bridge adapter on receiving side
    uint256 gasLimit,
    uint256 destinationChainId,
    bytes memory message
  ) external;
}

File 5 of 21 : IBaseReceiverPortal.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title IBaseReceiverPortal
 * @author BGD Labs
 * @notice interface defining the method that needs to be implemented by all receiving portals, as its the one that
           will be called when a received message gets confirmed
 */
interface IBaseReceiverPortal {
  /**
   * @notice method called by CrossChainController when a message has been confirmed
   * @param originSender address of the sender of the bridged message
   * @param originChainId id of the chain where the message originated
   * @param message bytes bridged containing the desired information
   */
  function receiveCrossChainMessage(
    address originSender,
    uint256 originChainId,
    bytes memory message
  ) external;
}

File 6 of 21 : ICrossChainController.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import './ICrossChainForwarder.sol';
import './ICrossChainReceiver.sol';

/**
 * @title ICrossChainController
 * @author BGD Labs
 * @notice interface containing the objects, events and methods definitions of the CrossChainController contract
 */
interface ICrossChainController is ICrossChainForwarder, ICrossChainReceiver {
  /**
   * @notice method called to initialize the proxy
   * @param owner address of the owner of the cross chain controller
   * @param guardian address of the guardian of the cross chain controller
   * @param clEmergencyOracle address of the chainlink emergency oracle
   * @param initialRequiredConfirmations number of confirmations the messages need to be accepted as valid
   * @param receiverBridgeAdaptersToAllow array of addresses of the bridge adapters that can receive messages
   * @param forwarderBridgeAdaptersToEnable array specifying for every bridgeAdapter, the destinations it can have
   * @param sendersToApprove array of addresses to allow as forwarders
   */
  function initialize(
    address owner,
    address guardian,
    address clEmergencyOracle,
    uint256 initialRequiredConfirmations,
    address[] memory receiverBridgeAdaptersToAllow,
    BridgeAdapterConfigInput[] memory forwarderBridgeAdaptersToEnable,
    address[] memory sendersToApprove
  ) external;

  /**
   * @notice method called to rescue tokens sent erroneously to the contract. Only callable by owner
   * @param erc20Token address of the token to rescue
   * @param to address to send the tokens
   * @param amount of tokens to rescue
   */
  function emergencyTokenTransfer(address erc20Token, address to, uint256 amount) external;

  /**
   * @notice method called to rescue ether sent erroneously to the contract. Only callable by owner
   * @param to address to send the eth
   * @param amount of eth to rescue
   */
  function emergencyEtherTransfer(address to, uint256 amount) external;

  /**
  * @notice method to check if there is a new emergency state, indicated by chainlink emergency oracle.
         This method is callable by anyone as a new emergency will be determined by the oracle, and this way
         it will be easier / faster to enter into emergency.
  * @param newConfirmations number of confirmations necessary for a message to be routed to destination
  * @param newValidityTimestamp timestamp in seconds indicating the point to where not confirmed messages will be
  *        invalidated.
  * @param receiverBridgeAdaptersToAllow list of bridge adapter addresses to be allowed to receive messages
  * @param receiverBridgeAdaptersToDisallow list of bridge adapter addresses to be disallowed
  * @param sendersToApprove list of addresses to be approved as senders
  * @param sendersToRemove list of sender addresses to be removed
  * @param forwarderBridgeAdaptersToEnable list of bridge adapters to be enabled to send messages
  * @param forwarderBridgeAdaptersToDisable list of bridge adapters to be disabled
  */
  function solveEmergency(
    uint256 newConfirmations,
    uint120 newValidityTimestamp,
    address[] memory receiverBridgeAdaptersToAllow,
    address[] memory receiverBridgeAdaptersToDisallow,
    address[] memory sendersToApprove,
    address[] memory sendersToRemove,
    BridgeAdapterConfigInput[] memory forwarderBridgeAdaptersToEnable,
    BridgeAdapterToDisable[] memory forwarderBridgeAdaptersToDisable
  ) external;
}

File 7 of 21 : ICrossChainForwarder.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;

/**
 * @title ICrossChainForwarder
 * @author BGD Labs
 * @notice interface containing the objects, events and methods definitions of the CrossChainForwarder contract
 */
interface ICrossChainForwarder {
  /**
   * @notice object storing the connected pair of bridge adapters, on current and destination chain
   * @param destinationBridgeAdapter address of the bridge adapter on the destination chain
   * @param currentChainBridgeAdapter address of the bridge adapter deployed on current network
   */
  struct ChainIdBridgeConfig {
    address destinationBridgeAdapter;
    address currentChainBridgeAdapter;
  }

  /**
   * @notice object with the necessary information to remove bridge adapters
   * @param bridgeAdapter address of the bridge adapter to remove
   * @param chainIds array of chain ids where the bridge adapter connects
   */
  struct BridgeAdapterToDisable {
    address bridgeAdapter;
    uint256[] chainIds;
  }

  /**
   * @notice object storing the pair bridgeAdapter (current deployed chain) destination chain bridge adapter configuration
   * @param currentChainBridgeAdapter address of the bridge adapter deployed on current chain
   * @param destinationBridgeAdapter address of the bridge adapter on the destination chain
   * @param dstChainId id of the destination chain using our own nomenclature
   */
  struct BridgeAdapterConfigInput {
    address currentChainBridgeAdapter;
    address destinationBridgeAdapter;
    uint256 destinationChainId;
  }

  /**
   * @notice emitted when a bridge adapter failed to send a message
   * @param destinationChainId id of the destination chain in our notation
   * @param bridgeAdapter address of the bridge adapter that failed (deployed on current network)
   * @param destinationBridgeAdapter address of the connected bridge adapter on destination chain
   * @param destinationChainId id of destination chain
   * @param message bytes intended to be bridged
   * @param returndata bytes with error information
   */
  event AdapterFailed(
    uint256 indexed destinationChainId,
    address indexed bridgeAdapter,
    address indexed destinationBridgeAdapter,
    bytes message,
    bytes returndata
  );

  /**
   * @notice emitted when a message is successfully forwarded through a bridge adapter
   * @param destinationChainId id of the destination chain in our notation
   * @param bridgeAdapter address of the bridge adapter that failed (deployed on current network)
   * @param destinationBridgeAdapter address of the connected bridge adapter on destination chain
   * @param destinationChainId id of destination chain
   * @param message bytes intended to be bridged
   */
  event MessageForwarded(
    uint256 indexed destinationChainId,
    address indexed bridgeAdapter,
    address indexed destinationBridgeAdapter,
    bytes message
  );

  /**
   * @notice emitted when a bridge adapter has been added to the allowed list
   * @param destinationChainId id of the destination chain in our notation
   * @param bridgeAdapter address of the bridge adapter added (deployed on current network)
   * @param destinationBridgeAdapter address of the connected bridge adapter on destination chain
   * @param allowed boolean indicating if the bridge adapter is allowed or disallowed
   */
  event BridgeAdapterUpdated(
    uint256 indexed destinationChainId,
    address indexed bridgeAdapter,
    address destinationBridgeAdapter,
    bool indexed allowed
  );

  /**
   * @notice emitted when a sender has been updated
   * @param sender address of the updated sender
   * @param isApproved boolean that indicates if the sender has been approved or removed
   */
  event SenderUpdated(address indexed sender, bool indexed isApproved);

  /**
   * @notice method to get the current sent message nonce
   * @return the current nonce
   */
  function getCurrentNonce() external view returns (uint256);

  /**
   * @notice method to check if a message has been previously forwarded.
   * @param destinationChainId id of the destination chain where the message needs to be bridged
   * @param origin address where the message originates from
   * @param destination address where the message is intended for
   * @param message bytes that need to be bridged
   * @return boolean indicating if the message has been forwarded
   */
  function isMessageForwarded(
    uint256 destinationChainId,
    address origin,
    address destination,
    bytes memory message
  ) external view returns (bool);

  /**
   * @notice method called to initiate message forwarding to other networks.
   * @param destinationChainId id of the destination chain where the message needs to be bridged
   * @param destination address where the message is intended for
   * @param gasLimit gas cost on receiving side of the message
   * @param message bytes that need to be bridged
   */
  function forwardMessage(
    uint256 destinationChainId,
    address destination,
    uint256 gasLimit,
    bytes memory message
  ) external;

  /**
   * @notice method called to re forward a previously sent message.
   * @param destinationChainId id of the destination chain where the message needs to be bridged
   * @param origin address where the message originates from
   * @param destination address where the message is intended for
   * @param gasLimit gas cost on receiving side of the message
   * @param message bytes that need to be bridged
   */
  function retryMessage(
    uint256 destinationChainId,
    address origin,
    address destination,
    uint256 gasLimit,
    bytes memory message
  ) external;

  /**
   * @notice method to enable bridge adapters
   * @param bridgeAdapters array of new bridge adapter configurations
   */
  function enableBridgeAdapters(BridgeAdapterConfigInput[] memory bridgeAdapters) external;

  /**
   * @notice method to disable bridge adapters
   * @param bridgeAdapters array of bridge adapter addresses to disable
   */
  function disableBridgeAdapters(BridgeAdapterToDisable[] memory bridgeAdapters) external;

  /**
   * @notice method to remove sender addresses
   * @param senders list of addresses to remove
   */
  function removeSenders(address[] memory senders) external;

  /**
   * @notice method to approve new sender addresses
   * @param senders list of addresses to approve
   */
  function approveSenders(address[] memory senders) external;

  /**
   * @notice method to get all the bridge adapters of a chain
   * @param chainId id of the chain we want to get the adateprs from
   * @return an array of chain configurations where the bridge adapter can communicate
   */
  function getBridgeAdaptersByChain(
    uint256 chainId
  ) external view returns (ChainIdBridgeConfig[] memory);

  /**
   * @notice method to get if a sender is approved
   * @param sender address that we want to check if approved
   * @return boolean indicating if the address has been approved as sender
   */
  function isSenderApproved(address sender) external view returns (bool);
}

File 8 of 21 : ICrossChainReceiver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;

/**
 * @title ICrossChainReceiver
 * @author BGD Labs
 * @notice interface containing the objects, events and methods definitions of the CrossChainReceiver contract
 */
interface ICrossChainReceiver {
  /**
   * @notice object that stores the internal information of the message
   * @param confirmations number of times that this message has been bridged
   * @param bridgedByAdapterNonce stores the nonce of when the message has been bridged by a determined bridge adapter
   * @param delivered boolean indicating if the bridged message has been delivered to the destination
   */
  struct InternalBridgedMessageStateWithoutAdapters {
    uint120 confirmations;
    uint120 firstBridgedAt;
    bool delivered;
  }
  /**
   * @notice object that stores the internal information of the message
   * @param confirmations number of times that this message has been bridged
   * @param bridgedByAdapterNonce stores the nonce of when the message has been bridged by a determined bridge adapter
   * @param delivered boolean indicating if the bridged message has been delivered to the destination
   * @param bridgedByAdapter list of bridge adapters that have bridged the message
   */
  struct InternalBridgedMessage {
    uint120 confirmations;
    uint120 firstBridgedAt;
    bool delivered;
    mapping(address => bool) bridgedByAdapter;
  }

  /**
   * @notice emitted when a message has reached the necessary number of confirmations
   * @param msgDestination address of consumer of the message
   * @param msgOrigin address where the message originated
   * @param message bytes confirmed
   */
  event MessageConfirmed(address indexed msgDestination, address indexed msgOrigin, bytes message);

  /**
   * @notice emitted when a message has been received successfully
   * @param internalId message id assigned on the controller, used for internal purposes: hash(to, from, message)
   * @param bridgeAdapter address of the bridge adapter who received the message (deployed on current network)
   * @param msgDestination address of consumer of the message
   * @param msgOrigin address where the message originated (CrossChainController on origin chain)
   * @param message bytes bridged
   * @param confirmations number of current confirmations for this message
   */
  event MessageReceived(
    bytes32 internalId,
    address indexed bridgeAdapter,
    address indexed msgDestination,
    address indexed msgOrigin,
    bytes message,
    uint256 confirmations
  );

  /**
   * @notice emitted when a bridge adapter gets disallowed
   * @param brigeAdapter address of the disallowed bridge adapter
   * @param allowed boolean indicating if the bridge adapter has been allowed or disallowed
   */
  event ReceiverBridgeAdaptersUpdated(address indexed brigeAdapter, bool indexed allowed);

  /**
   * @notice emitted when number of confirmations needed to validate a message changes
   * @param newConfirmations number of new confirmations needed for a message to be valid
   */
  event ConfirmationsUpdated(uint256 newConfirmations);

  /**
   * @notice emitted when a new timestamp for invalidations gets set
   * @param invalidTimestamp timestamp to invalidate previous messages
   */
  event NewInvalidation(uint256 invalidTimestamp);

  /**
   * @notice method to get the needed confirmations for a message to be accepted as valid
   * @return the number of required bridged message confirmations (how many bridges have bridged the message correctly)
   *         for a message to be sent to destination
   */
  function getRequiredConfirmations() external view returns (uint256);

  /**
   * @notice method to get the timestamp from where the messages will be valid
   * @return timestamp indicating the point from where the messages are valid.
   */
  function getValidityTimestamp() external view returns (uint120);

  /**
   * @notice method to get if a bridge adapter is allowed
   * @param bridgeAdapter address of the brige adapter to check
   * @return boolean indicating if brige adapter is allowed
   */
  function isReceiverBridgeAdapterAllowed(address bridgeAdapter) external view returns (bool);

  /**
   * @notice  method to get the internal message information
   * @param internalId hash(originChain + payload) identifying the message internally
   * @return number of confirmations of internal message identified by internalId and the updated timestamp
   */
  function getInternalMessageState(
    bytes32 internalId
  ) external view returns (InternalBridgedMessageStateWithoutAdapters memory);

  /**
   * @notice method to get if message has been received by bridge adapter
   * @param internalId id of the message as stored internally
   * @param bridgeAdapter address of the bridge adapter to check if it has bridged the message
   * @return boolean indicating if the message has been received
   */
  function isInternalMessageReceivedByAdapter(
    bytes32 internalId,
    address bridgeAdapter
  ) external view returns (bool);

  /**
   * @notice method to set a new timestamp from where the messages will be valid.
   * @param newValidityTimestamp timestamp where all the previous unconfirmed messages must be invalidated.
   */
  function updateMessagesValidityTimestamp(uint120 newValidityTimestamp) external;

  /**
   * @notice method to update the number of confirmations necessary for the messages to be accepted as valid
   * @param newConfirmations new number of needed confirmations
   */
  function updateConfirmations(uint256 newConfirmations) external;

  /**
   * @notice method that registers a received message, updates the confirmations, and sets it as valid if number
   of confirmations has been reached.
   * @param payload bytes of the payload, containing the information to operate with it
   */
  function receiveCrossChainMessage(bytes memory payload, uint256 originChainId) external;

  /**
   * @notice method to add bridge adapters to the allowed list
   * @param bridgeAdapters array of new bridge adapter configurations
   */
  function allowReceiverBridgeAdapters(address[] memory bridgeAdapters) external;

  /**
   * @notice method to remove bridge adapters from the allowed list
   * @param bridgeAdapters array of bridge adapter addresses to remove from the allow list
   */
  function disallowReceiverBridgeAdapters(address[] memory bridgeAdapters) external;
}

File 9 of 21 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Errors library
 * @author BGD Labs
 * @notice Defines the error messages emitted by the different contracts of the Aave Governance V3
 */
library Errors {
  string public constant ETH_TRANSFER_FAILED = '1'; // failed to transfer eth to destination
  string public constant CALLER_IS_NOT_APPROVED_SENDER = '2'; // caller must be an approved message sender
  string public constant MESSAGE_REQUIRED_TO_HAVE_BEEN_PREVIOUSLY_FORWARDED = '3'; // message can only be retried if it has been previously forwarded
  string public constant NO_MESSAGE_FORWARDED_SUCCESSFULLY = '4'; // message was not able to be forwarded
  string public constant CURRENT_OR_DESTINATION_CHAIN_ADAPTER_NOT_SET = '5'; // can not enable bridge adapter if the current or destination chain adapter is 0 address
  string public constant CALLER_NOT_APPROVED_BRIDGE = '6'; // caller must be an approved bridge
  string public constant TIMESTAMP_ALREADY_PASSED = '7'; // timestamp is older than current timestamp (in the past)
  string public constant CALLER_NOT_CCIP_ROUTER = '8'; // caller must be bridge provider contract
  string public constant CCIP_ROUTER_CANT_BE_ADDRESS_0 = '9'; // CCIP bridge adapters needs a CCIP Router
  string public constant RECEIVER_NOT_SET = '10'; // receiver address on destination chain can not be 0
  string public constant DESTINATION_CHAIN_ID_NOT_SUPPORTED = '11'; // destination chain id must be supported by bridge provider
  string public constant NOT_ENOUGH_VALUE_TO_PAY_BRIDGE_FEES = '12'; // cross chain controller does not have enough funds to forward the message
  string public constant INCORRECT_ORIGIN_CHAIN_ID = '13'; // message origination chain id is not from a supported chain
  string public constant REMOTE_NOT_TRUSTED = '14'; // remote address has not been registered as a trusted origin
  string public constant CALLER_NOT_HL_MAILBOX = '15'; // caller must be the HyperLane Mailbox contract
}

File 10 of 21 : OwnableWithGuardian.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0;

import {IWithGuardian} from './interfaces/IWithGuardian.sol';
import {Ownable} from '../oz-common/Ownable.sol';

abstract contract OwnableWithGuardian is Ownable, IWithGuardian {
  address private _guardian;

  constructor() {
    _updateGuardian(_msgSender());
  }

  modifier onlyGuardian() {
    _checkGuardian();
    _;
  }

  modifier onlyOwnerOrGuardian() {
    _checkOwnerOrGuardian();
    _;
  }

  function guardian() public view override returns (address) {
    return _guardian;
  }

  /// @inheritdoc IWithGuardian
  function updateGuardian(address newGuardian) external override onlyGuardian {
    _updateGuardian(newGuardian);
  }

  /**
   * @dev method to update the guardian
   * @param newGuardian the new guardian address
   */
  function _updateGuardian(address newGuardian) internal {
    address oldGuardian = _guardian;
    _guardian = newGuardian;
    emit GuardianUpdated(oldGuardian, newGuardian);
  }

  function _checkGuardian() internal view {
    require(guardian() == _msgSender(), 'ONLY_BY_GUARDIAN');
  }

  function _checkOwnerOrGuardian() internal view {
    require(_msgSender() == owner() || _msgSender() == guardian(), 'ONLY_BY_OWNER_OR_GUARDIAN');
  }
}

File 11 of 21 : IWithGuardian.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0;

interface IWithGuardian {
  /**
   * @dev Event emitted when guardian gets updated
   * @param oldGuardian address of previous guardian
   * @param newGuardian address of the new guardian
   */
  event GuardianUpdated(address oldGuardian, address newGuardian);

  /**
   * @dev get guardian address;
   */
  function guardian() external view returns (address);

  /**
   * @dev method to update the guardian
   * @param newGuardian the new guardian address
   */
  function updateGuardian(address newGuardian) external;
}

File 12 of 21 : EmergencyConsumer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IEmergencyConsumer} from './interfaces/IEmergencyConsumer.sol';
import {ICLEmergencyOracle} from './interfaces/ICLEmergencyOracle.sol';

abstract contract EmergencyConsumer is IEmergencyConsumer {
  address internal _chainlinkEmergencyOracle;

  uint256 internal _emergencyCount;

  /// @dev modifier that checks if the oracle emergency is greater than the last resolved one, and if so
  ///      lets execution pass
  modifier onlyInEmergency() {
    require(address(_chainlinkEmergencyOracle) != address(0), 'CL_EMERGENCY_ORACLE_NOT_SET');

    (, int256 answer, , , ) = ICLEmergencyOracle(_chainlinkEmergencyOracle).latestRoundData();

    uint256 nextEmergencyCount = ++_emergencyCount;
    require(answer == int256(nextEmergencyCount), 'NOT_IN_EMERGENCY');
    _;

    emit EmergencySolved(nextEmergencyCount);
  }

  /**
   * @param newChainlinkEmergencyOracle address of the new chainlink emergency mode oracle
   */
  constructor(address newChainlinkEmergencyOracle) {
    _updateCLEmergencyOracle(newChainlinkEmergencyOracle);
  }

  /// @dev This method is made virtual as it is expected to have access control, but this way it is delegated to implementation.
  function _validateEmergencyAdmin() internal virtual;

  /// @inheritdoc IEmergencyConsumer
  function updateCLEmergencyOracle(address newChainlinkEmergencyOracle) external {
    _validateEmergencyAdmin();
    _updateCLEmergencyOracle(newChainlinkEmergencyOracle);
  }

  /// @inheritdoc IEmergencyConsumer
  function getChainlinkEmergencyOracle() public view returns (address) {
    return _chainlinkEmergencyOracle;
  }

  /// @inheritdoc IEmergencyConsumer
  function getEmergencyCount() public view returns (uint256) {
    return _emergencyCount;
  }

  /**
   * @dev method to update the chainlink emergency oracle
   * @param newChainlinkEmergencyOracle address of the new oracle
   */
  function _updateCLEmergencyOracle(address newChainlinkEmergencyOracle) internal {
    _chainlinkEmergencyOracle = newChainlinkEmergencyOracle;

    emit CLEmergencyOracleUpdated(newChainlinkEmergencyOracle);
  }
}

File 13 of 21 : ICLEmergencyOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ICLEmergencyOracle {
  /**
   * @notice get data about the latest round. Consumers are encouraged to check
   * that they're receiving fresh data by inspecting the updatedAt and
   * answeredInRound return values.
   * Note that different underlying implementations of AggregatorV3Interface
   * have slightly different semantics for some of the return values. Consumers
   * should determine what implementations they expect to receive
   * data from and validate that they can properly handle return data from all
   * of them.
   * @return roundId is the round ID from the aggregator for which the data was
   * retrieved combined with an phase to ensure that round IDs get larger as
   * time moves forward.
   * @return answer is the answer for the given round
   * @return startedAt is the timestamp when the round was started.
   * (Only some AggregatorV3Interface implementations return meaningful values)
   * @return updatedAt is the timestamp when the round last was updated (i.e.
   * answer was last computed)
   * @return answeredInRound is the round ID of the round in which the answer
   * was computed.
   * (Only some AggregatorV3Interface implementations return meaningful values)
   * @dev Note that answer and updatedAt may change between queries.
   */
  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );
}

File 14 of 21 : IEmergencyConsumer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IEmergencyConsumer {
  /**
   * @dev emitted when chainlink emergency oracle gets updated
   * @param newChainlinkEmergencyOracle address of the new oracle
   */
  event CLEmergencyOracleUpdated(address indexed newChainlinkEmergencyOracle);

  /**
   * @dev emitted when the emergency is solved
   * @param emergencyCount number of emergencies solved. Used to check if a new emergency is active.
   */
  event EmergencySolved(uint256 emergencyCount);

  /// @dev method that returns the last emergency solved
  function getEmergencyCount() external view returns (uint256);

  /// @dev method that returns the address of the current chainlink emergency oracle
  function getChainlinkEmergencyOracle() external view returns (address);

  /**
   * @dev method to update the chainlink emergency mode address.
   *      This method is made virtual as it is expected to have access control, but this way it is delegated to implementation.
   *      It should call _updateCLEmergencyOracle when implemented
   * @param newChainlinkEmergencyOracle address of the new chainlink emergency mode oracle
   */
  function updateCLEmergencyOracle(address newChainlinkEmergencyOracle) external;
}

File 15 of 21 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
// From commit https://github.com/OpenZeppelin/openzeppelin-contracts/commit/8b778fa20d6d76340c5fac1ed66c80273f05b95a

pragma solidity ^0.8.1;

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

    return account.code.length > 0;
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

File 16 of 21 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
// From commit https://github.com/OpenZeppelin/openzeppelin-contracts/commit/8b778fa20d6d76340c5fac1ed66c80273f05b95a

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
  function _msgSender() internal view virtual returns (address) {
    return msg.sender;
  }

  function _msgData() internal view virtual returns (bytes calldata) {
    return msg.data;
  }
}

File 17 of 21 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
// From commit https://github.com/OpenZeppelin/openzeppelin-contracts/commit/8b778fa20d6d76340c5fac1ed66c80273f05b95a

pragma solidity ^0.8.0;

import './Context.sol';

/**
 * @dev 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 with {transferOwnership}.
 *
 * 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.
 */
abstract contract Ownable is Context {
  address private _owner;

  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  /**
   * @dev Initializes the contract setting the deployer as the initial owner.
   */
  constructor() {
    _transferOwnership(_msgSender());
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    _checkOwner();
    _;
  }

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

  /**
   * @dev Throws if the sender is not the owner.
   */
  function _checkOwner() internal view virtual {
    require(owner() == _msgSender(), 'Ownable: caller is not the owner');
  }

  /**
   * @dev Leaves the contract without owner. It will not be possible to call
   * `onlyOwner` functions anymore. Can only be called by the current owner.
   *
   * NOTE: Renouncing ownership will leave the contract without an owner,
   * thereby removing any functionality that is only available to the owner.
   */
  function renounceOwnership() public virtual onlyOwner {
    _transferOwnership(address(0));
  }

  /**
   * @dev Transfers ownership of the contract to a new account (`newOwner`).
   * Can only be called by the current owner.
   */
  function transferOwnership(address newOwner) public virtual onlyOwner {
    require(newOwner != address(0), 'Ownable: new owner is the zero address');
    _transferOwnership(newOwner);
  }

  /**
   * @dev Transfers ownership of the contract to a new account (`newOwner`).
   * Internal function without access restriction.
   */
  function _transferOwnership(address newOwner) internal virtual {
    address oldOwner = _owner;
    _owner = newOwner;
    emit OwnershipTransferred(oldOwner, newOwner);
  }
}

File 18 of 21 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)
// From commit https://github.com/OpenZeppelin/openzeppelin-contracts/commit/3dac7bbed7b4c0dbf504180c33e8ed8e350b93eb

pragma solidity ^0.8.0;

import './interfaces/IERC20.sol';
import './interfaces/draft-IERC20Permit.sol';
import './Address.sol';

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
  using Address for address;

  function safeTransfer(IERC20 token, address to, uint256 value) internal {
    _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
  }

  function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
    _callOptionalReturn(
      token,
      abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
    );
  }

  /**
   * @dev Deprecated. This function has issues similar to the ones found in
   * {IERC20-approve}, and its usage is discouraged.
   *
   * Whenever possible, use {safeIncreaseAllowance} and
   * {safeDecreaseAllowance} instead.
   */
  function safeApprove(IERC20 token, address spender, uint256 value) internal {
    // safeApprove should only be called when setting an initial allowance,
    // or when resetting it to zero. To increase and decrease it, use
    // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
    require(
      (value == 0) || (token.allowance(address(this), spender) == 0),
      'SafeERC20: approve from non-zero to non-zero allowance'
    );
    _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
  }

  function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
    uint256 newAllowance = token.allowance(address(this), spender) + value;
    _callOptionalReturn(
      token,
      abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
    );
  }

  function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
    unchecked {
      uint256 oldAllowance = token.allowance(address(this), spender);
      require(oldAllowance >= value, 'SafeERC20: decreased allowance below zero');
      uint256 newAllowance = oldAllowance - value;
      _callOptionalReturn(
        token,
        abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
      );
    }
  }

  function safePermit(
    IERC20Permit token,
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) internal {
    uint256 nonceBefore = token.nonces(owner);
    token.permit(owner, spender, value, deadline, v, r, s);
    uint256 nonceAfter = token.nonces(owner);
    require(nonceAfter == nonceBefore + 1, 'SafeERC20: permit did not succeed');
  }

  /**
   * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
   * on the return value: the return value is optional (but if data is returned, it must not be false).
   * @param token The token targeted by the call.
   * @param data The call data (encoded using abi.encode or one of its variants).
   */
  function _callOptionalReturn(IERC20 token, bytes memory data) private {
    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
    // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
    // the target address contains contract code and also asserts for success in the low-level call.

    bytes memory returndata = address(token).functionCall(data, 'SafeERC20: low-level call failed');
    if (returndata.length > 0) {
      // Return data is optional
      require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed');
    }
  }
}

File 19 of 21 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
// From commit https://github.com/OpenZeppelin/openzeppelin-contracts/commit/a035b235b4f2c9af4ba88edc4447f02e37f8d124

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
  /**
   * @dev Emitted when `value` tokens are moved from one account (`from`) to
   * another (`to`).
   *
   * Note that `value` may be zero.
   */
  event Transfer(address indexed from, address indexed to, uint256 value);

  /**
   * @dev Emitted when the allowance of a `spender` for an `owner` is set by
   * a call to {approve}. `value` is the new allowance.
   */
  event Approval(address indexed owner, address indexed spender, uint256 value);

  /**
   * @dev Returns the amount of tokens in existence.
   */
  function totalSupply() external view returns (uint256);

  /**
   * @dev Returns the amount of tokens owned by `account`.
   */
  function balanceOf(address account) external view returns (uint256);

  /**
   * @dev Moves `amount` tokens from the caller's account to `to`.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * Emits a {Transfer} event.
   */
  function transfer(address to, uint256 amount) external returns (bool);

  /**
   * @dev Returns the remaining number of tokens that `spender` will be
   * allowed to spend on behalf of `owner` through {transferFrom}. This is
   * zero by default.
   *
   * This value changes when {approve} or {transferFrom} are called.
   */
  function allowance(address owner, address spender) external view returns (uint256);

  /**
   * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * IMPORTANT: Beware that changing an allowance with this method brings the risk
   * that someone may use both the old and the new allowance by unfortunate
   * transaction ordering. One possible solution to mitigate this race
   * condition is to first reduce the spender's allowance to 0 and set the
   * desired value afterwards:
   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   *
   * Emits an {Approval} event.
   */
  function approve(address spender, uint256 amount) external returns (bool);

  /**
   * @dev Moves `amount` tokens from `from` to `to` using the
   * allowance mechanism. `amount` is then deducted from the caller's
   * allowance.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * Emits a {Transfer} event.
   */
  function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 20 of 21 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
// From commit https://github.com/OpenZeppelin/openzeppelin-contracts/commit/6bd6b76d1156e20e45d1016f355d154141c7e5b9

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
  /**
   * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
   * given ``owner``'s signed approval.
   *
   * IMPORTANT: The same issues {IERC20-approve} has related to transaction
   * ordering also apply here.
   *
   * Emits an {Approval} event.
   *
   * Requirements:
   *
   * - `spender` cannot be the zero address.
   * - `deadline` must be a timestamp in the future.
   * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
   * over the EIP712-formatted function arguments.
   * - the signature must use ``owner``'s current nonce (see {nonces}).
   *
   * For more information on the signature format, see the
   * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
   * section].
   */
  function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) external;

  /**
   * @dev Returns the current nonce for `owner`. This value must be
   * included whenever a signature is generated for {permit}.
   *
   * Every successful call to {permit} increases ``owner``'s nonce by one. This
   * prevents a signature from being used multiple times.
   */
  function nonces(address owner) external view returns (uint256);

  /**
   * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
   */
  // solhint-disable-next-line func-name-mixedcase
  function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 21 of 21 : Initializable.sol
// SPDX-License-Identifier: MIT

/**
 * @dev OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
 * From https://github.com/OpenZeppelin/openzeppelin-contracts/tree/8b778fa20d6d76340c5fac1ed66c80273f05b95a
 *
 * BGD Labs adaptations:
 * - Added a constructor disabling initialization for implementation contracts
 * - Linting
 */

pragma solidity ^0.8.2;

import '../oz-common/Address.sol';

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
  /**
   * @dev Indicates that the contract has been initialized.
   * @custom:oz-retyped-from bool
   */
  uint8 private _initialized;

  /**
   * @dev Indicates that the contract is in the process of being initialized.
   */
  bool private _initializing;

  /**
   * @dev Triggered when the contract has been initialized or reinitialized.
   */
  event Initialized(uint8 version);

  /**
   * @dev OPINIONATED. Generally is not a good practise to allow initialization of implementations
   */
  constructor() {
    _disableInitializers();
  }

  /**
   * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
   * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
   */
  modifier initializer() {
    bool isTopLevelCall = !_initializing;
    require(
      (isTopLevelCall && _initialized < 1) ||
        (!Address.isContract(address(this)) && _initialized == 1),
      'Initializable: contract is already initialized'
    );
    _initialized = 1;
    if (isTopLevelCall) {
      _initializing = true;
    }
    _;
    if (isTopLevelCall) {
      _initializing = false;
      emit Initialized(1);
    }
  }

  /**
   * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
   * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
   * used to initialize parent contracts.
   *
   * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
   * initialization step. This is essential to configure modules that are added through upgrades and that require
   * initialization.
   *
   * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
   * a contract, executing them in the right order is up to the developer or operator.
   */
  modifier reinitializer(uint8 version) {
    require(
      !_initializing && _initialized < version,
      'Initializable: contract is already initialized'
    );
    _initialized = version;
    _initializing = true;
    _;
    _initializing = false;
    emit Initialized(version);
  }

  /**
   * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
   * {initializer} and {reinitializer} modifiers, directly or indirectly.
   */
  modifier onlyInitializing() {
    require(_initializing, 'Initializable: contract is not initializing');
    _;
  }

  /**
   * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
   * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
   * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
   * through proxies.
   */
  function _disableInitializers() internal virtual {
    require(!_initializing, 'Initializable: contract is initializing');
    if (_initialized < type(uint8).max) {
      _initialized = type(uint8).max;
      emit Initialized(type(uint8).max);
    }
  }
}

Settings
{
  "remappings": [
    "@aave/core-v3/=lib/aave-a-token-with-delegation/lib/aave-address-book/lib/aave-v3-core/",
    "@aave/periphery-v3/=lib/aave-a-token-with-delegation/lib/aave-address-book/lib/aave-v3-periphery/",
    "@openzeppelin/=lib/aave-crosschain-infra/lib/openzeppelin-contracts/",
    "aave-a-token-with-delegation/=lib/aave-a-token-with-delegation/src/",
    "aave-address-book/=lib/aave-a-token-with-delegation/lib/aave-address-book/src/",
    "aave-crosschain-infra/=lib/aave-crosschain-infra/src/",
    "aave-helpers/=lib/aave-stk-gov-v3/lib/aave-helpers/",
    "aave-stk-gov-v3/=lib/aave-stk-gov-v3/src/",
    "aave-stk-slashing-mgmt/=lib/aave-stk-slashing-mgmt/src/",
    "aave-token-v2/=lib/aave-token-v3/lib/aave-token-v2/contracts/",
    "aave-token-v3/=lib/aave-token-v3/src/",
    "aave-v3-core/=lib/aave-a-token-with-delegation/lib/aave-v3-core/",
    "aave-v3-periphery/=lib/aave-a-token-with-delegation/lib/aave-address-book/lib/aave-v3-periphery/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "emergency-exit/=lib/emergency-exit/src/",
    "erc4626-tests/=lib/aave-stk-gov-v3/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "hyperlane-monorepo/=lib/aave-crosschain-infra/lib/hyperlane-monorepo/solidity/",
    "openzeppelin-contracts/=lib/aave-crosschain-infra/lib/openzeppelin-contracts/",
    "solidity-examples/=lib/aave-crosschain-infra/lib/solidity-examples/contracts/",
    "solidity-utils/=lib/solidity-utils/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"clEmergencyOracle","type":"address"},{"internalType":"uint256","name":"initialRequiredConfirmations","type":"uint256"},{"internalType":"address[]","name":"receiverBridgeAdaptersToAllow","type":"address[]"},{"components":[{"internalType":"address","name":"currentChainBridgeAdapter","type":"address"},{"internalType":"address","name":"destinationBridgeAdapter","type":"address"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"}],"internalType":"struct ICrossChainForwarder.BridgeAdapterConfigInput[]","name":"forwarderBridgeAdaptersToEnable","type":"tuple[]"},{"internalType":"address[]","name":"sendersToApprove","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"bridgeAdapter","type":"address"},{"indexed":true,"internalType":"address","name":"destinationBridgeAdapter","type":"address"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"returndata","type":"bytes"}],"name":"AdapterFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"bridgeAdapter","type":"address"},{"indexed":false,"internalType":"address","name":"destinationBridgeAdapter","type":"address"},{"indexed":true,"internalType":"bool","name":"allowed","type":"bool"}],"name":"BridgeAdapterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newChainlinkEmergencyOracle","type":"address"}],"name":"CLEmergencyOracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newConfirmations","type":"uint256"}],"name":"ConfirmationsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"emergencyCount","type":"uint256"}],"name":"EmergencySolved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newGuardian","type":"address"}],"name":"GuardianUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"msgDestination","type":"address"},{"indexed":true,"internalType":"address","name":"msgOrigin","type":"address"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"MessageConfirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"bridgeAdapter","type":"address"},{"indexed":true,"internalType":"address","name":"destinationBridgeAdapter","type":"address"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"MessageForwarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"internalId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"bridgeAdapter","type":"address"},{"indexed":true,"internalType":"address","name":"msgDestination","type":"address"},{"indexed":true,"internalType":"address","name":"msgOrigin","type":"address"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"confirmations","type":"uint256"}],"name":"MessageReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"invalidTimestamp","type":"uint256"}],"name":"NewInvalidation","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":"brigeAdapter","type":"address"},{"indexed":true,"internalType":"bool","name":"allowed","type":"bool"}],"name":"ReceiverBridgeAdaptersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"SenderUpdated","type":"event"},{"inputs":[{"internalType":"address[]","name":"bridgeAdapters","type":"address[]"}],"name":"allowReceiverBridgeAdapters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"senders","type":"address[]"}],"name":"approveSenders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"bridgeAdapter","type":"address"},{"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"internalType":"struct ICrossChainForwarder.BridgeAdapterToDisable[]","name":"bridgeAdapters","type":"tuple[]"}],"name":"disableBridgeAdapters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"bridgeAdapters","type":"address[]"}],"name":"disallowReceiverBridgeAdapters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"emergencyEtherTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"erc20Token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"emergencyTokenTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"currentChainBridgeAdapter","type":"address"},{"internalType":"address","name":"destinationBridgeAdapter","type":"address"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"}],"internalType":"struct ICrossChainForwarder.BridgeAdapterConfigInput[]","name":"bridgeAdapters","type":"tuple[]"}],"name":"enableBridgeAdapters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"forwardMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getBridgeAdaptersByChain","outputs":[{"components":[{"internalType":"address","name":"destinationBridgeAdapter","type":"address"},{"internalType":"address","name":"currentChainBridgeAdapter","type":"address"}],"internalType":"struct ICrossChainForwarder.ChainIdBridgeConfig[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChainlinkEmergencyOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEmergencyCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"internalId","type":"bytes32"}],"name":"getInternalMessageState","outputs":[{"components":[{"internalType":"uint120","name":"confirmations","type":"uint120"},{"internalType":"uint120","name":"firstBridgedAt","type":"uint120"},{"internalType":"bool","name":"delivered","type":"bool"}],"internalType":"struct ICrossChainReceiver.InternalBridgedMessageStateWithoutAdapters","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRequiredConfirmations","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getValidityTimestamp","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"guardian","type":"address"},{"internalType":"address","name":"clEmergencyOracle","type":"address"},{"internalType":"uint256","name":"initialRequiredConfirmations","type":"uint256"},{"internalType":"address[]","name":"receiverBridgeAdaptersToAllow","type":"address[]"},{"components":[{"internalType":"address","name":"currentChainBridgeAdapter","type":"address"},{"internalType":"address","name":"destinationBridgeAdapter","type":"address"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"}],"internalType":"struct ICrossChainForwarder.BridgeAdapterConfigInput[]","name":"forwarderBridgeAdaptersToEnable","type":"tuple[]"},{"internalType":"address[]","name":"sendersToApprove","type":"address[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"internalId","type":"bytes32"},{"internalType":"address","name":"bridgeAdapter","type":"address"}],"name":"isInternalMessageReceivedByAdapter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"address","name":"origin","type":"address"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"isMessageForwarded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bridgeAdapter","type":"address"}],"name":"isReceiverBridgeAdapterAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"isSenderApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"uint256","name":"originChainId","type":"uint256"}],"name":"receiveCrossChainMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"senders","type":"address[]"}],"name":"removeSenders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"address","name":"origin","type":"address"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"retryMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newConfirmations","type":"uint256"},{"internalType":"uint120","name":"newValidityTimestamp","type":"uint120"},{"internalType":"address[]","name":"receiverBridgeAdaptersToAllow","type":"address[]"},{"internalType":"address[]","name":"receiverBridgeAdaptersToDisallow","type":"address[]"},{"internalType":"address[]","name":"sendersToApprove","type":"address[]"},{"internalType":"address[]","name":"sendersToRemove","type":"address[]"},{"components":[{"internalType":"address","name":"currentChainBridgeAdapter","type":"address"},{"internalType":"address","name":"destinationBridgeAdapter","type":"address"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"}],"internalType":"struct ICrossChainForwarder.BridgeAdapterConfigInput[]","name":"forwarderBridgeAdaptersToEnable","type":"tuple[]"},{"components":[{"internalType":"address","name":"bridgeAdapter","type":"address"},{"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"internalType":"struct ICrossChainForwarder.BridgeAdapterToDisable[]","name":"forwarderBridgeAdaptersToDisable","type":"tuple[]"}],"name":"solveEmergency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newChainlinkEmergencyOracle","type":"address"}],"name":"updateCLEmergencyOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newConfirmations","type":"uint256"}],"name":"updateConfirmations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGuardian","type":"address"}],"name":"updateGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"newValidityTimestamp","type":"uint120"}],"name":"updateMessagesValidityTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

Deployed Bytecode

0x6080604052600436106101e75760003560e01c8063895785a711610102578063ed68595a11610095578063f35e5d4b11610064578063f35e5d4b14610647578063f363b34014610691578063f3840abe146106ca578063fc525395146106df57600080fd5b8063ed68595a146105c7578063edc1de03146105e7578063eed88b8d14610607578063f2fde38b1461062757600080fd5b8063a3d5b255116100d1578063a3d5b2551461053c578063a8ad51d61461055c578063c4eed1401461057a578063e4ec2b841461059a57600080fd5b8063895785a7146104be5780638da5cb5b146104de57806390f7af54146104fc578063917cbb9b1461051c57600080fd5b806324cb76041161017a578063452a932011610149578063452a93201461043757806355c4fed414610469578063715018a6146104895780637670d1d81461049e57600080fd5b806324cb76041461039257806329408273146103b15780633805e84e146103d95780633a60c3861461042257600080fd5b80631394c98a116101b65780631394c98a146102755780631d92ab2c14610332578063225c0e761461035257806322b3d6ba1461037257600080fd5b80630441d3cb146101f35780630a234b15146102155780630b10f6041461023557806311a916b31461025557600080fd5b366101ee57005b600080fd5b3480156101ff57600080fd5b5061021361020e366004612085565b6106ff565b005b34801561022157600080fd5b5061021361023036600461215f565b610715565b34801561024157600080fd5b50610213610250366004612193565b610726565b34801561026157600080fd5b5061021361027036600461225a565b61087e565b34801561028157600080fd5b506102fb61029036600461227e565b60408051606081018252600080825260208201819052918101919091525060408051606081018252600083815260086020818152848320546001600160781b038082168652600160781b82041682860152959092529052600160f01b90920460ff1615159082015290565b6040805182516001600160781b03908116825260208085015190911690820152918101511515908201526060015b60405180910390f35b34801561033e57600080fd5b5061021361034d36600461230f565b61088f565b34801561035e57600080fd5b5061021361036d3660046124bc565b6108f3565b34801561037e57600080fd5b5061021361038d3660046125cc565b610ab0565b34801561039e57600080fd5b506006545b604051908152602001610329565b3480156103bd57600080fd5b506007546040516001600160781b039091168152602001610329565b3480156103e557600080fd5b506104126103f436600461225a565b6001600160a01b031660009081526003602052604090205460ff1690565b6040519015158152602001610329565b34801561042e57600080fd5b506002546103a3565b34801561044357600080fd5b506001546001600160a01b03165b6040516001600160a01b039091168152602001610329565b34801561047557600080fd5b506102136104843660046125e7565b610ac1565b34801561049557600080fd5b50610213610b20565b3480156104aa57600080fd5b506102136104b9366004612085565b610b34565b3480156104ca57600080fd5b506102136104d936600461227e565b610b47565b3480156104ea57600080fd5b506000546001600160a01b0316610451565b34801561050857600080fd5b50610213610517366004612085565b610b58565b34801561052857600080fd5b50610213610537366004612649565b610b6b565b34801561054857600080fd5b5061021361055736600461267d565b610b7c565b34801561056857600080fd5b50600a546001600160a01b0316610451565b34801561058657600080fd5b50610213610595366004612085565b610b9d565b3480156105a657600080fd5b506105ba6105b536600461227e565b610bb0565b60405161032991906126be565b3480156105d357600080fd5b506102136105e236600461271a565b610c3b565b3480156105f357600080fd5b5061041261060236600461275e565b610efb565b34801561061357600080fd5b506102136106223660046127b1565b610f49565b34801561063357600080fd5b5061021361064236600461225a565b610f5f565b34801561065357600080fd5b506104126106623660046127dd565b60008281526008602090815260408083206001600160a01b038516845260010190915290205460ff1692915050565b34801561069d57600080fd5b506104126106ac36600461225a565b6001600160a01b031660009081526009602052604090205460ff1690565b3480156106d657600080fd5b50600b546103a3565b3480156106eb57600080fd5b506102136106fa36600461225a565b610fd5565b610707610fe6565b610712816001611040565b50565b61071d610fe6565b61071281611106565b600c54610100900460ff16158080156107465750600c54600160ff909116105b806107605750303b1580156107605750600c5460ff166001145b6107c85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b600c805460ff1916600117905580156107eb57600c805461ff0019166101001790555b6107f488611324565b6107fd87611374565b610806866113d5565b61080f8561141f565b61081a846001611040565b61082383611106565b61082e82600161145b565b801561087457600c805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b610886611521565b610712816113d5565b610897611529565b6108a385858584610efb565b604080518082019091526001808252603360f81b602083015290911515146108de5760405162461bcd60e51b81526004016107bf9190612865565b506108ec8585858585611598565b5050505050565b6108fb61188b565b600a546001600160a01b03166109535760405162461bcd60e51b815260206004820152601b60248201527f434c5f454d455247454e43595f4f5241434c455f4e4f545f534554000000000060448201526064016107bf565b600a5460408051633fabe5a360e21b815290516000926001600160a01b03169163feaf968c9160048083019260a09291908290030181865afa15801561099d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c19190612892565b5050509150506000600b600081546109d8906128f8565b91829055509050818114610a215760405162461bcd60e51b815260206004820152601060248201526f4e4f545f494e5f454d455247454e435960801b60448201526064016107bf565b610a2c886001611040565b610a37876000611040565b610a408a61141f565b610a49896118d8565b610a5486600161145b565b610a5f85600061145b565b610a6884611106565b610a7183611977565b6040518181527f47f02156b74b79adfd983cf25ed1f4b9f268b61865bee36b1a9bf924853ff41c9060200160405180910390a150505050505050505050565b610ab8610fe6565b610712816118d8565b3360009081526003602052604090205460ff16604051806040016040528060018152602001601960f91b81525090610b0c5760405162461bcd60e51b81526004016107bf9190612865565b50610b1a8433858585611598565b50505050565b610b28610fe6565b610b326000611324565b565b610b3c610fe6565b61071281600061145b565b610b4f610fe6565b6107128161141f565b610b60610fe6565b61071281600161145b565b610b73610fe6565b61071281611977565b610b84610fe6565b610b986001600160a01b0384168383611c4c565b505050565b610ba5610fe6565b610712816000611040565b606060056000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610c30576000848152602090819020604080518082019091526002850290910180546001600160a01b03908116835260019182015416828401529083529092019101610be5565b505050509050919050565b3360009081526009602052604090205460ff16604051806040016040528060018152602001601b60f91b81525090610c865760405162461bcd60e51b81526004016107bf9190612865565b50600080600084806020019051810190610ca09190612913565b9350935093505060008486604051602001610cbc9291906129ba565b60408051601f198184030181529181528151602092830120600081815260089093529120805460075492935090916001600160781b03600160781b9092048216911681118015610d1e575033600090815260018301602052604090205460ff16155b80610d3057506001600160781b038116155b15610874576001600160781b038116610d6e5781546effffffffffffffffffffffffffffff60781b1916600160781b426001600160781b0316021782555b815460009083908290610d89906001600160781b03166129d3565b82546001600160781b039182166101009390930a83810292021916179091553360008181526001868101602052604091829020805460ff19169091179055519192506001600160a01b038981169290891691907f1cc5a30605f6a77aff509ab8ae5b4a3467277f3bfbc73fafdf48982fdda4f75290610e0d9089908b9088906129fa565b60405180910390a460065481148015610e2f57508254600160f01b900460ff16155b15610ef057604051630a81a65d60e11b81526001600160a01b038716906315034cba90610e64908a908c908a90600401612a23565b600060405180830381600087803b158015610e7e57600080fd5b505af1158015610e92573d6000803e3d6000fd5b5050845460ff60f01b1916600160f01b17855550506040516001600160a01b0380891691908816907fd583802c660d9112814a15b22eb6fd5c0c24d4cfce06faa031582b817da7920290610ee7908990612865565b60405180910390a35b505050505050505050565b60008085858585604051602001610f159493929190612a53565b60408051601f1981840301815291815281516020928301206000908152600490925290205460ff169150505b949350505050565b610f51610fe6565b610f5b8282611c9e565b5050565b610f67610fe6565b6001600160a01b038116610fcc5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016107bf565b61071281611324565b610fdd61188b565b61071281611374565b6000546001600160a01b03163314610b325760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016107bf565b60005b8251811015610b9857816009600085848151811061106357611063612a8f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055508115158382815181106110b7576110b7612a8f565b60200260200101516001600160a01b03167f2241f9166c38735399d4fa288d41557f4afff9881f3c27c0e753f24b163d28cc60405160405180910390a3806110fe816128f8565b915050611043565b60005b8151811015610f5b57600082828151811061112657611126612a8f565b6020026020010151905060006001600160a01b031681602001516001600160a01b031614158015611160575080516001600160a01b031615155b604051806040016040528060018152602001603560f81b815250906111985760405162461bcd60e51b81526004016107bf9190612865565b506040808201516000908152600560205290812090805b825481101561124f5760008382815481106111cc576111cc612a8f565b60009182526020909120865160029092020160018101549092506001600160a01b039182169116141561123c57602085015181546001600160a01b0390811691161461123257602085015181546001600160a01b0319166001600160a01b039091161781555b600192505061124f565b5080611247816128f8565b9150506111af565b50806112be57604080518082019091526020808501516001600160a01b039081168352855181168284019081528554600181810188556000888152949094209451600290910290940180549483166001600160a01b031995861617815590519201805492909116919092161790555b825160408085015160208087015192516001600160a01b03938416815260019493909316927f2152376b51b154ef9693e64efbda43bd7ecd04ccb98df7f6caf781078eca308d910160405180910390a4505050808061131c906128f8565b915050611109565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600180546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f064d28d3d3071c5cbc271a261c10c2f0f0d9e319390397101aa0eb23c6bad909910160405180910390a15050565b600a80546001600160a01b0319166001600160a01b0383169081179091556040517fa3389e5f21b6844aaa11a57272052dff01c5ded1f1253c1be0468658239119bf90600090a250565b60068190556040518181527f9c074a6f0520fac8e989214faa81afb74d3fb0a90a55b6a8e736dcb49c74e9a3906020015b60405180910390a150565b60005b8251811015610b9857816003600085848151811061147e5761147e612a8f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055508115158382815181106114d2576114d2612a8f565b60200260200101516001600160a01b03167f626c27c1d088fd70034e681d579a5efd004c3d47a56d3ee07ad256ac7301433360405160405180910390a380611519816128f8565b91505061145e565b610b32610fe6565b6000546001600160a01b031633148061154c57506001546001600160a01b031633145b610b325760405162461bcd60e51b815260206004820152601960248201527f4f4e4c595f42595f4f574e45525f4f525f475541524449414e0000000000000060448201526064016107bf565b60028054600091826115a9836128f8565b919050558585846040516020016115c39493929190612a53565b60408051601f1981840301815260008981526005602090815283822080548083028701830190955284865292955090939290849084015b82821015611645576000848152602090819020604080518082019091526002850290910180546001600160a01b039081168352600191820154168284015290835290920191016115fa565b505050509050600080600090505b825181101561180057600083828151811061167057611670612a8f565b6020026020010151905060008082602001516001600160a01b03166336da7a0660e01b84600001518b8f8b6040516024016116ae9493929190612aa5565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516116ec9190612ad2565b600060405180830381855af49150503d8060008114611727576040519150601f19603f3d011682016040523d82523d6000602084013e61172c565b606091505b5091509150816117915782600001516001600160a01b031683602001516001600160a01b03168d7f4b3043ae7160b13e56489baffc0fd12b7d7347a9b5db399f722d43b04c75ab258a85604051611784929190612aee565b60405180910390a46117ea565b6001945082600001516001600160a01b031683602001516001600160a01b03168d7fde70eb88ff32e1e397d3f48e22bdfb61668f2abd3634e851cdbb8273607320e98a6040516117e19190612865565b60405180910390a45b50505080806117f8906128f8565b915050611653565b506040805180820190915260018152600d60fa1b6020820152816118375760405162461bcd60e51b81526004016107bf9190612865565b506000888888876040516020016118519493929190612a53565b60408051601f198184030181529181528151602092830120600090815260049092529020805460ff19166001179055505050505050505050565b6001546001600160a01b03163314610b325760405162461bcd60e51b815260206004820152601060248201526f27a7262cafa12cafa3aaa0a92224a0a760811b60448201526064016107bf565b6007546040805180820190915260018152603760f81b6020820152906001600160781b03908116908316116119205760405162461bcd60e51b81526004016107bf9190612865565b50600780546effffffffffffffffffffffffffffff19166001600160781b0383169081179091556040519081527ffc1ba755a762810501ff246c851b2e2575e560e69aa024cc0193bff3f1c1b00890602001611450565b60005b8151811015610f5b5760005b82828151811061199857611998612a8f565b60200260200101516020015151811015611c39576000600560008585815181106119c4576119c4612a8f565b60200260200101516020015184815181106119e1576119e1612a8f565b60200260200101518152602001908152602001600020905060005b8154811015611c2457848481518110611a1757611a17612a8f565b6020026020010151600001516001600160a01b0316828281548110611a3e57611a3e612a8f565b60009182526020909120600160029092020101546001600160a01b03161415611c12576000828281548110611a7557611a75612a8f565b600091825260209091206002909102015483546001600160a01b0390911691508214611b225782548390611aab90600190612b13565b81548110611abb57611abb612a8f565b9060005260206000209060020201838381548110611adb57611adb612a8f565b60009182526020909120825460029092020180546001600160a01b039283166001600160a01b03199182161782556001938401549390910180549390921692169190911790555b82805480611b3257611b32612b2a565b60008281526020812060026000199093019283020180546001600160a01b031990811682556001919091018054909116905591558651879087908110611b7a57611b7a612a8f565b6020026020010151600001516001600160a01b0316878781518110611ba157611ba1612a8f565b6020026020010151602001518681518110611bbe57611bbe612a8f565b60200260200101517f2152376b51b154ef9693e64efbda43bd7ecd04ccb98df7f6caf781078eca308d84604051611c0491906001600160a01b0391909116815260200190565b60405180910390a450611c24565b80611c1c816128f8565b9150506119fc565b50508080611c31906128f8565b915050611986565b5080611c44816128f8565b91505061197a565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610b98908490611d47565b604080516000808252602082019092526001600160a01b038416908390604051611cc89190612ad2565b60006040518083038185875af1925050503d8060008114611d05576040519150601f19603f3d011682016040523d82523d6000602084013e611d0a565b606091505b5050905080604051806040016040528060018152602001603160f81b81525090610b1a5760405162461bcd60e51b81526004016107bf9190612865565b6000611d9c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611e199092919063ffffffff16565b805190915015610b985780806020019051810190611dba9190612b40565b610b985760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107bf565b6060610f41848460008585600080866001600160a01b03168587604051611e409190612ad2565b60006040518083038185875af1925050503d8060008114611e7d576040519150601f19603f3d011682016040523d82523d6000602084013e611e82565b606091505b5091509150611e9387838387611e9e565b979650505050505050565b60608315611f0a578251611f03576001600160a01b0385163b611f035760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107bf565b5081610f41565b610f418383815115611f1f5781518083602001fd5b8060405162461bcd60e51b81526004016107bf9190612865565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715611f7157611f71611f39565b60405290565b604080519081016001600160401b0381118282101715611f7157611f71611f39565b604051601f8201601f191681016001600160401b0381118282101715611fc157611fc1611f39565b604052919050565b60006001600160401b03821115611fe257611fe2611f39565b5060051b60200190565b6001600160a01b038116811461071257600080fd5b803561200c81611fec565b919050565b600082601f83011261202257600080fd5b8135602061203761203283611fc9565b611f99565b82815260059290921b8401810191818101908684111561205657600080fd5b8286015b8481101561207a57803561206d81611fec565b835291830191830161205a565b509695505050505050565b60006020828403121561209757600080fd5b81356001600160401b038111156120ad57600080fd5b610f4184828501612011565b600082601f8301126120ca57600080fd5b813560206120da61203283611fc9565b828152606092830285018201928282019190878511156120f957600080fd5b8387015b858110156121525781818a0312156121155760008081fd5b61211d611f4f565b813561212881611fec565b81528186013561213781611fec565b818701526040828101359082015284529284019281016120fd565b5090979650505050505050565b60006020828403121561217157600080fd5b81356001600160401b0381111561218757600080fd5b610f41848285016120b9565b600080600080600080600060e0888a0312156121ae57600080fd5b87356121b981611fec565b965060208801356121c981611fec565b95506121d760408901612001565b94506060880135935060808801356001600160401b03808211156121fa57600080fd5b6122068b838c01612011565b945060a08a013591508082111561221c57600080fd5b6122288b838c016120b9565b935060c08a013591508082111561223e57600080fd5b5061224b8a828b01612011565b91505092959891949750929550565b60006020828403121561226c57600080fd5b813561227781611fec565b9392505050565b60006020828403121561229057600080fd5b5035919050565b60006001600160401b038211156122b0576122b0611f39565b50601f01601f191660200190565b600082601f8301126122cf57600080fd5b81356122dd61203282612297565b8181528460208386010111156122f257600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a0868803121561232757600080fd5b85359450602086013561233981611fec565b9350604086013561234981611fec565b92506060860135915060808601356001600160401b0381111561236b57600080fd5b612377888289016122be565b9150509295509295909350565b80356001600160781b038116811461200c57600080fd5b600082601f8301126123ac57600080fd5b813560206123bc61203283611fc9565b828152600592831b85018201928282019190878511156123db57600080fd5b8387015b858110156121525780356001600160401b03808211156123ff5760008081fd5b908901906040828c03601f19018113156124195760008081fd5b612421611f77565b8884013561242e81611fec565b815283820135838111156124425760008081fd5b8085019450508c603f85011261245a57600092508283fd5b88840135925061246c61203284611fc9565b83815292861b8401820192898101908e8511156124895760008081fd5b948301945b848610156124a75785358252948a0194908a019061248e565b828b01525087525050509284019284016123df565b600080600080600080600080610100898b0312156124d957600080fd5b883597506124e960208a01612384565b965060408901356001600160401b038082111561250557600080fd5b6125118c838d01612011565b975060608b013591508082111561252757600080fd5b6125338c838d01612011565b965060808b013591508082111561254957600080fd5b6125558c838d01612011565b955060a08b013591508082111561256b57600080fd5b6125778c838d01612011565b945060c08b013591508082111561258d57600080fd5b6125998c838d016120b9565b935060e08b01359150808211156125af57600080fd5b506125bc8b828c0161239b565b9150509295985092959890939650565b6000602082840312156125de57600080fd5b61227782612384565b600080600080608085870312156125fd57600080fd5b84359350602085013561260f81611fec565b92506040850135915060608501356001600160401b0381111561263157600080fd5b61263d878288016122be565b91505092959194509250565b60006020828403121561265b57600080fd5b81356001600160401b0381111561267157600080fd5b610f418482850161239b565b60008060006060848603121561269257600080fd5b833561269d81611fec565b925060208401356126ad81611fec565b929592945050506040919091013590565b602080825282518282018190526000919060409081850190868401855b8281101561270d57815180516001600160a01b03908116865290870151168685015292840192908501906001016126db565b5091979650505050505050565b6000806040838503121561272d57600080fd5b82356001600160401b0381111561274357600080fd5b61274f858286016122be565b95602094909401359450505050565b6000806000806080858703121561277457600080fd5b84359350602085013561278681611fec565b9250604085013561279681611fec565b915060608501356001600160401b0381111561263157600080fd5b600080604083850312156127c457600080fd5b82356127cf81611fec565b946020939093013593505050565b600080604083850312156127f057600080fd5b82359150602083013561280281611fec565b809150509250929050565b60005b83811015612828578181015183820152602001612810565b83811115610b1a5750506000910152565b6000815180845261285181602086016020860161280d565b601f01601f19169290920160200192915050565b6020815260006122776020830184612839565b805169ffffffffffffffffffff8116811461200c57600080fd5b600080600080600060a086880312156128aa57600080fd5b6128b386612878565b94506020860151935060408601519250606086015191506128d660808701612878565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b600060001982141561290c5761290c6128e2565b5060010190565b6000806000806080858703121561292957600080fd5b84519350602085015161293b81611fec565b604086015190935061294c81611fec565b60608601519092506001600160401b0381111561296857600080fd5b8501601f8101871361297957600080fd5b805161298761203282612297565b81815288602083850101111561299c57600080fd5b6129ad82602083016020860161280d565b9598949750929550505050565b828152604060208201526000610f416040830184612839565b60006001600160781b03808316818114156129f0576129f06128e2565b6001019392505050565b838152606060208201526000612a136060830185612839565b9050826040830152949350505050565b60018060a01b0384168152826020820152606060408201526000612a4a6060830184612839565b95945050505050565b8481526001600160a01b03848116602083015283166040820152608060608201819052600090612a8590830184612839565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b60018060a01b0385168152836020820152826040820152608060608201526000612a856080830184612839565b60008251612ae481846020870161280d565b9190910192915050565b604081526000612b016040830185612839565b8281036020840152612a4a8185612839565b600082821015612b2557612b256128e2565b500390565b634e487b7160e01b600052603160045260246000fd5b600060208284031215612b5257600080fd5b8151801515811461227757600080fdfea26469706673582212201529a3100eaf75d9a9620573478d9737c35d844b5e9b3500e601f919da8057fd64736f6c634300080a0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits

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.