ETH Price: $3,662.82 (+0.72%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
167876722023-03-09 2:25:47669 days ago1678328747  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TelepathyRouter

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 31 : TelepathyRouter.sol
pragma solidity 0.8.16;

import {UUPSUpgradeable} from "openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

import {ILightClient} from "src/lightclient/interfaces/ILightClient.sol";

import {TelepathyStorage} from "./TelepathyStorage.sol";
import {
    ITelepathyReceiver,
    Message,
    MessageStatus,
    ITelepathyHandler,
    ITelepathyRouter
} from "./interfaces/ITelepathy.sol";
import {TargetAMB} from "./TargetAMB.sol";
import {SourceAMB} from "./SourceAMB.sol";
import {TelepathyAccess} from "./TelepathyAccess.sol";

/// @title Telepathy Router
/// @author Succinct Labs
/// @notice Send and receive arbitrary messages from other chains.
contract TelepathyRouter is SourceAMB, TargetAMB, TelepathyAccess, UUPSUpgradeable {
    /// @notice Returns current contract version.
    uint8 public constant VERSION = 1;

    /// @notice Prevents the implementation contract from being initialized outside of the upgradeable proxy.
    constructor() {
        _disableInitializers();
    }

    /// @notice Initializes the contract and the parent contracts once.
    function initialize(
        uint32[] memory _sourceChainIds,
        address[] memory _lightClients,
        address[] memory _broadcasters,
        address _timelock,
        address _guardian,
        bool _sendingEnabled
    ) external initializer {
        __ReentrancyGuard_init();
        __AccessControl_init();
        _grantRole(GUARDIAN_ROLE, _guardian);
        _grantRole(TIMELOCK_ROLE, _timelock);
        _grantRole(DEFAULT_ADMIN_ROLE, _timelock);
        __UUPSUpgradeable_init();

        require(_sourceChainIds.length == _lightClients.length);
        require(_sourceChainIds.length == _broadcasters.length);

        sourceChainIds = _sourceChainIds;
        for (uint32 i = 0; i < sourceChainIds.length; i++) {
            lightClients[sourceChainIds[i]] = ILightClient(_lightClients[i]);
            broadcasters[sourceChainIds[i]] = _broadcasters[i];
        }
        sendingEnabled = _sendingEnabled;
        version = VERSION;
    }

    /// @notice Authorizes an upgrade for the implementation contract.
    function _authorizeUpgrade(address newImplementation) internal override onlyTimelock {}
}

File 2 of 31 : AccessControlUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        StringsUpgradeable.toHexString(account),
                        " is missing role ",
                        StringsUpgradeable.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 3 of 31 : IAccessControlUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControlUpgradeable {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

File 4 of 31 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _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);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 5 of 31 : draft-IERC1822Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822ProxiableUpgradeable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

File 6 of 31 : ERC1967UpgradeUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967UpgradeUpgradeable is Initializable {
    function __ERC1967Upgrade_init() internal onlyInitializing {
    }

    function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
    }
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallUUPS(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        // Upgrades from old implementations will perform a rollback test. This test requires the new
        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
        // this special case will break upgrade paths from old UUPS implementation to new ones.
        if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
            } catch {
                revert("ERC1967Upgrade: new implementation is not UUPS");
            }
            _upgradeToAndCall(newImplementation, data, forceCall);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Emitted when the beacon is upgraded.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
        }
    }

    /**
     * @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) private returns (bytes memory) {
        require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 7 of 31 : IBeaconUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeaconUpgradeable {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

File 8 of 31 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.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 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.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.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.
     *
     * 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.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * 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.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    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.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 9 of 31 : UUPSUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.0;

import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
    function __UUPSUpgradeable_init() internal onlyInitializing {
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
    address private immutable __self = address(this);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        require(address(this) != __self, "Function must be called through delegatecall");
        require(_getImplementation() == __self, "Function must be called through active proxy");
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
        _;
    }

    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
        return _IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeTo(address newImplementation) external virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data, true);
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeTo} and {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal override onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 10 of 31 : ReentrancyGuardUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 11 of 31 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @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 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 12 of 31 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @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 ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 13 of 31 : StorageSlotUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlotUpgradeable {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }
}

File 14 of 31 : StringsUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/MathUpgradeable.sol";

/**
 * @dev String operations.
 */
library StringsUpgradeable {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = MathUpgradeable.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, MathUpgradeable.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

File 15 of 31 : ERC165Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165Upgradeable).interfaceId;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 16 of 31 : IERC165Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165Upgradeable {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 17 of 31 : MathUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library MathUpgradeable {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10**64) {
                value /= 10**64;
                result += 64;
            }
            if (value >= 10**32) {
                value /= 10**32;
                result += 32;
            }
            if (value >= 10**16) {
                value /= 10**16;
                result += 16;
            }
            if (value >= 10**8) {
                value /= 10**8;
                result += 8;
            }
            if (value >= 10**4) {
                value /= 10**4;
                result += 4;
            }
            if (value >= 10**2) {
                value /= 10**2;
                result += 2;
            }
            if (value >= 10**1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}

File 18 of 31 : Bytes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Bytes
 * @notice Bytes is a library for manipulating byte arrays.
 */
library Bytes {
    /**
     * @custom:attribution https://github.com/GNSPS/solidity-bytes-utils
     * @notice Slices a byte array with a given starting index and length. Returns a new byte array
     *         as opposed to a pointer to the original array. Will throw if trying to slice more
     *         bytes than exist in the array.
     *
     * @param _bytes Byte array to slice.
     * @param _start Starting index of the slice.
     * @param _length Length of the slice.
     *
     * @return Slice of the input byte array.
     */
    function slice(
        bytes memory _bytes,
        uint256 _start,
        uint256 _length
    ) internal pure returns (bytes memory) {
        unchecked {
            require(_length + 31 >= _length, "slice_overflow");
            require(_start + _length >= _start, "slice_overflow");
            require(_bytes.length >= _start + _length, "slice_outOfBounds");
        }

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)

                //zero out the 32 bytes slice we are about to return
                //we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    /**
     * @notice Slices a byte array with a given starting index up to the end of the original byte
     *         array. Returns a new array rathern than a pointer to the original.
     *
     * @param _bytes Byte array to slice.
     * @param _start Starting index of the slice.
     *
     * @return Slice of the input byte array.
     */
    function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) {
        if (_start >= _bytes.length) {
            return bytes("");
        }
        return slice(_bytes, _start, _bytes.length - _start);
    }

    /**
     * @notice Converts a byte array into a nibble array by splitting each byte into two nibbles.
     *         Resulting nibble array will be exactly twice as long as the input byte array.
     *
     * @param _bytes Input byte array to convert.
     *
     * @return Resulting nibble array.
     */
    function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
        uint256 bytesLength = _bytes.length;
        bytes memory nibbles = new bytes(bytesLength * 2);
        bytes1 b;

        for (uint256 i = 0; i < bytesLength; ) {
            b = _bytes[i];
            nibbles[i * 2] = b >> 4;
            nibbles[i * 2 + 1] = b & 0x0f;
            unchecked {
                ++i;
            }
        }

        return nibbles;
    }

    /**
     * @notice Compares two byte arrays by comparing their keccak256 hashes.
     *
     * @param _bytes First byte array to compare.
     * @param _other Second byte array to compare.
     *
     * @return True if the two byte arrays are equal, false otherwise.
     */
    function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) {
        return keccak256(_bytes) == keccak256(_other);
    }
}

File 19 of 31 : RLPReader.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;

/**
 * @custom:attribution https://github.com/hamdiallam/Solidity-RLP
 * @title RLPReader
 * @notice RLPReader is a library for parsing RLP-encoded byte arrays into Solidity types. Adapted
 *         from Solidity-RLP (https://github.com/hamdiallam/Solidity-RLP) by Hamdi Allam with
 *         various tweaks to improve readability.
 */
library RLPReader {
    /**
     * Custom pointer type to avoid confusion between pointers and uint256s.
     */
    type MemoryPointer is uint256;

    /**
     * @notice RLP item types.
     *
     * @custom:value DATA_ITEM Represents an RLP data item (NOT a list).
     * @custom:value LIST_ITEM Represents an RLP list item.
     */
    enum RLPItemType {
        DATA_ITEM,
        LIST_ITEM
    }

    /**
     * @notice Struct representing an RLP item.
     *
     * @custom:field length Length of the RLP item.
     * @custom:field ptr    Pointer to the RLP item in memory.
     */
    struct RLPItem {
        uint256 length;
        MemoryPointer ptr;
    }

    /**
     * @notice Max list length that this library will accept.
     */
    uint256 internal constant MAX_LIST_LENGTH = 32;

    /**
     * @notice Converts bytes to a reference to memory position and length.
     *
     * @param _in Input bytes to convert.
     *
     * @return Output memory reference.
     */
    function toRLPItem(bytes memory _in) internal pure returns (RLPItem memory) {
        // Empty arrays are not RLP items.
        require(
            _in.length > 0,
            "RLPReader: length of an RLP item must be greater than zero to be decodable"
        );

        MemoryPointer ptr;
        assembly {
            ptr := add(_in, 32)
        }

        return RLPItem({ length: _in.length, ptr: ptr });
    }

    /**
     * @notice Reads an RLP list value into a list of RLP items.
     *
     * @param _in RLP list value.
     *
     * @return Decoded RLP list items.
     */
    function readList(RLPItem memory _in) internal pure returns (RLPItem[] memory) {
        (uint256 listOffset, uint256 listLength, RLPItemType itemType) = _decodeLength(_in);

        require(
            itemType == RLPItemType.LIST_ITEM,
            "RLPReader: decoded item type for list is not a list item"
        );

        require(
            listOffset + listLength == _in.length,
            "RLPReader: list item has an invalid data remainder"
        );

        // Solidity in-memory arrays can't be increased in size, but *can* be decreased in size by
        // writing to the length. Since we can't know the number of RLP items without looping over
        // the entire input, we'd have to loop twice to accurately size this array. It's easier to
        // simply set a reasonable maximum list length and decrease the size before we finish.
        RLPItem[] memory out = new RLPItem[](MAX_LIST_LENGTH);

        uint256 itemCount = 0;
        uint256 offset = listOffset;
        while (offset < _in.length) {
            (uint256 itemOffset, uint256 itemLength, ) = _decodeLength(
                RLPItem({
                    length: _in.length - offset,
                    ptr: MemoryPointer.wrap(MemoryPointer.unwrap(_in.ptr) + offset)
                })
            );

            // We don't need to check itemCount < out.length explicitly because Solidity already
            // handles this check on our behalf, we'd just be wasting gas.
            out[itemCount] = RLPItem({
                length: itemLength + itemOffset,
                ptr: MemoryPointer.wrap(MemoryPointer.unwrap(_in.ptr) + offset)
            });

            itemCount += 1;
            offset += itemOffset + itemLength;
        }

        // Decrease the array size to match the actual item count.
        assembly {
            mstore(out, itemCount)
        }

        return out;
    }

    /**
     * @notice Reads an RLP list value into a list of RLP items.
     *
     * @param _in RLP list value.
     *
     * @return Decoded RLP list items.
     */
    function readList(bytes memory _in) internal pure returns (RLPItem[] memory) {
        return readList(toRLPItem(_in));
    }

    /**
     * @notice Reads an RLP bytes value into bytes.
     *
     * @param _in RLP bytes value.
     *
     * @return Decoded bytes.
     */
    function readBytes(RLPItem memory _in) internal pure returns (bytes memory) {
        (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in);

        require(
            itemType == RLPItemType.DATA_ITEM,
            "RLPReader: decoded item type for bytes is not a data item"
        );

        require(
            _in.length == itemOffset + itemLength,
            "RLPReader: bytes value contains an invalid remainder"
        );

        return _copy(_in.ptr, itemOffset, itemLength);
    }

    /**
     * @notice Reads an RLP bytes value into bytes.
     *
     * @param _in RLP bytes value.
     *
     * @return Decoded bytes.
     */
    function readBytes(bytes memory _in) internal pure returns (bytes memory) {
        return readBytes(toRLPItem(_in));
    }

    /**
     * @notice Reads the raw bytes of an RLP item.
     *
     * @param _in RLP item to read.
     *
     * @return Raw RLP bytes.
     */
    function readRawBytes(RLPItem memory _in) internal pure returns (bytes memory) {
        return _copy(_in.ptr, 0, _in.length);
    }

    /**
     * @notice Decodes the length of an RLP item.
     *
     * @param _in RLP item to decode.
     *
     * @return Offset of the encoded data.
     * @return Length of the encoded data.
     * @return RLP item type (LIST_ITEM or DATA_ITEM).
     */
    function _decodeLength(RLPItem memory _in)
        private
        pure
        returns (
            uint256,
            uint256,
            RLPItemType
        )
    {
        // Short-circuit if there's nothing to decode, note that we perform this check when
        // the user creates an RLP item via toRLPItem, but it's always possible for them to bypass
        // that function and create an RLP item directly. So we need to check this anyway.
        require(
            _in.length > 0,
            "RLPReader: length of an RLP item must be greater than zero to be decodable"
        );

        MemoryPointer ptr = _in.ptr;
        uint256 prefix;
        assembly {
            prefix := byte(0, mload(ptr))
        }

        if (prefix <= 0x7f) {
            // Single byte.
            return (0, 1, RLPItemType.DATA_ITEM);
        } else if (prefix <= 0xb7) {
            // Short string.

            // slither-disable-next-line variable-scope
            uint256 strLen = prefix - 0x80;

            require(
                _in.length > strLen,
                "RLPReader: length of content must be greater than string length (short string)"
            );

            bytes1 firstByteOfContent;
            assembly {
                firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff))
            }

            require(
                strLen != 1 || firstByteOfContent >= 0x80,
                "RLPReader: invalid prefix, single byte < 0x80 are not prefixed (short string)"
            );

            return (1, strLen, RLPItemType.DATA_ITEM);
        } else if (prefix <= 0xbf) {
            // Long string.
            uint256 lenOfStrLen = prefix - 0xb7;

            require(
                _in.length > lenOfStrLen,
                "RLPReader: length of content must be > than length of string length (long string)"
            );

            bytes1 firstByteOfContent;
            assembly {
                firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff))
            }

            require(
                firstByteOfContent != 0x00,
                "RLPReader: length of content must not have any leading zeros (long string)"
            );

            uint256 strLen;
            assembly {
                strLen := shr(sub(256, mul(8, lenOfStrLen)), mload(add(ptr, 1)))
            }

            require(
                strLen > 55,
                "RLPReader: length of content must be greater than 55 bytes (long string)"
            );

            require(
                _in.length > lenOfStrLen + strLen,
                "RLPReader: length of content must be greater than total length (long string)"
            );

            return (1 + lenOfStrLen, strLen, RLPItemType.DATA_ITEM);
        } else if (prefix <= 0xf7) {
            // Short list.
            // slither-disable-next-line variable-scope
            uint256 listLen = prefix - 0xc0;

            require(
                _in.length > listLen,
                "RLPReader: length of content must be greater than list length (short list)"
            );

            return (1, listLen, RLPItemType.LIST_ITEM);
        } else {
            // Long list.
            uint256 lenOfListLen = prefix - 0xf7;

            require(
                _in.length > lenOfListLen,
                "RLPReader: length of content must be > than length of list length (long list)"
            );

            bytes1 firstByteOfContent;
            assembly {
                firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff))
            }

            require(
                firstByteOfContent != 0x00,
                "RLPReader: length of content must not have any leading zeros (long list)"
            );

            uint256 listLen;
            assembly {
                listLen := shr(sub(256, mul(8, lenOfListLen)), mload(add(ptr, 1)))
            }

            require(
                listLen > 55,
                "RLPReader: length of content must be greater than 55 bytes (long list)"
            );

            require(
                _in.length > lenOfListLen + listLen,
                "RLPReader: length of content must be greater than total length (long list)"
            );

            return (1 + lenOfListLen, listLen, RLPItemType.LIST_ITEM);
        }
    }

    /**
     * @notice Copies the bytes from a memory location.
     *
     * @param _src    Pointer to the location to read from.
     * @param _offset Offset to start reading from.
     * @param _length Number of bytes to read.
     *
     * @return Copied bytes.
     */
    function _copy(
        MemoryPointer _src,
        uint256 _offset,
        uint256 _length
    ) private pure returns (bytes memory) {
        bytes memory out = new bytes(_length);
        if (_length == 0) {
            return out;
        }

        // Mostly based on Solidity's copy_memory_to_memory:
        // solhint-disable max-line-length
        // https://github.com/ethereum/solidity/blob/34dd30d71b4da730488be72ff6af7083cf2a91f6/libsolidity/codegen/YulUtilFunctions.cpp#L102-L114
        uint256 src = MemoryPointer.unwrap(_src) + _offset;
        assembly {
            let dest := add(out, 32)
            let i := 0
            for {

            } lt(i, _length) {
                i := add(i, 32)
            } {
                mstore(add(dest, i), mload(add(src, i)))
            }

            if gt(i, _length) {
                mstore(add(dest, _length), 0)
            }
        }

        return out;
    }

    /**
     * Reads an RLP bytes32 value into a bytes32.
     * @param _in RLP bytes32 value.
     * @return Decoded bytes32.
     */
    function readBytes32(RLPItem memory _in) internal pure returns (bytes32) {
        require(_in.length <= 33, "Invalid RLP bytes32 value.");

        (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in);

        require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes32 value.");

        uint256 ptr = MemoryPointer.unwrap(_in.ptr) + itemOffset;
        bytes32 out;
        assembly {
            out := mload(ptr)

            // Shift the bytes over to match the item size.
            if lt(itemLength, 32) {
                out := div(out, exp(256, sub(32, itemLength)))
            }
        }

        return out;
    }

    /**
     * Reads an RLP uint256 value into a uint256.
     * @param _in RLP uint256 value.
     * @return Decoded uint256.
     */
    function readUint256(RLPItem memory _in) internal pure returns (uint256) {
        return uint256(readBytes32(_in));
    }

    /**
     * Reads an RLP address value into a address.
     * @param _in RLP address value.
     * @return Decoded address.
     */
    function readAddress(RLPItem memory _in) internal pure returns (address) {
        if (_in.length == 1) {
            return address(0);
        }

        require(_in.length == 21, "Invalid RLP address value.");

        return address(uint160(readUint256(_in)));
    }
}

File 20 of 31 : RLPWriter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode
 * @title RLPWriter
 * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's
 *         RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor
 *         modifications to improve legibility.
 */
