// File: src/contracts/emergency/EmergencyRegistry.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;

import {Ownable} from 'solidity-utils/contracts/oz-common/Ownable.sol';
import {IEmergencyRegistry} from './interfaces/IEmergencyRegistry.sol';
import {Errors} from '../libs/Errors.sol';

/**
 * @title EmergencyRegistry
 * @author BGD Labs
 * @notice Registry smart contract, to be used by the Aave Governance through one of its Executors to signal if an
 *         emergency mode should be triggered on a different network
 */
contract EmergencyRegistry is IEmergencyRegistry, Ownable {
  mapping(uint256 => int256) internal _emergencyStateByNetwork;

  constructor() {}

  /// @inheritdoc IEmergencyRegistry
  function getNetworkEmergencyCount(uint256 chainId) external view returns (int256) {
    return _emergencyStateByNetwork[chainId];
  }

  /// @inheritdoc IEmergencyRegistry
  function setEmergency(uint256[] memory emergencyChains) external onlyOwner {
    for (uint256 i = 0; i < emergencyChains.length; i++) {
      for (uint256 j = i + 1; j < emergencyChains.length; j++) {
        require(
          emergencyChains[i] != emergencyChains[j],
          Errors.ONLY_ONE_EMERGENCY_UPDATE_PER_CHAIN
        );
      }
      unchecked {
        _emergencyStateByNetwork[emergencyChains[i]]++;
      }

      emit NetworkEmergencyStateUpdated(
        emergencyChains[i],
        _emergencyStateByNetwork[emergencyChains[i]]
      );
    }
  }
}

// File: lib/solidity-utils/src/contracts/oz-common/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: src/contracts/emergency/interfaces/IEmergencyRegistry.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title IEmergencyRegistry
 * @author BGD Labs
 * @notice interface containing the events and methods definitions of the EmergencyRegistry contract
 */
interface IEmergencyRegistry {
  /**
   * @notice emitted when there is a change of the emergency state of a network
   * @param chainId id of the network updated
   * @param emergencyNumber indicates the emergency number for network chainId
   */
  event NetworkEmergencyStateUpdated(uint256 indexed chainId, int256 emergencyNumber);

  /**
   * @notice method to get the current state of emergency for a network
   * @param chainId id of the network to check
   * @return number indicating the emergency counter of the chain
   */
  function getNetworkEmergencyCount(uint256 chainId) external view returns (int256);

  /**
   * @notice sets the state of emergency for determined networks
   * @param emergencyChains list of chains which will move to emergency mode
   */
  function setEmergency(uint256[] memory emergencyChains) external;
}

// File: src/contracts/libs/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 ENVELOPE_NOT_PREVIOUSLY_REGISTERED = '3'; // envelope can only be retried if it has been previously registered
  string public constant CURRENT_OR_DESTINATION_CHAIN_ADAPTER_NOT_SET = '4'; // can not enable bridge adapter if the current or destination chain adapter is 0 address
  string public constant CALLER_NOT_APPROVED_BRIDGE = '5'; // caller must be an approved bridge
  string public constant INVALID_VALIDITY_TIMESTAMP = '6'; // new validity timestamp is not correct (< last validity or in the future
  string public constant CALLER_NOT_CCIP_ROUTER = '7'; // caller must be bridge provider contract
  string public constant CCIP_ROUTER_CANT_BE_ADDRESS_0 = '8'; // CCIP bridge adapters needs a CCIP Router
  string public constant RECEIVER_NOT_SET = '9'; // receiver address on destination chain can not be 0
  string public constant DESTINATION_CHAIN_ID_NOT_SUPPORTED = '10'; // destination chain id must be supported by bridge provider
  string public constant NOT_ENOUGH_VALUE_TO_PAY_BRIDGE_FEES = '11'; // cross chain controller does not have enough funds to forward the message
  string public constant INCORRECT_ORIGIN_CHAIN_ID = '12'; // message origination chain id is not from a supported chain
  string public constant REMOTE_NOT_TRUSTED = '13'; // remote address has not been registered as a trusted origin
  string public constant CALLER_NOT_HL_MAILBOX = '14'; // caller must be the HyperLane Mailbox contract
  string public constant NO_BRIDGE_ADAPTERS_FOR_SPECIFIED_CHAIN = '15'; // no bridge adapters are configured for the specified destination chain
  string public constant ONLY_ONE_EMERGENCY_UPDATE_PER_CHAIN = '16'; // only one emergency update is allowed at the time
  string public constant INVALID_REQUIRED_CONFIRMATIONS = '17'; // required confirmations must be less or equal than allowed adapters or bigger or equal than 1
  string public constant BRIDGE_ADAPTER_NOT_SET_FOR_ANY_CHAIN = '18'; // a bridge adapter must support at least one chain
  string public constant DESTINATION_CHAIN_NOT_SAME_AS_CURRENT_CHAIN = '19'; // destination chain must be the same chain as the current chain where contract is deployed
  string public constant INVALID_BRIDGE_ADAPTER = '20'; // a bridge adapter address can not be the 0 address
  string public constant TRANSACTION_NOT_PREVIOUSLY_FORWARDED = '21'; // to retry sending a transaction, it needs to have been previously sent
  string public constant TRANSACTION_RETRY_FAILED = '22'; // transaction retry has failed (no bridge adapters where able to send)
  string public constant ENVELOPE_RETRY_FAILED = '23'; // envelope retry has failed (no bridge adapters where able to send)
  string public constant BRIDGE_ADAPTERS_SHOULD_BE_UNIQUE = '23'; // can not use the same bridge adapter twice
  string public constant ENVELOPE_NOT_CONFIRMED_OR_DELIVERED = '24'; // to deliver an envelope, this should have been previously confirmed
  string public constant ENVELOPE_DELIVERY_FAILED = '25'; // envelope has not been delivered
  string public constant INVALID_BASE_ADAPTER_CROSS_CHAIN_CONTROLLER = '27'; // crossChainController address can not be 0
  string public constant DELEGATE_CALL_FORBIDDEN = '28'; // calling this function during delegatecall is forbidden
  string public constant CALLER_NOT_LZ_ENDPOINT = '29'; // caller must be the LayerZero endpoint contract
  string public constant INVALID_LZ_ENDPOINT = '30'; // LayerZero endpoint can't be 0
  string public constant INVALID_TRUSTED_REMOTE = '31'; // trusted remote endpoint can't be 0
  string public constant INVALID_EMERGENCY_ORACLE = '32'; // emergency oracle can not be 0 because if not, system could not be rescued on emergency
  string public constant SYSTEM_NEEDS_AT_LEAST_ONE_CONFIRMATION = '33';
  string public constant INVALID_CONFIRMATIONS_FOR_ALLOWED_ADAPTERS = '34';
  string public constant NOT_IN_EMERGENCY = '35'; // execution can only happen when in an emergency
  string public constant LINK_TOKEN_CANT_BE_ADDRESS_0 = '36'; // link token address should be set
  string public constant CCIP_MESSAGE_IS_INVALID = '37'; // link token address should be set
  string public constant ADAPTER_PAYMENT_SETUP_FAILED = '38'; // adapter payment setup failed
  string public constant CHAIN_ID_MISMATCH = '39'; // the message delivered to/from wrong network
}

// File: lib/solidity-utils/src/contracts/oz-common/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;
  }
}