library RLPWriter {
    /**
     * @notice RLP encodes a byte string.
     *
     * @param _in The byte string to encode.
     *
     * @return The RLP encoded string in bytes.
     */
    function writeBytes(bytes memory _in) internal pure returns (bytes memory) {
        bytes memory encoded;

        if (_in.length == 1 && uint8(_in[0]) < 128) {
            encoded = _in;
        } else {
            encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);
        }

        return encoded;
    }

    /**
     * @notice RLP encodes a list of RLP encoded byte byte strings.
     *
     * @param _in The list of RLP encoded byte strings.
     *
     * @return The RLP encoded list of items in bytes.
     */
    function writeList(bytes[] memory _in) internal pure returns (bytes memory) {
        bytes memory list = _flatten(_in);
        return abi.encodePacked(_writeLength(list.length, 192), list);
    }

    /**
     * @notice RLP encodes a string.
     *
     * @param _in The string to encode.
     *
     * @return The RLP encoded string in bytes.
     */
    function writeString(string memory _in) internal pure returns (bytes memory) {
        return writeBytes(bytes(_in));
    }

    /**
     * @notice RLP encodes an address.
     *
     * @param _in The address to encode.
     *
     * @return The RLP encoded address in bytes.
     */
    function writeAddress(address _in) internal pure returns (bytes memory) {
        return writeBytes(abi.encodePacked(_in));
    }

    /**
     * @notice RLP encodes a uint.
     *
     * @param _in The uint256 to encode.
     *
     * @return The RLP encoded uint256 in bytes.
     */
    function writeUint(uint256 _in) internal pure returns (bytes memory) {
        return writeBytes(_toBinary(_in));
    }

    /**
     * @notice RLP encodes a bool.
     *
     * @param _in The bool to encode.
     *
     * @return The RLP encoded bool in bytes.
     */
    function writeBool(bool _in) internal pure returns (bytes memory) {
        bytes memory encoded = new bytes(1);
        encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));
        return encoded;
    }

    /**
     * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55.
     *
     * @param _len    The length of the string or the payload.
     * @param _offset 128 if item is string, 192 if item is list.
     *
     * @return RLP encoded bytes.
     */
    function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {
        bytes memory encoded;

        if (_len < 56) {
            encoded = new bytes(1);
            encoded[0] = bytes1(uint8(_len) + uint8(_offset));
        } else {
            uint256 lenLen;
            uint256 i = 1;
            while (_len / i != 0) {
                lenLen++;
                i *= 256;
            }

            encoded = new bytes(lenLen + 1);
            encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);
            for (i = 1; i <= lenLen; i++) {
                encoded[i] = bytes1(uint8((_len / (256**(lenLen - i))) % 256));
            }
        }

        return encoded;
    }

    /**
     * @notice Encode integer in big endian binary form with no leading zeroes.
     *
     * @param _x The integer to encode.
     *
     * @return RLP encoded bytes.
     */
    function _toBinary(uint256 _x) private pure returns (bytes memory) {
        bytes memory b = abi.encodePacked(_x);

        uint256 i = 0;
        for (; i < 32; i++) {
            if (b[i] != 0) {
                break;
            }
        }

        bytes memory res = new bytes(32 - i);
        for (uint256 j = 0; j < res.length; j++) {
            res[j] = b[i++];
        }

        return res;
    }

    /**
     * @custom:attribution https://github.com/Arachnid/solidity-stringutils
     * @notice Copies a piece of memory to another location.
     *
     * @param _dest Destination location.
     * @param _src  Source location.
     * @param _len  Length of memory to copy.
     */
    function _memcpy(
        uint256 _dest,
        uint256 _src,
        uint256 _len
    ) private pure {
        uint256 dest = _dest;
        uint256 src = _src;
        uint256 len = _len;

        for (; len >= 32; len -= 32) {
            assembly {
                mstore(dest, mload(src))
            }
            dest += 32;
            src += 32;
        }

        uint256 mask;
        unchecked {
            mask = 256**(32 - len) - 1;
        }
        assembly {
            let srcpart := and(mload(src), not(mask))
            let destpart := and(mload(dest), mask)
            mstore(dest, or(destpart, srcpart))
        }
    }

    /**
     * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder
     * @notice Flattens a list of byte strings into one byte string.
     *
     * @param _list List of byte strings to flatten.
     *
     * @return The flattened byte string.
     */
    function _flatten(bytes[] memory _list) private pure returns (bytes memory) {
        if (_list.length == 0) {
            return new bytes(0);
        }

        uint256 len;
        uint256 i = 0;
        for (; i < _list.length; i++) {
            len += _list[i].length;
        }

        bytes memory flattened = new bytes(len);
        uint256 flattenedPtr;
        assembly {
            flattenedPtr := add(flattened, 0x20)
        }

        for (i = 0; i < _list.length; i++) {
            bytes memory item = _list[i];

            uint256 listPtr;
            assembly {
                listPtr := add(item, 0x20)
            }

            _memcpy(flattenedPtr, listPtr, item.length);
            flattenedPtr += _list[i].length;
        }

        return flattened;
    }
}

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

import { Bytes } from "../Bytes.sol";
import { RLPReader } from "../rlp/RLPReader.sol";

/**
 * @title MerkleTrie
 * @notice MerkleTrie is a small library for verifying standard Ethereum Merkle-Patricia trie
 *         inclusion proofs. By default, this library assumes a hexary trie. One can change the
 *         trie radix constant to support other trie radixes.
 */
library MerkleTrie {
    /**
     * @notice Struct representing a node in the trie.
     *
     * @custom:field encoded The RLP-encoded node.
     * @custom:field decoded The RLP-decoded node.
     */
    struct TrieNode {
        bytes encoded;
        RLPReader.RLPItem[] decoded;
    }

    /**
     * @notice Determines the number of elements per branch node.
     */
    uint256 internal constant TREE_RADIX = 16;

    /**
     * @notice Branch nodes have TREE_RADIX elements and one value element.
     */
    uint256 internal constant BRANCH_NODE_LENGTH = TREE_RADIX + 1;

    /**
     * @notice Leaf nodes and extension nodes have two elements, a `path` and a `value`.
     */
    uint256 internal constant LEAF_OR_EXTENSION_NODE_LENGTH = 2;

    /**
     * @notice Prefix for even-nibbled extension node paths.
     */
    uint8 internal constant PREFIX_EXTENSION_EVEN = 0;

    /**
     * @notice Prefix for odd-nibbled extension node paths.
     */
    uint8 internal constant PREFIX_EXTENSION_ODD = 1;

    /**
     * @notice Prefix for even-nibbled leaf node paths.
     */
    uint8 internal constant PREFIX_LEAF_EVEN = 2;

    /**
     * @notice Prefix for odd-nibbled leaf node paths.
     */
    uint8 internal constant PREFIX_LEAF_ODD = 3;

    /**
     * @notice Verifies a proof that a given key/value pair is present in the trie.
     *
     * @param _key   Key of the node to search for, as a hex string.
     * @param _value Value of the node to search for, as a hex string.
     * @param _proof Merkle trie inclusion proof for the desired node. Unlike traditional Merkle
     *               trees, this proof is executed top-down and consists of a list of RLP-encoded
     *               nodes that make a path down to the target node.
     * @param _root  Known root of the Merkle trie. Used to verify that the included proof is
     *               correctly constructed.
     *
     * @return Whether or not the proof is valid.
     */
    function verifyInclusionProof(
        bytes memory _key,
        bytes memory _value,
        bytes[] memory _proof,
        bytes32 _root
    ) internal pure returns (bool) {
        return Bytes.equal(_value, get(_key, _proof, _root));
    }

    /**
     * @notice Retrieves the value associated with a given key.
     *
     * @param _key   Key to search for, as hex bytes.
     * @param _proof Merkle trie inclusion proof for the key.
     * @param _root  Known root of the Merkle trie.
     *
     * @return Value of the key if it exists.
     */
    function get(
        bytes memory _key,
        bytes[] memory _proof,
        bytes32 _root
    ) internal pure returns (bytes memory) {
        require(_key.length > 0, "MerkleTrie: empty key");

        TrieNode[] memory proof = _parseProof(_proof);
        bytes memory key = Bytes.toNibbles(_key);
        bytes memory currentNodeID = abi.encodePacked(_root);
        uint256 currentKeyIndex = 0;

        // Proof is top-down, so we start at the first element (root).
        for (uint256 i = 0; i < proof.length; i++) {
            TrieNode memory currentNode = proof[i];

            // Key index should never exceed total key length or we'll be out of bounds.
            require(
                currentKeyIndex <= key.length,
                "MerkleTrie: key index exceeds total key length"
            );

            if (currentKeyIndex == 0) {
                // First proof element is always the root node.
                require(
                    Bytes.equal(abi.encodePacked(keccak256(currentNode.encoded)), currentNodeID),
                    "MerkleTrie: invalid root hash"
                );
            } else if (currentNode.encoded.length >= 32) {
                // Nodes 32 bytes or larger are hashed inside branch nodes.
                require(
                    Bytes.equal(abi.encodePacked(keccak256(currentNode.encoded)), currentNodeID),
                    "MerkleTrie: invalid large internal hash"
                );
            } else {
                // Nodes smaller than 32 bytes aren't hashed.
                require(
                    Bytes.equal(currentNode.encoded, currentNodeID),
                    "MerkleTrie: invalid internal node hash"
                );
            }

            if (currentNode.decoded.length == BRANCH_NODE_LENGTH) {
                if (currentKeyIndex == key.length) {
                    // Value is the last element of the decoded list (for branch nodes). There's
                    // some ambiguity in the Merkle trie specification because bytes(0) is a
                    // valid value to place into the trie, but for branch nodes bytes(0) can exist
                    // even when the value wasn't explicitly placed there. Geth treats a value of
                    // bytes(0) as "key does not exist" and so we do the same.
                    bytes memory value = RLPReader.readBytes(currentNode.decoded[TREE_RADIX]);
                    require(
                        value.length > 0,
                        "MerkleTrie: value length must be greater than zero (branch)"
                    );

                    // Extra proof elements are not allowed.
                    require(
                        i == proof.length - 1,
                        "MerkleTrie: value node must be last node in proof (branch)"
                    );

                    return value;
                } else {
                    // We're not at the end of the key yet.
                    // Figure out what the next node ID should be and continue.
                    uint8 branchKey = uint8(key[currentKeyIndex]);
                    RLPReader.RLPItem memory nextNode = currentNode.decoded[branchKey];
                    currentNodeID = _getNodeID(nextNode);
                    currentKeyIndex += 1;
                }
            } else if (currentNode.decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) {
                bytes memory path = _getNodePath(currentNode);
                uint8 prefix = uint8(path[0]);
                uint8 offset = 2 - (prefix % 2);
                bytes memory pathRemainder = Bytes.slice(path, offset);
                bytes memory keyRemainder = Bytes.slice(key, currentKeyIndex);
                uint256 sharedNibbleLength = _getSharedNibbleLength(pathRemainder, keyRemainder);

                // Whether this is a leaf node or an extension node, the path remainder MUST be a
                // prefix of the key remainder (or be equal to the key remainder) or the proof is
                // considered invalid.
                require(
                    pathRemainder.length == sharedNibbleLength,
                    "MerkleTrie: path remainder must share all nibbles with key"
                );

                if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) {
                    // Prefix of 2 or 3 means this is a leaf node. For the leaf node to be valid,
                    // the key remainder must be exactly equal to the path remainder. We already
                    // did the necessary byte comparison, so it's more efficient here to check that
                    // the key remainder length equals the shared nibble length, which implies
                    // equality with the path remainder (since we already did the same check with
                    // the path remainder and the shared nibble length).
                    require(
                        keyRemainder.length == sharedNibbleLength,
                        "MerkleTrie: key remainder must be identical to path remainder"
                    );

                    // Our Merkle Trie is designed specifically for the purposes of the Ethereum
                    // state trie. Empty values are not allowed in the state trie, so we can safely
                    // say that if the value is empty, the key should not exist and the proof is
                    // invalid.
                    bytes memory value = RLPReader.readBytes(currentNode.decoded[1]);
                    require(
                        value.length > 0,
                        "MerkleTrie: value length must be greater than zero (leaf)"
                    );

                    // Extra proof elements are not allowed.
                    require(
                        i == proof.length - 1,
                        "MerkleTrie: value node must be last node in proof (leaf)"
                    );

                    return value;
                } else if (prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD) {
                    // Prefix of 0 or 1 means this is an extension node. We move onto the next node
                    // in the proof and increment the key index by the length of the path remainder
                    // which is equal to the shared nibble length.
                    currentNodeID = _getNodeID(currentNode.decoded[1]);
                    currentKeyIndex += sharedNibbleLength;
                } else {
                    revert("MerkleTrie: received a node with an unknown prefix");
                }
            } else {
                revert("MerkleTrie: received an unparseable node");
            }
        }

        revert("MerkleTrie: ran out of proof elements");
    }

    /**
     * @notice Parses an array of proof elements into a new array that contains both the original
     *         encoded element and the RLP-decoded element.
     *
     * @param _proof Array of proof elements to parse.
     *
     * @return Proof parsed into easily accessible structs.
     */
    function _parseProof(bytes[] memory _proof) private pure returns (TrieNode[] memory) {
        uint256 length = _proof.length;
        TrieNode[] memory proof = new TrieNode[](length);
        for (uint256 i = 0; i < length; ) {
            proof[i] = TrieNode({ encoded: _proof[i], decoded: RLPReader.readList(_proof[i]) });
            unchecked {
                ++i;
            }
        }
        return proof;
    }

    /**
     * @notice Picks out the ID for a node. Node ID is referred to as the "hash" within the
     *         specification, but nodes < 32 bytes are not actually hashed.
     *
     * @param _node Node to pull an ID for.
     *
     * @return ID for the node, depending on the size of its contents.
     */
    function _getNodeID(RLPReader.RLPItem memory _node) private pure returns (bytes memory) {
        return _node.length < 32 ? RLPReader.readRawBytes(_node) : RLPReader.readBytes(_node);
    }

    /**
     * @notice Gets the path for a leaf or extension node.
     *
     * @param _node Node to get a path for.
     *
     * @return Node path, converted to an array of nibbles.
     */
    function _getNodePath(TrieNode memory _node) private pure returns (bytes memory) {
        return Bytes.toNibbles(RLPReader.readBytes(_node.decoded[0]));
    }

    /**
     * @notice Utility; determines the number of nibbles shared between two nibble arrays.
     *
     * @param _a First nibble array.
     * @param _b Second nibble array.
     *
     * @return Number of shared nibbles.
     */
    function _getSharedNibbleLength(bytes memory _a, bytes memory _b)
        private
        pure
        returns (uint256)
    {
        uint256 shared;
        uint256 max = (_a.length < _b.length) ? _a.length : _b.length;
        for (; shared < max && _a[shared] == _b[shared]; ) {
            unchecked {
                ++shared;
            }
        }
        return shared;
    }
}

File 22 of 31 : SourceAMB.sol
pragma solidity 0.8.16;

import {UUPSUpgradeable} from "openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {OwnableUpgradeable} from "openzeppelin-contracts-upgradeable/access/OwnableUpgradeable.sol";

import {Bytes32} from "src/libraries/Typecast.sol";
import {MessageEncoding} from "src/libraries/MessageEncoding.sol";
import {ITelepathyRouter, Message} from "./interfaces/ITelepathy.sol";
import {TelepathyAccess} from "./TelepathyAccess.sol";
import {TelepathyStorage} from "./TelepathyStorage.sol";

/// @title Source Arbitrary Message Bridge
/// @author Succinct Labs
/// @notice This contract is the entrypoint for sending messages to other chains.
contract SourceAMB is TelepathyStorage, ITelepathyRouter {
    /// @notice Modifier to require that sending is enabled.
    modifier isSendingEnabled() {
        require(sendingEnabled, "Sending is disabled");
        _;
    }

    /// @notice Sends a message to a target chain.
    /// @param recipientChainId The chain id that specifies the target chain.
    /// @param recipientAddress The contract address that will be called on the target chain.
    /// @param data The data passed to the contract on the other chain
    /// @return bytes32 A unique identifier for a message.
    function send(uint32 recipientChainId, bytes32 recipientAddress, bytes calldata data)
        external
        isSendingEnabled
        returns (bytes32)
    {
        require(recipientChainId != block.chainid, "Cannot send to same chain");
        (bytes memory message, bytes32 messageRoot) =
            _getMessageAndRoot(recipientChainId, recipientAddress, data);
        emit SentMessage(nonce++, messageRoot, message);
        return messageRoot;
    }

    function send(uint32 recipientChainId, address recipientAddress, bytes calldata data)
        external
        isSendingEnabled
        returns (bytes32)
    {
        require(recipientChainId != block.chainid, "Cannot send to same chain");
        (bytes memory message, bytes32 messageRoot) =
            _getMessageAndRoot(recipientChainId, Bytes32.fromAddress(recipientAddress), data);
        emit SentMessage(nonce++, messageRoot, message);
        return messageRoot;
    }

    /// @notice Sends a message to a target chain.
    /// @notice This method is more expensive than the `send` method as it requires adding to
    ///         contract storage. Use `send` when interacting with Telepathy to save gas.
    /// @param recipientChainId The chain id that specifies the target chain.
    /// @param recipientAddress The contract address that will be called on the target chain.
    /// @param data The data passed to the contract on the other chain
    /// @return bytes32 A unique identifier for a message.
    function sendViaStorage(uint32 recipientChainId, bytes32 recipientAddress, bytes calldata data)
        external
        isSendingEnabled
        returns (bytes32)
    {
        require(recipientChainId != block.chainid, "Cannot send to same chain");
        (bytes memory message, bytes32 messageRoot) =
            _getMessageAndRoot(recipientChainId, recipientAddress, data);
        messages[nonce] = messageRoot;
        emit SentMessage(nonce++, messageRoot, message);
        return messageRoot;
    }

    function sendViaStorage(uint32 recipientChainId, address recipientAddress, bytes calldata data)
        external
        isSendingEnabled
        returns (bytes32)
    {
        require(recipientChainId != block.chainid, "Cannot send to same chain");
        (bytes memory message, bytes32 messageRoot) =
            _getMessageAndRoot(recipientChainId, Bytes32.fromAddress(recipientAddress), data);
        messages[nonce] = messageRoot;
        emit SentMessage(nonce++, messageRoot, message);
        return messageRoot;
    }

    /// @notice Gets the message and message root from the user-provided arguments to `send`
    /// @param recipientChainId The chain id that specifies the target chain.
    /// @param recipientAddress The contract address that will be called on the target chain.
    /// @param data The calldata used when calling the contract on the target chain.
    /// @return messageBytes The message encoded as bytes, used in SentMessage event.
    /// @return messageRoot The hash of messageBytes, used as a unique identifier for a message.
    function _getMessageAndRoot(
        uint32 recipientChainId,
        bytes32 recipientAddress,
        bytes calldata data
    ) internal view returns (bytes memory messageBytes, bytes32 messageRoot) {
        messageBytes = MessageEncoding.encode(
            version,
            nonce,
            uint32(block.chainid),
            msg.sender,
            recipientChainId,
            recipientAddress,
            data
        );
        messageRoot = keccak256(messageBytes);
    }
}

File 23 of 31 : TargetAMB.sol
pragma solidity 0.8.16;

import {ReentrancyGuardUpgradeable} from
    "openzeppelin-contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

import {SSZ} from "src/libraries/SimpleSerialize.sol";
import {StorageProof, EventProof} from "src/libraries/StateProofHelper.sol";
import {Address} from "src/libraries/Typecast.sol";
import {MessageEncoding} from "src/libraries/MessageEncoding.sol";

import {TelepathyStorage} from "./TelepathyStorage.sol";
import {
    ITelepathyHandler,
    ITelepathyReceiver,
    Message,
    MessageStatus
} from "./interfaces/ITelepathy.sol";

/// @title Target Arbitrary Message Bridge
/// @author Succinct Labs
/// @notice Executes messages sent from the source chain on the target chain.
contract TargetAMB is TelepathyStorage, ReentrancyGuardUpgradeable, ITelepathyReceiver {
    /// @notice The minimum delay for using any information from the light client.
    uint256 public constant MIN_LIGHT_CLIENT_DELAY = 2 minutes;

    /// @notice The ITelepathyBroadcaster SentMessage event signature used in `executeMessageFromLog`.
    bytes32 internal constant SENT_MESSAGE_EVENT_SIG =
        keccak256("SentMessage(uint64,bytes32,bytes)");

    /// @notice The topic index of the message root in the SourceAMB SentMessage event.
    /// @dev Because topic[0] is the hash of the event signature (`SENT_MESSAGE_EVENT_SIG` above),
    ///      the topic index of msgHash is 2.
    uint256 internal constant MSG_HASH_TOPIC_IDX = 2;

    /// @notice The index of the `messages` mapping in TelepathyStorage.sol.
    /// @dev We need this when calling `executeMessage` via storage proofs, as it is used in
    /// getting the slot key.
    uint256 internal constant MESSAGES_MAPPING_STORAGE_INDEX = 1;

    /// @notice Gets the length of the sourceChainIds array.
    /// @return The length of the sourceChainIds array.
    function sourceChainIdsLength() external view returns (uint256) {
        return sourceChainIds.length;
    }

    /// @notice Executes a message given a storage proof.
    /// @param slot Specifies which execution state root should be read from the light client.
    /// @param messageBytes The message we want to execute provided as bytes.
    /// @param accountProof Used to prove the broadcaster's state root.
    /// @param storageProof Used to prove the existence of the message root inside the broadcaster.
    function executeMessage(
        uint64 slot,
        bytes calldata messageBytes,
        bytes[] calldata accountProof,
        bytes[] calldata storageProof
    ) external nonReentrant {
        (Message memory message, bytes32 messageRoot) = _checkPreconditions(messageBytes);
        requireLightClientConsistency(message.sourceChainId);
        requireNotFrozen(message.sourceChainId);

        {
            requireLightClientDelay(slot, message.sourceChainId);

            bytes32 storageRoot;
            bytes32 cacheKey = keccak256(
                abi.encodePacked(message.sourceChainId, slot, broadcasters[message.sourceChainId])
            );

            // If the cache is empty for the cacheKey, then we get the
            // storageRoot using the provided accountProof.
            if (storageRootCache[cacheKey] == 0) {
                bytes32 executionStateRoot =
                    lightClients[message.sourceChainId].executionStateRoots(slot);
                require(executionStateRoot != 0, "Execution State Root is not set");
                storageRoot = StorageProof.getStorageRoot(
                    accountProof, broadcasters[message.sourceChainId], executionStateRoot
                );
                storageRootCache[cacheKey] = storageRoot;
            } else {
                storageRoot = storageRootCache[cacheKey];
            }

            bytes32 slotKey = keccak256(
                abi.encode(keccak256(abi.encode(message.nonce, MESSAGES_MAPPING_STORAGE_INDEX)))
            );
            uint256 slotValue = StorageProof.getStorageValue(slotKey, storageRoot, storageProof);

            if (bytes32(slotValue) != messageRoot) {
                revert("Invalid message hash.");
            }
        }

        _executeMessage(message, messageRoot, messageBytes);
    }

    /// @notice Executes a message given an event proof.
    /// @param srcSlotTxSlotPack The slot where we want to read the header from and the slot where
    ///                          the tx executed, packed as two uint64s.
    /// @param messageBytes The message we want to execute provided as bytes.
    /// @param receiptsRootProof A merkle proof proving the receiptsRoot in the block header.
    /// @param receiptsRoot The receipts root which contains our "SentMessage" event.
    /// @param txIndexRLPEncoded The index of our transaction inside the block RLP encoded.
    /// @param logIndex The index of the event in our transaction.
    function executeMessageFromLog(
        bytes calldata srcSlotTxSlotPack,
        bytes calldata messageBytes,
        bytes32[] calldata receiptsRootProof,
        bytes32 receiptsRoot,
        bytes[] calldata receiptProof,
        bytes memory txIndexRLPEncoded,
        uint256 logIndex
    ) external nonReentrant {
        // Verify receiptsRoot against header from light client
        (Message memory message, bytes32 messageRoot) = _checkPreconditions(messageBytes);
        requireLightClientConsistency(message.sourceChainId);
        requireNotFrozen(message.sourceChainId);

        {
            (uint64 srcSlot, uint64 txSlot) = abi.decode(srcSlotTxSlotPack, (uint64, uint64));
            requireLightClientDelay(srcSlot, message.sourceChainId);
            bytes32 headerRoot = lightClients[message.sourceChainId].headers(srcSlot);
            require(headerRoot != bytes32(0), "HeaderRoot is missing");
            bool isValid =
                SSZ.verifyReceiptsRoot(receiptsRoot, receiptsRootProof, headerRoot, srcSlot, txSlot);
            require(isValid, "Invalid receipts root proof");
        }

        {
            // TODO maybe we can save calldata by passing in the txIndex as a uint and rlp encode it
            // to derive txIndexRLPEncoded instead of passing in `bytes memory txIndexRLPEncoded`
            bytes32 receiptMessageRoot = bytes32(
                EventProof.getEventTopic(
                    receiptProof,
                    receiptsRoot,
                    txIndexRLPEncoded,
                    logIndex,
                    broadcasters[message.sourceChainId],
                    SENT_MESSAGE_EVENT_SIG,
                    MSG_HASH_TOPIC_IDX
                )
            );
            require(receiptMessageRoot == messageRoot, "Invalid message hash.");
        }

        _executeMessage(message, messageRoot, messageBytes);
    }

    /// @notice Checks that the light client for a given chainId is consistent.
    function requireLightClientConsistency(uint32 chainId) internal view {
        require(address(lightClients[chainId]) != address(0), "Light client is not set.");
        require(lightClients[chainId].consistent(), "Light client is inconsistent.");
    }

    /// @notice Checks that the chainId is not frozen.
    function requireNotFrozen(uint32 chainId) internal view {
        require(!frozen[chainId], "Contract is frozen.");
    }

    /// @notice Checks that the light client delay is adequate.
    function requireLightClientDelay(uint64 slot, uint32 chainId) internal view {
        require(address(lightClients[chainId]) != address(0), "Light client is not set.");
        require(lightClients[chainId].timestamps(slot) != 0, "Timestamp is not set for slot.");
        uint256 elapsedTime = block.timestamp - lightClients[chainId].timestamps(slot);
        require(elapsedTime >= MIN_LIGHT_CLIENT_DELAY, "Must wait longer to use this slot.");
    }

    /// @notice Decodes the message from messageBytes and checks conditions before message execution
    /// @param messageBytes The message we want to execute provided as bytes.
    function _checkPreconditions(bytes calldata messageBytes)
        internal
        view
        returns (Message memory, bytes32)
    {
        Message memory message = MessageEncoding.decode(messageBytes);
        bytes32 messageRoot = keccak256(messageBytes);

        if (messageStatus[messageRoot] != MessageStatus.NOT_EXECUTED) {
            revert("Message already executed.");
        } else if (message.recipientChainId != block.chainid) {
            revert("Wrong chain.");
        } else if (message.version != version) {
            revert("Wrong version.");
        } else if (
            address(lightClients[message.sourceChainId]) == address(0)
                || broadcasters[message.sourceChainId] == address(0)
        ) {
            revert("Light client or broadcaster for source chain is not set");
        }
        return (message, messageRoot);
    }

    /// @notice Executes a message and updates storage with status and emits an event.
    /// @dev Assumes that the message is valid and has not been already executed.
    /// @dev Assumes that message, messageRoot and messageBytes have already been validated.
    /// @param message The message we want to execute.
    /// @param messageRoot The message root of the message.
    /// @param messageBytes The message we want to execute provided as bytes for use in the event.
    function _executeMessage(Message memory message, bytes32 messageRoot, bytes memory messageBytes)
        internal
    {
        bool status;
        bytes memory data;
        {
            bytes memory receiveCall = abi.encodeWithSelector(
                ITelepathyHandler.handleTelepathy.selector,
                message.sourceChainId,
                message.senderAddress,
                message.data
            );
            address recipient = Address.fromBytes32(message.recipientAddress);
            (status, data) = recipient.call(receiveCall);
        }

        // Unfortunately, there are some edge cases where a call may have a successful status but
        // not have actually called the handler. Thus, we enforce that the handler must return
        // a magic constant that we can check here. To avoid stack underflow / decoding errors, we
        // only decode the returned bytes if one EVM word was returned by the call.
        bool implementsHandler = false;
        if (data.length == 32) {
            (bytes4 magic) = abi.decode(data, (bytes4));
            implementsHandler = magic == ITelepathyHandler.handleTelepathy.selector;
        }

        if (status && implementsHandler) {
            messageStatus[messageRoot] = MessageStatus.EXECUTION_SUCCEEDED;
        } else {
            messageStatus[messageRoot] = MessageStatus.EXECUTION_FAILED;
        }

        emit ExecutedMessage(
            message.sourceChainId, message.nonce, messageRoot, messageBytes, status
        );
    }
}

File 24 of 31 : TelepathyAccess.sol
pragma solidity 0.8.16;

import {AccessControlUpgradeable} from
    "openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol";

import {ILightClient} from "src/lightclient/interfaces/ILightClient.sol";
import {TelepathyStorage} from "./TelepathyStorage.sol";

contract TelepathyAccess is TelepathyStorage, AccessControlUpgradeable {
    /// @notice Emitted when the sendingEnabled flag is changed.
    event SendingEnabled(bool enabled);

    /// @notice Emitted when freezeAll is called.
    event FreezeAll();

    /// @notice Emitted when freeze is called.
    event Freeze(uint32 indexed chainId);

    /// @notice Emitted when unfreezeAll is called.
    event UnfreezeAll();

    /// @notice Emitted when unfreeze is called.
    event Unfreeze(uint32 indexed chainId);

    /// @notice Emitted when setLightClientAndBroadcaster is called.
    event SetLightClientAndBroadcaster(
        uint32 indexed chainId, address lightClient, address broadcaster
    );

    /// @notice Emitted when a new source chain is added.
    event SourceChainAdded(uint32 indexed chainId);

    /// @notice A random constant used to identify addresses with the permission of a 'guardian'.
    bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");

    /// @notice A random constant used to identify addresses with the permission of a 'timelock'.
    bytes32 public constant TIMELOCK_ROLE = keccak256("TIMELOCK_ROLE");

    modifier onlyAdmin() {
        require(
            hasRole(DEFAULT_ADMIN_ROLE, msg.sender),
            "TelepathyRouter: only admin can call this function"
        );
        _;
    }

    modifier onlyTimelock() {
        require(
            hasRole(TIMELOCK_ROLE, msg.sender),
            "TelepathyRouter: only timelock can call this function"
        );
        _;
    }

    modifier onlyGuardian() {
        require(
            hasRole(GUARDIAN_ROLE, msg.sender),
            "TelepathyRouter: only guardian can call this function"
        );
        _;
    }

    /// @notice Allows the owner to control whether sending is enabled or not.
    function setSendingEnabled(bool enabled) external onlyGuardian {
        sendingEnabled = enabled;
        emit SendingEnabled(enabled);
    }

    /// @notice Freezes messages from all chains.
    /// @dev This is a safety mechanism to prevent the contract from being used after a security
    ///      vulnerability is detected.
    function freezeAll() external onlyGuardian {
        for (uint32 i = 0; i < sourceChainIds.length; i++) {
            frozen[sourceChainIds[i]] = true;
        }
        emit FreezeAll();
    }

    /// @notice Freezes messages from the specified chain.
    /// @dev This is a safety mechanism to prevent the contract from being used after a security
    ///      vulnerability is detected.
    function freeze(uint32 chainId) external onlyGuardian {
        frozen[chainId] = true;
        emit Freeze(chainId);
    }

    /// @notice Unfreezes messages from the specified chain.
    /// @dev This is a safety mechanism to continue usage of the contract after a security
    ///      vulnerability is patched.
    function unfreeze(uint32 chainId) external onlyGuardian {
        frozen[chainId] = false;
        emit Unfreeze(chainId);
    }

    /// @notice Unfreezes messages from all chains.
    /// @dev This is a safety mechanism to continue usage of the contract after a security
    ///      vulnerability is patched.
    function unfreezeAll() external onlyGuardian {
        for (uint32 i = 0; i < sourceChainIds.length; i++) {
            frozen[sourceChainIds[i]] = false;
        }
        emit UnfreezeAll();
    }

    /// @notice Sets the light client contract and broadcaster for a given chainId.
    /// @dev This is controlled by the timelock as it is a potentially dangerous method
    ///      since both the light client and broadcaster address are critical in verifying
    ///      that only valid sent messages are executed.
    function setLightClientAndBroadcaster(uint32 chainId, address lightclient, address broadcaster)
        external
        onlyTimelock
    {
        bool chainIdExists = false;
        for (uint256 i = 0; i < sourceChainIds.length; i++) {
            if (sourceChainIds[i] == chainId) {
                chainIdExists = true;
                break;
            }
        }
        if (!chainIdExists) {
            sourceChainIds.push(chainId);
            emit SourceChainAdded(chainId);
        }
        lightClients[chainId] = ILightClient(lightclient);
        broadcasters[chainId] = broadcaster;
        emit SetLightClientAndBroadcaster(chainId, lightclient, broadcaster);
    }
}

File 25 of 31 : TelepathyStorage.sol
pragma solidity 0.8.16;

import {ILightClient} from "src/lightclient/interfaces/ILightClient.sol";
import {MessageStatus} from "./interfaces/ITelepathy.sol";

contract TelepathyStorage {
    /*//////////////////////////////////////////////////////////////
                           BROADCASTER STORAGE
    //////////////////////////////////////////////////////////////*/

    /// @notice Whether sending is enabled or not.
    bool public sendingEnabled;

    /// @notice Mapping between a nonce and a message root.
    mapping(uint64 => bytes32) public messages;

    /// @notice Keeps track of the next nonce to be used.
    uint64 public nonce;

    /*//////////////////////////////////////////////////////////////
                           RECEIVER STORAGE
    //////////////////////////////////////////////////////////////*/

    /// @notice All sourceChainIds.
    uint32[] public sourceChainIds;

    /// @notice Mapping between source chainId and the corresponding light client.
    mapping(uint32 => ILightClient) public lightClients;

    /// @notice Mapping between source chainId and the address of the Telepathy broadcaster on that chain.
    mapping(uint32 => address) public broadcasters;

    /// @notice Mapping between a source chainId and whether it's frozen.
    mapping(uint32 => bool) public frozen;

    /// @notice Mapping between a message root and its status.
    mapping(bytes32 => MessageStatus) public messageStatus;

    /*//////////////////////////////////////////////////////////////
                           SHARED STORAGE
    //////////////////////////////////////////////////////////////*/

    /// @notice Returns current contract version.
    uint8 public version;

    /*//////////////////////////////////////////////////////////////
                        RECEIVER STORAGE V2
    //////////////////////////////////////////////////////////////*/

    /// @notice Storage root cache.
    mapping(bytes32 => bytes32) public storageRootCache;

    /// @dev This empty reserved space is put in place to allow future versions to add new variables
    /// without shifting down storage in the inheritance chain.
    /// See: https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#storage-gaps
    uint256[40] private __gap;
}

File 26 of 31 : ITelepathy.sol
pragma solidity ^0.8.0;

enum MessageStatus {
    NOT_EXECUTED,
    EXECUTION_FAILED,
    EXECUTION_SUCCEEDED
}

struct Message {
    uint8 version;
    uint64 nonce;
    uint32 sourceChainId;
    address senderAddress;
    uint32 recipientChainId;
    bytes32 recipientAddress;
    bytes data;
}

interface ITelepathyRouter {
    event SentMessage(uint64 indexed nonce, bytes32 indexed msgHash, bytes message);

    function send(uint32 recipientChainId, bytes32 recipientAddress, bytes calldata data)
        external
        returns (bytes32);

    function send(uint32 recipientChainId, address recipientAddress, bytes calldata data)
        external
        returns (bytes32);

    function sendViaStorage(uint32 recipientChainId, bytes32 recipientAddress, bytes calldata data)
        external
        returns (bytes32);

    function sendViaStorage(uint32 recipientChainId, address recipientAddress, bytes calldata data)
        external
        returns (bytes32);
}

interface ITelepathyReceiver {
    event ExecutedMessage(
        uint32 indexed sourceChainId,
        uint64 indexed nonce,
        bytes32 indexed msgHash,
        bytes message,
        bool status
    );

    function executeMessage(
        uint64 slot,
        bytes calldata message,
        bytes[] calldata accountProof,
        bytes[] calldata storageProof
    ) external;

    function executeMessageFromLog(
        bytes calldata srcSlotTxSlotPack,
        bytes calldata messageBytes,
        bytes32[] calldata receiptsRootProof,
        bytes32 receiptsRoot,
        bytes[] calldata receiptProof, // receipt proof against receipt root
        bytes memory txIndexRLPEncoded,
        uint256 logIndex
    ) external;
}

interface ITelepathyHandler {
    function handleTelepathy(uint32 _sourceChainId, address _senderAddress, bytes memory _data)
        external
        returns (bytes4);
}

File 27 of 31 : MessageEncoding.sol
pragma solidity 0.8.16;

import {Message} from "src/amb/interfaces/ITelepathy.sol";

// From here: https://stackoverflow.com/questions/74443594/how-to-slice-bytes-memory-in-solidity
library BytesLib {
    function slice(bytes memory _bytes, uint256 _start, uint256 _length)
        internal
        pure
        returns (bytes memory)
    {
        require(_length + 31 >= _length, "slice_overflow");
        require(_bytes.length >= _start + _length, "slice_outOfBounds");

        bytes memory tempBytes;

        // Check length is 0. `iszero` return 1 for `true` and 0 for `false`.
        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // Calculate length mod 32 to handle slices that are not a multiple of 32 in size.
                let lengthmod := and(_length, 31)

                // tempBytes will have the following format in memory: <length><data>
                // When copying data we will offset the start forward to avoid allocating additional memory
                // Therefore part of the length area will be written, but this will be overwritten later anyways.
                // In case no offset is require, the start is set to the data region (0x20 from the tempBytes)
                // mc will be used to keep track where to copy the data to.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // Same logic as for mc is applied and additionally the start offset specified for the method is added
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    // increase `mc` and `cc` to read the next word from memory
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    // Copy the data from source (cc location) to the slice data (mc location)
                    mstore(mc, mload(cc))
                }

                // Store the length of the slice. This will overwrite any partial data that
                // was copied when having slices that are not a multiple of 32.
                mstore(tempBytes, _length)

                // update free-memory pointer
                // allocating the array padded to 32 bytes like the compiler does now
                // To set the used memory as a multiple of 32, add 31 to the actual memory usage (mc)
                // and remove the modulo 32 (the `and` with `not(31)`)
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            // if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)
                // zero out the 32 bytes slice we are about to return
                // we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                // update free-memory pointer
                // tempBytes uses 32 bytes in memory (even when empty) for the length.
                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }
}

library MessageEncoding {
    function encode(Message memory message) internal pure returns (bytes memory data) {
        data = abi.encodePacked(
            message.version,
            message.nonce,
            message.sourceChainId,
            message.senderAddress,
            message.recipientChainId,
            message.recipientAddress,
            message.data
        );
    }

    function encode(
        uint8 version,
        uint64 nonce,
        uint32 sourceChainId,
        address senderAddress,
        uint32 recipientChainId,
        bytes32 recipientAddress,
        bytes memory data
    ) internal pure returns (bytes memory) {
        return abi.encodePacked(
            version, nonce, sourceChainId, senderAddress, recipientChainId, recipientAddress, data
        );
    }

    function decode(bytes memory data) internal pure returns (Message memory message) {
        uint8 version;
        uint64 nonce; // 64 / 8 = 8
        uint32 sourceChainId; // 32 / 8 = 4
        address senderAddress; // 20 bytes
        uint32 recipientChainId; // 4 bytes
        bytes32 recipientAddress; // 32
        // 8 + 4 + 20 + 4 + 32 = 68
        assembly {
            version := mload(add(data, 1))

            nonce := mload(add(data, 9))

            sourceChainId := mload(add(data, 13))

            senderAddress := mload(add(data, 33))

            recipientChainId := mload(add(data, 37))

            recipientAddress := mload(add(data, 69))
        }
        message.version = version;
        message.nonce = nonce;
        message.sourceChainId = sourceChainId;
        message.senderAddress = senderAddress;
        message.recipientChainId = recipientChainId;
        message.recipientAddress = recipientAddress;
        message.data = BytesLib.slice(data, 69, data.length - 69);
    }
}

File 28 of 31 : SimpleSerialize.sol
pragma solidity 0.8.16;

struct BeaconBlockHeader {
    uint64 slot;
    uint64 proposerIndex;
    bytes32 parentRoot;
    bytes32 stateRoot;
    bytes32 bodyRoot;
}

library SSZ {
    uint256 internal constant HISTORICAL_ROOTS_LIMIT = 16777216;
    uint256 internal constant SLOTS_PER_HISTORICAL_ROOT = 8192;

    function toLittleEndian(uint256 v) internal pure returns (bytes32) {
        v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8)
            | ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8);
        v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16)
            | ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16);
        v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32)
            | ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32);
        v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64)
            | ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64);
        v = (v >> 128) | (v << 128);
        return bytes32(v);
    }

    function restoreMerkleRoot(bytes32 leaf, uint256 index, bytes32[] memory branch)
        internal
        pure
        returns (bytes32)
    {
        require(2 ** (branch.length + 1) > index);
        bytes32 value = leaf;
        uint256 i = 0;
        while (index != 1) {
            if (index % 2 == 1) {
                value = sha256(bytes.concat(branch[i], value));
            } else {
                value = sha256(bytes.concat(value, branch[i]));
            }
            index /= 2;
            i++;
        }
        return value;
    }

    function isValidMerkleBranch(bytes32 leaf, uint256 index, bytes32[] memory branch, bytes32 root)
        internal
        pure
        returns (bool)
    {
        bytes32 restoredMerkleRoot = restoreMerkleRoot(leaf, index, branch);
        return root == restoredMerkleRoot;
    }

    function sszBeaconBlockHeader(BeaconBlockHeader memory header)
        internal
        pure
        returns (bytes32)
    {
        bytes32 left = sha256(
            bytes.concat(
                sha256(
                    bytes.concat(toLittleEndian(header.slot), toLittleEndian(header.proposerIndex))
                ),
                sha256(bytes.concat(header.parentRoot, header.stateRoot))
            )
        );
        bytes32 right = sha256(
            bytes.concat(
                sha256(bytes.concat(header.bodyRoot, bytes32(0))),
                sha256(bytes.concat(bytes32(0), bytes32(0)))
            )
        );

        return sha256(bytes.concat(left, right));
    }

    function computeDomain(bytes4 forkVersion, bytes32 genesisValidatorsRoot)
        internal
        pure
        returns (bytes32)
    {
        return bytes32(uint256(0x07 << 248))
            | (sha256(abi.encode(forkVersion, genesisValidatorsRoot)) >> 32);
    }

    function verifyReceiptsRoot(
        bytes32 receiptsRoot,
        bytes32[] memory receiptsRootProof,
        bytes32 headerRoot,
        uint64 srcSlot,
        uint64 txSlot
    ) internal pure returns (bool) {
        uint256 index;
        if (srcSlot == txSlot) {
            index = 8 + 3;
            index = index * 2 ** 9 + 387;
        } else if (srcSlot - txSlot <= SLOTS_PER_HISTORICAL_ROOT) {
            index = 8 + 3;
            index = index * 2 ** 5 + 6;
            index = index * SLOTS_PER_HISTORICAL_ROOT + txSlot % SLOTS_PER_HISTORICAL_ROOT;
            index = index * 2 ** 9 + 387;
        } else if (txSlot < srcSlot) {
            index = 8 + 3;
            index = index * 2 ** 5 + 7;
            index = index * 2 + 0;
            index = index * HISTORICAL_ROOTS_LIMIT + txSlot / SLOTS_PER_HISTORICAL_ROOT;
            index = index * 2 + 1;
            index = index * SLOTS_PER_HISTORICAL_ROOT + txSlot % SLOTS_PER_HISTORICAL_ROOT;
            index = index * 2 ** 9 + 387;
        } else {
            revert("TrustlessAMB: invalid target slot");
        }
        return isValidMerkleBranch(receiptsRoot, index, receiptsRootProof, headerRoot);
    }
}

File 29 of 31 : StateProofHelper.sol
pragma solidity 0.8.16;

import {RLPReader} from "@optimism-bedrock/rlp/RLPReader.sol";
import {RLPWriter} from "@optimism-bedrock/rlp/RLPWriter.sol";
import {MerkleTrie} from "@optimism-bedrock/trie/MerkleTrie.sol";

library StorageProof {
    using RLPReader for RLPReader.RLPItem;
    using RLPReader for bytes;

    function getStorageValue(bytes32 slotHash, bytes32 storageRoot, bytes[] memory _stateProof)
        internal
        pure
        returns (uint256)
    {
        bytes memory valueRlpBytes =
            MerkleTrie.get(abi.encodePacked(slotHash), _stateProof, storageRoot);
        require(valueRlpBytes.length > 0, "Storage value does not exist");
        return valueRlpBytes.toRLPItem().readUint256();
    }

    function getStorageRoot(bytes[] memory proof, address contractAddress, bytes32 stateRoot)
        internal
        pure
        returns (bytes32)
    {
        bytes32 addressHash = keccak256(abi.encodePacked(contractAddress));
        bytes memory acctRlpBytes = MerkleTrie.get(abi.encodePacked(addressHash), proof, stateRoot);
        require(acctRlpBytes.length > 0, "Account does not exist");
        RLPReader.RLPItem[] memory acctFields = acctRlpBytes.toRLPItem().readList();
        require(acctFields.length == 4);
        return bytes32(acctFields[2].readUint256());
    }
}

library EventProof {
    using RLPReader for RLPReader.RLPItem;
    using RLPReader for bytes;

    function getEventTopic(
        bytes[] memory proof,
        bytes32 receiptRoot,
        bytes memory key,
        uint256 logIndex,
        address claimedEmitter,
        bytes32 eventSignature,
        uint256 topicIndex
    ) internal pure returns (bytes32) {
        bytes memory value = MerkleTrie.get(key, proof, receiptRoot);
        bytes1 txTypeOrFirstByte = value[0];

        // Currently, there are three possible transaction types on Ethereum. Receipts either come
        // in the form "TransactionType | ReceiptPayload" or "ReceiptPayload". The currently
        // supported set of transaction types are 0x01 and 0x02. In this case, we must truncate
        // the first byte to access the payload. To detect the other case, we can use the fact
        // that the first byte of a RLP-encoded list will always be greater than 0xc0.
        // Reference 1: https://eips.ethereum.org/EIPS/eip-2718
        // Reference 2: https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp
        uint256 offset;
        if (txTypeOrFirstByte == 0x01 || txTypeOrFirstByte == 0x02) {
            offset = 1;
        } else if (txTypeOrFirstByte >= 0xc0) {
            offset = 0;
        } else {
            revert("Unsupported transaction type");
        }

        // Truncate the first byte if eneded and get the RLP decoding of the receipt.
        uint256 ptr;
        assembly {
            ptr := add(value, 32)
        }
        RLPReader.RLPItem memory valueAsItem = RLPReader.RLPItem({
            length: value.length - offset,
            ptr: RLPReader.MemoryPointer.wrap(ptr + offset)
        });

        // The length of the receipt must be at least four, as the fourth entry contains events
        RLPReader.RLPItem[] memory valueAsList = valueAsItem.readList();
        require(valueAsList.length == 4, "Invalid receipt length");

        // Read the logs from the receipts and check that it is not ill-formed
        RLPReader.RLPItem[] memory logs = valueAsList[3].readList();
        require(logIndex < logs.length, "Log index out of bounds");
        RLPReader.RLPItem[] memory relevantLog = logs[logIndex].readList();
        require(relevantLog.length == 3, "Log has incorrect number of fields");

        // Validate that the correct contract emitted the event
        address contractAddress = relevantLog[0].readAddress();
        require(contractAddress == claimedEmitter, "Event was not emitted by claimedEmitter");
        RLPReader.RLPItem[] memory topics = relevantLog[1].readList();

        // Validate that the correct event was emitted by checking the event signature
        require(
            bytes32(topics[0].readUint256()) == eventSignature,
            "Event signature does not match eventSignature"
        );

        return topics[topicIndex].readBytes32();
    }
}

File 30 of 31 : Typecast.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.16;

library Address {
    function fromBytes32(bytes32 buffer) internal pure returns (address) {
        return address(uint160(uint256(buffer)));
    }
}

library Bytes32 {
    function fromAddress(address addr) internal pure returns (bytes32) {
        return bytes32(uint256(uint160(addr)));
    }
}

File 31 of 31 : ILightClient.sol
pragma solidity ^0.8.0;

interface ILightClient {
    function consistent() external view returns (bool);

    function head() external view returns (uint256);

    function headers(uint256 slot) external view returns (bytes32);

    function executionStateRoots(uint256 slot) external view returns (bytes32);

    function timestamps(uint256 slot) external view returns (uint256);
}

Settings
{
  "remappings": [
    "@optimism-bedrock/=lib/optimism-bedrock-contracts/",
    "@uniswap/=lib/",
    "Solidity-RLP/=lib/Solidity-RLP/contracts/",
    "curve-merkle-oracle/=lib/curve-merkle-oracle/contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "optimism-bedrock-contracts/=lib/optimism-bedrock-contracts/",
    "v3-core/=lib/v3-core/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"sourceChainId","type":"uint32"},{"indexed":true,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"ExecutedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"Freeze","type":"event"},{"anonymous":false,"inputs":[],"name":"FreezeAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"SendingEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"SentMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"chainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"lightClient","type":"address"},{"indexed":false,"internalType":"address","name":"broadcaster","type":"address"}],"name":"SetLightClientAndBroadcaster","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"SourceChainAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"Unfreeze","type":"event"},{"anonymous":false,"inputs":[],"name":"UnfreezeAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARDIAN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LIGHT_CLIENT_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMELOCK_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"broadcasters","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"slot","type":"uint64"},{"internalType":"bytes","name":"messageBytes","type":"bytes"},{"internalType":"bytes[]","name":"accountProof","type":"bytes[]"},{"internalType":"bytes[]","name":"storageProof","type":"bytes[]"}],"name":"executeMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"srcSlotTxSlotPack","type":"bytes"},{"internalType":"bytes","name":"messageBytes","type":"bytes"},{"internalType":"bytes32[]","name":"receiptsRootProof","type":"bytes32[]"},{"internalType":"bytes32","name":"receiptsRoot","type":"bytes32"},{"internalType":"bytes[]","name":"receiptProof","type":"bytes[]"},{"internalType":"bytes","name":"txIndexRLPEncoded","type":"bytes"},{"internalType":"uint256","name":"logIndex","type":"uint256"}],"name":"executeMessageFromLog","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"freeze","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"freezeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"frozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"_sourceChainIds","type":"uint32[]"},{"internalType":"address[]","name":"_lightClients","type":"address[]"},{"internalType":"address[]","name":"_broadcasters","type":"address[]"},{"internalType":"address","name":"_timelock","type":"address"},{"internalType":"address","name":"_guardian","type":"address"},{"internalType":"bool","name":"_sendingEnabled","type":"bool"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"lightClients","outputs":[{"internalType":"contract ILightClient","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"messageStatus","outputs":[{"internalType":"enum MessageStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"messages","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"recipientChainId","type":"uint32"},{"internalType":"address","name":"recipientAddress","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"send","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"recipientChainId","type":"uint32"},{"internalType":"bytes32","name":"recipientAddress","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"send","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"recipientChainId","type":"uint32"},{"internalType":"address","name":"recipientAddress","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"sendViaStorage","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"recipientChainId","type":"uint32"},{"internalType":"bytes32","name":"recipientAddress","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"sendViaStorage","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sendingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"},{"internalType":"address","name":"lightclient","type":"address"},{"internalType":"address","name":"broadcaster","type":"address"}],"name":"setLightClientAndBroadcaster","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setSendingEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"sourceChainIds","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sourceChainIdsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"storageRootCache","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"unfreeze","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfreezeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"}]

60a0604052306080523480156200001557600080fd5b506200002062000026565b620000e8565b603254610100900460ff1615620000935760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60325460ff9081161015620000e6576032805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b608051615f3662000120600039600081816109f701528181610a3701528181610d9f01528181610ddf0152610e6e0152615f366000f3fe6080604052600436106102255760003560e01c806366c5c4a0116101235780639a2ed203116100ab578063d547741f1161006f578063d547741f146106fb578063e4407b151461071b578063ed762d4414610730578063f288a2e214610750578063ffa1ad741461077257600080fd5b80639a2ed203146106395780639efeff1c14610659578063a217fddf1461068e578063a96a2e92146106a3578063affed0e0146106c357600080fd5b80637acc6754116100f25780637acc6754146105975780638d080d1d146105b757806391cd8bfd146105e457806391d148541461060457806399464c891461062457600080fd5b806366c5c4a01461050c57806368346a92146105215780636fdbccbf146105415780637599735c1461056157600080fd5b806336ae7c18116101b15780634f1ef286116101755780634f1ef2861461044a57806352d1902d1461045d57806354fd4d501461047257806359f897871461049e5780635cb77819146104ec57600080fd5b806336ae7c181461038e57806337d5af84146103be5780633c6cf473146103de5780633e99e9ce1461041b5780634552f5631461043557600080fd5b8063248a9ca3116101f8578063248a9ca3146102dc57806324ea54f41461030c5780632f2ff15d1461032e57806336568abe1461034e5780633659cfe61461036e57600080fd5b806301ffc9a71461022a578063029d67131461025f578063147bce491461029a5780631f3d25a9146102ba575b600080fd5b34801561023657600080fd5b5061024a610245366004614f74565b610787565b60405190151581526020015b60405180910390f35b34801561026b57600080fd5b5061028c61027a366004614fad565b60016020526000908152604090205481565b604051908152602001610256565b3480156102a657600080fd5b5061028c6102b5366004615034565b6107be565b3480156102c657600080fd5b506102da6102d5366004615094565b6108cb565b005b3480156102e857600080fd5b5061028c6102f73660046150af565b600090815260c9602052604090206001015490565b34801561031857600080fd5b5061028c600080516020615ee183398151915281565b34801561033a57600080fd5b506102da6103493660046150c8565b610945565b34801561035a57600080fd5b506102da6103693660046150c8565b61096f565b34801561037a57600080fd5b506102da6103893660046150f4565b6109ed565b34801561039a57600080fd5b5061024a6103a9366004615094565b60066020526000908152604090205460ff1681565b3480156103ca57600080fd5b506102da6103d9366004615208565b610acc565b3480156103ea57600080fd5b5061040e6103f93660046150af565b60076020526000908152604090205460ff1681565b604051610256919061531b565b34801561042757600080fd5b5060005461024a9060ff1681565b34801561044157600080fd5b5060035461028c565b6102da610458366004615343565b610d95565b34801561046957600080fd5b5061028c610e61565b34801561047e57600080fd5b5060085461048c9060ff1681565b60405160ff9091168152602001610256565b3480156104aa57600080fd5b506104d46104b9366004615094565b6005602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610256565b3480156104f857600080fd5b506102da61050736600461543e565b610f14565b34801561051857600080fd5b506102da611217565b34801561052d57600080fd5b5061028c61053c366004615034565b6112fc565b34801561054d57600080fd5b5061028c61055c366004615552565b61137b565b34801561056d57600080fd5b506104d461057c366004615094565b6004602052600090815260409020546001600160a01b031681565b3480156105a357600080fd5b506102da6105b2366004615593565b6113d2565b3480156105c357600080fd5b5061028c6105d23660046150af565b60096020526000908152604090205481565b3480156105f057600080fd5b506102da6105ff36600461563d565b6116e7565b34801561061057600080fd5b5061024a61061f3660046150c8565b611898565b34801561063057600080fd5b506102da6118c3565b34801561064557600080fd5b506102da610654366004615094565b6119a8565b34801561066557600080fd5b506106796106743660046150af565b611a25565b60405163ffffffff9091168152602001610256565b34801561069a57600080fd5b5061028c600081565b3480156106af57600080fd5b5061028c6106be366004615552565b611a5f565b3480156106cf57600080fd5b506002546106e3906001600160401b031681565b6040516001600160401b039091168152602001610256565b34801561070757600080fd5b506102da6107163660046150c8565b611ab6565b34801561072757600080fd5b5061028c607881565b34801561073c57600080fd5b506102da61074b366004615680565b611adb565b34801561075c57600080fd5b5061028c600080516020615e5a83398151915281565b34801561077e57600080fd5b5061048c600181565b60006001600160e01b03198216637965db0b60e01b14806107b857506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805460ff166107ea5760405162461bcd60e51b81526004016107e19061569d565b60405180910390fd5b468563ffffffff160361080f5760405162461bcd60e51b81526004016107e1906156ca565b600080610828876001600160a01b0388165b8787611b56565b600280546001600160401b03908116600090815260016020526040812084905582549496509294508493169161085d83615717565b91906101000a8154816001600160401b0302191690836001600160401b031602179055506001600160401b03167fe5944a34d67c652e0ebf2304b48432aae0b55e40f79ba8a21a4d7054c169ffac846040516108b9919061578d565b60405180910390a39695505050505050565b6108e3600080516020615ee183398151915233611898565b6108ff5760405162461bcd60e51b81526004016107e1906157a0565b63ffffffff8116600081815260066020526040808220805460ff19169055517f9fd67bd682613b07687b42f99d8b24402d09feabb75df93abdb26b8fcf9845839190a250565b600082815260c9602052604090206001015461096081611bcd565b61096a8383611bd7565b505050565b6001600160a01b03811633146109df5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016107e1565b6109e98282611c5d565b5050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610a355760405162461bcd60e51b81526004016107e1906157f5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610a7e600080516020615e9a833981519152546001600160a01b031690565b6001600160a01b031614610aa45760405162461bcd60e51b81526004016107e190615841565b610aad81611cc4565b60408051600080825260208201909252610ac991839190611cf8565b50565b610ad4611e63565b600080610ae18b8b611ebc565b91509150610af28260400151612126565b610aff8260400151612255565b6000808e8e810190610b11919061588d565b91509150610b238285604001516122b1565b60408481015163ffffffff166000908152600460208190528282205492516356f90d7960e01b81526001600160401b0386169181019190915290916001600160a01b0316906356f90d7990602401602060405180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb291906158b7565b905080610bf95760405162461bcd60e51b8152602060048201526015602482015274486561646572526f6f74206973206d697373696e6760581b60448201526064016107e1565b6000610c3d8b8e8e808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508792508991508890506124e5565b905080610c8c5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726563656970747320726f6f742070726f6f66000000000060448201526064016107e1565b505050506000610cf1878790610ca291906158d0565b60408086015163ffffffff166000908152600560205220548a90889088906001600160a01b03167fe5944a34d67c652e0ebf2304b48432aae0b55e40f79ba8a21a4d7054c169ffac600261268d565b9050818114610d3a5760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b21036b2b9b9b0b3b2903430b9b41760591b60448201526064016107e1565b50610d7c82828d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a4092505050565b5050610d886001603355565b5050505050505050505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610ddd5760405162461bcd60e51b81526004016107e1906157f5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610e26600080516020615e9a833981519152546001600160a01b031690565b6001600160a01b031614610e4c5760405162461bcd60e51b81526004016107e190615841565b610e5582611cc4565b6109e982826001611cf8565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f015760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016107e1565b50600080516020615e9a83398151915290565b603254610100900460ff1615808015610f345750603254600160ff909116105b80610f4e5750303b158015610f4e575060325460ff166001145b610fb15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016107e1565b6032805460ff191660011790558015610fd4576032805461ff0019166101001790555b610fdc612bee565b610fe4612c1f565b610ffc600080516020615ee183398151915284611bd7565b611014600080516020615e5a83398151915285611bd7565b61101f600085611bd7565b611027612c1f565b855187511461103557600080fd5b845187511461104357600080fd5b86516110569060039060208a0190614e9a565b5060005b60035463ffffffff821610156111aa57868163ffffffff168151811061108257611082615937565b60200260200101516004600060038463ffffffff16815481106110a7576110a7615937565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550858163ffffffff168151811061112357611123615937565b60200260200101516005600060038463ffffffff168154811061114857611148615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff168352820192909252604001902080546001600160a01b0319166001600160a01b0392909216919091179055806111a28161594d565b91505061105a565b506000805483151560ff1991821617909155600880549091166001179055801561120e576032805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b61122f600080516020615ee183398151915233611898565b61124b5760405162461bcd60e51b81526004016107e1906157a0565b60005b60035463ffffffff821610156112d05760006006600060038463ffffffff168154811061127d5761127d615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff1683528201929092526040019020805460ff1916911515919091179055806112c88161594d565b91505061124e565b506040517fe6fdbf73945dd61794a752b9181ea29f77170a7b1ffd37e0a7ff9d2c6f7258b990600090a1565b6000805460ff1661131f5760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff16036113445760405162461bcd60e51b81526004016107e1906156ca565b60008061135a876001600160a01b038816610821565b6002805492945090925082916001600160401b031690600061085d83615717565b6000805460ff1661139e5760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff16036113c35760405162461bcd60e51b81526004016107e1906156ca565b60008061082887878787611b56565b6113da611e63565b6000806113e78888611ebc565b915091506113f88260400151612126565b6114058260400151612255565b6114138983604001516122b1565b60408281015163ffffffff811660009081526005602090815283822054845160e09490941b6001600160e01b0319168483015260c08e901b6001600160c01b031916602485015260601b6001600160601b031916602c840152835180840382018152928401845282519281019290922080825260099092529182205482036115c55760408085015163ffffffff16600090815260046020819052828220549251637623ee2960e01b81526001600160401b038f169181019190915290916001600160a01b031690637623ee2990602401602060405180830381865afa158015611500573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152491906158b7565b905060008190036115775760405162461bcd60e51b815260206004820152601f60248201527f457865637574696f6e20537461746520526f6f74206973206e6f74207365740060448201526064016107e1565b6115ab611584898b6158d0565b60408088015163ffffffff166000908152600560205220546001600160a01b031683612c46565b600083815260096020526040902081905592506115d79050565b60008181526009602052604090205491505b6000846020015160016040516020016116059291906001600160401b03929092168252602082015260400190565b60408051808303601f1901815282825280516020918201208184015281518084038201815292820190915281519101209050600061164d82856116488a8c6158d0565b612d3d565b90508481146116965760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b21036b2b9b9b0b3b2903430b9b41760591b60448201526064016107e1565b505050506116db82828a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a4092505050565b505061120e6001603355565b6116ff600080516020615e5a83398151915233611898565b61171b5760405162461bcd60e51b81526004016107e190615966565b6000805b600354811015611787578463ffffffff166003828154811061174357611743615937565b6000918252602090912060088204015460079091166004026101000a900463ffffffff16036117755760019150611787565b8061177f816159bb565b91505061171f565b508061181057600380546001810182556000918252600881047fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01805463ffffffff80891660046007909516949094026101000a84810291021990911617905560405190917f65a791dc0a39717013964ace2b78f8307f275c293b7fdb425346ce8e18cb318891a25b63ffffffff8416600081815260046020908152604080832080546001600160a01b038981166001600160a01b031992831681179093556005855294839020805495891695909116851790558151908152918201929092527f0205eaadbbed4fbe918b2a594d41bceb212a89010cc678c6762b18d65679b2ef910160405180910390a250505050565b600091825260c9602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6118db600080516020615ee183398151915233611898565b6118f75760405162461bcd60e51b81526004016107e1906157a0565b60005b60035463ffffffff8216101561197c5760016006600060038463ffffffff168154811061192957611929615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff1683528201929092526040019020805460ff1916911515919091179055806119748161594d565b9150506118fa565b506040517f61340a1b154d5d21d259a74bf95379201799b9d12cc6509bb46cb56dc281df5590600090a1565b6119c0600080516020615ee183398151915233611898565b6119dc5760405162461bcd60e51b81526004016107e1906157a0565b63ffffffff8116600081815260066020526040808220805460ff19166001179055517ff6cf9095f1dcea2429c26c832cbcc084fa0a1692b2c301601edd75b9d83520b29190a250565b60038181548110611a3557600080fd5b9060005260206000209060089182820401919006600402915054906101000a900463ffffffff1681565b6000805460ff16611a825760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff1603611aa75760405162461bcd60e51b81526004016107e1906156ca565b60008061135a87878787611b56565b600082815260c96020526040902060010154611ad181611bcd565b61096a8383611c5d565b611af3600080516020615ee183398151915233611898565b611b0f5760405162461bcd60e51b81526004016107e1906157a0565b6000805460ff19168215159081179091556040519081527f3eea1dc6ce990571e1081137b38c853529a3893b52e9719a48a2f4ac5e3a956c9060200160405180910390a150565b600854600254604080516020601f8601819004810282018101909252848152606093600093611bb99360ff909216926001600160401b0390911691469133918c918c918c908c9081908401838280828437600092019190915250612dd992505050565b805160208201209097909650945050505050565b610ac98133612e14565b611be18282611898565b6109e957600082815260c9602090815260408083206001600160a01b03851684529091529020805460ff19166001179055611c193390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b611c678282611898565b156109e957600082815260c9602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b611cdc600080516020615e5a83398151915233611898565b610ac95760405162461bcd60e51b81526004016107e190615966565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611d2b5761096a83612e6d565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611d85575060408051601f3d908101601f19168201909252611d82918101906158b7565b60015b611de85760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016107e1565b600080516020615e9a8339815191528114611e575760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016107e1565b5061096a838383612f09565b600260335403611eb55760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016107e1565b6002603355565b6040805160e08101825260008082526020820181905291810182905260608082018390526080820183905260a082019290925260c0810191909152600080611f3985858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612f3492505050565b905060008585604051611f4d9291906159d4565b60405190819003902090506000808281526007602052604090205460ff166002811115611f7c57611f7c615305565b14611fc95760405162461bcd60e51b815260206004820152601960248201527f4d65737361676520616c72656164792065786563757465642e0000000000000060448201526064016107e1565b46826080015163ffffffff16146120115760405162461bcd60e51b815260206004820152600c60248201526b2bb937b7339031b430b4b71760a11b60448201526064016107e1565b600854825160ff90811691161461205b5760405162461bcd60e51b815260206004820152600e60248201526d2bb937b733903b32b939b4b7b71760911b60448201526064016107e1565b60408083015163ffffffff166000908152600460205220546001600160a01b031615806120a6575060408083015163ffffffff166000908152600560205220546001600160a01b0316155b156121195760405162461bcd60e51b815260206004820152603760248201527f4c6967687420636c69656e74206f722062726f616463617374657220666f722060448201527f736f7572636520636861696e206973206e6f742073657400000000000000000060648201526084016107e1565b90925090505b9250929050565b63ffffffff81166000908152600460205260409020546001600160a01b031661218c5760405162461bcd60e51b81526020600482015260186024820152772634b3b43a1031b634b2b73a1034b9903737ba1039b2ba1760411b60448201526064016107e1565b63ffffffff8116600090815260046020818152604092839020548351632bcccca560e01b815293516001600160a01b0390911693632bcccca5938181019392918290030181865afa1580156121e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220991906159e4565b610ac95760405162461bcd60e51b815260206004820152601d60248201527f4c6967687420636c69656e7420697320696e636f6e73697374656e742e00000060448201526064016107e1565b63ffffffff811660009081526006602052604090205460ff1615610ac95760405162461bcd60e51b815260206004820152601360248201527221b7b73a3930b1ba1034b990333937bd32b71760691b60448201526064016107e1565b63ffffffff81166000908152600460205260409020546001600160a01b03166123175760405162461bcd60e51b81526020600482015260186024820152772634b3b43a1031b634b2b73a1034b9903737ba1039b2ba1760411b60448201526064016107e1565b63ffffffff8116600090815260046020819052604091829020549151638bc33af360e01b81526001600160401b038516918101919091526001600160a01b0390911690638bc33af390602401602060405180830381865afa158015612380573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a491906158b7565b6000036123f35760405162461bcd60e51b815260206004820152601e60248201527f54696d657374616d70206973206e6f742073657420666f7220736c6f742e000060448201526064016107e1565b63ffffffff81166000908152600460208190526040808320549051638bc33af360e01b81526001600160401b038616928101929092526001600160a01b031690638bc33af390602401602060405180830381865afa158015612459573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247d91906158b7565b6124879042615a01565b9050607881101561096a5760405162461bcd60e51b815260206004820152602260248201527f4d7573742077616974206c6f6e67657220746f20757365207468697320736c6f6044820152613a1760f11b60648201526084016107e1565b600080826001600160401b0316846001600160401b0316036125235750600b61251081610200615a14565b61251c90610183615a33565b9050612676565b6120006125308486615a46565b6001600160401b0316116125925750600b61254c816020615a14565b612557906006615a33565b905061256e6120006001600160401b038516615a83565b61257a61200083615a14565b6125849190615a33565b905061251081610200615a14565b836001600160401b0316836001600160401b031610156126245750600b6125ba816020615a14565b6125c5906007615a33565b90506125d2816002615a14565b6125dd906000615a33565b90506125f46120006001600160401b038516615a97565b612602630100000083615a14565b61260c9190615a33565b9050612619816002615a14565b612557906001615a33565b60405162461bcd60e51b815260206004820152602160248201527f54727573746c657373414d423a20696e76616c69642074617267657420736c6f6044820152601d60fa1b60648201526084016107e1565b61268287828888612ff9565b979650505050505050565b60008061269b878a8a613013565b90506000816000815181106126b2576126b2615937565b01602001516001600160f81b03191690506000600160f81b8214806126e45750600160f91b6001600160f81b03198316145b156126f157506001612756565b600360fe1b6001600160f81b031983161061270e57506000612756565b60405162461bcd60e51b815260206004820152601c60248201527f556e737570706f72746564207472616e73616374696f6e20747970650000000060448201526064016107e1565b6000602084019050600060405180604001604052808487516127789190615a01565b81526020016127878585615a33565b905290506000612796826138b3565b905080516004146127e25760405162461bcd60e51b8152602060048201526016602482015275092dcecc2d8d2c840e4cac6cad2e0e840d8cadccee8d60531b60448201526064016107e1565b6000612807826003815181106127fa576127fa615937565b60200260200101516138b3565b905080518c106128595760405162461bcd60e51b815260206004820152601760248201527f4c6f6720696e646578206f7574206f6620626f756e647300000000000000000060448201526064016107e1565b6000612870828e815181106127fa576127fa615937565b905080516003146128ce5760405162461bcd60e51b815260206004820152602260248201527f4c6f672068617320696e636f7272656374206e756d626572206f66206669656c604482015261647360f01b60648201526084016107e1565b60006128f3826000815181106128e6576128e6615937565b6020026020010151613ad8565b90508c6001600160a01b0316816001600160a01b0316146129665760405162461bcd60e51b815260206004820152602760248201527f4576656e7420776173206e6f7420656d697474656420627920636c61696d656460448201526622b6b4ba3a32b960c91b60648201526084016107e1565b600061297e836001815181106127fa576127fa615937565b90508c6129a48260008151811061299757612997615937565b6020026020010151613b42565b14612a075760405162461bcd60e51b815260206004820152602d60248201527f4576656e74207369676e617475726520646f6573206e6f74206d61746368206560448201526c76656e745369676e617475726560981b60648201526084016107e1565b612a29818d81518110612a1c57612a1c615937565b6020026020010151613b49565b9a5050505050505050505050979650505050505050565b600060606000633bdc60d660e01b866040015187606001518860c00151604051602401612a6f93929190615aab565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915260a0870151909150806001600160a01b031682604051612ac19190615adb565b6000604051808303816000865af19150503d8060008114612afe576040519150601f19603f3d011682016040523d82523d6000602084013e612b03565b606091505b5080519195509350600092506020039050612b4557600082806020019051810190612b2e9190615af7565b6001600160e01b031916631dee306b60e11b149150505b828015612b4f5750805b15612b72576000858152600760205260409020805460ff19166002179055612b8c565b6000858152600760205260409020805460ff191660011790555b8486602001516001600160401b0316876040015163ffffffff167f1f26985f3389d5ee1e49b37cdef193b3e98c927d7dd8b6a1f9cddd17a1fe89478787604051612bd7929190615b14565b60405180910390a4505050505050565b6001603355565b603254610100900460ff16612c155760405162461bcd60e51b81526004016107e190615b38565b612c1d613c4c565b565b603254610100900460ff16612c1d5760405162461bcd60e51b81526004016107e190615b38565b6040516001600160601b0319606084901b16602082015260009081906034016040516020818303038152906040528051906020012090506000612cab82604051602001612c9591815260200190565b6040516020818303038152906040528786613013565b90506000815111612cf75760405162461bcd60e51b81526020600482015260166024820152751058d8dbdd5b9d08191bd95cc81b9bdd08195e1a5cdd60521b60448201526064016107e1565b6000612d0a612d0583613c73565b6138b3565b90508051600414612d1a57600080fd5b612d308160028151811061299757612997615937565b93505050505b9392505050565b600080612d6c85604051602001612d5691815260200190565b6040516020818303038152906040528486613013565b90506000815111612dbf5760405162461bcd60e51b815260206004820152601c60248201527f53746f726167652076616c756520646f6573206e6f742065786973740000000060448201526064016107e1565b612dd0612dcb82613c73565b613b42565b95945050505050565b606087878787878787604051602001612df89796959493929190615b83565b6040516020818303038152906040529050979650505050505050565b612e1e8282611898565b6109e957612e2b81613cc6565b612e36836020613cd8565b604051602001612e47929190615c0a565b60408051601f198184030181529082905262461bcd60e51b82526107e19160040161578d565b6001600160a01b0381163b612eda5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016107e1565b600080516020615e9a83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b612f1283613e73565b600082511180612f1f5750805b1561096a57612f2e8383613eb3565b50505050565b6040805160e08101825260008082526020820181905291810182905260608082018390526080820183905260a082019290925260c081019190915260018201516009830151600d8401516021850151602586015160458088015160ff871688526001600160401b038616602089015263ffffffff80861660408a01526001600160a01b03851660608a01528316608089015260a0880181905288519091612fe8918a9190612fe3908290615a01565b613f9e565b60c088015250949695505050505050565b60008061300786868661408a565b90921495945050505050565b6060600084511161305e5760405162461bcd60e51b81526020600482015260156024820152744d65726b6c65547269653a20656d707479206b657960581b60448201526064016107e1565b600061306984614219565b9050600061307686614307565b905060008460405160200161308d91815260200190565b60405160208183030381529060405290506000805b845181101561385c5760008582815181106130bf576130bf615937565b6020026020010151905084518311156131315760405162461bcd60e51b815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201526d0e8c2d840d6caf240d8cadccee8d60931b60648201526084016107e1565b826000036131d0578051805160209182012060405161317f9261315992910190815260200190565b604051602081830303815290604052858051602091820120825192909101919091201490565b6131cb5760405162461bcd60e51b815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f74206861736800000060448201526064016107e1565b6132c6565b80515160201161325657805180516020918201206040516131fa9261315992910190815260200190565b6131cb5760405162461bcd60e51b815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e6044820152660c2d840d0c2e6d60cb1b60648201526084016107e1565b8051845160208087019190912082519190920120146132c65760405162461bcd60e51b815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f646044820152650ca40d0c2e6d60d31b60648201526084016107e1565b6132d260106001615a33565b8160200151510361347f578451830361341757600061330e826020015160108151811061330157613301615937565b6020026020010151614421565b905060008151116133875760405162461bcd60e51b815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e636829000000000060648201526084016107e1565b600187516133959190615a01565b83146134095760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e63682900000000000060648201526084016107e1565b9650612d3695505050505050565b600085848151811061342b5761342b615937565b602001015160f81c60f81b60f81c9050600082602001518260ff168151811061345657613456615937565b6020026020010151905061346981614544565b9550613476600186615a33565b94505050613849565b6002816020015151036137f057600061349782614569565b90506000816000815181106134ae576134ae615937565b016020015160f81c905060006134c5600283615c7f565b6134d0906002615ca1565b905060006134e1848360ff1661458d565b905060006134ef8a8961458d565b905060006134fd83836145c3565b9050808351146135755760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b657900000000000060648201526084016107e1565b60ff85166002148061358a575060ff85166003145b1561373057808251146136055760405162461bcd60e51b815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e64657200000060648201526084016107e1565b6000613621886020015160018151811061330157613301615937565b9050600081511161369a5760405162461bcd60e51b815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c656166290000000000000060648201526084016107e1565b60018d516136a89190615a01565b891461371c5760405162461bcd60e51b815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c65616629000000000000000060648201526084016107e1565b9c50612d369b505050505050505050505050565b60ff85161580613743575060ff85166001145b156137825761376f876020015160018151811061376257613762615937565b6020026020010151614544565b995061377b818a615a33565b98506137e5565b60405162461bcd60e51b815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f64652077697468604482015271040c2dc40eadcd6dcdeeedc40e0e4caccd2f60731b60648201526084016107e1565b505050505050613849565b60405162461bcd60e51b815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e706172736561604482015267626c65206e6f646560c01b60648201526084016107e1565b5080613854816159bb565b9150506130a2565b5060405162461bcd60e51b815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c656044820152646d656e747360d81b60648201526084016107e1565b606060008060006138c385614642565b9194509250905060018160018111156138de576138de615305565b146139515760405162461bcd60e51b815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d000000000000000060648201526084016107e1565b845161395d8385615a33565b146139c55760405162461bcd60e51b815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e76616044820152713634b2103230ba30903932b6b0b4b73232b960711b60648201526084016107e1565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816139de5790505090506000845b8751811015613acc57600080613a516040518060400160405280858d60000151613a359190615a01565b8152602001858d60200151613a4a9190615a33565b9052614642565b509150915060405180604001604052808383613a6d9190615a33565b8152602001848c60200151613a829190615a33565b815250858581518110613a9757613a97615937565b6020908102919091010152613aad600185615a33565b9350613ab98183615a33565b613ac39084615a33565b92505050613a0b565b50815295945050505050565b8051600090600103613aec57506000919050565b8151601514613b3d5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020616464726573732076616c75652e00000000000060448201526064016107e1565b6107b8825b60006107b8825b6000602182600001511115613ba05760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e00000000000060448201526064016107e1565b6000806000613bae85614642565b919450925090506000816001811115613bc957613bc9615305565b14613c165760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e00000000000060448201526064016107e1565b6000838660200151613c289190615a33565b80519091506020841015613c425760208490036101000a90045b9695505050505050565b603254610100900460ff16612be75760405162461bcd60e51b81526004016107e190615b38565b60408051808201909152600080825260208201526000825111613ca85760405162461bcd60e51b81526004016107e190615cba565b50604080518082019091528151815260209182019181019190915290565b60606107b86001600160a01b03831660145b60606000613ce7836002615a14565b613cf2906002615a33565b6001600160401b03811115613d0957613d09615153565b6040519080825280601f01601f191660200182016040528015613d33576020820181803683370190505b509050600360fc1b81600081518110613d4e57613d4e615937565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110613d7d57613d7d615937565b60200101906001600160f81b031916908160001a9053506000613da1846002615a14565b613dac906001615a33565b90505b6001811115613e24576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110613de057613de0615937565b1a60f81b828281518110613df657613df6615937565b60200101906001600160f81b031916908160001a90535060049490941c93613e1d81615d2a565b9050613daf565b508315612d365760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016107e1565b613e7c81612e6d565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b613f1b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016107e1565b600080846001600160a01b031684604051613f369190615adb565b600060405180830381855af49150503d8060008114613f71576040519150601f19603f3d011682016040523d82523d6000602084013e613f76565b606091505b5091509150612dd08282604051806060016040528060278152602001615eba60279139614d05565b606081613fac81601f615a33565b1015613fca5760405162461bcd60e51b81526004016107e190615d41565b613fd48284615a33565b845110156140185760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016107e1565b6060821580156140375760405191506000825260208201604052614081565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015614070578051835260209283019201614058565b5050858452601f01601f1916604052505b50949350505050565b6000828251600161409b9190615a33565b6140a6906002615e4d565b116140b057600080fd5b8360005b84600114614081576140c7600286615a83565b6001036141665760028482815181106140e2576140e2615937565b602002602001015183604051602001614105929190918252602082015260400190565b60408051601f198184030181529082905261411f91615adb565b602060405180830381855afa15801561413c573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061415f91906158b7565b91506141fa565b60028285838151811061417b5761417b615937565b602002602001015160405160200161419d929190918252602082015260400190565b60408051601f19818403018152908290526141b791615adb565b602060405180830381855afa1580156141d4573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906141f791906158b7565b91505b614205600286615a97565b945080614211816159bb565b9150506140b4565b80516060906000816001600160401b0381111561423857614238615153565b60405190808252806020026020018201604052801561427d57816020015b60408051808201909152606080825260208201528152602001906001900390816142565790505b50905060005b828110156142ff5760405180604001604052808683815181106142a8576142a8615937565b602002602001015181526020016142d78784815181106142ca576142ca615937565b6020026020010151614d1e565b8152508282815181106142ec576142ec615937565b6020908102919091010152600101614283565b509392505050565b80516060906000614319826002615a14565b6001600160401b0381111561433057614330615153565b6040519080825280601f01601f19166020018201604052801561435a576020820181803683370190505b5090506000805b838110156144175785818151811061437b5761437b615937565b6020910101516001600160f81b03198116925060041c60ff60f41b16836143a3836002615a14565b815181106143b3576143b3615937565b60200101906001600160f81b031916908160001a905350600f60f81b8216836143dd836002615a14565b6143e8906001615a33565b815181106143f8576143f8615937565b60200101906001600160f81b031916908160001a905350600101614361565b5090949350505050565b6060600080600061443185614642565b91945092509050600081600181111561444c5761444c615305565b146144bf5760405162461bcd60e51b815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d0000000000000060648201526084016107e1565b6144c98284615a33565b8551146145355760405162461bcd60e51b815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527330b71034b73b30b634b2103932b6b0b4b73232b960611b60648201526084016107e1565b612dd085602001518484614d2c565b606060208260000151106145605761455b82614421565b6107b8565b6107b882614dcc565b60606107b8614588836020015160008151811061330157613301615937565b614307565b6060825182106145ac57506040805160208101909152600081526107b8565b612d3683838486516145be9190615a01565b614de2565b600080600083518551106145d85783516145db565b84515b90505b808210801561463257508382815181106145fa576145fa615937565b602001015160f81c60f81b6001600160f81b03191685838151811061462157614621615937565b01602001516001600160f81b031916145b156142ff578160010191506145de565b60008060008084600001511161466a5760405162461bcd60e51b81526004016107e190615cba565b6020840151805160001a607f811161468f576000600160009450945094505050614cfe565b60b781116147ec5760006146a4608083615a01565b9050808760000151116147245760405162461bcd60e51b815260206004820152604e6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201526d2873686f727420737472696e672960901b608482015260a4016107e1565b6001838101516001600160f81b03191690821415806147515750600160ff1b6001600160f81b0319821610155b6147d95760405162461bcd60e51b815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201526c73686f727420737472696e672960981b608482015260a4016107e1565b5060019550935060009250614cfe915050565b60bf8111614a2d57600061480160b783615a01565b9050808760000151116148845760405162461bcd60e51b81526020600482015260516024820152600080516020615e7a83398151915260448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527067746820286c6f6e6720737472696e672960781b608482015260a4016107e1565b60018301516001600160f81b031916600081900361490b5760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152696e6720737472696e672960b01b608482015260a4016107e1565b600184015160088302610100031c6037811161498e5760405162461bcd60e51b81526020600482015260486024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201526720737472696e672960c01b608482015260a4016107e1565b6149988184615a33565b895111614a105760405162461bcd60e51b815260206004820152604c6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201526b6c6f6e6720737472696e672960a01b608482015260a4016107e1565b614a1b836001615a33565b9750955060009450614cfe9350505050565b60f78111614acf576000614a4260c083615a01565b905080876000015111614abe5760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e206c697374206c656e677468202873606482015269686f7274206c6973742960b01b608482015260a4016107e1565b600195509350849250614cfe915050565b6000614adc60f783615a01565b905080876000015111614b5b5760405162461bcd60e51b815260206004820152604d6024820152600080516020615e7a83398151915260448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201526c6820286c6f6e67206c6973742960981b608482015260a4016107e1565b60018301516001600160f81b0319166000819003614be05760405162461bcd60e51b81526020600482015260486024820152600080516020615e7a83398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152676e67206c6973742960c01b608482015260a4016107e1565b600184015160088302610100031c60378111614c615760405162461bcd60e51b81526020600482015260466024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e67606482015265206c6973742960d01b608482015260a4016107e1565b614c6b8184615a33565b895111614ce15760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e67746820286064820152696c6f6e67206c6973742960b01b608482015260a4016107e1565b614cec836001615a33565b9750955060019450614cfe9350505050565b9193909250565b60608315614d14575081612d36565b612d368383614e70565b60606107b8612d0583613c73565b60606000826001600160401b03811115614d4857614d48615153565b6040519080825280601f01601f191660200182016040528015614d72576020820181803683370190505b50905082600003614d84579050612d36565b6000614d908587615a33565b90506020820160005b85811015614db1578281015182820152602001614d99565b85811115614dc0576000868301525b50919695505050505050565b60606107b8826020015160008460000151614d2c565b60608182601f011015614e075760405162461bcd60e51b81526004016107e190615d41565b828284011015614e295760405162461bcd60e51b81526004016107e190615d41565b818301845110156140185760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016107e1565b815115614e805781518083602001fd5b8060405162461bcd60e51b81526004016107e1919061578d565b82805482825590600052602060002090600701600890048101928215614f395791602002820160005b83821115614f0757835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614ec3565b8015614f375782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614f07565b505b50614f45929150614f49565b5090565b5b80821115614f455760008155600101614f4a565b6001600160e01b031981168114610ac957600080fd5b600060208284031215614f8657600080fd5b8135612d3681614f5e565b80356001600160401b0381168114614fa857600080fd5b919050565b600060208284031215614fbf57600080fd5b612d3682614f91565b803563ffffffff81168114614fa857600080fd5b80356001600160a01b0381168114614fa857600080fd5b60008083601f84011261500557600080fd5b5081356001600160401b0381111561501c57600080fd5b60208301915083602082850101111561211f57600080fd5b6000806000806060858703121561504a57600080fd5b61505385614fc8565b935061506160208601614fdc565b925060408501356001600160401b0381111561507c57600080fd5b61508887828801614ff3565b95989497509550505050565b6000602082840312156150a657600080fd5b612d3682614fc8565b6000602082840312156150c157600080fd5b5035919050565b600080604083850312156150db57600080fd5b823591506150eb60208401614fdc565b90509250929050565b60006020828403121561510657600080fd5b612d3682614fdc565b60008083601f84011261512157600080fd5b5081356001600160401b0381111561513857600080fd5b6020830191508360208260051b850101111561211f57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561519157615191615153565b604052919050565b600082601f8301126151aa57600080fd5b81356001600160401b038111156151c3576151c3615153565b6151d6601f8201601f1916602001615169565b8181528460208386010111156151eb57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600080600080600080600060e08c8e03121561522957600080fd5b6001600160401b03808d35111561523f57600080fd5b61524c8e8e358f01614ff3565b909c509a5060208d013581101561526257600080fd5b6152728e60208f01358f01614ff3565b909a50985060408d013581101561528857600080fd5b6152988e60408f01358f0161510f565b909850965060608d0135955060808d01358110156152b557600080fd5b6152c58e60808f01358f0161510f565b909550935060a08d01358110156152db57600080fd5b506152ec8d60a08e01358e01615199565b915060c08c013590509295989b509295989b9093969950565b634e487b7160e01b600052602160045260246000fd5b602081016003831061533d57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561535657600080fd5b61535f83614fdc565b915060208301356001600160401b0381111561537a57600080fd5b61538685828601615199565b9150509250929050565b60006001600160401b038211156153a9576153a9615153565b5060051b60200190565b600082601f8301126153c457600080fd5b813560206153d96153d483615390565b615169565b82815260059290921b840181019181810190868411156153f857600080fd5b8286015b8481101561541a5761540d81614fdc565b83529183019183016153fc565b509695505050505050565b8015158114610ac957600080fd5b8035614fa881615425565b60008060008060008060c0878903121561545757600080fd5b86356001600160401b038082111561546e57600080fd5b818901915089601f83011261548257600080fd5b813560206154926153d483615390565b82815260059290921b8401810191818101908d8411156154b157600080fd5b948201945b838610156154d6576154c786614fc8565b825294820194908201906154b6565b9a50508a0135925050808211156154ec57600080fd5b6154f88a838b016153b3565b9650604089013591508082111561550e57600080fd5b5061551b89828a016153b3565b94505061552a60608801614fdc565b925061553860808801614fdc565b915061554660a08801615433565b90509295509295509295565b6000806000806060858703121561556857600080fd5b61557185614fc8565b93506020850135925060408501356001600160401b0381111561507c57600080fd5b60008060008060008060006080888a0312156155ae57600080fd5b6155b788614f91565b965060208801356001600160401b03808211156155d357600080fd5b6155df8b838c01614ff3565b909850965060408a01359150808211156155f857600080fd5b6156048b838c0161510f565b909650945060608a013591508082111561561d57600080fd5b5061562a8a828b0161510f565b989b979a50959850939692959293505050565b60008060006060848603121561565257600080fd5b61565b84614fc8565b925061566960208501614fdc565b915061567760408501614fdc565b90509250925092565b60006020828403121561569257600080fd5b8135612d3681615425565b60208082526013908201527214d95b991a5b99c81a5cc8191a5cd8589b1959606a1b604082015260600190565b60208082526019908201527f43616e6e6f742073656e6420746f2073616d6520636861696e00000000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60006001600160401b0380831681810361573357615733615701565b6001019392505050565b60005b83811015615758578181015183820152602001615740565b50506000910152565b6000815180845261577981602086016020860161573d565b601f01601f19169290920160200192915050565b602081526000612d366020830184615761565b60208082526035908201527f54656c657061746879526f757465723a206f6e6c7920677561726469616e206360408201527430b71031b0b636103a3434b990333ab731ba34b7b760591b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600080604083850312156158a057600080fd5b6158a983614f91565b91506150eb60208401614f91565b6000602082840312156158c957600080fd5b5051919050565b60006158de6153d484615390565b80848252602080830192508560051b8501368111156158fc57600080fd5b855b81811015614dc05780356001600160401b0381111561591d5760008081fd5b61592936828a01615199565b8652509382019382016158fe565b634e487b7160e01b600052603260045260246000fd5b600063ffffffff80831681810361573357615733615701565b60208082526035908201527f54656c657061746879526f757465723a206f6e6c792074696d656c6f636b206360408201527430b71031b0b636103a3434b990333ab731ba34b7b760591b606082015260800190565b6000600182016159cd576159cd615701565b5060010190565b8183823760009101908152919050565b6000602082840312156159f657600080fd5b8151612d3681615425565b818103818111156107b8576107b8615701565b6000816000190483118215151615615a2e57615a2e615701565b500290565b808201808211156107b8576107b8615701565b6001600160401b03828116828216039080821115615a6657615a66615701565b5092915050565b634e487b7160e01b600052601260045260246000fd5b600082615a9257615a92615a6d565b500690565b600082615aa657615aa6615a6d565b500490565b63ffffffff841681526001600160a01b0383166020820152606060408201819052600090612dd090830184615761565b60008251615aed81846020870161573d565b9190910192915050565b600060208284031215615b0957600080fd5b8151612d3681614f5e565b604081526000615b276040830185615761565b905082151560208301529392505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160f81b031960f889901b1681526001600160c01b031960c088901b1660018201526001600160e01b031960e087811b821660098401526001600160601b0319606088901b16600d84015285901b166021820152602581018390528151600090615bf781604585016020870161573d565b9190910160450198975050505050505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615c4281601785016020880161573d565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615c7381602884016020880161573d565b01602801949350505050565b600060ff831680615c9257615c92615a6d565b8060ff84160691505092915050565b60ff82811682821603908111156107b8576107b8615701565b6020808252604a908201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60408201527f206d7573742062652067726561746572207468616e207a65726f20746f206265606082015269206465636f6461626c6560b01b608082015260a00190565b600081615d3957615d39615701565b506000190190565b6020808252600e908201526d736c6963655f6f766572666c6f7760901b604082015260600190565b600181815b80851115615da4578160001904821115615d8a57615d8a615701565b80851615615d9757918102915b93841c9390800290615d6e565b509250929050565b600082615dbb575060016107b8565b81615dc8575060006107b8565b8160018114615dde5760028114615de857615e04565b60019150506107b8565b60ff841115615df957615df9615701565b50506001821b6107b8565b5060208310610133831016604e8410600b8410161715615e27575081810a6107b8565b615e318383615d69565b8060001904821115615e4557615e45615701565b029392505050565b6000612d368383615dac56fef66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05524c505265616465723a206c656e677468206f6620636f6e74656e74206d7573360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656455435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041a2646970667358221220f69b1c44e29eed792424bef643e588366626efef00e60b2c59813e1a349096ed64736f6c63430008100033

Deployed Bytecode

0x6080604052600436106102255760003560e01c806366c5c4a0116101235780639a2ed203116100ab578063d547741f1161006f578063d547741f146106fb578063e4407b151461071b578063ed762d4414610730578063f288a2e214610750578063ffa1ad741461077257600080fd5b80639a2ed203146106395780639efeff1c14610659578063a217fddf1461068e578063a96a2e92146106a3578063affed0e0146106c357600080fd5b80637acc6754116100f25780637acc6754146105975780638d080d1d146105b757806391cd8bfd146105e457806391d148541461060457806399464c891461062457600080fd5b806366c5c4a01461050c57806368346a92146105215780636fdbccbf146105415780637599735c1461056157600080fd5b806336ae7c18116101b15780634f1ef286116101755780634f1ef2861461044a57806352d1902d1461045d57806354fd4d501461047257806359f897871461049e5780635cb77819146104ec57600080fd5b806336ae7c181461038e57806337d5af84146103be5780633c6cf473146103de5780633e99e9ce1461041b5780634552f5631461043557600080fd5b8063248a9ca3116101f8578063248a9ca3146102dc57806324ea54f41461030c5780632f2ff15d1461032e57806336568abe1461034e5780633659cfe61461036e57600080fd5b806301ffc9a71461022a578063029d67131461025f578063147bce491461029a5780631f3d25a9146102ba575b600080fd5b34801561023657600080fd5b5061024a610245366004614f74565b610787565b60405190151581526020015b60405180910390f35b34801561026b57600080fd5b5061028c61027a366004614fad565b60016020526000908152604090205481565b604051908152602001610256565b3480156102a657600080fd5b5061028c6102b5366004615034565b6107be565b3480156102c657600080fd5b506102da6102d5366004615094565b6108cb565b005b3480156102e857600080fd5b5061028c6102f73660046150af565b600090815260c9602052604090206001015490565b34801561031857600080fd5b5061028c600080516020615ee183398151915281565b34801561033a57600080fd5b506102da6103493660046150c8565b610945565b34801561035a57600080fd5b506102da6103693660046150c8565b61096f565b34801561037a57600080fd5b506102da6103893660046150f4565b6109ed565b34801561039a57600080fd5b5061024a6103a9366004615094565b60066020526000908152604090205460ff1681565b3480156103ca57600080fd5b506102da6103d9366004615208565b610acc565b3480156103ea57600080fd5b5061040e6103f93660046150af565b60076020526000908152604090205460ff1681565b604051610256919061531b565b34801561042757600080fd5b5060005461024a9060ff1681565b34801561044157600080fd5b5060035461028c565b6102da610458366004615343565b610d95565b34801561046957600080fd5b5061028c610e61565b34801561047e57600080fd5b5060085461048c9060ff1681565b60405160ff9091168152602001610256565b3480156104aa57600080fd5b506104d46104b9366004615094565b6005602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610256565b3480156104f857600080fd5b506102da61050736600461543e565b610f14565b34801561051857600080fd5b506102da611217565b34801561052d57600080fd5b5061028c61053c366004615034565b6112fc565b34801561054d57600080fd5b5061028c61055c366004615552565b61137b565b34801561056d57600080fd5b506104d461057c366004615094565b6004602052600090815260409020546001600160a01b031681565b3480156105a357600080fd5b506102da6105b2366004615593565b6113d2565b3480156105c357600080fd5b5061028c6105d23660046150af565b60096020526000908152604090205481565b3480156105f057600080fd5b506102da6105ff36600461563d565b6116e7565b34801561061057600080fd5b5061024a61061f3660046150c8565b611898565b34801561063057600080fd5b506102da6118c3565b34801561064557600080fd5b506102da610654366004615094565b6119a8565b34801561066557600080fd5b506106796106743660046150af565b611a25565b60405163ffffffff9091168152602001610256565b34801561069a57600080fd5b5061028c600081565b3480156106af57600080fd5b5061028c6106be366004615552565b611a5f565b3480156106cf57600080fd5b506002546106e3906001600160401b031681565b6040516001600160401b039091168152602001610256565b34801561070757600080fd5b506102da6107163660046150c8565b611ab6565b34801561072757600080fd5b5061028c607881565b34801561073c57600080fd5b506102da61074b366004615680565b611adb565b34801561075c57600080fd5b5061028c600080516020615e5a83398151915281565b34801561077e57600080fd5b5061048c600181565b60006001600160e01b03198216637965db0b60e01b14806107b857506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805460ff166107ea5760405162461bcd60e51b81526004016107e19061569d565b60405180910390fd5b468563ffffffff160361080f5760405162461bcd60e51b81526004016107e1906156ca565b600080610828876001600160a01b0388165b8787611b56565b600280546001600160401b03908116600090815260016020526040812084905582549496509294508493169161085d83615717565b91906101000a8154816001600160401b0302191690836001600160401b031602179055506001600160401b03167fe5944a34d67c652e0ebf2304b48432aae0b55e40f79ba8a21a4d7054c169ffac846040516108b9919061578d565b60405180910390a39695505050505050565b6108e3600080516020615ee183398151915233611898565b6108ff5760405162461bcd60e51b81526004016107e1906157a0565b63ffffffff8116600081815260066020526040808220805460ff19169055517f9fd67bd682613b07687b42f99d8b24402d09feabb75df93abdb26b8fcf9845839190a250565b600082815260c9602052604090206001015461096081611bcd565b61096a8383611bd7565b505050565b6001600160a01b03811633146109df5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016107e1565b6109e98282611c5d565b5050565b6001600160a01b037f0000000000000000000000000764f94b058da4f3dc480e038c35d2a6f7a7ef78163003610a355760405162461bcd60e51b81526004016107e1906157f5565b7f0000000000000000000000000764f94b058da4f3dc480e038c35d2a6f7a7ef786001600160a01b0316610a7e600080516020615e9a833981519152546001600160a01b031690565b6001600160a01b031614610aa45760405162461bcd60e51b81526004016107e190615841565b610aad81611cc4565b60408051600080825260208201909252610ac991839190611cf8565b50565b610ad4611e63565b600080610ae18b8b611ebc565b91509150610af28260400151612126565b610aff8260400151612255565b6000808e8e810190610b11919061588d565b91509150610b238285604001516122b1565b60408481015163ffffffff166000908152600460208190528282205492516356f90d7960e01b81526001600160401b0386169181019190915290916001600160a01b0316906356f90d7990602401602060405180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb291906158b7565b905080610bf95760405162461bcd60e51b8152602060048201526015602482015274486561646572526f6f74206973206d697373696e6760581b60448201526064016107e1565b6000610c3d8b8e8e808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508792508991508890506124e5565b905080610c8c5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726563656970747320726f6f742070726f6f66000000000060448201526064016107e1565b505050506000610cf1878790610ca291906158d0565b60408086015163ffffffff166000908152600560205220548a90889088906001600160a01b03167fe5944a34d67c652e0ebf2304b48432aae0b55e40f79ba8a21a4d7054c169ffac600261268d565b9050818114610d3a5760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b21036b2b9b9b0b3b2903430b9b41760591b60448201526064016107e1565b50610d7c82828d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a4092505050565b5050610d886001603355565b5050505050505050505050565b6001600160a01b037f0000000000000000000000000764f94b058da4f3dc480e038c35d2a6f7a7ef78163003610ddd5760405162461bcd60e51b81526004016107e1906157f5565b7f0000000000000000000000000764f94b058da4f3dc480e038c35d2a6f7a7ef786001600160a01b0316610e26600080516020615e9a833981519152546001600160a01b031690565b6001600160a01b031614610e4c5760405162461bcd60e51b81526004016107e190615841565b610e5582611cc4565b6109e982826001611cf8565b6000306001600160a01b037f0000000000000000000000000764f94b058da4f3dc480e038c35d2a6f7a7ef781614610f015760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016107e1565b50600080516020615e9a83398151915290565b603254610100900460ff1615808015610f345750603254600160ff909116105b80610f4e5750303b158015610f4e575060325460ff166001145b610fb15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016107e1565b6032805460ff191660011790558015610fd4576032805461ff0019166101001790555b610fdc612bee565b610fe4612c1f565b610ffc600080516020615ee183398151915284611bd7565b611014600080516020615e5a83398151915285611bd7565b61101f600085611bd7565b611027612c1f565b855187511461103557600080fd5b845187511461104357600080fd5b86516110569060039060208a0190614e9a565b5060005b60035463ffffffff821610156111aa57868163ffffffff168151811061108257611082615937565b60200260200101516004600060038463ffffffff16815481106110a7576110a7615937565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550858163ffffffff168151811061112357611123615937565b60200260200101516005600060038463ffffffff168154811061114857611148615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff168352820192909252604001902080546001600160a01b0319166001600160a01b0392909216919091179055806111a28161594d565b91505061105a565b506000805483151560ff1991821617909155600880549091166001179055801561120e576032805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b61122f600080516020615ee183398151915233611898565b61124b5760405162461bcd60e51b81526004016107e1906157a0565b60005b60035463ffffffff821610156112d05760006006600060038463ffffffff168154811061127d5761127d615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff1683528201929092526040019020805460ff1916911515919091179055806112c88161594d565b91505061124e565b506040517fe6fdbf73945dd61794a752b9181ea29f77170a7b1ffd37e0a7ff9d2c6f7258b990600090a1565b6000805460ff1661131f5760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff16036113445760405162461bcd60e51b81526004016107e1906156ca565b60008061135a876001600160a01b038816610821565b6002805492945090925082916001600160401b031690600061085d83615717565b6000805460ff1661139e5760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff16036113c35760405162461bcd60e51b81526004016107e1906156ca565b60008061082887878787611b56565b6113da611e63565b6000806113e78888611ebc565b915091506113f88260400151612126565b6114058260400151612255565b6114138983604001516122b1565b60408281015163ffffffff811660009081526005602090815283822054845160e09490941b6001600160e01b0319168483015260c08e901b6001600160c01b031916602485015260601b6001600160601b031916602c840152835180840382018152928401845282519281019290922080825260099092529182205482036115c55760408085015163ffffffff16600090815260046020819052828220549251637623ee2960e01b81526001600160401b038f169181019190915290916001600160a01b031690637623ee2990602401602060405180830381865afa158015611500573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152491906158b7565b905060008190036115775760405162461bcd60e51b815260206004820152601f60248201527f457865637574696f6e20537461746520526f6f74206973206e6f74207365740060448201526064016107e1565b6115ab611584898b6158d0565b60408088015163ffffffff166000908152600560205220546001600160a01b031683612c46565b600083815260096020526040902081905592506115d79050565b60008181526009602052604090205491505b6000846020015160016040516020016116059291906001600160401b03929092168252602082015260400190565b60408051808303601f1901815282825280516020918201208184015281518084038201815292820190915281519101209050600061164d82856116488a8c6158d0565b612d3d565b90508481146116965760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b21036b2b9b9b0b3b2903430b9b41760591b60448201526064016107e1565b505050506116db82828a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a4092505050565b505061120e6001603355565b6116ff600080516020615e5a83398151915233611898565b61171b5760405162461bcd60e51b81526004016107e190615966565b6000805b600354811015611787578463ffffffff166003828154811061174357611743615937565b6000918252602090912060088204015460079091166004026101000a900463ffffffff16036117755760019150611787565b8061177f816159bb565b91505061171f565b508061181057600380546001810182556000918252600881047fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01805463ffffffff80891660046007909516949094026101000a84810291021990911617905560405190917f65a791dc0a39717013964ace2b78f8307f275c293b7fdb425346ce8e18cb318891a25b63ffffffff8416600081815260046020908152604080832080546001600160a01b038981166001600160a01b031992831681179093556005855294839020805495891695909116851790558151908152918201929092527f0205eaadbbed4fbe918b2a594d41bceb212a89010cc678c6762b18d65679b2ef910160405180910390a250505050565b600091825260c9602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6118db600080516020615ee183398151915233611898565b6118f75760405162461bcd60e51b81526004016107e1906157a0565b60005b60035463ffffffff8216101561197c5760016006600060038463ffffffff168154811061192957611929615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff1683528201929092526040019020805460ff1916911515919091179055806119748161594d565b9150506118fa565b506040517f61340a1b154d5d21d259a74bf95379201799b9d12cc6509bb46cb56dc281df5590600090a1565b6119c0600080516020615ee183398151915233611898565b6119dc5760405162461bcd60e51b81526004016107e1906157a0565b63ffffffff8116600081815260066020526040808220805460ff19166001179055517ff6cf9095f1dcea2429c26c832cbcc084fa0a1692b2c301601edd75b9d83520b29190a250565b60038181548110611a3557600080fd5b9060005260206000209060089182820401919006600402915054906101000a900463ffffffff1681565b6000805460ff16611a825760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff1603611aa75760405162461bcd60e51b81526004016107e1906156ca565b60008061135a87878787611b56565b600082815260c96020526040902060010154611ad181611bcd565b61096a8383611c5d565b611af3600080516020615ee183398151915233611898565b611b0f5760405162461bcd60e51b81526004016107e1906157a0565b6000805460ff19168215159081179091556040519081527f3eea1dc6ce990571e1081137b38c853529a3893b52e9719a48a2f4ac5e3a956c9060200160405180910390a150565b600854600254604080516020601f8601819004810282018101909252848152606093600093611bb99360ff909216926001600160401b0390911691469133918c918c918c908c9081908401838280828437600092019190915250612dd992505050565b805160208201209097909650945050505050565b610ac98133612e14565b611be18282611898565b6109e957600082815260c9602090815260408083206001600160a01b03851684529091529020805460ff19166001179055611c193390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b611c678282611898565b156109e957600082815260c9602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b611cdc600080516020615e5a83398151915233611898565b610ac95760405162461bcd60e51b81526004016107e190615966565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611d2b5761096a83612e6d565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611d85575060408051601f3d908101601f19168201909252611d82918101906158b7565b60015b611de85760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016107e1565b600080516020615e9a8339815191528114611e575760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016107e1565b5061096a838383612f09565b600260335403611eb55760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016107e1565b6002603355565b6040805160e08101825260008082526020820181905291810182905260608082018390526080820183905260a082019290925260c0810191909152600080611f3985858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612f3492505050565b905060008585604051611f4d9291906159d4565b60405190819003902090506000808281526007602052604090205460ff166002811115611f7c57611f7c615305565b14611fc95760405162461bcd60e51b815260206004820152601960248201527f4d65737361676520616c72656164792065786563757465642e0000000000000060448201526064016107e1565b46826080015163ffffffff16146120115760405162461bcd60e51b815260206004820152600c60248201526b2bb937b7339031b430b4b71760a11b60448201526064016107e1565b600854825160ff90811691161461205b5760405162461bcd60e51b815260206004820152600e60248201526d2bb937b733903b32b939b4b7b71760911b60448201526064016107e1565b60408083015163ffffffff166000908152600460205220546001600160a01b031615806120a6575060408083015163ffffffff166000908152600560205220546001600160a01b0316155b156121195760405162461bcd60e51b815260206004820152603760248201527f4c6967687420636c69656e74206f722062726f616463617374657220666f722060448201527f736f7572636520636861696e206973206e6f742073657400000000000000000060648201526084016107e1565b90925090505b9250929050565b63ffffffff81166000908152600460205260409020546001600160a01b031661218c5760405162461bcd60e51b81526020600482015260186024820152772634b3b43a1031b634b2b73a1034b9903737ba1039b2ba1760411b60448201526064016107e1565b63ffffffff8116600090815260046020818152604092839020548351632bcccca560e01b815293516001600160a01b0390911693632bcccca5938181019392918290030181865afa1580156121e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220991906159e4565b610ac95760405162461bcd60e51b815260206004820152601d60248201527f4c6967687420636c69656e7420697320696e636f6e73697374656e742e00000060448201526064016107e1565b63ffffffff811660009081526006602052604090205460ff1615610ac95760405162461bcd60e51b815260206004820152601360248201527221b7b73a3930b1ba1034b990333937bd32b71760691b60448201526064016107e1565b63ffffffff81166000908152600460205260409020546001600160a01b03166123175760405162461bcd60e51b81526020600482015260186024820152772634b3b43a1031b634b2b73a1034b9903737ba1039b2ba1760411b60448201526064016107e1565b63ffffffff8116600090815260046020819052604091829020549151638bc33af360e01b81526001600160401b038516918101919091526001600160a01b0390911690638bc33af390602401602060405180830381865afa158015612380573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a491906158b7565b6000036123f35760405162461bcd60e51b815260206004820152601e60248201527f54696d657374616d70206973206e6f742073657420666f7220736c6f742e000060448201526064016107e1565b63ffffffff81166000908152600460208190526040808320549051638bc33af360e01b81526001600160401b038616928101929092526001600160a01b031690638bc33af390602401602060405180830381865afa158015612459573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247d91906158b7565b6124879042615a01565b9050607881101561096a5760405162461bcd60e51b815260206004820152602260248201527f4d7573742077616974206c6f6e67657220746f20757365207468697320736c6f6044820152613a1760f11b60648201526084016107e1565b600080826001600160401b0316846001600160401b0316036125235750600b61251081610200615a14565b61251c90610183615a33565b9050612676565b6120006125308486615a46565b6001600160401b0316116125925750600b61254c816020615a14565b612557906006615a33565b905061256e6120006001600160401b038516615a83565b61257a61200083615a14565b6125849190615a33565b905061251081610200615a14565b836001600160401b0316836001600160401b031610156126245750600b6125ba816020615a14565b6125c5906007615a33565b90506125d2816002615a14565b6125dd906000615a33565b90506125f46120006001600160401b038516615a97565b612602630100000083615a14565b61260c9190615a33565b9050612619816002615a14565b612557906001615a33565b60405162461bcd60e51b815260206004820152602160248201527f54727573746c657373414d423a20696e76616c69642074617267657420736c6f6044820152601d60fa1b60648201526084016107e1565b61268287828888612ff9565b979650505050505050565b60008061269b878a8a613013565b90506000816000815181106126b2576126b2615937565b01602001516001600160f81b03191690506000600160f81b8214806126e45750600160f91b6001600160f81b03198316145b156126f157506001612756565b600360fe1b6001600160f81b031983161061270e57506000612756565b60405162461bcd60e51b815260206004820152601c60248201527f556e737570706f72746564207472616e73616374696f6e20747970650000000060448201526064016107e1565b6000602084019050600060405180604001604052808487516127789190615a01565b81526020016127878585615a33565b905290506000612796826138b3565b905080516004146127e25760405162461bcd60e51b8152602060048201526016602482015275092dcecc2d8d2c840e4cac6cad2e0e840d8cadccee8d60531b60448201526064016107e1565b6000612807826003815181106127fa576127fa615937565b60200260200101516138b3565b905080518c106128595760405162461bcd60e51b815260206004820152601760248201527f4c6f6720696e646578206f7574206f6620626f756e647300000000000000000060448201526064016107e1565b6000612870828e815181106127fa576127fa615937565b905080516003146128ce5760405162461bcd60e51b815260206004820152602260248201527f4c6f672068617320696e636f7272656374206e756d626572206f66206669656c604482015261647360f01b60648201526084016107e1565b60006128f3826000815181106128e6576128e6615937565b6020026020010151613ad8565b90508c6001600160a01b0316816001600160a01b0316146129665760405162461bcd60e51b815260206004820152602760248201527f4576656e7420776173206e6f7420656d697474656420627920636c61696d656460448201526622b6b4ba3a32b960c91b60648201526084016107e1565b600061297e836001815181106127fa576127fa615937565b90508c6129a48260008151811061299757612997615937565b6020026020010151613b42565b14612a075760405162461bcd60e51b815260206004820152602d60248201527f4576656e74207369676e617475726520646f6573206e6f74206d61746368206560448201526c76656e745369676e617475726560981b60648201526084016107e1565b612a29818d81518110612a1c57612a1c615937565b6020026020010151613b49565b9a5050505050505050505050979650505050505050565b600060606000633bdc60d660e01b866040015187606001518860c00151604051602401612a6f93929190615aab565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915260a0870151909150806001600160a01b031682604051612ac19190615adb565b6000604051808303816000865af19150503d8060008114612afe576040519150601f19603f3d011682016040523d82523d6000602084013e612b03565b606091505b5080519195509350600092506020039050612b4557600082806020019051810190612b2e9190615af7565b6001600160e01b031916631dee306b60e11b149150505b828015612b4f5750805b15612b72576000858152600760205260409020805460ff19166002179055612b8c565b6000858152600760205260409020805460ff191660011790555b8486602001516001600160401b0316876040015163ffffffff167f1f26985f3389d5ee1e49b37cdef193b3e98c927d7dd8b6a1f9cddd17a1fe89478787604051612bd7929190615b14565b60405180910390a4505050505050565b6001603355565b603254610100900460ff16612c155760405162461bcd60e51b81526004016107e190615b38565b612c1d613c4c565b565b603254610100900460ff16612c1d5760405162461bcd60e51b81526004016107e190615b38565b6040516001600160601b0319606084901b16602082015260009081906034016040516020818303038152906040528051906020012090506000612cab82604051602001612c9591815260200190565b6040516020818303038152906040528786613013565b90506000815111612cf75760405162461bcd60e51b81526020600482015260166024820152751058d8dbdd5b9d08191bd95cc81b9bdd08195e1a5cdd60521b60448201526064016107e1565b6000612d0a612d0583613c73565b6138b3565b90508051600414612d1a57600080fd5b612d308160028151811061299757612997615937565b93505050505b9392505050565b600080612d6c85604051602001612d5691815260200190565b6040516020818303038152906040528486613013565b90506000815111612dbf5760405162461bcd60e51b815260206004820152601c60248201527f53746f726167652076616c756520646f6573206e6f742065786973740000000060448201526064016107e1565b612dd0612dcb82613c73565b613b42565b95945050505050565b606087878787878787604051602001612df89796959493929190615b83565b6040516020818303038152906040529050979650505050505050565b612e1e8282611898565b6109e957612e2b81613cc6565b612e36836020613cd8565b604051602001612e47929190615c0a565b60408051601f198184030181529082905262461bcd60e51b82526107e19160040161578d565b6001600160a01b0381163b612eda5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016107e1565b600080516020615e9a83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b612f1283613e73565b600082511180612f1f5750805b1561096a57612f2e8383613eb3565b50505050565b6040805160e08101825260008082526020820181905291810182905260608082018390526080820183905260a082019290925260c081019190915260018201516009830151600d8401516021850151602586015160458088015160ff871688526001600160401b038616602089015263ffffffff80861660408a01526001600160a01b03851660608a01528316608089015260a0880181905288519091612fe8918a9190612fe3908290615a01565b613f9e565b60c088015250949695505050505050565b60008061300786868661408a565b90921495945050505050565b6060600084511161305e5760405162461bcd60e51b81526020600482015260156024820152744d65726b6c65547269653a20656d707479206b657960581b60448201526064016107e1565b600061306984614219565b9050600061307686614307565b905060008460405160200161308d91815260200190565b60405160208183030381529060405290506000805b845181101561385c5760008582815181106130bf576130bf615937565b6020026020010151905084518311156131315760405162461bcd60e51b815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201526d0e8c2d840d6caf240d8cadccee8d60931b60648201526084016107e1565b826000036131d0578051805160209182012060405161317f9261315992910190815260200190565b604051602081830303815290604052858051602091820120825192909101919091201490565b6131cb5760405162461bcd60e51b815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f74206861736800000060448201526064016107e1565b6132c6565b80515160201161325657805180516020918201206040516131fa9261315992910190815260200190565b6131cb5760405162461bcd60e51b815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e6044820152660c2d840d0c2e6d60cb1b60648201526084016107e1565b8051845160208087019190912082519190920120146132c65760405162461bcd60e51b815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f646044820152650ca40d0c2e6d60d31b60648201526084016107e1565b6132d260106001615a33565b8160200151510361347f578451830361341757600061330e826020015160108151811061330157613301615937565b6020026020010151614421565b905060008151116133875760405162461bcd60e51b815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e636829000000000060648201526084016107e1565b600187516133959190615a01565b83146134095760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e63682900000000000060648201526084016107e1565b9650612d3695505050505050565b600085848151811061342b5761342b615937565b602001015160f81c60f81b60f81c9050600082602001518260ff168151811061345657613456615937565b6020026020010151905061346981614544565b9550613476600186615a33565b94505050613849565b6002816020015151036137f057600061349782614569565b90506000816000815181106134ae576134ae615937565b016020015160f81c905060006134c5600283615c7f565b6134d0906002615ca1565b905060006134e1848360ff1661458d565b905060006134ef8a8961458d565b905060006134fd83836145c3565b9050808351146135755760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b657900000000000060648201526084016107e1565b60ff85166002148061358a575060ff85166003145b1561373057808251146136055760405162461bcd60e51b815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e64657200000060648201526084016107e1565b6000613621886020015160018151811061330157613301615937565b9050600081511161369a5760405162461bcd60e51b815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c656166290000000000000060648201526084016107e1565b60018d516136a89190615a01565b891461371c5760405162461bcd60e51b815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c65616629000000000000000060648201526084016107e1565b9c50612d369b505050505050505050505050565b60ff85161580613743575060ff85166001145b156137825761376f876020015160018151811061376257613762615937565b6020026020010151614544565b995061377b818a615a33565b98506137e5565b60405162461bcd60e51b815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f64652077697468604482015271040c2dc40eadcd6dcdeeedc40e0e4caccd2f60731b60648201526084016107e1565b505050505050613849565b60405162461bcd60e51b815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e706172736561604482015267626c65206e6f646560c01b60648201526084016107e1565b5080613854816159bb565b9150506130a2565b5060405162461bcd60e51b815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c656044820152646d656e747360d81b60648201526084016107e1565b606060008060006138c385614642565b9194509250905060018160018111156138de576138de615305565b146139515760405162461bcd60e51b815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d000000000000000060648201526084016107e1565b845161395d8385615a33565b146139c55760405162461bcd60e51b815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e76616044820152713634b2103230ba30903932b6b0b4b73232b960711b60648201526084016107e1565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816139de5790505090506000845b8751811015613acc57600080613a516040518060400160405280858d60000151613a359190615a01565b8152602001858d60200151613a4a9190615a33565b9052614642565b509150915060405180604001604052808383613a6d9190615a33565b8152602001848c60200151613a829190615a33565b815250858581518110613a9757613a97615937565b6020908102919091010152613aad600185615a33565b9350613ab98183615a33565b613ac39084615a33565b92505050613a0b565b50815295945050505050565b8051600090600103613aec57506000919050565b8151601514613b3d5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020616464726573732076616c75652e00000000000060448201526064016107e1565b6107b8825b60006107b8825b6000602182600001511115613ba05760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e00000000000060448201526064016107e1565b6000806000613bae85614642565b919450925090506000816001811115613bc957613bc9615305565b14613c165760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e00000000000060448201526064016107e1565b6000838660200151613c289190615a33565b80519091506020841015613c425760208490036101000a90045b9695505050505050565b603254610100900460ff16612be75760405162461bcd60e51b81526004016107e190615b38565b60408051808201909152600080825260208201526000825111613ca85760405162461bcd60e51b81526004016107e190615cba565b50604080518082019091528151815260209182019181019190915290565b60606107b86001600160a01b03831660145b60606000613ce7836002615a14565b613cf2906002615a33565b6001600160401b03811115613d0957613d09615153565b6040519080825280601f01601f191660200182016040528015613d33576020820181803683370190505b509050600360fc1b81600081518110613d4e57613d4e615937565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110613d7d57613d7d615937565b60200101906001600160f81b031916908160001a9053506000613da1846002615a14565b613dac906001615a33565b90505b6001811115613e24576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110613de057613de0615937565b1a60f81b828281518110613df657613df6615937565b60200101906001600160f81b031916908160001a90535060049490941c93613e1d81615d2a565b9050613daf565b508315612d365760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016107e1565b613e7c81612e6d565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b613f1b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016107e1565b600080846001600160a01b031684604051613f369190615adb565b600060405180830381855af49150503d8060008114613f71576040519150601f19603f3d011682016040523d82523d6000602084013e613f76565b606091505b5091509150612dd08282604051806060016040528060278152602001615eba60279139614d05565b606081613fac81601f615a33565b1015613fca5760405162461bcd60e51b81526004016107e190615d41565b613fd48284615a33565b845110156140185760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016107e1565b6060821580156140375760405191506000825260208201604052614081565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015614070578051835260209283019201614058565b5050858452601f01601f1916604052505b50949350505050565b6000828251600161409b9190615a33565b6140a6906002615e4d565b116140b057600080fd5b8360005b84600114614081576140c7600286615a83565b6001036141665760028482815181106140e2576140e2615937565b602002602001015183604051602001614105929190918252602082015260400190565b60408051601f198184030181529082905261411f91615adb565b602060405180830381855afa15801561413c573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061415f91906158b7565b91506141fa565b60028285838151811061417b5761417b615937565b602002602001015160405160200161419d929190918252602082015260400190565b60408051601f19818403018152908290526141b791615adb565b602060405180830381855afa1580156141d4573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906141f791906158b7565b91505b614205600286615a97565b945080614211816159bb565b9150506140b4565b80516060906000816001600160401b0381111561423857614238615153565b60405190808252806020026020018201604052801561427d57816020015b60408051808201909152606080825260208201528152602001906001900390816142565790505b50905060005b828110156142ff5760405180604001604052808683815181106142a8576142a8615937565b602002602001015181526020016142d78784815181106142ca576142ca615937565b6020026020010151614d1e565b8152508282815181106142ec576142ec615937565b6020908102919091010152600101614283565b509392505050565b80516060906000614319826002615a14565b6001600160401b0381111561433057614330615153565b6040519080825280601f01601f19166020018201604052801561435a576020820181803683370190505b5090506000805b838110156144175785818151811061437b5761437b615937565b6020910101516001600160f81b03198116925060041c60ff60f41b16836143a3836002615a14565b815181106143b3576143b3615937565b60200101906001600160f81b031916908160001a905350600f60f81b8216836143dd836002615a14565b6143e8906001615a33565b815181106143f8576143f8615937565b60200101906001600160f81b031916908160001a905350600101614361565b5090949350505050565b6060600080600061443185614642565b91945092509050600081600181111561444c5761444c615305565b146144bf5760405162461bcd60e51b815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d0000000000000060648201526084016107e1565b6144c98284615a33565b8551146145355760405162461bcd60e51b815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527330b71034b73b30b634b2103932b6b0b4b73232b960611b60648201526084016107e1565b612dd085602001518484614d2c565b606060208260000151106145605761455b82614421565b6107b8565b6107b882614dcc565b60606107b8614588836020015160008151811061330157613301615937565b614307565b6060825182106145ac57506040805160208101909152600081526107b8565b612d3683838486516145be9190615a01565b614de2565b600080600083518551106145d85783516145db565b84515b90505b808210801561463257508382815181106145fa576145fa615937565b602001015160f81c60f81b6001600160f81b03191685838151811061462157614621615937565b01602001516001600160f81b031916145b156142ff578160010191506145de565b60008060008084600001511161466a5760405162461bcd60e51b81526004016107e190615cba565b6020840151805160001a607f811161468f576000600160009450945094505050614cfe565b60b781116147ec5760006146a4608083615a01565b9050808760000151116147245760405162461bcd60e51b815260206004820152604e6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201526d2873686f727420737472696e672960901b608482015260a4016107e1565b6001838101516001600160f81b03191690821415806147515750600160ff1b6001600160f81b0319821610155b6147d95760405162461bcd60e51b815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201526c73686f727420737472696e672960981b608482015260a4016107e1565b5060019550935060009250614cfe915050565b60bf8111614a2d57600061480160b783615a01565b9050808760000151116148845760405162461bcd60e51b81526020600482015260516024820152600080516020615e7a83398151915260448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527067746820286c6f6e6720737472696e672960781b608482015260a4016107e1565b60018301516001600160f81b031916600081900361490b5760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152696e6720737472696e672960b01b608482015260a4016107e1565b600184015160088302610100031c6037811161498e5760405162461bcd60e51b81526020600482015260486024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201526720737472696e672960c01b608482015260a4016107e1565b6149988184615a33565b895111614a105760405162461bcd60e51b815260206004820152604c6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201526b6c6f6e6720737472696e672960a01b608482015260a4016107e1565b614a1b836001615a33565b9750955060009450614cfe9350505050565b60f78111614acf576000614a4260c083615a01565b905080876000015111614abe5760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e206c697374206c656e677468202873606482015269686f7274206c6973742960b01b608482015260a4016107e1565b600195509350849250614cfe915050565b6000614adc60f783615a01565b905080876000015111614b5b5760405162461bcd60e51b815260206004820152604d6024820152600080516020615e7a83398151915260448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201526c6820286c6f6e67206c6973742960981b608482015260a4016107e1565b60018301516001600160f81b0319166000819003614be05760405162461bcd60e51b81526020600482015260486024820152600080516020615e7a83398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152676e67206c6973742960c01b608482015260a4016107e1565b600184015160088302610100031c60378111614c615760405162461bcd60e51b81526020600482015260466024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e67606482015265206c6973742960d01b608482015260a4016107e1565b614c6b8184615a33565b895111614ce15760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e67746820286064820152696c6f6e67206c6973742960b01b608482015260a4016107e1565b614cec836001615a33565b9750955060019450614cfe9350505050565b9193909250565b60608315614d14575081612d36565b612d368383614e70565b60606107b8612d0583613c73565b60606000826001600160401b03811115614d4857614d48615153565b6040519080825280601f01601f191660200182016040528015614d72576020820181803683370190505b50905082600003614d84579050612d36565b6000614d908587615a33565b90506020820160005b85811015614db1578281015182820152602001614d99565b85811115614dc0576000868301525b50919695505050505050565b60606107b8826020015160008460000151614d2c565b60608182601f011015614e075760405162461bcd60e51b81526004016107e190615d41565b828284011015614e295760405162461bcd60e51b81526004016107e190615d41565b818301845110156140185760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016107e1565b815115614e805781518083602001fd5b8060405162461bcd60e51b81526004016107e1919061578d565b82805482825590600052602060002090600701600890048101928215614f395791602002820160005b83821115614f0757835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614ec3565b8015614f375782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614f07565b505b50614f45929150614f49565b5090565b5b80821115614f455760008155600101614f4a565b6001600160e01b031981168114610ac957600080fd5b600060208284031215614f8657600080fd5b8135612d3681614f5e565b80356001600160401b0381168114614fa857600080fd5b919050565b600060208284031215614fbf57600080fd5b612d3682614f91565b803563ffffffff81168114614fa857600080fd5b80356001600160a01b0381168114614fa857600080fd5b60008083601f84011261500557600080fd5b5081356001600160401b0381111561501c57600080fd5b60208301915083602082850101111561211f57600080fd5b6000806000806060858703121561504a57600080fd5b61505385614fc8565b935061506160208601614fdc565b925060408501356001600160401b0381111561507c57600080fd5b61508887828801614ff3565b95989497509550505050565b6000602082840312156150a657600080fd5b612d3682614fc8565b6000602082840312156150c157600080fd5b5035919050565b600080604083850312156150db57600080fd5b823591506150eb60208401614fdc565b90509250929050565b60006020828403121561510657600080fd5b612d3682614fdc565b60008083601f84011261512157600080fd5b5081356001600160401b0381111561513857600080fd5b6020830191508360208260051b850101111561211f57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561519157615191615153565b604052919050565b600082601f8301126151aa57600080fd5b81356001600160401b038111156151c3576151c3615153565b6151d6601f8201601f1916602001615169565b8181528460208386010111156151eb57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600080600080600080600060e08c8e03121561522957600080fd5b6001600160401b03808d35111561523f57600080fd5b61524c8e8e358f01614ff3565b909c509a5060208d013581101561526257600080fd5b6152728e60208f01358f01614ff3565b909a50985060408d013581101561528857600080fd5b6152988e60408f01358f0161510f565b909850965060608d0135955060808d01358110156152b557600080fd5b6152c58e60808f01358f0161510f565b909550935060a08d01358110156152db57600080fd5b506152ec8d60a08e01358e01615199565b915060c08c013590509295989b509295989b9093969950565b634e487b7160e01b600052602160045260246000fd5b602081016003831061533d57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561535657600080fd5b61535f83614fdc565b915060208301356001600160401b0381111561537a57600080fd5b61538685828601615199565b9150509250929050565b60006001600160401b038211156153a9576153a9615153565b5060051b60200190565b600082601f8301126153c457600080fd5b813560206153d96153d483615390565b615169565b82815260059290921b840181019181810190868411156153f857600080fd5b8286015b8481101561541a5761540d81614fdc565b83529183019183016153fc565b509695505050505050565b8015158114610ac957600080fd5b8035614fa881615425565b60008060008060008060c0878903121561545757600080fd5b86356001600160401b038082111561546e57600080fd5b818901915089601f83011261548257600080fd5b813560206154926153d483615390565b82815260059290921b8401810191818101908d8411156154b157600080fd5b948201945b838610156154d6576154c786614fc8565b825294820194908201906154b6565b9a50508a0135925050808211156154ec57600080fd5b6154f88a838b016153b3565b9650604089013591508082111561550e57600080fd5b5061551b89828a016153b3565b94505061552a60608801614fdc565b925061553860808801614fdc565b915061554660a08801615433565b90509295509295509295565b6000806000806060858703121561556857600080fd5b61557185614fc8565b93506020850135925060408501356001600160401b0381111561507c57600080fd5b60008060008060008060006080888a0312156155ae57600080fd5b6155b788614f91565b965060208801356001600160401b03808211156155d357600080fd5b6155df8b838c01614ff3565b909850965060408a01359150808211156155f857600080fd5b6156048b838c0161510f565b909650945060608a013591508082111561561d57600080fd5b5061562a8a828b0161510f565b989b979a50959850939692959293505050565b60008060006060848603121561565257600080fd5b61565b84614fc8565b925061566960208501614fdc565b915061567760408501614fdc565b90509250925092565b60006020828403121561569257600080fd5b8135612d3681615425565b60208082526013908201527214d95b991a5b99c81a5cc8191a5cd8589b1959606a1b604082015260600190565b60208082526019908201527f43616e6e6f742073656e6420746f2073616d6520636861696e00000000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60006001600160401b0380831681810361573357615733615701565b6001019392505050565b60005b83811015615758578181015183820152602001615740565b50506000910152565b6000815180845261577981602086016020860161573d565b601f01601f19169290920160200192915050565b602081526000612d366020830184615761565b60208082526035908201527f54656c657061746879526f757465723a206f6e6c7920677561726469616e206360408201527430b71031b0b636103a3434b990333ab731ba34b7b760591b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600080604083850312156158a057600080fd5b6158a983614f91565b91506150eb60208401614f91565b6000602082840312156158c957600080fd5b5051919050565b60006158de6153d484615390565b80848252602080830192508560051b8501368111156158fc57600080fd5b855b81811015614dc05780356001600160401b0381111561591d5760008081fd5b61592936828a01615199565b8652509382019382016158fe565b634e487b7160e01b600052603260045260246000fd5b600063ffffffff80831681810361573357615733615701565b60208082526035908201527f54656c657061746879526f757465723a206f6e6c792074696d656c6f636b206360408201527430b71031b0b636103a3434b990333ab731ba34b7b760591b606082015260800190565b6000600182016159cd576159cd615701565b5060010190565b8183823760009101908152919050565b6000602082840312156159f657600080fd5b8151612d3681615425565b818103818111156107b8576107b8615701565b6000816000190483118215151615615a2e57615a2e615701565b500290565b808201808211156107b8576107b8615701565b6001600160401b03828116828216039080821115615a6657615a66615701565b5092915050565b634e487b7160e01b600052601260045260246000fd5b600082615a9257615a92615a6d565b500690565b600082615aa657615aa6615a6d565b500490565b63ffffffff841681526001600160a01b0383166020820152606060408201819052600090612dd090830184615761565b60008251615aed81846020870161573d565b9190910192915050565b600060208284031215615b0957600080fd5b8151612d3681614f5e565b604081526000615b276040830185615761565b905082151560208301529392505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160f81b031960f889901b1681526001600160c01b031960c088901b1660018201526001600160e01b031960e087811b821660098401526001600160601b0319606088901b16600d84015285901b166021820152602581018390528151600090615bf781604585016020870161573d565b9190910160450198975050505050505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615c4281601785016020880161573d565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615c7381602884016020880161573d565b01602801949350505050565b600060ff831680615c9257615c92615a6d565b8060ff84160691505092915050565b60ff82811682821603908111156107b8576107b8615701565b6020808252604a908201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60408201527f206d7573742062652067726561746572207468616e207a65726f20746f206265606082015269206465636f6461626c6560b01b608082015260a00190565b600081615d3957615d39615701565b506000190190565b6020808252600e908201526d736c6963655f6f766572666c6f7760901b604082015260600190565b600181815b80851115615da4578160001904821115615d8a57615d8a615701565b80851615615d9757918102915b93841c9390800290615d6e565b509250929050565b600082615dbb575060016107b8565b81615dc8575060006107b8565b8160018114615dde5760028114615de857615e04565b60019150506107b8565b60ff841115615df957615df9615701565b50506001821b6107b8565b5060208310610133831016604e8410600b8410161715615e27575081810a6107b8565b615e318383615d69565b8060001904821115615e4557615e45615701565b029392505050565b6000612d368383615dac56fef66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05524c505265616465723a206c656e677468206f6620636f6e74656e74206d7573360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656455435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041a2646970667358221220f69b1c44e29eed792424bef643e588366626efef00e60b2c59813e1a349096ed64736f6c63430008100033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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.