ETH Price: $1,982.13 (-5.07%)

Contract

0x370634E1064B945e9010DDfA6077F321EcA431cf
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Contract Source Code Verified (Exact Match)

Contract Name:
UpgradableMeson

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 100 runs

Other Settings:
paris EvmVersion, MIT license
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "./MesonManager.sol";

contract UpgradableMeson is UUPSUpgradeable, MesonManager {
  function initialize(address owner, address premiumManager) external initializer {
    _transferOwnership(owner);
    _transferPremiumManager(premiumManager);
  }

  function _authorizeUpgrade(address) internal override onlyOwner {}
}

File 2 of 47 : 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 3 of 47 : 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);
}

// 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 5 of 47 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (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. Equivalent to `reinitializer(1)`.
     */
    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.
     *
     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
     * initialization step. This is essential to configure modules that are added through upgrades and that require
     * initialization.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.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 that the this implementation remains valid after 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;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20Upgradeable.sol";
import "./extensions/IERC20MetadataUpgradeable.sol";
import "../../utils/ContextUpgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
        __ERC20_init_unchained(name_, symbol_);
    }

    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
        }
        _balances[to] += amount;

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) 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[45] private __gap;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20Upgradeable.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason 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 {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// 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;
}

// 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 13 of 47 : draft-IERC1822.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 IERC1822Proxiable {
    /**
     * @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);
}

// 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 IBeacon {
    /**
     * @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);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)

pragma solidity ^0.8.0;

import "../Proxy.sol";
import "./ERC1967Upgrade.sol";

/**
 * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
 * implementation address that can be changed. This address is stored in storage in the location specified by
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
 * implementation behind the proxy.
 */
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
    /**
     * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
     *
     * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
     * function call, and allows initializing the storage of the proxy like a Solidity constructor.
     */
    constructor(address _logic, bytes memory _data) payable {
        _upgradeToAndCall(_logic, _data, false);
    }

    /**
     * @dev Returns the current implementation address.
     */
    function _implementation() internal view virtual override returns (address impl) {
        return ERC1967Upgrade._getImplementation();
    }
}

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

pragma solidity ^0.8.2;

import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.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 ERC1967Upgrade {
    // 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 StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlot.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) {
            Address.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 (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822Proxiable(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 StorageSlot.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");
        StorageSlot.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 StorageSlot.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            Address.isContract(IBeacon(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlot.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) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)

pragma solidity ^0.8.0;

/**
 * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
 * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
 * be specified by overriding the virtual {_implementation} function.
 *
 * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
 * different contract through the {_delegate} function.
 *
 * The success and return data of the delegated call will be returned back to the caller of the proxy.
 */
abstract contract Proxy {
    /**
     * @dev Delegates the current call to `implementation`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _delegate(address implementation) internal virtual {
        assembly {
            // Copy msg.data. We take full control of memory in this inline assembly
            // block because it will not return to Solidity code. We overwrite the
            // Solidity scratch pad at memory position 0.
            calldatacopy(0, 0, calldatasize())

            // Call the implementation.
            // out and outsize are 0 because we don't know the size yet.
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())

            switch result
            // delegatecall returns 0 on error.
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    /**
     * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
     * and {_fallback} should delegate.
     */
    function _implementation() internal view virtual returns (address);

    /**
     * @dev Delegates the current call to the address returned by `_implementation()`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _fallback() internal virtual {
        _beforeFallback();
        _delegate(_implementation());
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
     * function in the contract matches the call data.
     */
    fallback() external payable virtual {
        _fallback();
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
     * is empty.
     */
    receive() external payable virtual {
        _fallback();
    }

    /**
     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
     * call, or as part of the Solidity `fallback` or `receive` functions.
     *
     * If overridden should call `super._beforeFallback()`.
     */
    function _beforeFallback() internal virtual {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
        }
        _balances[to] += amount;

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason 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 {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

// 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 StorageSlot {
    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
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/// @title Interface for depositWithBeneficiary
interface IDepositWithBeneficiary {
  /// @notice Make a token transfer that the *signer* is paying tokens but benefits are given to the *beneficiary*
  /// @param token The contract address of the transferring token
  /// @param amount The amount of the transfer
  /// @param beneficiary The address that will receive benefits of this transfer
  /// @param data Extra data passed to the contract
  /// @return Returns true for a successful transfer.
  function depositWithBeneficiary(address token, uint256 amount, address beneficiary, uint64 data)
    payable external returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

/// @title Minimal ERC20 interface for Uniswap
/// @notice Contains a subset of the full ERC20 interface that is used in Uniswap V3
interface IERC20Minimal {
  /// @notice Returns the balance of a token
  /// @param account The account for which to look up the number of tokens it has, i.e. its balance
  /// @return The number of tokens held by the account
  function balanceOf(address account) external view returns (uint256);

  /// @notice Transfers the amount of token from the `msg.sender` to the recipient
  /// @param recipient The account that will receive the amount transferred
  /// @param amount The number of tokens to send from the sender to the recipient
  /// @return Returns true for a successful transfer, false for an unsuccessful transfer
  function transfer(address recipient, uint256 amount) external returns (bool);

  /// @notice Returns the current allowance given to a spender by an owner
  /// @param owner The account of the token owner
  /// @param spender The account of the token spender
  /// @return The current allowance granted by `owner` to `spender`
  function allowance(address owner, address spender) external view returns (uint256);

  /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount`
  /// @param spender The account which will be allowed to spend a given amount of the owners tokens
  /// @param amount The amount of tokens allowed to be used by `spender`
  /// @return Returns true for a successful approval, false for unsuccessful
  function approve(address spender, uint256 amount) external returns (bool);

  /// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender`
  /// @param sender The account from which the transfer will be initiated
  /// @param recipient The recipient of the transfer
  /// @param amount The amount of the transfer
  /// @return Returns true for a successful transfer, false for unsuccessful
  function transferFrom(
      address sender,
      address recipient,
      uint256 amount
  ) external returns (bool);

  /// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`.
  /// @param from The account from which the tokens were sent, i.e. the balance decreased
  /// @param to The account to which the tokens were sent, i.e. the balance increased
  /// @param value The amount of tokens that were transferred
  event Transfer(address indexed from, address indexed to, uint256 value);

  /// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes.
  /// @param owner The account that approved spending of its tokens
  /// @param spender The account for which the spending allowance was modified
  /// @param value The new allowance from the owner to the spender
  event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 26 of 47 : Meson.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "./MesonManager.sol";

/// @title Meson
/// @notice A plain non-upgradeable Meson
contract Meson is MesonManager {
  constructor(address premiumManager) {
    _transferOwnership(_msgSender());
    _transferPremiumManager(premiumManager);
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "./Swap/MesonSwap.sol";
import "./Pools/MesonPools.sol";

/// @title MesonManager
/// @notice The class to store data related to management permissions of Meson
contract MesonManager is MesonSwap, MesonPools {
  /// @notice The admin of meson contract
  /// The owner has the permission to upgrade meson contract. In future versions,
  /// the management authority of meson contract will be decentralized.
  address internal _owner;

  /// @notice The manager to authorized fee waived swaps
  /// Only the premium manager can authorize the execution to release for fee waived swaps.
  /// This address is managed by Meson team.
  address internal _premiumManager;

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

  event OwnerTransferred(address indexed prevOwner, address indexed newOwner);

  event PremiumManagerTransferred(address indexed prevPremiumManager, address indexed newPremiumManager);

  /// @notice The owner will also have the permission to add supported tokens
  function addSupportToken(address token, uint8 index) external onlyOwner {
    _addSupportToken(token, index);
  }

  /// @notice The owner will also have the permission to remove a supported tokens
  function removeSupportToken(uint8 index) external onlyOwner {
    _removeSupportToken(index);
  }

  /// @notice Add multiple tokens
  function addMultipleSupportedTokens(address[] memory tokens, uint8[] memory indexes) external onlyOwner {
    require(tokens.length == indexes.length, "Tokens and indexes should have the same length");
    for (uint8 i = 0; i < tokens.length; i++) {
      _addSupportToken(tokens[i], indexes[i]);
    }
  }

  function transferOwnership(address newOwner) public onlyOwner {
    _transferOwnership(newOwner);
  }

  function transferPremiumManager(address newPremiumManager) public {
    require(_isPremiumManager(), "Caller is not the premium manager");
    _transferPremiumManager(newPremiumManager);
  }

  function withdrawServiceFee(uint8 tokenIndex, uint256 amount, uint40 toPoolIndex) external onlyOwner {
    require(ownerOfPool[toPoolIndex] != address(0), "Pool index not registered");
    _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 0)] -= amount;
    _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, toPoolIndex)] += amount;
  }

  function adjustToPool(uint8 tokenIndex, uint256 amount, uint40 toPoolIndex) external onlyOwner {
    require(ownerOfPool[toPoolIndex] != address(0), "Pool index not registered");
    _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, toPoolIndex)] += amount;
  }

  modifier onlyOwner() {
    require(_owner == _msgSender(), "Caller is not the owner");
    _;
  }

  function _transferOwnership(address newOwner) internal {
    require(newOwner != address(0), "New owner cannot be zero address");
    address prevOwner = _owner;
    _owner = newOwner;
    emit OwnerTransferred(prevOwner, newOwner);
  }

  function _isPremiumManager() internal view override returns (bool) {
    return _premiumManager == _msgSender();
  }

  function _transferPremiumManager(address newPremiumManager) internal {
    require(newPremiumManager != address(0), "New premium manager be zero address");
    address prevPremiumManager = _premiumManager;
    _premiumManager = newPremiumManager;
    emit PremiumManagerTransferred(prevPremiumManager, newPremiumManager);
  }

  function directSwap(uint256 encodedSwap, address recipient, bytes32 r, bytes32 yParityAndS)
    external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap) forTargetChain(encodedSwap)
  {
    require(recipient != address(0), "Recipient cannot be zero address");

    bytes32 digest = keccak256(abi.encodePacked(encodedSwap, recipient));
    _checkSignature(digest, r, yParityAndS, _premiumManager);

    uint256 amount = _amountFrom(encodedSwap);
    uint8 inTokenIndex = _inTokenIndexFrom(encodedSwap);
    uint256 releaseAmount = amount - _feeForLp(encodedSwap);

    _balanceOfPoolToken[_poolTokenIndexFrom(inTokenIndex, 1)] += amount;
    _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, 1)] -= releaseAmount;

    _unsafeDepositToken(inTokenIndex, _msgSender(), amount);
    _release(encodedSwap, _outTokenIndexFrom(encodedSwap), _msgSender(), recipient, releaseAmount);

    emit SwapReleased(encodedSwap);
  }
}

File 28 of 47 : IMesonPoolsEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/// @title MesonPools Interface
interface IMesonPoolsEvents {
  /// @notice Event when an LP pool is registered.
  /// Emit at the end of `depositAndRegister()` calls.
  /// @param poolIndex Pool index
  /// @param owner Pool owner
  event PoolRegistered(uint40 indexed poolIndex, address owner);

  /// @notice Event when fund was deposited to an LP pool.
  /// Emit at the end of `depositAndRegister()` and `deposit()` calls.
  /// @param poolTokenIndex Concatenation of pool index & token index
  /// @param amount The amount of tokens to be added to the pool
  event PoolDeposited(uint48 indexed poolTokenIndex, uint256 amount);

  /// @notice Event when fund was withdrawn from an LP pool.
  /// Emit at the end of `withdraw()` calls.
  /// @param poolTokenIndex Concatenation of pool index & token index
  /// @param amount The amount of tokens to be removed from the pool
  event PoolWithdrawn(uint48 indexed poolTokenIndex, uint256 amount);

  /// @notice Event when an authorized address was added for an LP pool.
  /// Emit at the end of `depositAndRegister()` calls.
  /// @param poolIndex Pool index
  /// @param addr Authorized address to be added
  event PoolAuthorizedAddrAdded(uint40 indexed poolIndex, address addr);

  /// @notice Event when an authorized address was removed for an LP pool.
  /// Emit at the end of `depositAndRegister()` calls.
  /// @param poolIndex Pool index
  /// @param addr Authorized address to be removed
  event PoolAuthorizedAddrRemoved(uint40 indexed poolIndex, address addr);

  /// @notice Event when the ownership of a pool was transferred.
  /// Emit at the end of `transferPoolOwner()` calls.
  /// @param poolIndex Pool index
  /// @param prevOwner Previous owner of the pool
  /// @param newOwner New owner of the pool
  event PoolOwnerTransferred(uint40 indexed poolIndex, address prevOwner, address newOwner);

  /// @notice Event when a swap was locked.
  /// Emit at the end of `lock()` and `lockSwap()` calls.
  /// @param encodedSwap Encoded swap
  event SwapLocked(uint256 indexed encodedSwap);

  /// @notice Event when a swap was unlocked.
  /// Emit at the end of `unlock()` calls.
  /// @param encodedSwap Encoded swap
  event SwapUnlocked(uint256 indexed encodedSwap);

  /// @notice Event when a swap was released.
  /// Emit at the end of `release()`, `directRelease()` calls.
  /// @param encodedSwap Encoded swap
  event SwapReleased(uint256 indexed encodedSwap);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "./IMesonPoolsEvents.sol";
import "../utils/MesonStates.sol";

/// @title MesonPools
/// @notice The class to manage pools for LPs, and perform swap operations on the target 
/// chain side.
/// Methods in this class will be executed when a user wants to swap into this chain.
/// LP pool operations are also provided in this class.
contract MesonPools is IMesonPoolsEvents, MesonStates {
  /// @notice Locked Swaps
  /// key: `swapId` is calculated from `encodedSwap` and `initiator`. See `_getSwapId` in `MesonHelpers.sol`
  ///   encodedSwap: see `MesonSwap.sol` for defination;
  ///   initiator: The user address who created and signed the swap request.
  /// value: `lockedSwap` in format of `until:uint40|poolIndex:uint40`
  ///   until: The expiration time of this swap on the target chain. Need to `release` the swap fund before `until`;
  ///   poolIndex: The index of an LP pool. See `ownerOfPool` in `MesonStates.sol` for more information.
  mapping(bytes32 => uint80) internal _lockedSwaps;

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

  /// @notice Initially deposit tokens into an LP pool and register a pool index.
  /// This is the prerequisite for LPs if they want to participate in Meson swaps.
  /// @dev Designed to be used by a new address who wants to be an LP and register a pool index
  /// @param amount The amount of tokens to be added to the pool
  /// @param poolTokenIndex In format of `tokenIndex:uint8|poolIndex:uint40`. See `_balanceOfPoolToken` in `MesonStates.sol` for more information.
  function depositAndRegister(uint256 amount, uint48 poolTokenIndex) payable external {
    require(amount > 0, "Amount must be positive");

    address poolOwner = _msgSender();
    uint40 poolIndex = _poolIndexFrom(poolTokenIndex);
    require(poolIndex != 0, "Cannot use 0 as pool index"); // pool 0 is reserved for meson service fee
    require(ownerOfPool[poolIndex] == address(0), "Pool index already registered");
    require(poolOfAuthorizedAddr[poolOwner] == 0, "Signer address already registered");
    ownerOfPool[poolIndex] = poolOwner;
    poolOfAuthorizedAddr[poolOwner] = poolIndex;

    _balanceOfPoolToken[poolTokenIndex] += amount;
    uint8 tokenIndex = _tokenIndexFrom(poolTokenIndex);
    _unsafeDepositToken(tokenIndex, poolOwner, amount);

    emit PoolRegistered(poolIndex, poolOwner);
    emit PoolDeposited(poolTokenIndex, amount);
  }

  /// @notice Deposit tokens into the liquidity pool.
  /// The LP should be careful to make sure the `poolTokenIndex` is correct.
  /// Make sure to call `depositAndRegister` first and register a pool index.
  /// Otherwise, token may be deposited to others.
  /// @dev Designed to be used by addresses authorized to a pool
  /// @param amount The amount of tokens to be added to the pool
  /// @param poolTokenIndex In format of `tokenIndex:uint8|poolIndex:uint40`. See `_balanceOfPoolToken` in `MesonStates.sol` for more information.
  function deposit(uint256 amount, uint48 poolTokenIndex) payable external {
    require(amount > 0, "Amount must be positive");

    uint40 poolIndex = _poolIndexFrom(poolTokenIndex);
    require(poolIndex != 0, "Cannot use 0 as pool index"); // pool 0 is reserved for meson service fee
    require(poolIndex == poolOfAuthorizedAddr[_msgSender()], "Need an authorized address as the signer");
    _balanceOfPoolToken[poolTokenIndex] += amount;
    uint8 tokenIndex = _tokenIndexFrom(poolTokenIndex);
    _unsafeDepositToken(tokenIndex, _msgSender(), amount);

    emit PoolDeposited(poolTokenIndex, amount);
  }

  /// @notice Withdraw tokens from the liquidity pool.
  /// @dev Designed to be used by LPs (pool owners) who have already registered a pool index
  /// @param amount The amount to be removed from the pool
  /// @param poolTokenIndex In format of `tokenIndex:uint8|poolIndex:uint40. See `_balanceOfPoolToken` in `MesonStates.sol` for more information.
  function withdraw(uint256 amount, uint48 poolTokenIndex) external {
    require(amount > 0, "Amount must be positive");

    uint40 poolIndex = _poolIndexFrom(poolTokenIndex);
    require(poolIndex != 0, "Cannot use 0 as pool index"); // pool 0 is reserved for meson service fee
    require(ownerOfPool[poolIndex] == _msgSender(), "Need the pool owner as the signer");
    _balanceOfPoolToken[poolTokenIndex] -= amount;
    uint8 tokenIndex = _tokenIndexFrom(poolTokenIndex);
    _safeTransfer(tokenIndex, _msgSender(), amount);

    emit PoolWithdrawn(poolTokenIndex, amount);
  }

  /// @notice Add an authorized address to the pool
  /// @dev Designed to be used by LPs (pool owners)
  /// @param addr The address to be added
  function addAuthorizedAddr(address addr) external {
    address poolOwner = _msgSender();
    uint40 poolIndex = poolOfAuthorizedAddr[poolOwner];
    require(poolIndex != 0, "The signer does not register a pool");
    require(poolOwner == ownerOfPool[poolIndex], "Need the pool owner as the signer");
    require(poolOfAuthorizedAddr[addr] == 0, "Addr is authorized for another pool");
    poolOfAuthorizedAddr[addr] = poolIndex;

    emit PoolAuthorizedAddrAdded(poolIndex, addr);
  }
  
  /// @notice Remove an authorized address from the pool
  /// @dev Designed to be used by LPs (pool owners)
  /// @param addr The address to be removed
  function removeAuthorizedAddr(address addr) external {
    address poolOwner = _msgSender();
    uint40 poolIndex = poolOfAuthorizedAddr[poolOwner];
    require(poolIndex != 0, "The signer does not register a pool");
    require(poolOwner == ownerOfPool[poolIndex], "Need the pool owner as the signer");
    require(poolOfAuthorizedAddr[addr] == poolIndex, "Addr is not authorized for the signer's pool");
    delete poolOfAuthorizedAddr[addr];

    emit PoolAuthorizedAddrRemoved(poolIndex, addr);
  }

  /// @notice Transfer the ownership of a pool to another address
  /// @dev Designed to be used by LPs (pool owners)
  /// @param addr The new address to be the pool owner
  function transferPoolOwner(address addr) external {
    address poolOwner = _msgSender();
    uint40 poolIndex = poolOfAuthorizedAddr[poolOwner];
    require(poolIndex != 0, "The signer does not register a pool");
    require(poolOwner == ownerOfPool[poolIndex], "Need the pool owner as the signer");
    require(poolOfAuthorizedAddr[addr] == poolIndex, "Addr is not authorized for the signer's pool");
    ownerOfPool[poolIndex] = addr;

    emit PoolOwnerTransferred(poolIndex, poolOwner, addr);
  }

  function lock(uint256 encodedSwap, bytes32, bytes32, address initiator) external {
    // deprecated
    lockSwap(encodedSwap, initiator);
  }

  /// @notice Lock funds to match a swap request. This is step 2️⃣ in a swap.
  /// The authorized address of the bonding pool should call this method,
  /// which will lock swapping fund on the target chain for `LOCK_TIME_PERIOD`
  /// and wait for fund release and execution.
  /// @dev Designed to be used by authorized addresses or pool owners
  /// @param encodedSwap Encoded swap information
  /// @param initiator The swap initiator who created and signed the swap request
  function lockSwap(uint256 encodedSwap, address initiator)
    public matchProtocolVersion(encodedSwap) forTargetChain(encodedSwap)
  {
    bytes32 swapId = _getSwapId(encodedSwap, initiator);
    require(_lockedSwaps[swapId] == 0, "Swap already exists");

    uint40 poolIndex = poolOfAuthorizedAddr[_msgSender()];
    require(poolIndex != 0, "Caller not registered. Call depositAndRegister.");

    uint256 until = block.timestamp + LOCK_TIME_PERIOD;
    require(until < _expireTsFrom(encodedSwap) - 5 minutes, "Cannot lock because expireTs is soon.");

    uint48 poolTokenIndex = _poolTokenIndexForOutToken(encodedSwap, poolIndex);
    _balanceOfPoolToken[poolTokenIndex] -= _amountToLock(encodedSwap); // The service fee will be charged on release

    uint256 coreAmount = _coreTokenAmount(encodedSwap);
    if (coreAmount > 0) {
      _balanceOfPoolToken[_poolTokenIndexFrom(indexOfToken[address(1)], poolIndex)] -= coreAmount;
    }

    _lockedSwaps[swapId] = _lockedSwapFrom(until, poolIndex);

    emit SwapLocked(encodedSwap);
  }

  /// @notice If the locked swap is not released after `LOCK_TIME_PERIOD`,
  /// the authorized address can call this method to unlock the swapping fund.
  /// @dev Designed to be used by authorized addresses or pool owners
  /// @param encodedSwap Encoded swap information
  /// @param initiator The swap initiator who created and signed the swap request
  function unlock(uint256 encodedSwap, address initiator) external {
    bytes32 swapId = _getSwapId(encodedSwap, initiator);
    uint80 lockedSwap = _lockedSwaps[swapId];
    require(lockedSwap > 1, "Swap does not exist");
    require(_untilFromLocked(lockedSwap) < block.timestamp, "Swap still in lock");

    uint40 poolIndex = _poolIndexFromLocked(lockedSwap);
    uint48 poolTokenIndex = _poolTokenIndexForOutToken(encodedSwap, poolIndex);
    _balanceOfPoolToken[poolTokenIndex] += _amountToLock(encodedSwap);

    uint256 coreAmount = _coreTokenAmount(encodedSwap);
    if (coreAmount > 0) {
      _balanceOfPoolToken[_poolTokenIndexFrom(indexOfToken[address(1)], poolIndex)] += coreAmount;
    }

    delete _lockedSwaps[swapId];

    emit SwapUnlocked(encodedSwap);
  }

  /// @notice Release tokens to satisfy a locked swap. This is step 3️⃣ in a swap.
  /// This method requires a release signature from the swap initiator,
  /// but anyone (initiator herself, the LP, and other people) with the signature 
  /// can call this method to make sure the swapping fund is guaranteed to be released.
  /// @dev Designed to be used by anyone
  /// @param encodedSwap Encoded swap information
  /// @param r Part of the release signature (same as in the `executeSwap` call)
  /// @param yParityAndS Part of the release signature (same as in the `executeSwap` call)
  /// @param initiator The swap initiator who created and signed the swap request
  /// @param recipient The recipient address of the swap
  function release(
    uint256 encodedSwap,
    bytes32 r,
    bytes32 yParityAndS,
    address initiator,
    address recipient
  ) external {
    require(_msgSender() == tx.origin, "Cannot be called through contracts");
    require(_expireTsFrom(encodedSwap) > block.timestamp, "Cannot release because expired");
    require(recipient != address(0), "Recipient cannot be zero address");

    bool feeWaived = _feeWaived(encodedSwap);
    if (feeWaived) {
      // For swaps that service fee is waived, need the premium manager as the signer
      require(_isPremiumManager(), "Caller is not the premium manager");
    }
    // For swaps that charge service fee, anyone can call

    bytes32 swapId = _getSwapId(encodedSwap, initiator);
    require(_lockedSwaps[swapId] > 1, "Swap does not exist");

    _checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, initiator);
    _lockedSwaps[swapId] = 1;

    // LP fee will be subtracted from the swap amount
    uint256 releaseAmount = _amountToLock(encodedSwap);
    if (!feeWaived) { // If the swap should pay service fee (charged by Meson protocol)
      uint256 serviceFee = _serviceFee(encodedSwap);
      // Subtract service fee from the release amount
      releaseAmount -= serviceFee;
      // Collected service fee will be stored in `_balanceOfPoolToken` with `poolIndex = 0`.
      // Currently, no one is capable to withdraw fund from pool 0. In the future, Meson protocol
      // will specify the purpose of service fee and its usage permission, and upgrade the contract
      // accordingly.
      _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, 0)] += serviceFee;
    }

    uint256 amountToShare = _amountToShare(encodedSwap);
    if (amountToShare > 0) {
      releaseAmount -= amountToShare;
      _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, _poolIndexToShare(encodedSwap))] += amountToShare;
    }

    uint256 coreAmount = _coreTokenAmount(encodedSwap);
    if (coreAmount > 0) {
      _transferCoreToken(recipient, coreAmount);
    }
    _release(encodedSwap, _outTokenIndexFrom(encodedSwap), initiator, recipient, releaseAmount);

    emit SwapReleased(encodedSwap);
  }

  function directRelease(
    uint256 encodedSwap,
    bytes32 r,
    bytes32 yParityAndS,
    address initiator,
    address recipient
  ) external matchProtocolVersion(encodedSwap) forTargetChain(encodedSwap) {
    require(_msgSender() == tx.origin, "Cannot be called through contracts");
    require(recipient != address(0), "Recipient cannot be zero address");

    bool feeWaived = _feeWaived(encodedSwap);
    if (feeWaived) {
      require(_isPremiumManager(), "Caller is not the premium manager");
    }

    bytes32 swapId = _getSwapId(encodedSwap, initiator);
    require(_lockedSwaps[swapId] == 0, "Swap already exists");

    uint40 poolIndex = poolOfAuthorizedAddr[_msgSender()];
    require(poolIndex != 0, "Caller not registered. Call depositAndRegister.");

    if (r != bytes32(0x0)) {
      require(_expireTsFrom(encodedSwap) > block.timestamp, "Cannot release because expired");
      _checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, initiator);
    } else if (!feeWaived) {
      require(_isPremiumManager(), "Caller is not the premium manager");
    }
    _lockedSwaps[swapId] = 1;

    uint256 releaseAmount = _amountToLock(encodedSwap);
    _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, poolIndex)] -= releaseAmount;

    if (!feeWaived) {
      uint256 serviceFee = _serviceFee(encodedSwap);
      releaseAmount -= serviceFee;
      _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, 0)] += serviceFee;
    }

    uint256 amountToShare = _amountToShare(encodedSwap);
    if (amountToShare > 0) {
      releaseAmount -= amountToShare;
      _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, _poolIndexToShare(encodedSwap))] += amountToShare;
    }

    uint256 coreAmount = _coreTokenAmount(encodedSwap);
    if (coreAmount > 0) {
      _balanceOfPoolToken[_poolTokenIndexFrom(indexOfToken[address(1)], poolIndex)] -= coreAmount;
      _transferCoreToken(recipient, coreAmount);
    }
    _release(encodedSwap, _outTokenIndexFrom(encodedSwap), initiator, recipient, releaseAmount);

    emit SwapReleased(encodedSwap);
  }

  function _release(uint256 encodedSwap, uint8 tokenIndex, address initiator, address recipient, uint256 amount) internal {
    if (_willTransferToContract(encodedSwap)) {
      _transferToContract(tokenIndex, recipient, initiator, amount, _saltDataFrom(encodedSwap));
    } else if (amount > 0) {
      _safeTransfer(tokenIndex, recipient, amount);
      if ((SHORT_COIN_TYPE == 0x9296 || SHORT_COIN_TYPE == 0xb4b1 || SHORT_COIN_TYPE == 0x6c62) && _swapForCoreToken(encodedSwap)) {
        _callSkaleFaucet(recipient);
      }
    }
  }

  function _callSkaleFaucet(address recipient) private {
    if (SHORT_COIN_TYPE == 0x9296) {
      // SKALE Europa
      bytes memory data = abi.encodeWithSelector(bytes4(0x6a627842), recipient);
      (bool success, ) = address(0x2B267A3e49b351DEdac892400a530ABb2f899d23).call(data);
      require(success, "Call faucet not successful");
    } else if (SHORT_COIN_TYPE == 0xb4b1) {
      // SKALE Nebula
      bytes memory data = abi.encodeWithSelector(bytes4(0x0c11dedd), recipient);
      (bool success, ) = address(0x5a6869ef5b81DCb58EBF51b8F893c31f5AFE3Fa8).call(data);
      require(success, "Call faucet not successful");
    } else if (SHORT_COIN_TYPE == 0x6c62) {
      // SKALE Calypso
      bytes memory data = abi.encodeWithSelector(bytes4(0x0c11dedd), recipient);
      (bool success, ) = address(0x02891b34B7911A9C68e82C193cd7A6fBf0c3b30A).call(data);
      require(success, "Call faucet not successful");
    }
  }

  /// @notice Read information for a locked swap
  function getLockedSwap(uint256 encodedSwap, address initiator) external view
    returns (address poolOwner, uint40 until)
  {
    bytes32 swapId = _getSwapId(encodedSwap, initiator);
    uint80 lockedSwap = _lockedSwaps[swapId];
    if (lockedSwap == 1) {
      poolOwner = address(1);
      until = 0;
    } else {
      poolOwner = ownerOfPool[_poolIndexFromLocked(lockedSwap)];
      until = uint40(_untilFromLocked(lockedSwap));
    }
  }

  modifier forTargetChain(uint256 encodedSwap) {
    require(_outChainFrom(encodedSwap) == SHORT_COIN_TYPE, "Swap not for this chain");
    _;
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import "./UpgradableMeson.sol";

// Some blockchains do not support deploying another contract in constructor
contract Proxy2ToMeson is ERC1967Proxy {
  bytes4 private constant INITIALIZE_SELECTOR = bytes4(keccak256("initialize(address,address)"));

  constructor(address implAddress, address premiumManager) ERC1967Proxy(implAddress, _encodeData(msg.sender, premiumManager)) {}

  function _encodeData(address owner, address premiumManager) private pure returns (bytes memory) {
    return abi.encodeWithSelector(INITIALIZE_SELECTOR, owner, premiumManager);
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import "./UpgradableMeson.sol";

contract ProxyToMeson is ERC1967Proxy {
  bytes4 private constant INITIALIZE_SELECTOR = bytes4(keccak256("initialize(address,address)"));

  constructor(address premiumManager) ERC1967Proxy(_deployImpl(), _encodeData(msg.sender, premiumManager)) {}

  function _deployImpl() private returns (address) {
    UpgradableMeson _impl = new UpgradableMeson();
    return address(_impl);
  }

  function _encodeData(address owner, address premiumManager) private pure returns (bytes memory) {
    return abi.encodeWithSelector(INITIALIZE_SELECTOR, owner, premiumManager);
  }
}

File 32 of 47 : IMesonSwapEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/// @title MesonSwapEvents Interface
interface IMesonSwapEvents {
  /// @notice Event when a swap request was posted.
  /// Emit at the end of `postSwap()` and `postSwapWithSignature()` calls.
  /// @param encodedSwap Encoded swap
  event SwapPosted(uint256 indexed encodedSwap);

  /// @notice Event when a swap request was bonded.
  /// Emit at the end of `bondSwap()` calls.
  /// @param encodedSwap Encoded swap
  event SwapBonded(uint256 indexed encodedSwap);

  /// @notice Event when a swap request was cancelled.
  /// Emit at the end of `cancelSwap()` and `cancelSwapTo()` calls.
  /// @param encodedSwap Encoded swap
  event SwapCancelled(uint256 indexed encodedSwap);

  /// @notice Event when a swap request was executed.
  /// Emit at the end of `executeSwap()`, `directExecuteSwap()` and `simpleExecuteSwap()` calls.
  /// @param encodedSwap Encoded swap
  event SwapExecuted(uint256 indexed encodedSwap);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "./IMesonSwapEvents.sol";
import "../utils/MesonStates.sol";

/// @title MesonSwap
/// @notice The class to receive and process swap requests on the initial chain side.
/// Methods in this class will be executed by swap initiators or LPs
/// on the initial chain of swaps.
contract MesonSwap is IMesonSwapEvents, MesonStates {
  /// @notice Posted Swaps
  /// key: `encodedSwap` in format of `version:uint8|amount:uint40|salt:uint80|fee:uint40|expireTs:uint40|outChain:uint16|outToken:uint8|inChain:uint16|inToken:uint8`
  ///   version: Version of encoding
  ///   amount: The amount of tokens of this swap, always in decimal 6. The amount of a swap is capped at $100k so it can be safely encoded in uint48;
  ///   salt: The salt value of this swap, carrying some information below:
  ///     salt & 0x80000000000000000000 == true => will release to an EOA address, otherwise a smart contract;
  ///     salt & 0x40000000000000000000 == true => will waive *service fee*;
  ///     salt & 0x30000000000000000000 == 0x3. => from TransferToMesonContract;
  ///     salt & 0x30000000000000000000 == 0x2. => meson.to;
  ///     salt & 0x30000000000000000000 == 0x1. => API;
  ///     salt & 0x08000000000000000000 == true => use *non-typed signing* (some wallets such as hardware wallets don't support EIP-712v1);
  ///     salt & 0x04000000000000000000 == true => swap for core token (n/a for releasing to contract);
  ///         salt & 0xfffff00000000000         => price for core token;
  ///         salt & 0x00000fff00000000         => amount for core token;
  ///     salt & 0x02000000000000000000 == true => share some release amount to partner;
  ///         salt & 0xffff000000000000 + 65536 => pool index to share;
  ///         salt & 0x0000ffff00000000         => amount to share;
  ///     salt & 0x01000000000000000000 == true => use points to waive service fee;
  ///                                              in reality, the salt header would be 0x41
  ///     salt & 0x0000ffffffffffffffff: customized data that can be passed to integrated 3rd-party smart contract;
  ///   fee: The fee given to LPs (liquidity providers). An extra service fee maybe charged afterwards;
  ///   expireTs: The expiration time of this swap on the initial chain. The LP should `executeSwap` and receive his funds before `expireTs`;
  ///   outChain: The target chain of a cross-chain swap (given by the last 2 bytes of SLIP-44);
  ///   outToken: The index of the token on the target chain. See `tokenForIndex` in `MesonToken.sol`;
  ///   inChain: The initial chain of a cross-chain swap (given by the last 2 bytes of SLIP-44);
  ///   inToken: The index of the token on the initial chain. See `tokenForIndex` in `MesonToken.sol`.
  /// value: `postedSwap` in format of `tokenNotFromInitiator:byte1|initiator:address|poolIndex:uint40`
  ///   tokenNotFromInitiator: Token not from initiator (usually sent from a smart contract);
  ///   initiator: The swap initiator who created and signed the swap request (not necessarily the one who posted the swap);
  //    poolIndex: The index of an LP pool. See `ownerOfPool` in `MesonStates.sol` for more information.
  mapping(uint256 => uint208) internal _postedSwaps;

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

  function postSwap(uint256 encodedSwap, address initiator, uint40 poolIndex)
    payable public matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap)
  {
    _postedSwaps[encodedSwap] = _postedSwapFrom(initiator, poolIndex, _msgSender() != initiator);

    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _unsafeDepositToken(tokenIndex, _msgSender(), _amountFrom(encodedSwap));

    emit SwapPosted(encodedSwap);
  }

  /// @notice Anyone can call this method to post a swap request. This is step 1️⃣ in a swap.
  /// The r,s,v signature must be signed by the swap initiator. The initiator can call
  /// this method directly, in which case `poolIndex` should be zero and wait for LPs
  /// to call `bondSwap`. Initiators can also send the swap requests offchain (through the
  /// meson relayer service). An LP (pool owner or authorized addresses) who receives requests through
  /// the relayer can call this method to post and bond the swap in a single contract execution,
  /// in which case he should give his own `poolIndex`.
  ///
  /// The swap will last until `expireTs` and at most one LP pool can bond to it.
  /// After the swap expires, the initiator can cancel the swap and withdraw funds.
  ///
  /// Once a swap is posted and bonded, the bonding LP should call `lock` on the target chain.
  ///
  /// @dev Designed to be used by both swap initiators, pool owner, or authorized addresses
  /// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
  /// @param r Part of the signature
  /// @param yParityAndS Part of the signature
  /// @param initiator Initiator
  /// @param poolIndex Pool index
  function postSwapWithSignature(uint256 encodedSwap, bytes32 r, bytes32 yParityAndS, address initiator, uint40 poolIndex)
    external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap)
  {
    if (poolIndex > 0 && _msgSender() != initiator) {
      // If pool index is given, the signer should be the initiator or an authorized address
      require(poolOfAuthorizedAddr[_msgSender()] == poolIndex, "Signer should be an authorized address of the given pool");
    } // Otherwise, this is posted without bonding to a specific pool. Need to execute `bondSwap` later

    _checkRequestSignature(encodedSwap, r, yParityAndS, initiator);
    _postedSwaps[encodedSwap] = _postedSwapFrom(initiator, poolIndex, false);

    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _unsafeDepositToken(tokenIndex, initiator, _amountFrom(encodedSwap));

    emit SwapPosted(encodedSwap);
  }

  // deprecated
  function postSwapFromInitiator(uint256 encodedSwap, uint200 postingValue) payable external {
    postSwap(encodedSwap, _initiatorFromPosted(postingValue), _poolIndexFromPosted(postingValue));
  }

  /// @notice If `postSwap` is called by the initiator of the swap and `poolIndex`
  /// is zero, an LP (pool owner or authorized addresses) can call this to bond the swap to himself.
  /// @dev Designed to be used by pool owner or authorized addresses
  /// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
  /// @param poolIndex The index of an LP pool. See `ownerOfPool` in `MesonStates.sol` for more information.
  function bondSwap(uint256 encodedSwap, uint40 poolIndex) external {
    uint208 postedSwap = _postedSwaps[encodedSwap];
    require(postedSwap > 1, "Swap does not exist");
    require(_poolIndexFromPosted(postedSwap) == 0, "Swap bonded to another pool");
    require(poolOfAuthorizedAddr[_msgSender()] == poolIndex, "Signer should be an authorized address of the given pool");

    _postedSwaps[encodedSwap] = postedSwap | poolIndex;
    emit SwapBonded(encodedSwap);
  }

  /// @notice Cancel a swap. The swap initiator can call this method to withdraw funds
  /// from an expired swap request.
  /// @dev Designed to be used by swap initiators
  /// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
  function cancelSwap(uint256 encodedSwap) external {
    uint208 postedSwap = _postedSwaps[encodedSwap];
    require(postedSwap > 1, "Swap does not exist");
    require(_expireTsFrom(encodedSwap) < block.timestamp, "Swap is still locked");
    require((postedSwap >> 200) == 0, "Swap token not from initiator");

    delete _postedSwaps[encodedSwap]; // Swap expired so the same one cannot be posted again

    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _safeTransfer(tokenIndex, _initiatorFromPosted(postedSwap), _amountFrom(encodedSwap));

    emit SwapCancelled(encodedSwap);
  }

  function cancelSwapTo(uint256 encodedSwap, address recipient) external {
    require(_isPremiumManager(), "Caller is not the premium manager");

    uint208 postedSwap = _postedSwaps[encodedSwap];
    require(postedSwap > 1, "Swap does not exist");
    require(_expireTsFrom(encodedSwap) < block.timestamp, "Swap is still locked");

    delete _postedSwaps[encodedSwap]; // Swap expired so the same one cannot be posted again

    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _safeTransfer(tokenIndex, recipient, _amountFrom(encodedSwap));

    emit SwapCancelled(encodedSwap);
  }

  /// @notice Execute the swap by providing a release signature. This is step 4️⃣ in a swap.
  /// Once the signature is verified, the current bonding pool will receive funds deposited 
  /// by the swap initiator.
  /// @dev Designed to be used by pool owner or authorized addresses of the current bonding pool
  /// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
  /// @param r Part of the release signature (same as in the `release` call)
  /// @param yParityAndS Part of the release signature (same as in the `release` call)
  /// @param recipient The recipient address of the swap
  /// @param depositToPool Whether to deposit funds to the pool (will save gas)
  function executeSwap(
    uint256 encodedSwap,
    bytes32 r,
    bytes32 yParityAndS,
    address recipient,
    bool depositToPool
  ) external {
    uint208 postedSwap = _postedSwaps[encodedSwap];
    require(postedSwap > 1, "Swap does not exist");

    // Swap expiredTs < current + MIN_BOND_TIME_PERIOD
    if (_expireTsFrom(encodedSwap) < block.timestamp + MIN_BOND_TIME_PERIOD) {
      // The swap cannot be posted again and therefore safe to remove it.
      // LPs who execute in this mode can save ~5000 gas.
      delete _postedSwaps[encodedSwap];
    } else {
      // The same swap information can be posted again, so set `_postedSwaps` value to 1 to prevent that.
      _postedSwaps[encodedSwap] = 1;
    }

    _checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, _initiatorFromPosted(postedSwap));

    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    uint40 poolIndex = _poolIndexFromPosted(postedSwap);
    if (depositToPool) {
      _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, poolIndex)] += _amountFrom(encodedSwap);
    } else {
      _safeTransfer(tokenIndex, ownerOfPool[poolIndex], _amountFrom(encodedSwap));
    }

    emit SwapExecuted(encodedSwap);
  }

  function directExecuteSwap(
    uint256 encodedSwap,
    bytes32 r,
    bytes32 yParityAndS,
    address initiator,
    address recipient
  ) payable external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap) {
    _checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, initiator);

    _postedSwaps[encodedSwap] = 1;

    uint256 amount = _amountFrom(encodedSwap);
    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 1)] += amount;

    _unsafeDepositToken(tokenIndex, initiator, amount);

    emit SwapExecuted(encodedSwap);
  }

  function simpleExecuteSwap(uint256 encodedSwap)
    payable external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap)
  {
    _postedSwaps[encodedSwap] = 1;

    uint256 amount = _amountFrom(encodedSwap);
    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 1)] += amount;

    _unsafeDepositToken(tokenIndex, _msgSender(), amount);

    emit SwapExecuted(encodedSwap);
  }

  /// @notice Read information for a posted swap
  function getPostedSwap(uint256 encodedSwap) external view
    returns (address initiator, address poolOwner, bool exist)
  {
    uint208 postedSwap = _postedSwaps[encodedSwap];
    initiator = _initiatorFromPosted(postedSwap);
    exist = postedSwap > 0;
    if (initiator == address(0)) {
      poolOwner = address(0);
    } else {
      poolOwner = ownerOfPool[_poolIndexFromPosted(postedSwap)];
    }
  }

  modifier verifyEncodedSwap(uint256 encodedSwap) {
    require(_inChainFrom(encodedSwap) == SHORT_COIN_TYPE, "Swap not for this chain");
    require(
      _tokenType(_inTokenIndexFrom(encodedSwap)) == _tokenType(_outTokenIndexFrom(encodedSwap)),
      "In & out token types do not match"
    );
    require(_postedSwaps[encodedSwap] == 0, "Swap already exists");

    require(_amountFrom(encodedSwap) <= MAX_SWAP_AMOUNT, "For security reason, amount cannot be greater than 100k");

    uint256 delta = _expireTsFrom(encodedSwap) - block.timestamp;
    require(delta > MIN_BOND_TIME_PERIOD, "Expire ts too early");
    require(delta < MAX_BOND_TIME_PERIOD, "Expire ts too late");

    _;
  }
}

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

interface IERC20 {
    function transferFrom(address from, address to, uint256 value) external returns (bool);
    function approve(address spender, uint256 value) external returns (bool);
}

interface UniswapV3SwapRouter {
    struct ExactInputParams {
        bytes   path;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
    }

    function exactInput(ExactInputParams calldata params)
        external
        payable
        returns (uint256 amountOut);
}

contract CfxSwapAxCNHProxy {
    UniswapV3SwapRouter constant ROUTER = UniswapV3SwapRouter(0x3B02e356d09E758E2711bC64CF33e48f3E1239b8);

    bytes constant PATH = hex"fe97e85d13abd9c1c33384e796f10b73905637ce0001f470bfd7f7eadf9b9827541272589a6b2bb760ae2e";

    function depositWithBeneficiary(
        address token,
        uint256 amount,
        address beneficiary,
        uint64 data
    ) payable external returns (bool) {
        if (token == address(0)) {
            revert("ETH not supported");
        } else {
            IERC20(token).transferFrom(msg.sender, address(this), amount);
            IERC20(token).approve(address(ROUTER), amount);

            // Build params with constant path
            UniswapV3SwapRouter.ExactInputParams memory params = UniswapV3SwapRouter.ExactInputParams({
                path: PATH,
                recipient: beneficiary,
                deadline: block.timestamp + 10 minutes,
                amountIn: amount,
                amountOutMinimum: amount * (data >> 32) / 1e6 / 1e12
            });

            ROUTER.exactInput(params);
        }

        return true;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "../interfaces/IERC20Minimal.sol";
import "../interfaces/IDepositWithBeneficiary.sol";

/// @notice A sample of 3rd-party dapp that interacts with meson
/// With `depositWithBeneficiary`, the meson contract will be able
/// to deposit cross-chain'ed stablecoins to the 3rd-party dapp contract
/// on behalf of the user. The user will receive the benefits corresponding
/// to this deposit.
contract ForwardTokenContract is IDepositWithBeneficiary {
  function depositWithBeneficiary(
    address token,
    uint256 amount,
    address beneficiary,
    uint64
  ) payable external override returns (bool) {
    if (token == address(0)) {
      // ETH
      // No need to take ETH since it is transferred in msg.value
    } else {
      // Stablecoins
      // Required. Take cross-chain'ed token to dapp's contract
      IERC20Minimal(token).transferFrom(msg.sender, address(this), amount);
    }

    // The dapp can do it's own logic with depositing tokens
    // e.g. exchange for other tokens, mint NFTs, etc.
    // Could use data to determine specific operations.


    // Send benefits to the user. Here as an example we just transfer
    // deposited tokens to the user.
    if (token == address(0)) {
      // ETH
      (bool success, ) = beneficiary.call{value: amount}("");
      require(success, "Transfer failed");
    } else {
      // Stablecoins
      IERC20Minimal(token).transfer(beneficiary, amount);
    }

    return true;
  }
}

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

import "../interfaces/IERC20Minimal.sol";
import "../interfaces/IDepositWithBeneficiary.sol";

interface ITako {
  function deposit(
    address asset,
    uint256 amount,
    address onBehalfOf,
    uint16 referralCode
  ) external;
}

/// @notice A sample of 3rd-party dapp that interacts with meson
/// With `depositWithBeneficiary`, the meson contract will be able
/// to deposit cross-chain'ed stablecoins to the 3rd-party dapp contract
/// on behalf of the user. The user will receive the benefits corresponding
/// to this deposit.
contract FreeDirecToTako is IDepositWithBeneficiary {
  address constant _target = address(0x3A2Fd8a16030fFa8D66E47C3f1C0507c673C841e);
  address private _admin;
  uint16 private _referralCode = 0;

  constructor () {
    _admin = msg.sender;
  }

  function setReferralCode(uint16 code) external {
    require(_admin == msg.sender, "Not authorized");
    _referralCode = code;
  }

  function depositWithBeneficiary(
    address token,
    uint256 amount,
    address beneficiary,
    uint64
  ) payable external override returns (bool) {
    if (token == address(0)) {
      revert("ETH not supported");
    } else {
      IERC20Minimal(token).transferFrom(msg.sender, address(this), amount);
      IERC20Minimal(token).approve(_target, amount);
      ITako(_target).deposit(token, amount, beneficiary, _referralCode);
    }

    return true;
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "../Pools/MesonPools.sol";

contract MesonPoolsTest is MesonPools {
  address internal _premiumManager;

  constructor(address token, address premiumManager) {
    _addSupportToken(token, 1);
    _premiumManager = premiumManager;
  }

  function _isPremiumManager() internal view override returns (bool) {
    return _premiumManager == _msgSender();
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "../utils/MesonStates.sol";

contract MesonStatesTest is MesonStates {
  function addSupportToken(address token, uint8 index) external {
    _addSupportToken(token, index);
  }

  function encodeSwap(
    uint8 version,
    uint40 amount,
    uint80 salt,
    uint40 fee,
    uint40 expireTs,
    bytes2 outChain,
    uint8 outToken,
    bytes2 inChain,
    uint8 inToken
  ) external pure returns (bytes memory) {
    return
      abi.encodePacked(
        version,
        amount,
        salt,
        fee,
        expireTs,
        outChain,
        outToken,
        inChain,
        inToken
      );
  }

  function decodeSwap(uint256 encodedSwap, uint40 poolIndex) external pure returns (
    uint8 version,
    uint256 amount,
    uint256 feeForLp,
    uint256 serviceFee,
    uint80 salt,
    uint256 expireTs,
    bytes2 inChain,
    uint8 inTokenIndex,
    bytes2 outChain,
    uint8 outTokenIndex,
    bytes6 poolTokenIndexForOutToken
  ) {
    version = _versionFrom(encodedSwap);
    amount = _amountFrom(encodedSwap);
    feeForLp = _feeForLp(encodedSwap);
    serviceFee = _serviceFee(encodedSwap);
    salt = _saltFrom(encodedSwap);
    expireTs = _expireTsFrom(encodedSwap);
    inChain = bytes2(_inChainFrom(encodedSwap));
    inTokenIndex = _inTokenIndexFrom(encodedSwap);
    outChain = bytes2(_outChainFrom(encodedSwap));
    outTokenIndex = _outTokenIndexFrom(encodedSwap);
    poolTokenIndexForOutToken = bytes6(_poolTokenIndexForOutToken(encodedSwap, poolIndex));
  }

  function decodePostedSwap(uint200 postedSwap) external pure returns (
    address initiator,
    uint40 poolIndex
  ) {
    initiator = _initiatorFromPosted(postedSwap);
    poolIndex = _poolIndexFromPosted(postedSwap);
  }

  function lockedSwapFrom(uint256 until, uint40 poolIndex) external pure returns (uint80) {
    return _lockedSwapFrom(until, poolIndex);
  }

  function decodeLockedSwap(uint80 lockedSwap) external pure returns (uint40 poolIndex, uint256 until) {
    poolIndex = _poolIndexFromLocked(lockedSwap);
    until = _untilFromLocked(lockedSwap);
  }

  function poolTokenIndexFrom(uint8 tokenIndex, uint40 poolIndex) external pure returns (bytes6) {
    return bytes6(_poolTokenIndexFrom(tokenIndex, poolIndex));
  }

  function decodePoolTokenIndex(uint48 poolTokenIndex) external pure returns (
    uint8 tokenIndex,
    uint40 poolIndex
  ) {
    tokenIndex = _tokenIndexFrom(poolTokenIndex);
    poolIndex = _poolIndexFrom(poolTokenIndex);
  }

  function checkRequestSignature(
    uint256 encodedSwap,
    bytes32 r,
    bytes32 yParityAndS,
    address signer
  ) external pure {
    _checkRequestSignature(encodedSwap, r, yParityAndS, signer);
  }

  function checkReleaseSignature(
    uint256 encodedSwap,
    address recipient,
    bytes32 r,
    bytes32 yParityAndS,
    address signer
  ) external pure {
    _checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, signer);
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "../Swap/MesonSwap.sol";

contract MesonSwapTest is MesonSwap {
  constructor(address token) {
    _addSupportToken(token, 1);
  }

  function register(uint40 poolIndex) external {
    address poolOwner = _msgSender();
    require(poolIndex != 0, "Cannot use index 0");
    require(ownerOfPool[poolIndex] == address(0), "Pool index already registered");
    require(poolOfAuthorizedAddr[poolOwner] == 0, "Signer address already registered");
    ownerOfPool[poolIndex] = poolOwner;
    poolOfAuthorizedAddr[poolOwner] = poolIndex;
  }
}

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MockToken is ERC20 {
  uint8 private _decimals;

  constructor(
    string memory name,
    string memory symbol,
    uint256 initialSupply,
    uint8 decimals_
  ) ERC20(name, symbol) {
    _decimals = decimals_;
    _mint(msg.sender, initialSupply);
  }

  function decimals() public view override returns (uint8) {
    return _decimals;
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";

/// @title PoDUpgradeable
/// @notice The contract of POD, a token minted by Meson as the Proof of Deposit
contract PoDUpgradeable is UUPSUpgradeable, ERC20Upgradeable {
  address private _owner;
  address private _minter;
  address private _mesonContract;

  mapping(address => uint256) private _lockedBalances;
  mapping(address => uint256) private _lockedSince;

  uint256 private _rewardRatePerSecTimes1e12;
  mapping(address => uint256) private _prevRewards;

  uint256 constant NO_REWARD_LOCK_PERIOD = 3 days;
  uint256 constant LESS_REWARD_LOCK_PERIOD = 7 days;

  function initialize(address minter, address mesonContract) public initializer {
    __ERC20_init("Proof of Deposit (meson.fi)", "PoD");
    _owner = _msgSender();
    _minter = minter;
    require(mesonContract != address(0), "Address of meson contract cannot be zero");
    _mesonContract = mesonContract;
  }

  function decimals() public pure override returns (uint8) {
    return 6;
  }

  function mint(address account, uint256 amount) external onlyMinter {
    _mint(account, amount);
  }

  function _authorizeUpgrade(address) internal view override {
    require(_msgSender() == _owner, "Unauthorized");
  }

  /// @notice Override the default ERC20 allowance method
  /// mesonContract will have max allowance so users don't need to execute approve
  function allowance(address owner, address spender) public view override returns (uint256) {
    if (spender == _mesonContract) {
      uint256 x = 0;
      unchecked { x--; }
      return x;
    }
    return ERC20Upgradeable.allowance(owner, spender);
  }

  function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
    address msgSender = _msgSender();
    if (msgSender == _mesonContract && ERC20Upgradeable.allowance(sender, msgSender) < amount) {
      uint256 x = 0;
      unchecked { x--; }
      _approve(sender, msgSender, x);
    }
    return ERC20Upgradeable.transferFrom(sender, recipient, amount);
  }

  function setRewardFactor(uint256 annualPercentageRateTimes1e4) external onlyOwner {
    _rewardRatePerSecTimes1e12 = annualPercentageRateTimes1e4 * 1e8 / 365 days;
  }

  function getCurrentAPR() public view returns (uint256) {
    return _rewardRatePerSecTimes1e12 * 365 days / 1e8;
  }

  function getLockedBalance(address account) public view returns (uint256) {
    return _lockedBalances[account];
  }
  
  function _getRewards(address account) internal view returns (uint256 total, uint256 pending) {
    uint256 lockedBalance = _lockedBalances[account];
    if (lockedBalance == 0) {
      return (_prevRewards[account], 0);
    }

    uint256 sinceLastLock = block.timestamp - _lockedSince[account];
    uint256 rewardsForCurrentLock = sinceLastLock * lockedBalance * _rewardRatePerSecTimes1e12 / 1e12;
    if (sinceLastLock > LESS_REWARD_LOCK_PERIOD) {
      return (_prevRewards[account] + rewardsForCurrentLock, 0);
    } else if (sinceLastLock > NO_REWARD_LOCK_PERIOD) {
      return (_prevRewards[account] + rewardsForCurrentLock, 3 days * lockedBalance * _rewardRatePerSecTimes1e12 / 1e12);
    } else {
      return (_prevRewards[account] + rewardsForCurrentLock, rewardsForCurrentLock);
    }
  }

  function getTotalRewards(address account) public view returns (uint256) {
    (uint256 total, ) = _getRewards(account);
    return total;
  }

  function getClaimableRewards(address account) public view returns (uint256) {
    (uint256 total, uint256 pending) = _getRewards(account);
    return total - pending;
  }

  function lockPoD(uint256 amount) external {
    require(amount > 0, "amount must be greater than 0");
    address account = _msgSender();

    (uint256 total, uint256 pending) = _getRewards(account);
    _prevRewards[account] = total - pending;

    uint256 newLockedBalance = _lockedBalances[account] + amount;
    _lockedSince[account] = block.timestamp - pending * 1e12 / _rewardRatePerSecTimes1e12 / newLockedBalance;
    _lockedBalances[account] = newLockedBalance;

    _transfer(account, address(this), amount);
  }

  function unlockPoD(uint256 amount) external {
    require(amount > 0, "amount must be greater than 0");
    address account = _msgSender();

    _prevRewards[account] = getClaimableRewards(account);

    uint256 newLockedBalance = _lockedBalances[account] - amount; // will throw error if overdrawn
    _lockedSince[account] = newLockedBalance > 0 ? block.timestamp : 0;
    _lockedBalances[account] = newLockedBalance;

    _transfer(address(this), account, amount);
  }

  function withdrawRewards(uint256 amount) external {
    require(amount > 0, "amount must be greater than 0");
    address account = _msgSender();

    uint256 claimableRewards = getClaimableRewards(account);
    require(amount <= claimableRewards, "Insufficient claimable rewards");

    _prevRewards[account] = claimableRewards - amount;
    if (_lockedSince[account] > 0) {
      _lockedSince[account] = block.timestamp;
    }

    _mint(account, amount);
  }

  modifier onlyOwner() {
    require(_owner == _msgSender(), "Caller is not the owner");
    _;
  }

  modifier onlyMinter() {
    require(_minter == _msgSender(), "Caller is not the owner");
    _;
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";

/// @title UCTUpgradeable
/// @notice The contract of UCT, a token minted by Meson for promotional events
/// UCT (USD Coupon Token) is issued by Meson team to mark participants for 
/// community events (such as airdrops, cashbacks, etc). UCT is not an asset 
/// and it has no value. UCT obtained directly from Meson during the event period 
/// can be redeemed for the actual USDT/USDC rewards on https://meson.fi/ at 
/// a ratio of 100:1. UCT has no usage other than redemption for USDT/USDC, 
/// and all UCTs will be destroyed at the end of the event.
contract UCTUpgradeable is UUPSUpgradeable, ERC20Upgradeable {
  address private _owner;
  address private _minter;
  address private _mesonContract;

  function initialize(address minter, address mesonContract) public initializer {
    __ERC20_init("USD Coupon Token (https://meson.fi)", "UCT");
    _owner = _msgSender();
    _minter = minter;
    require(mesonContract != address(0), "Address of meson contract cannot be zero");
    _mesonContract = mesonContract;
  }

  function decimals() public pure override returns (uint8) {
    return 4;
  }

  function batchMint(address[] memory targets, uint256 amount) external onlyMinter {
    require(targets.length > 0, "Target array is empty");
    require(targets.length < 2048, "Target array is too large");
    for (uint i = 0; i < targets.length; i++) {
      _mint(targets[i], amount);
    }
  }

  function batchMint2(address[] memory targets, uint256[] memory amounts) external onlyMinter {
    require(targets.length > 0, "Target array is empty");
    require(targets.length < 2048, "Target array is too large");
    require(targets.length == amounts.length, "Targets and amounts should have the same length");
    for (uint i = 0; i < targets.length; i++) {
      _mint(targets[i], amounts[i]);
    }
  }

  function _authorizeUpgrade(address) internal view override {
    require(_msgSender() == _owner, "Unauthorized");
  }

  /// @notice Override the default ERC20 allowance method
  /// mesonContract will have max allowance so users don't need to execute approve
  function allowance(address owner, address spender) public view override returns (uint256) {
    if (spender == _mesonContract) {
      uint256 x = 0;
      unchecked { x--; }
      return x;
    }
    return ERC20Upgradeable.allowance(owner, spender);
  }

  function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
    address msgSender = _msgSender();
    if (msgSender == _mesonContract && ERC20Upgradeable.allowance(sender, msgSender) < amount) {
      uint256 x = 0;
      unchecked { x--; }
      _approve(sender, msgSender, x);
    }
    return ERC20Upgradeable.transferFrom(sender, recipient, amount);
  }

  modifier onlyOwner() {
    require(_owner == _msgSender(), "Caller is not the owner");
    _;
  }

  modifier onlyMinter() {
    require(_minter == _msgSender(), "Caller is not the owner");
    _;
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IMesonMinimal {
    function tokenForIndex(uint8 tokenIndex) external view returns (address);
    function _isCoreToken(uint8 tokenIndex) external view returns (bool);
    function _amountFactor(uint8 tokenIndex) external view returns (uint256);
    function simpleExecuteSwap(uint256 encodedSwap) payable external;
}

contract TransferToMesonFactory {
    function deploy(address mesonAddress, uint16 destChain, bytes32 destAddr, address via) external returns (address deployedAddress) {
        bytes memory bytecode = abi.encodePacked(
            type(TransferToMesonContract).creationCode,
            abi.encode(mesonAddress, destChain, destAddr, via)
        );

        assembly {
            deployedAddress := create2(0, add(bytecode, 32), mload(bytecode), "")
            if iszero(deployedAddress) {
                revert(0, 0)
            }
        }
    }
}

contract TransferToMesonContract {
    bytes4 private constant ERC20_APPROVE_SELECTOR = bytes4(keccak256("approve(address,uint256)"));

    IMesonMinimal public immutable meson;
    uint16 public immutable destChain;
    bytes32 public immutable destAddr; // Could be used for non-EVMs
    address public immutable via;

    error EInvalidEncoded();
    error EIncorrectDestChain();
    error ENeedToContract();
    error EApprove();

    constructor(address mesonAddress, uint16 _destChain, bytes32 _destAddr, address _via) {
        meson = IMesonMinimal(mesonAddress);
        destChain = _destChain;
        destAddr = _destAddr;
        via = _via;
    }

    receive() external payable {}

    function transferToMeson(uint256 encodedSwap) external {
        require((encodedSwap & 0x3000000000000000000000000000000000000000000000000000) == 0x3000000000000000000000000000000000000000000000000000, EInvalidEncoded());
        require(destChain == uint16(encodedSwap >> 32), EIncorrectDestChain());
        if (via != address(0)) {
            require((encodedSwap & 0x8000000000000000000000000000000000000000000000000000) == 0, ENeedToContract());
        }

        uint8 tokenIndex = uint8(encodedSwap);
        uint256 amount = (encodedSwap >> 208) & 0xFFFFFFFFFF;

        if (meson._isCoreToken(tokenIndex)) {
            meson.simpleExecuteSwap{value: amount * 10 ** 12}(encodedSwap);
        } else {
            address tokenAddr = meson.tokenForIndex(tokenIndex);
            (bool success, bytes memory data) = tokenAddr.call(
                abi.encodeWithSelector(ERC20_APPROVE_SELECTOR, address(meson), amount * meson._amountFactor(tokenIndex))
            );
            require(success && (data.length == 0 || abi.decode(data, (bool))), EApprove());

            meson.simpleExecuteSwap(encodedSwap);
        }
    }
}

File 44 of 47 : MesonConfig.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/// @notice Parameters of the Meson contract
/// for Ethereum
contract MesonConfig {
  uint8 constant MESON_PROTOCOL_VERSION = 1;

  // Ref https://github.com/satoshilabs/slips/blob/master/slip-0044.md
  uint16 constant SHORT_COIN_TYPE = 0x003c;

  uint256 constant MAX_SWAP_AMOUNT = 1e11; // 100,000.000000 = 100k
  uint256 constant SERVICE_FEE_RATE = 5; // service fee = 5 / 10000 = 0.05%
  uint256 constant SERVICE_FEE_MINIMUM = 500_000; // min $0.5
  uint256 constant SERVICE_FEE_MINIMUM_ETH = 500; // min 0.0005 ETH (or SOL)
  uint256 constant SERVICE_FEE_MINIMUM_BNB = 5000; // min 0.005 BNB
  uint256 constant SERVICE_FEE_MINIMUM_BTC = 10; // min 0.00001 BTC

  uint256 constant MIN_BOND_TIME_PERIOD = 1 hours;
  uint256 constant MAX_BOND_TIME_PERIOD = 2 hours;
  uint256 constant LOCK_TIME_PERIOD = 40 minutes;

  bytes28 constant ETH_SIGN_HEADER = bytes28("\x19Ethereum Signed Message:\n32");
  bytes28 constant ETH_SIGN_HEADER_52 = bytes28("\x19Ethereum Signed Message:\n52");
  bytes25 constant TRON_SIGN_HEADER = bytes25("\x19TRON Signed Message:\n32\n");
  bytes25 constant TRON_SIGN_HEADER_33 = bytes25("\x19TRON Signed Message:\n33\n");
  bytes25 constant TRON_SIGN_HEADER_53 = bytes25("\x19TRON Signed Message:\n53\n");

  bytes32 constant REQUEST_TYPE_HASH = keccak256("bytes32 Sign to request a swap on Meson");
  bytes32 constant RELEASE_TYPE_HASH = keccak256("bytes32 Sign to release a swap on Mesonaddress Recipient");

  bytes32 constant RELEASE_TO_TRON_TYPE_HASH = keccak256("bytes32 Sign to release a swap on Mesonaddress Recipient (tron address in hex format)");
}

File 45 of 47 : MesonHelpers.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "@openzeppelin/contracts/utils/Context.sol";
import "./MesonConfig.sol";

/// @title MesonHelpers
/// @notice The class that provides helper functions for Meson protocol
contract MesonHelpers is MesonConfig, Context {
  modifier matchProtocolVersion(uint256 encodedSwap) {
    require(_versionFrom(encodedSwap) == MESON_PROTOCOL_VERSION, "Incorrect encoding version");
    _;
  }

  function getShortCoinType() external pure returns (bytes2) {
    return bytes2(SHORT_COIN_TYPE);
  }

  /// @notice Calculate `swapId` from `encodedSwap`, `initiator`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _getSwapId(uint256 encodedSwap, address initiator) internal pure returns (bytes32) {
    return keccak256(abi.encodePacked(encodedSwap, initiator));
  }

  /// @notice Decode `version` from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _versionFrom(uint256 encodedSwap) internal pure returns (uint8) {
    return uint8(encodedSwap >> 248);
  }

  /// @notice Decode `amount` from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _amountFrom(uint256 encodedSwap) internal pure returns (uint256) {
    return (encodedSwap >> 208) & 0xFFFFFFFFFF;
  }

  function _amountToLock(uint256 encodedSwap) internal pure returns (uint256) {
    return _amountFrom(encodedSwap) - _feeForLp(encodedSwap) - _amountForCoreTokenFrom(encodedSwap);
  }

  /// @notice Calculate the service fee from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _serviceFee(uint256 encodedSwap) internal pure returns (uint256) {
    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    uint256 minFee;
    if (tokenIndex >= 252) {
      minFee = SERVICE_FEE_MINIMUM_ETH;
    } else if (tokenIndex >= 248) {
      minFee = SERVICE_FEE_MINIMUM_BNB;
    } else if (tokenIndex >= 244) {
      minFee = SERVICE_FEE_MINIMUM_ETH;
    } else if (tokenIndex >= 240) {
      minFee = SERVICE_FEE_MINIMUM_BTC;
    } else {
      minFee = SERVICE_FEE_MINIMUM;
    }
    // Default to `serviceFee` = 0.05% * `amount`
    uint256 fee = _amountFrom(encodedSwap) * SERVICE_FEE_RATE / 10000;
    return fee > minFee ? fee : minFee;
  }

  /// @notice Decode `fee` (the fee for LPs) from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _feeForLp(uint256 encodedSwap) internal pure returns (uint256) {
    return (encodedSwap >> 88) & 0xFFFFFFFFFF;
  }

  /// @notice Decode `salt` from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _saltFrom(uint256 encodedSwap) internal pure returns (uint80) {
    return uint80(encodedSwap >> 128);
  }

  /// @notice Decode data from `salt`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _saltDataFrom(uint256 encodedSwap) internal pure returns (uint64) {
    return uint64(encodedSwap >> 128);
  }

  /// @notice Whether the swap should release to a 3rd-party integrated dapp contract
  /// See method `release` in `MesonPools.sol` for more details
  function _willTransferToContract(uint256 encodedSwap) internal pure returns (bool) {
    return (encodedSwap & 0x8000000000000000000000000000000000000000000000000000) == 0;
  }

  /// @notice Whether the swap needs to pay service fee
  /// See method `release` in `MesonPools.sol` for more details about the service fee
  function _feeWaived(uint256 encodedSwap) internal pure returns (bool) {
    return (encodedSwap & 0x4000000000000000000000000000000000000000000000000000) > 0;
  }
  
  /// @notice Whether the swap was signed in the non-typed manner (usually by hardware wallets)
  function _signNonTyped(uint256 encodedSwap) internal pure returns (bool) {
    return (encodedSwap & 0x0800000000000000000000000000000000000000000000000000) > 0;
  }

  function _swapForCoreToken(uint256 encodedSwap) internal pure returns (bool) {
    return (_outTokenIndexFrom(encodedSwap) < 191) &&
      ((encodedSwap & 0x8410000000000000000000000000000000000000000000000000) == 0x8410000000000000000000000000000000000000000000000000);
  }

  function _amountForCoreTokenFrom(uint256 encodedSwap) internal pure returns (uint256) {
    if (_swapForCoreToken(encodedSwap)) {
      uint256 d = (encodedSwap >> 160) & 0xFFFF;
      if (d == 0xFFFF) {
        return _amountFrom(encodedSwap) - _feeForLp(encodedSwap) - (_feeWaived(encodedSwap) ? 0 : _serviceFee(encodedSwap));
      }
      return _decompressFixedPrecision(d) * 1e3;
    }
    return 0;
  }

  function _coreTokenAmount(uint256 encodedSwap) internal pure returns (uint256) {
    uint256 amountForCore = _amountForCoreTokenFrom(encodedSwap);
    if (amountForCore > 0) {
      return amountForCore * 1e4 / _decompressFixedPrecision((encodedSwap >> 176) & 0xFFFF);
    }
    return 0;
  }

  function _shareWithPartner(uint256 encodedSwap) internal pure returns (bool) {
    return !_willTransferToContract(encodedSwap)
      && ((encodedSwap & 0x0600000000000000000000000000000000000000000000000000) == 0x0200000000000000000000000000000000000000000000000000);
  }

  function _amountToShare(uint256 encodedSwap) internal pure returns (uint256) {
    if (_shareWithPartner(encodedSwap)) {
      return _decompressFixedPrecision((encodedSwap >> 160) & 0xFFFF);
    }
    return 0;
  }

  function _decompressFixedPrecision(uint256 d) internal pure returns (uint256) {
    if (d <= 1000) {
      return d;
    }
    return ((d - 1000) % 9000 + 1000) * 10 ** ((d - 1000) / 9000);
  }

  function _poolIndexToShare(uint256 encodedSwap) internal pure returns (uint40) {
    if (_shareWithPartner(encodedSwap)) {
      return (uint40(encodedSwap >> 176) & 0xFFFF) + 65536;
    }
    return 0;
  }

  /// @notice Decode `expireTs` from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _expireTsFrom(uint256 encodedSwap) internal pure returns (uint256) {
    return (encodedSwap >> 48) & 0xFFFFFFFFFF;
    // [Suggestion]: return uint40(encodedSwap >> 48);
  }

  /// @notice Decode the initial chain (`inChain`) from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _inChainFrom(uint256 encodedSwap) internal pure returns (uint16) {
    return uint16(encodedSwap >> 8);
  }

  /// @notice Decode the token index of initial chain (`inToken`) from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _inTokenIndexFrom(uint256 encodedSwap) internal pure returns (uint8) {
    return uint8(encodedSwap);
  }

  /// @notice Decode the target chain (`outChain`) from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _outChainFrom(uint256 encodedSwap) internal pure returns (uint16) {
    return uint16(encodedSwap >> 32);
  }

  /// @notice Decode the token index of target chain (`outToken`) from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _outTokenIndexFrom(uint256 encodedSwap) internal pure returns (uint8) {
    return uint8(encodedSwap >> 24);
  }

  function _tokenType(uint8 tokenIndex) internal pure returns (uint8) {
    if (tokenIndex >= 192) {
      // Non stablecoins [192, 255] -> [48, 63]
      return tokenIndex / 4;
    } else if (tokenIndex <= 64) {
      // Stablecoins [1, 64] -> 0
      return 0;
    } else if (tokenIndex <= 112) {
      // 3rd party tokens [65, 112] -> [1, 24]
      return (tokenIndex + 1) / 2 - 32;
    } else if (tokenIndex <= 128) {
      // 3rd party tokens [113, 128] -> [33, 48]
      return tokenIndex - 80;
    }
    revert("Token index not allowed for swapping");
  }

  /// @notice Decode `outToken` from `encodedSwap`, and encode it with `poolIndex` to `poolTokenIndex`.
  /// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
  function _poolTokenIndexForOutToken(uint256 encodedSwap, uint40 poolIndex) internal pure returns (uint48) {
    return uint48((encodedSwap & 0xFF000000) << 16) | poolIndex;
  }

  /// @notice Encode `postedSwap` from `initiator` and `poolIndex`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `postedSwap`
  function _postedSwapFrom(address initiator, uint40 poolIndex, bool tokenNotFromInitiator)
    internal pure returns (uint208)
  {
    return (tokenNotFromInitiator ? (uint208(1) << 200) : uint208(0)) | (uint208(uint160(initiator)) << 40) | poolIndex;
  }

  /// @notice Decode `initiator` from `postedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `postedSwap`
  function _initiatorFromPosted(uint208 postedSwap) internal pure returns (address) {
    return address(uint160(postedSwap >> 40));
  }

  /// @notice Decode `poolIndex` from `postedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `postedSwap`
  function _poolIndexFromPosted(uint208 postedSwap) internal pure returns (uint40) {
    return uint40(postedSwap);
  }
  
  /// @notice Encode `lockedSwap` from `until` and `poolIndex`
  /// See variable `_lockedSwaps` in `MesonPools.sol` for the defination of `lockedSwap`
  function _lockedSwapFrom(uint256 until, uint40 poolIndex) internal pure returns (uint80) {
    return (uint80(until) << 40) | poolIndex;
  }

  /// @notice Decode `poolIndex` from `lockedSwap`
  /// See variable `_lockedSwaps` in `MesonPools.sol` for the defination of `lockedSwap`
  function _poolIndexFromLocked(uint80 lockedSwap) internal pure returns (uint40) {
    return uint40(lockedSwap);
  }

  /// @notice Decode `until` from `lockedSwap`
  /// See variable `_lockedSwaps` in `MesonPools.sol` for the defination of `lockedSwap`
  function _untilFromLocked(uint80 lockedSwap) internal pure returns (uint256) {
    return uint256(lockedSwap >> 40);
  }

  /// @notice Encode `poolTokenIndex` from `tokenIndex` and `poolIndex`
  /// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
  function _poolTokenIndexFrom(uint8 tokenIndex, uint40 poolIndex) internal pure returns (uint48) {
    return (uint48(tokenIndex) << 40) | poolIndex;
  }

  /// @notice Decode `tokenIndex` from `poolTokenIndex`
  /// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
  function _tokenIndexFrom(uint48 poolTokenIndex) internal pure returns (uint8) {
    return uint8(poolTokenIndex >> 40);
  }

  /// @notice Decode `poolIndex` from `poolTokenIndex`
  /// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
  function _poolIndexFrom(uint48 poolTokenIndex) internal pure returns (uint40) {
    return uint40(poolTokenIndex);
  }

  /// @notice Check the initiator's signature for a swap request
  /// Signatures are constructed with the package `mesonfi/sdk`. Go to `packages/sdk/src/SwapSigner.ts` and 
  /// see how to generate a signautre in class `EthersWalletSwapSigner` method `signSwapRequest`
  /// @param encodedSwap Encoded swap information. See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  /// @param r Part of the signature
  /// @param yParityAndS Part of the signature
  /// @param signer The signer for the swap request which is the `initiator`
  function _checkRequestSignature(
    uint256 encodedSwap,
    bytes32 r,
    bytes32 yParityAndS,
    address signer
  ) internal pure {
    require(signer != address(0), "Signer cannot be empty address");
    bytes32 s = yParityAndS & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
    uint8 v = uint8((uint256(yParityAndS) >> 255) + 27);
    require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "Invalid signature");

    bool nonTyped = _signNonTyped(encodedSwap);
    bytes32 digest;
    if (_inChainFrom(encodedSwap) == 0x00c3) {
      digest = keccak256(abi.encodePacked(nonTyped ? TRON_SIGN_HEADER_33 : TRON_SIGN_HEADER, encodedSwap));
    } else if (nonTyped) {
      digest = keccak256(abi.encodePacked(ETH_SIGN_HEADER, encodedSwap));
    } else {
      bytes32 typehash = REQUEST_TYPE_HASH;
      assembly {
        mstore(0, encodedSwap)
        mstore(32, keccak256(0, 32))
        mstore(0, typehash)
        digest := keccak256(0, 64)
      }
    }
    require(signer == ecrecover(digest, v, r, s), "Invalid signature");
  }

  /// @notice Check the initiator's signature for the release request
  /// Signatures are constructed with the package `mesonfi/sdk`. Go to `packages/sdk/src/SwapSigner.ts` and 
  /// see how to generate a signautre in class `EthersWalletSwapSigner` method `signSwapRelease`
  /// @param encodedSwap Encoded swap information. See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  /// @param recipient The recipient address of the swap
  /// @param r Part of the signature
  /// @param yParityAndS Part of the signature
  /// @param signer The signer for the swap request which is the `initiator`
  function _checkReleaseSignature(
    uint256 encodedSwap,
    address recipient,
    bytes32 r,
    bytes32 yParityAndS,
    address signer
  ) internal pure {
    require(signer != address(0), "Signer cannot be empty address");
    bytes32 s = yParityAndS & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
    uint8 v = uint8((uint256(yParityAndS) >> 255) + 27);
    require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "Invalid signature");

    bool nonTyped = _signNonTyped(encodedSwap);
    bytes32 digest;
    if (_inChainFrom(encodedSwap) == 0x00c3) {
      digest = keccak256(abi.encodePacked(nonTyped ? TRON_SIGN_HEADER_53 : TRON_SIGN_HEADER, encodedSwap, recipient));
    } else if (nonTyped) {
      digest = keccak256(abi.encodePacked(ETH_SIGN_HEADER_52, encodedSwap, recipient));
    } else {
      bytes32 typehash = _outChainFrom(encodedSwap) == 0x00c3 ? RELEASE_TO_TRON_TYPE_HASH : RELEASE_TYPE_HASH;
      assembly {
        mstore(20, recipient)
        mstore(0, encodedSwap)
        mstore(32, keccak256(0, 52))
        mstore(0, typehash)
        digest := keccak256(0, 64)
      }
    }
    require(signer == ecrecover(digest, v, r, s), "Invalid signature");
  }

  function _checkSignature(bytes32 digest, bytes32 r, bytes32 yParityAndS, address signer) internal pure {
    require(signer != address(0), "Signer cannot be empty address");
    bytes32 s = yParityAndS & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
    uint8 v = uint8((uint256(yParityAndS) >> 255) + 27);
    require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "Invalid signature");

    require(signer == ecrecover(digest, v, r, s), "Invalid signature");
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "@openzeppelin/contracts/utils/Address.sol";
import "../interfaces/IERC20Minimal.sol";
import "../interfaces/IDepositWithBeneficiary.sol";
import "./MesonTokens.sol";
import "./MesonHelpers.sol";

/// @title MesonStates
/// @notice The class that keeps track of LP pool states
contract MesonStates is MesonTokens, MesonHelpers {
  bytes4 private constant ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
  bytes4 private constant ERC20_TRANSFER_FROM_SELECTOR = bytes4(keccak256("transferFrom(address,address,uint256)"));

  /// @notice The mapping from *authorized addresses* to LP pool indexes.
  /// See `ownerOfPool` to understand how pool index is defined and used.
  ///
  /// This mapping records the relation between *authorized addresses* and pool indexes, where
  /// authorized addresses are those who have the permision to match and complete a swap with funds 
  /// in a pool with specific index. For example, for an LP pool with index `i` there could be multiple
  /// addresses that `poolOfAuthorizedAddr[address] = i`, which means these addresses can all sign to match
  /// (call `bondSwap`, `lock`) a swap and complete it (call `release`) with funds in pool `i`. That helps
  /// an LP to give other addresses the permission to perform daily swap transactions. However, authorized
  /// addresses cannot withdraw funds from the LP pool, unless it's given in `ownerOfPool` which records
  /// the *owner* address for each pool.
  ///
  /// The pool index 0 is reserved for use by Meson
  mapping(address => uint40) public poolOfAuthorizedAddr;

  /// @notice The mapping from LP pool indexes to their owner addresses.
  /// Each LP pool in Meson has a uint40 index `i` and each LP needs to register an pool index at
  /// initial deposit by calling `depositAndRegister`. The balance for each LP pool is tracked by its
  /// pool index and token index (see `_balanceOfPoolToken`).
  /// 
  /// This mapping records the *owner* address for each LP pool. Only the owner address can withdraw funds
  /// from its corresponding LP pool.
  ///
  /// The pool index 0 is reserved for use by Meson
  mapping(uint40 => address) public ownerOfPool;

  /// @notice Balance for each token in LP pool, tracked by the `poolTokenIndex`.
  /// See `ownerOfPool` to understand how pool index is defined and used.
  ///
  /// The balance of a token in an LP pool is `_balanceOfPoolToken[poolTokenIndex]` in which
  /// the `poolTokenIndex` is in format of `tokenIndex:uint8|poolIndex:uint40`. `tokenIndex`
  /// is the index of supported tokens given by `tokenForIndex` (see definition in `MesonTokens.sol`).
  /// The balances are always store as tokens have decimal 6, which is the case for USDC/USDT on most chains
  /// except BNB Smart Chain & Conflux. In the exceptional cases, the value of token amount will be converted
  /// on deposit and withdrawal (see `_safeTransfer` and `_unsafeDepositToken` in `MesonHelpers.sol`).
  ///
  /// The pool index 0 is reserved for use by Meson to store service fees
  mapping(uint48 => uint256) internal _balanceOfPoolToken;

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

  function _isPremiumManager() internal view virtual returns (bool) {}

  function poolTokenBalance(address token, address addr) external view returns (uint256) {
    uint8 tokenIndex = indexOfToken[token];
    uint40 poolIndex = poolOfAuthorizedAddr[addr];
    if (poolIndex == 0 || tokenIndex == 0) {
      return 0;
    }
    return _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, poolIndex)];
  }
  
  /// @notice The collected service fee of a specific token.
  /// @param tokenIndex The index of a supported token. See `tokenForIndex` in `MesonTokens.sol`
  function serviceFeeCollected(uint8 tokenIndex) external view returns (uint256) {
    return _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 0)];
  }

  /// @notice Help the senders to transfer their assets to the Meson contract
  /// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
  /// @param sender The sender of the transfer
  /// @param amount The value of the transfer (always in decimal 6)
  function _unsafeDepositToken(
    uint8 tokenIndex,
    address sender,
    uint256 amount
  ) internal {
    require(amount > 0, "Amount must be greater than zero");

    if (_isCoreToken(tokenIndex)) {
      // Core tokens (e.g. ETH or BNB)
      require(amount * 1e12 == msg.value, "msg.value does not match the amount");
    } else {
      // Stablecoins
      address token = tokenForIndex[tokenIndex];

      require(token != address(0), "Token not supported");
      require(Address.isContract(token), "The given token address is not a contract");

      amount *= _amountFactor(tokenIndex);
      (bool success, bytes memory data) = token.call(abi.encodeWithSelector(
        ERC20_TRANSFER_FROM_SELECTOR,
        sender,
        address(this),
        amount
      ));
      require(success && (data.length == 0 || abi.decode(data, (bool))), "transferFrom failed");
    }
  }

  /// @notice Safe transfers tokens from Meson contract to a recipient
  /// for interacting with ERC20 tokens that do not consistently return true/false
  /// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
  /// @param recipient The recipient of the transfer
  /// @param amount The value of the transfer (always in decimal 6)
  function _safeTransfer(
    uint8 tokenIndex,
    address recipient,
    uint256 amount
  ) internal {
    if (_isCoreToken(tokenIndex)) {
      // Core tokens (e.g. ETH or BNB)
      _transferCoreToken(recipient, amount);
    } else {
      // Stablecoins
      address token = tokenForIndex[tokenIndex];

      require(Address.isContract(token), "The given token address is not a contract");

      amount *= _amountFactor(tokenIndex);
      if (SHORT_COIN_TYPE == 0x00c3) {
        IERC20Minimal(token).transfer(recipient, amount);
      } else {
        // This doesn't works on Tron
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(
          ERC20_TRANSFER_SELECTOR,
          recipient,
          amount
        ));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "transfer failed");
      }
    }
  }

  function _transferCoreToken(address recipient, uint256 amount) internal {
    (bool success, ) = recipient.call{value: amount * 1e12}("");
    require(success, "Transfer failed");
  }

  /// @notice Transfer tokens to a contract using `depositWithBeneficiary`
  /// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
  /// @param contractAddr The smart contract address that will receive transferring tokens
  /// @param beneficiary The beneficiary of `depositWithBeneficiary`
  /// @param amount The value of the transfer (always in decimal 6)
  /// @param data Extra data passed to the contract
  function _transferToContract(
    uint8 tokenIndex,
    address contractAddr,
    address beneficiary,
    uint256 amount,
    uint64 data
  ) internal {
    require(Address.isContract(contractAddr), "The given recipient address is not a contract");

    amount *= _amountFactor(tokenIndex);
    if (_isCoreToken(tokenIndex)) {
      // Core tokens (e.g. ETH or BNB)
      IDepositWithBeneficiary(contractAddr).depositWithBeneficiary{value: amount}(
        address(0),
        amount,
        beneficiary,
        data
      );
    } else {
      // Stablecoins
      address token = tokenForIndex[tokenIndex];
      require(Address.isContract(token), "The given token address is not a contract");
      
      IERC20Minimal(token).approve(contractAddr, amount);
      IDepositWithBeneficiary(contractAddr).depositWithBeneficiary(
        token,
        amount,
        beneficiary,
        data
      );
    }
  }

  /// @notice Determine if token has decimal 18 and therefore need to adjust amount
  /// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
  function _amountFactor(uint8 tokenIndex) public pure returns (uint256) {
    if (tokenIndex <= 32) {
      return 1;
    } else if (tokenIndex == 242 && SHORT_COIN_TYPE != 0x02ca && SHORT_COIN_TYPE != 0x1771) {
      return 100;
    } else if (tokenIndex > 112 && tokenIndex <= 123) {
      return 100;
    } else if (tokenIndex > 123 && tokenIndex <= 128) {
      return 1000;
    }
    return 1e12;
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/// @title MesonTokens
/// @notice The class that stores the information of Meson's supported tokens
contract MesonTokens {
  /// @notice The whitelist of supported tokens in Meson
  /// Meson use a whitelist for supported stablecoins, which is specified on first deployment
  /// or added through `_addSupportToken` Only modify this mapping through `_addSupportToken`.
  /// key: `tokenIndex` in range of 1-255
  ///     0:       unsupported
  ///     1-32:    stablecoins with decimals 6
  ///       1, 9:    USDC, USDC.e
  ///       2, 10:   USDT, USDT.e
  ///       3:       BUSD
  ///       6:       CUSD (Viction/Tomo)
  ///       7:       pUSD
  ///       16:      USD1
  ///       17:      PoD USDC
  ///       18:      PoD USDT
  ///       19:      PoD BUSD
  ///       32:      PoD
  ///     33-48:   stablecoins with decimals 18
  ///       33:      USDC
  ///       34:      USDT
  ///       35:      BUSD
  ///       36:      (reserved for DAI)
  ///       37:      cUSD (Celo)
  ///       39:      USDB (Blast)
  ///       40:      FDUSD
  ///       41:      BBUSD
  ///       48:      USD1
  ///     49-64:   stablecoins as core (decimals 18)
  ///       49:      USDC
  ///       52:      DAI
  ///     65-112:  3rd party tokens (decimals 18)
  ///       65:      iUSD (iZUMi Bond USD)
  ///       67:      M-BTC (Merlin BTC)
  ///       69:      MERL
  ///       71:      STONE
  ///       73:      SolvBTC.m
  ///       75:      SolvBTC
  ///       77:      SolvBTC.a
  ///       79:      uBTC
  ///       81:      xSolvBTC
  ///       83:      SolvBTC.ENA
  ///       85:      SolvBTC.JUP
  ///       87:      PUMP
  ///       89:      B2
  ///     113-123:  3rd party tokens (decimals 8)
  ///       113:     pumpBTC
  ///       114:     uniBTC
  ///       115:     cbBTC
  ///       116:     FBTC
  ///     124-128:  3rd party tokens (decimals 9)
  ///       124:     DUCK
  ///     129-190: (Unspecified)
  ///     191:     No-swap core
  ///     192-195: M & M equivalent
  ///       194:     ERC20 M
  ///       195:     M as core
  ///     196-199: M & M equivalent
  ///       198:     ERC20 TAKER
  ///       199:     TAKER as core
  ///     200-235: (Unspecified)
  ///     236-239: MATIC & MATIC equivalent
  ///       236:     PoD MATIC
  ///       238:     ERC20 MATIC
  ///       239:     MATIC as core
  ///     240-243: BTC & BTC equivalent
  ///       240:     PoD BTC
  ///       241:     ERC20 BTC (decimals 18)
  ///       242:     ERC20 BTC (decimals 8 except BNB Smart Chain & BounceBit)
  ///       243:     BTC as core
  ///     244-247: SOL & SOL equivalent
  ///       244:     PoD SOL
  ///       246:     ERC20 SOL
  ///       247:     SOL as core
  ///     248-251: BNB & BNB equivalent
  ///       248:     PoD BNB
  ///       250:     (reserved for ERC20 BNB)
  ///       251:     BNB as core
  ///     252-255: ETH & ETH equivalent
  ///       252:     PoD ETH
  ///       254:     Wrapped ETH
  ///       255:     ETH as core
  /// value: the supported token's contract address
  mapping(uint8 => address) public tokenForIndex;


  /// @notice The mapping to get `tokenIndex` from a supported token's address
  /// Only modify this mapping through `_addSupportToken`.
  /// key: the supported token's contract address
  /// value: `tokenIndex` in range of 1-255
  mapping(address => uint8) public indexOfToken;

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

  function _isCoreToken(uint8 tokenIndex) public pure returns (bool) {
    return (tokenIndex >= 49 && tokenIndex <= 64) || ((tokenIndex > 190) && ((tokenIndex % 4) == 3));
  }

  /// @notice Return all supported token addresses in an array ordered by `tokenIndex`
  /// This method will only return tokens with consecutive token indexes.
  function getSupportedTokens() external view returns (address[] memory tokens, uint8[] memory indexes) {
    uint8 i;
    uint8 num;
    for (i = 0; i < 255; i++) {
      if (tokenForIndex[i+1] != address(0)) {
        num++;
      }
    }
    tokens = new address[](num);
    indexes = new uint8[](num);
    uint8 j = 0;
    for (i = 0; i < 255; i++) {
      if (tokenForIndex[i+1] != address(0)) {
        tokens[j] = tokenForIndex[i+1];
        indexes[j] = i+1;
        j++;
      }
    }
  }

  function _addSupportToken(address token, uint8 index) internal {
    require(index != 0, "Cannot use 0 as token index");
    require(token != address(0), "Cannot use zero address");
    require(indexOfToken[token] == 0, "Token has been added before");
    require(tokenForIndex[index] == address(0), "Index has been used");
    if (_isCoreToken(index)) {
      require(token == address(0x1), "Core token requires adddress(0x1)");
    }
    indexOfToken[token] = index;
    tokenForIndex[index] = token;
  }

  function _removeSupportToken(uint8 index) internal {
    require(index != 0, "Cannot use 0 as token index");
    address token = tokenForIndex[index];
    require(token != address(0), "Token for the index does not exist");
    delete indexOfToken[token];
    delete tokenForIndex[index];
  }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "evmVersion": "paris",
  "viaIR": true,
  "metadata": {
    "bytecodeHash": "none"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"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":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint40","name":"poolIndex","type":"uint40"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"PoolAuthorizedAddrAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint40","name":"poolIndex","type":"uint40"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"PoolAuthorizedAddrRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint48","name":"poolTokenIndex","type":"uint48"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PoolDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint40","name":"poolIndex","type":"uint40"},{"indexed":false,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"PoolOwnerTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint40","name":"poolIndex","type":"uint40"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"PoolRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint48","name":"poolTokenIndex","type":"uint48"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PoolWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevPremiumManager","type":"address"},{"indexed":true,"internalType":"address","name":"newPremiumManager","type":"address"}],"name":"PremiumManagerTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"encodedSwap","type":"uint256"}],"name":"SwapBonded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"encodedSwap","type":"uint256"}],"name":"SwapCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"encodedSwap","type":"uint256"}],"name":"SwapExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"encodedSwap","type":"uint256"}],"name":"SwapLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"encodedSwap","type":"uint256"}],"name":"SwapPosted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"encodedSwap","type":"uint256"}],"name":"SwapReleased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"encodedSwap","type":"uint256"}],"name":"SwapUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[{"internalType":"uint8","name":"tokenIndex","type":"uint8"}],"name":"_amountFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint8","name":"tokenIndex","type":"uint8"}],"name":"_isCoreToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"addAuthorizedAddr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint8[]","name":"indexes","type":"uint8[]"}],"name":"addMultipleSupportedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"index","type":"uint8"}],"name":"addSupportToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"tokenIndex","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint40","name":"toPoolIndex","type":"uint40"}],"name":"adjustToPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"uint40","name":"poolIndex","type":"uint40"}],"name":"bondSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"}],"name":"cancelSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"cancelSwapTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint48","name":"poolTokenIndex","type":"uint48"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint48","name":"poolTokenIndex","type":"uint48"}],"name":"depositAndRegister","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"yParityAndS","type":"bytes32"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"directExecuteSwap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"yParityAndS","type":"bytes32"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"directRelease","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"yParityAndS","type":"bytes32"}],"name":"directSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"yParityAndS","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"depositToPool","type":"bool"}],"name":"executeSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"address","name":"initiator","type":"address"}],"name":"getLockedSwap","outputs":[{"internalType":"address","name":"poolOwner","type":"address"},{"internalType":"uint40","name":"until","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"}],"name":"getPostedSwap","outputs":[{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"poolOwner","type":"address"},{"internalType":"bool","name":"exist","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getShortCoinType","outputs":[{"internalType":"bytes2","name":"","type":"bytes2"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getSupportedTokens","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint8[]","name":"indexes","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"indexOfToken","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"premiumManager","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"initiator","type":"address"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"address","name":"initiator","type":"address"}],"name":"lockSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"","type":"uint40"}],"name":"ownerOfPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"poolOfAuthorizedAddr","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"addr","type":"address"}],"name":"poolTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"uint40","name":"poolIndex","type":"uint40"}],"name":"postSwap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"uint200","name":"postingValue","type":"uint200"}],"name":"postSwapFromInitiator","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"yParityAndS","type":"bytes32"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"uint40","name":"poolIndex","type":"uint40"}],"name":"postSwapWithSignature","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"yParityAndS","type":"bytes32"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"release","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"removeAuthorizedAddr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"removeSupportToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"tokenIndex","type":"uint8"}],"name":"serviceFeeCollected","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"}],"name":"simpleExecuteSwap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"tokenForIndex","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"transferPoolOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPremiumManager","type":"address"}],"name":"transferPremiumManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"encodedSwap","type":"uint256"},{"internalType":"address","name":"initiator","type":"address"}],"name":"unlock","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":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint48","name":"poolTokenIndex","type":"uint48"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"tokenIndex","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint40","name":"toPoolIndex","type":"uint40"}],"name":"withdrawServiceFee","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a0806040523460305730608052614f0b90816100368239608051818181610a2b01528181610ff401526130ae0152f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c8063051119f5146102d75780630ffad9c0146102d257806316f35d23146102cd5780631e2a6075146102c85780632335093c146102c3578063264849e7146102be57806330f00f3a146102b957806335eff30f146102b45780633659cfe6146102af57806337b90a4f146102aa578063485cc955146102a55780634a2377e2146102a05780634f1ef2861461029b578063515147ab1461029657806352d1902d1461029157806354d6a2b71461028c57806358d9b4e11461028757806360a2da98146102825780636484396e1461027d5780636f9b41fd146102785780637234cd9514610273578063741c8e2d1461026e5780637fe0282b14610269578063827c87cc1461026457806389a734c01461025f5780638b0a77651461025a5780638f487dc914610255578063a5c9c66c14610250578063ab115fd81461024b578063b805f32114610246578063c11d9ecb14610241578063c8173c441461023c578063cb4f999b14610237578063ce7f79b914610232578063d3c7c2c71461022d578063d3e95ea414610228578063d4f8232214610223578063decf2a481461021e578063eaf250b514610219578063eba7fb7714610214578063f1d2ec1d1461020f578063f2fde38b1461020a578063ff22f272146102055763ff3787191461020057600080fd5b612658565b6125af565b612578565b612447565b612427565b6123ae565b6122cb565b612286565b61225a565b612149565b61200d565b611f16565b611e76565b611dc7565b611d0f565b611aa8565b6118c3565b61172a565b6116e8565b6116a5565b611531565b6114e6565b61142f565b61137b565b611296565b61126b565b6111b8565b611196565b6110a1565b610fe1565b610df2565b610d7b565b610cf7565b610bf5565b610add565b610a0a565b6108f5565b610800565b61075e565b610721565b610651565b610587565b61046d565b610337565b600435906001600160a01b03821682036102f257565b600080fd5b606435906001600160a01b03821682036102f257565b602435906001600160a01b03821682036102f257565b35906001600160a01b03821682036102f257565b346102f25760203660031901126102f2576103506102dc565b3360005260996020527f475b83c893df40ee19fd0783cf26478cdb58478dff65bb62560e1e7c36e0f22f61042c64ffffffffff6040600020541692610396841515612694565b6000848152609a60205260409020546103ca906103c3906001600160a01b03165b6001600160a01b031690565b33146126ec565b6103f8846103f26103e86103dd85610707565b5464ffffffffff1690565b64ffffffffff1690565b14612742565b61041261040482610707565b805464ffffffffff19169055565b6040516001600160a01b0390911681529081906020820190565b0390a2005b6084359064ffffffffff821682036102f257565b6024359064ffffffffff821682036102f257565b6044359064ffffffffff821682036102f257565b346102f25760a03660031901126102f2576105856004356024356044356104926102f7565b9161049b610431565b936104ab60018260f81c146127a3565b6104ca603c61ffff6104c3600885901c5b61ffff1690565b16146127ef565b6104ff6104de60ff83166139f4565b6139f4565b60ff6104f76104f16104d9601887901c82565b60ff1690565b911614612835565b600081815260ce60205260409020610533906001600160d01b039061052c905b546001600160d01b031690565b161561288b565b61055064174876e80060d083901c64ffffffffff165b11156128cd565b610580611c2061056d603084901c64ffffffffff165b429061295f565b61057a610e10821161296c565b106129ae565b612a5c565b005b346102f25760403660031901126102f25760043561062a6105a661030d565b610135546105be906001600160a01b03163314612cfc565b8260005260ce6020526105df6001808060d01b036040600020541611612d52565b6105f6603084901c64ffffffffff165b4211612d94565b600083815260ce6020526040902080546001600160d01b031916905560ff83169060d084901c64ffffffffff165b91613ea0565b7ff6b6b4f7a13f02512c1b3aa8dcc4a07d7775a6a4becbd439efcbd37c5408e67f600080a2005b346102f25760203660031901126102f257600435600090815260ce60205260409020546001600160a01b03602882901c16906001600160d01b03811690826106cc57506106c86000925b604080516001600160a01b0392831681529490911660208501529115159183019190915281906060820190565b0390f35b6107016106f464ffffffffff6106c8931664ffffffffff16600052609a602052604060002090565b546001600160a01b031690565b9261069b565b6001600160a01b0316600090815260996020526040902090565b346102f25760203660031901126102f2576001600160a01b036107426102dc565b166000526066602052602060ff60406000205416604051908152f35b60203660031901126102f25761058560043561077f60018260f81c146127a3565b610794603c61ffff6104c3600885901c6104bc565b6107a36104de60ff83166139f4565b600081815260ce602052604090206107c7906001600160d01b039061052c9061051f565b6107e164174876e80060d083901c64ffffffffff16610549565b6107fb611c2061056d603084901c64ffffffffff16610566565b612e10565b346102f25760203660031901126102f2576108196102dc565b3360005260996020527fc94089e0c0b1b79fdecc6e64fb759cdd390590a15c7e50d281e681ea8273261c61042c64ffffffffff604060002054169261085f841515612694565b6000848152609a6020526040902054610884906103c3906001600160a01b03166103b7565b610897846103f26103e86103dd85610707565b6108d5816108b68664ffffffffff16600052609a602052604060002090565b80546001600160a01b0319166001600160a01b03909216919091179055565b604080513381526001600160a01b03909216602083015290918291820190565b346102f25760403660031901126102f257600435610911610445565b600082815260ce60205260409020546001600160d01b038116919064ffffffffff9061093f60018511612d52565b166109c55761099e9161096a64ffffffffff928361095f6103dd33610707565b9116931683146129ef565b1761097f8360005260ce602052604060002090565b80546001600160d01b0319166001600160d01b03909216919091179055565b7f60a99b51ae498c44acbbe11031aed2a06a32be66d2122e6e2a7a16c087865cc9600080a2005b60405162461bcd60e51b815260206004820152601b60248201527f5377617020626f6e64656420746f20616e6f7468657220706f6f6c00000000006044820152606490fd5b346102f25760203660031901126102f257610585610a266102dc565b610a7e7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610a5f30821415612ea2565b600080516020614edf833981519152546001600160a01b031614612f03565b610a9460018060a01b0361013454163314613397565b604051906020610aa48184610d3a565b60008352601f198101903690840137614036565b60409060031901126102f2576004359060243565ffffffffffff811681036102f25790565b610ae636610ab8565b610af1821515612f64565b64ffffffffff8116610b04811515612faa565b33600052609960205264ffffffffff80604060002054161603610b9f5765ffffffffffff81610b667f7d7d1df74ef3a6434d8d63dc0a25d13d5fa94dbe738c38a3cce26e6f892e2a769365ffffffffffff16600052609b602052604060002090565b610b71858254612e03565b9055610b8d8433610b88602885901c60ff166104f1565b613d5a565b6040519384521691806020810161042c565b60405162461bcd60e51b815260206004820152602860248201527f4e65656420616e20617574686f72697a65642061646472657373206173207468604482015267329039b4b3b732b960c11b6064820152608490fd5b346102f25760403660031901126102f257610c0e6102dc565b610c5b610c1961030d565b60005492610c3f60ff600886901c161580958196610cd9575b8115610cb9575b50612ff6565b83610c52600160ff196000541617600055565b610ca057613059565b610c6157005b610c7161ff001960005416600055565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602090a1005b610cb461010061ff00196000541617600055565b613059565b303b15915081610ccb575b5038610c39565b60ff16600114905038610cc4565b600160ff8216109150610c32565b6004359060ff821682036102f257565b346102f25760203660031901126102f2576020610d1a610d15610ce7565b613068565b6040519015158152f35b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b03821117610d5b57604052565b610d24565b6001600160401b038111610d5b57601f01601f191660200190565b60403660031901126102f257610d8f6102dc565b602435906001600160401b0382116102f257366023830112156102f257816004013590610dbb82610d60565b91610dc96040519384610d3a565b80835236602482860101116102f2576020816000926024610585970183870137840101526130a8565b346102f25760803660031901126102f257600435610f56610e3c610e146102f7565b610e2360018560f81c146127a3565b610e36603c61ffff8660201c16146127ef565b83614235565b610e6c6001600160501b0361052c610e5f84600052610101602052604060002090565b546001600160501b031690565b610f3b610f29610e7e6103dd33610707565b610e9064ffffffffff821615156131cc565b610e9942612dd7565b610eb7610eb0603089901c64ffffffffff1661294f565b8210613230565b601087901b60ff60281b1664ffffffffff831617610efb610ef3610eda8a614268565b9265ffffffffffff16600052609b602052604060002090565b91825461295f565b9055610f068761429d565b80610f7d575b5060281b69ffffffffff00000000001664ffffffffff9091161790565b91600052610101602052604060002090565b906001600160501b03166001600160501b0319825416179055565b7fbfb879c34323c5601fafe832c3a8a1e31e12c288695838726ddeada86034edb4600080a2005b60016000526066602052610fd9610ef3610fc185610fab600080516020614ebf8339815191525b5460ff1690565b60281b60ff60281b1664ffffffffff9091161790565b65ffffffffffff16600052609b602052604060002090565b905538610f0c565b346102f25760003660031901126102f2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316300361103b57604051600080516020614edf8339815191528152602090f35b60405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152608490fd5b346102f25760203660031901126102f257600435600081815260ce60205260409020546001600160d01b03166110d960018211612d52565b6110ed603083901c64ffffffffff166105ef565b60ff60c882901c166111515761062a906111246111148460005260ce602052604060002090565b80546001600160d01b0319169055565b60ff831690611140906103b79060281c6001600160a81b031681565b60d084901c64ffffffffff16610624565b60405162461bcd60e51b815260206004820152601d60248201527f5377617020746f6b656e206e6f742066726f6d20696e69746961746f720000006044820152606490fd5b346102f25760403660031901126102f257600435610f56610e3c610e1461030d565b346102f25760403660031901126102f2576004356111df6111d761030d565b600092614235565b815261010160205260408120546001600160501b03811691906001830361122c5750505060016000905b604080516001600160a01b0392909216825264ffffffffff929092166020820152f35b64ffffffffff9081168252609a6020526040909120546001600160a01b031691611265916103e89160281c165b6001600160501b031690565b90611209565b346102f25760203660031901126102f257602061128e611289610ce7565b61328a565b604051908152f35b60603660031901126102f2576105856004356112b061030d565b6112b8610459565b916112c860018260f81c146127a3565b6112dd603c61ffff6104c3600885901c6104bc565b6112ec6104de60ff83166139f4565b600081815260ce60205260409020611310906001600160d01b039061052c9061051f565b61132a64174876e80060d083901c64ffffffffff16610549565b611344611c2061056d603084901c64ffffffffff16610566565b613311565b60609060031901126102f25760043560ff811681036102f257906024359060443564ffffffffff811681036102f25790565b346102f25761138936611349565b6113a260018060a09594951b0361013454163314613397565b64ffffffffff81166000908152609a60205260409020546113cd906001600160a01b031615156133dd565b65ffffffffffff602883901b60ff60281b1616600052609b602052604060002080549184830392831161142a576114269361141e93610fc193559064ffffffffff60ff60281b91169160281b161790565b918254612e03565b9055005b612939565b346102f25760803660031901126102f25761058560043561144e61030d565b604435906064359261146560018260f81c146127a3565b61147a603c61ffff6104c3600885901c6104bc565b6114896104de60ff83166139f4565b600081815260ce602052604090206114ad906001600160d01b039061052c9061051f565b6114c764174876e80060d083901c64ffffffffff16610549565b6114e1611c2061056d603084901c64ffffffffff16610566565b613425565b346102f25760203660031901126102f2576001600160a01b036115076102dc565b166000526099602052602064ffffffffff60406000205416604051908152f35b801515036102f257565b346102f25760a03660031901126102f2576004356024356044356115e06115566102f7565b6084359261156384611527565b61157a61051f8760005260ce602052604060002090565b9461159060016001600160d01b03881611612d52565b603087901c64ffffffffff166115a542612de6565b1115611676576115c26111148860005260ce602052604060002090565b6115d96103b76001600160a81b03602889901c1681565b928761456d565b60ff83169164ffffffffff16901561164f5761141e610fc16116259261160e8664ffffffffff9060d01c1690565b9460281b60ff60281b1664ffffffffff9091161790565b90555b7f8d92c805c252261fcfff21ee60740eb8a38922469a7e6ee396976d57c22fc1c9600080a2005b906111406106f46116719364ffffffffff16600052609a602052604060002090565b611628565b6116a061168d8860005260ce602052604060002090565b80546001600160d01b0319166001179055565b6115c2565b346102f25760203660031901126102f25760043564ffffffffff81168091036102f257600052609a602052602060018060a01b0360406000205416604051908152f35b346102f25760203660031901126102f25765ffffffffffff60ff60281b61170d610ce7565b60281b1616600052609b6020526020604060002054604051908152f35b65ffffffffffff7f7d7d1df74ef3a6434d8d63dc0a25d13d5fa94dbe738c38a3cce26e6f892e2a7661175b36610ab8565b6117688294921515612f64565b64ffffffffff81166118058161177f811515612faa565b6117ae60018060a01b036117a76106f48464ffffffffff16600052609a602052604060002090565b16156135ab565b6117c66117c06103e86103dd33610707565b156135f7565b6117e5336108b68364ffffffffff16600052609a602052604060002090565b6117ee33610707565b9064ffffffffff1664ffffffffff19825416179055565b6118218265ffffffffffff16600052609b602052604060002090565b61182c868254612e03565b90556118438533610b88602886901c60ff166104f1565b6040513381527fb8d9c35a714d4e29eaf036b9bf8183a093c5573ac809453b4e8434e25c9126d290602090a26040519384521691806020810161042c565b60a09060031901126102f2576004359060243590604435906064356001600160a01b03811681036102f257906084356001600160a01b03811681036102f25790565b346102f25761198f6119d26119796118da36611881565b9396919490926118eb32331461364d565b611902603089901c64ffffffffff165b42106136a4565b6119166001600160a01b0386161515613560565b61196884600160ce1b8a1615159788611a8b575b611934828c614235565b9361196160016001600160501b0361195a610e5f89600052610101602052604060002090565b1611612d52565b888c61456d565b600052610101602052604060002090565b805469ffffffffffffffffffff19166001179055565b61199885614268565b9215611a47575b6119a885614839565b80611a09575b506119b88561429d565b806119f9575b506119cc601886901c6104f1565b856143a8565b7ffa628b578e095243f0544bfad9255f49d79d03a5bbf6c85875d05a215e247ad2600080a2005b611a03908361488a565b386119be565b9283611a149161295f565b92611a3f61141e610fc1611a278961485c565b899064ffffffffff60ff60281b91169160101b161790565b9055386119ae565b611a5a611a538661477a565b809461295f565b92611a8461141e601088901b60ff60281b1665ffffffffffff16600052609b602052604060002090565b905561199f565b61013554611aa3906001600160a01b03163314612cfc565b61192a565b346102f2576119d2611ab936611881565b9192611acd60018660f89897981c146127a3565b611ae0603c61ffff8860201c16146127ef565b611aeb32331461364d565b611aff6001600160a01b0384161515613560565b611b88611979600160ce1b881615159586611cf2575b8885611b218183614235565b92611b456001600160501b0361052c610e5f87600052610101602052604060002090565b611b516103dd33610707565b96611b6464ffffffffff891615156131cc565b8015611ccc5761196893611b819060301c64ffffffffff166118fb565b898d61456d565b611b9186614268565b93611bc1601088901b60ff60281b1664ffffffffff84161765ffffffffffff16600052609b602052604060002090565b611bcc86825461295f565b905515611c88575b611bdd86614839565b80611c4a575b50611bed8661429d565b80611c03575b506119cc9050601886901c6104f1565b60016000526066602052611c4391611c3090610fc190610fab600080516020614ebf833981519152610fa4565b611c3b82825461295f565b90558361488a565b3880611bf3565b9384611c559161295f565b93611c8061141e610fc1611c688a61485c565b8a9064ffffffffff60ff60281b91169160101b161790565b905538611be3565b611c9b611c948761477a565b809561295f565b93611cc561141e601089901b60ff60281b1665ffffffffffff16600052609b602052604060002090565b9055611bd4565b50505050866119685761013554611ced906001600160a01b03163314612cfc565b611968565b61013554611d0a906001600160a01b03163314612cfc565b611b15565b346102f25760203660031901126102f257610585611d2b6102dc565b61013554611d43906001600160a01b03163314612cfc565b614190565b6001600160401b038111610d5b5760051b60200190565b9080601f830112156102f257813590611d7782611d48565b92611d856040519485610d3a565b82845260208085019360051b8201019182116102f257602001915b818310611dad5750505090565b823560ff811681036102f257815260209283019201611da0565b346102f25760403660031901126102f2576004356001600160401b0381116102f257366023820112156102f257806004013590611e0382611d48565b91611e116040519384610d3a565b8083526024602084019160051b830101913683116102f257602401905b828210611e5e57602435846001600160401b0382116102f257611e58610585923690600401611d5f565b906136f0565b60208091611e6b84610323565b815201910190611e2e565b610585611e8236611881565b93611e9560018260f89694961c146127a3565b611eaa603c61ffff6104c3600885901c6104bc565b611eb96104de60ff83166139f4565b600081815260ce60205260409020611edd906001600160d01b039061052c9061051f565b611ef764174876e80060d083901c64ffffffffff16610549565b611f11611c2061056d603084901c64ffffffffff16610566565b613801565b346102f25760203660031901126102f257611f2f610ce7565b611f4560018060a01b0361013454163314613397565b60ff8116611f548115156148f5565b6000908152606560205260409020546001600160a01b03168015611fbd576001600160a01b03166000908152606660205260409020805460ff1916905561058590611fad905b60ff166000526065602052604060002090565b80546001600160a01b0319169055565b60405162461bcd60e51b815260206004820152602260248201527f546f6b656e20666f722074686520696e64657820646f6573206e6f74206578696044820152611cdd60f21b6064820152608490fd5b346102f25765ffffffffffff7f34c3d1c46f89307d63d8818fcc5c2a9c07a5f7a01ea4319bfba1899f40c6f40061204336610ab8565b6120508294921515612f64565b64ffffffffff8116612063811515612faa565b6000908152609a6020526040902054612086906001600160a01b031633146126ec565b6120a28165ffffffffffff16600052609b602052604060002090565b6120ad85825461295f565b9055610b8d84336120c4602885901c60ff166104f1565b613ea0565b6040810160408252825180915260206060830193019060005b81811061212a5750505060208183039101526020808351928381520192019060005b8181106121115750505090565b825160ff16845260209384019390920191600101612104565b82516001600160a01b03168552602094850194909201916001016120e2565b346102f25760003660031901126102f25760ff6000805b828082161061222357501661217d61217782613890565b91613890565b906000805b60ff8082161061219d5750506106c8604051928392836120c9565b6121af6103b76106f4611f9a8461387e565b6121bf575b60010160ff16612182565b90600161221a60ff926122156121da6106f4611f9a8861387e565b6121fa868416916121eb838b6137d7565b6001600160a01b039091169052565b61220d6122068861387e565b918a6137d7565b9060ff169052565b6137c6565b929150506121b4565b6122356103b76106f4611f9a8461387e565b612244575b6001018216612160565b90600161225184926137c6565b9291505061223a565b346102f25760403660031901126102f257602061128e6122786102dc565b61228061030d565b906138c2565b346102f25760403660031901126102f25761229f6102dc565b60243560ff811681036102f257610585916122c660018060a01b0361013454163314613397565b614a25565b60403660031901126102f2576004356024356001600160c81b03811691908281036102f2576105859260281c6001600160a01b03169064ffffffffff9061231860f885901c6001146127a3565b61232d603c61ffff6104c3600888901c6104bc565b61234f61233c60ff86166139f4565b60ff6104f76104f16104d960188a901c82565b600084815260ce60205260409020612373906001600160d01b039061052c9061051f565b61238d64174876e80060d086901c64ffffffffff16610549565b6123a7611c2061056d603087901c64ffffffffff16610566565b1691613311565b346102f25761240a65ffffffffffff6123c636611349565b9093916123df60018060a01b0361013454163314613397565b64ffffffffff82166000908152609a6020526040902054610fab906001600160a01b031615156133dd565b16600052609b6020526040600020805491820180921161142a5755005b346102f25760003660031901126102f257604051600f60f21b8152602090f35b346102f25760403660031901126102f25760043561251b61250861247261246c61030d565b84614235565b6124c061248d610e5f83600052610101602052604060002090565b6124a260016001600160501b03831611612d52565b6103e86124b964ffffffffff602884901c16611259565b4211613935565b601085901b60ff60281b1664ffffffffff8216176124e361141e610eda88614268565b90556124ee8561429d565b9081612542575b5050600052610101602052604060002090565b805469ffffffffffffffffffff19169055565b7fac7d23c4f0137a4cc35b0e4b4bc8061ea6cb65805e87ceb0a77ca0c85814858c600080a2005b6001600052606660205261256f9061141e90610fc190610fab600080516020614ebf833981519152610fa4565b905538806124f5565b346102f25760203660031901126102f2576105856125946102dc565b6125aa60018060a01b0361013454163314613397565b6140f8565b346102f25760203660031901126102f2576125c86102dc565b3360005260996020527fd49cde4f679ccef3d23ff07aae4f6845e1c661e23e9fe6a54da26f0723fb695f61042c64ffffffffff604060002054169261260e841515612694565b6000848152609a6020526040902054612633906103c3906001600160a01b03166103b7565b61264b6126456103e86103dd84610707565b15613976565b610412846117ee83610707565b346102f25760203660031901126102f25760ff612673610ce7565b166000526065602052602060018060a01b0360406000205416604051908152f35b1561269b57565b60405162461bcd60e51b815260206004820152602360248201527f546865207369676e657220646f6573206e6f74207265676973746572206120706044820152621bdbdb60ea1b6064820152608490fd5b156126f357565b60405162461bcd60e51b815260206004820152602160248201527f4e6565642074686520706f6f6c206f776e657220617320746865207369676e656044820152603960f91b6064820152608490fd5b1561274957565b60405162461bcd60e51b815260206004820152602c60248201527f41646472206973206e6f7420617574686f72697a656420666f7220746865207360448201526b1a59db995c89dcc81c1bdbdb60a21b6064820152608490fd5b156127aa57565b60405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420656e636f64696e672076657273696f6e0000000000006044820152606490fd5b156127f657565b60405162461bcd60e51b815260206004820152601760248201527629bbb0b8103737ba103337b9103a3434b99031b430b4b760491b6044820152606490fd5b1561283c57565b60405162461bcd60e51b815260206004820152602160248201527f496e2026206f757420746f6b656e20747970657320646f206e6f74206d6174636044820152600d60fb1b6064820152608490fd5b1561289257565b60405162461bcd60e51b81526020600482015260136024820152725377617020616c72656164792065786973747360681b6044820152606490fd5b156128d457565b60405162461bcd60e51b815260206004820152603760248201527f466f7220736563757269747920726561736f6e2c20616d6f756e742063616e6e6044820152766f742062652067726561746572207468616e203130306b60481b6064820152608490fd5b634e487b7160e01b600052601160045260246000fd5b61012b1981019190821161142a57565b9190820391821161142a57565b1561297357565b60405162461bcd60e51b815260206004820152601360248201527245787069726520747320746f6f206561726c7960681b6044820152606490fd5b156129b557565b60405162461bcd60e51b815260206004820152601260248201527145787069726520747320746f6f206c61746560701b6044820152606490fd5b156129f657565b60405162461bcd60e51b815260206004820152603860248201527f5369676e65722073686f756c6420626520616e20617574686f72697a6564206160448201527719191c995cdcc81bd9881d1a194819da5d995b881c1bdbdb60421b6064820152608490fd5b93909291600060209164ffffffffff841680151580612ce9575b612cc6575b506001600160a01b03851695612a92871515613ab1565b6001600160ff1b03821691612b7a90612ab1906104f19060ff1c612df5565b92612ad46fa2a8918ca85bafe22016d0b997e4df60600160ff1b03821115613afd565b600160cb1b8a16151560c361ffff612aef60088e901c6104bc565b16148614612c43578514612c2157780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519998560391b5b60405166ffffffffffffff19909116878201908152601981018c905290612b4f81603984015b03601f198101835282610d3a565b519020925b604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15612c1c57600051612bf593612bdf92612bcb929091612bad916001600160a01b03165b14613afd565b64ffffffffff1665010000000000600160c81b03602885901b161790565b61097f8560005260ce602052604060002090565b64ffffffffff60d084901c169060ff8416613d5a565b7f5ce4019f772fda6cb703b26bce3ec3006eb36b73f1d3a0eb441213317d9f5e9d600080a2565b613b3d565b780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519990560391b612b1b565b8514612c915789604051612c8881612b418a82019485603c917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008252601c8201520190565b51902092612b54565b89855285852086527f9862d877599564bcd97c37305a7b0fdbe621d9c2a125026f2ad601f754a75abc85526040852092612b54565b612ce3903384526099855264ffffffffff604085205416146129ef565b38612a7b565b50336001600160a01b0387161415612a76565b15612d0357565b60405162461bcd60e51b815260206004820152602160248201527f43616c6c6572206973206e6f7420746865207072656d69756d206d616e6167656044820152603960f91b6064820152608490fd5b15612d5957565b60405162461bcd60e51b815260206004820152601360248201527214ddd85c08191bd95cc81b9bdd08195e1a5cdd606a1b6044820152606490fd5b15612d9b57565b60405162461bcd60e51b815260206004820152601460248201527314ddd85c081a5cc81cdd1a5b1b081b1bd8dad95960621b6044820152606490fd5b90610960820180921161142a57565b90610e10820180921161142a57565b90601b820180921161142a57565b9190820180921161142a57565b600081815260ce6020526040902080546001600160d01b031916600117905560ff811660d082901c64ffffffffff1665ffffffffffff602884901b60ff60281b1660011716600052609b602052604060002091825482810180911161142a57612e7b93553390613d5a565b7f8d92c805c252261fcfff21ee60740eb8a38922469a7e6ee396976d57c22fc1c9600080a2565b15612ea957565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b15612f0a57565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b6064820152608490fd5b15612f6b57565b60405162461bcd60e51b8152602060048201526017602482015276416d6f756e74206d75737420626520706f73697469766560481b6044820152606490fd5b15612fb157565b60405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f7420757365203020617320706f6f6c20696e6465780000000000006044820152606490fd5b15612ffd57565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b90611d43613066926140f8565b565b60ff8116906031821015918261309c575b821561308457505090565b60be10915081613092575090565b6003915081161490565b60408111159250613079565b906130e27f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610a5f30821415612ea2565b6130f860018060a01b0361013454163314613397565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561312c575061306690614c42565b6040516352d1902d60e01b8152906020826004816001600160a01b0387165afa6000928161319b575b506131775760405162461bcd60e51b81528061317360048201613fe7565b0390fd5b61306692613196600080516020614edf83398151915260019414613f89565b614b26565b6131be91935060203d6020116131c5575b6131b68183610d3a565b810190613f7a565b9138613155565b503d6131ac565b156131d357565b60405162461bcd60e51b815260206004820152602f60248201527f43616c6c6572206e6f7420726567697374657265642e2043616c6c206465706f60448201526e39b4ba20b7322932b3b4b9ba32b91760891b6064820152608490fd5b1561323757565b60405162461bcd60e51b815260206004820152602560248201527f43616e6e6f74206c6f636b20626563617573652065787069726554732069732060448201526439b7b7b71760d91b6064820152608490fd5b60ff166020811161329b5750600190565b60f2811480613309575b80613301575b156132b65750606490565b60708111806132f6575b156132cb5750606490565b607b811190816132ea575b506132e45764e8d4a5100090565b6103e890565b608091501115386132d6565b50607b8111156132c0565b5060016132ab565b5060016132a5565b91613379916000919064ffffffffff906001600160a01b031633811461339157600160c81b935b5065010000000000600160d01b039060281b1691169117178260005260ce60205260406000209060018060d01b031665ffffffffffff60d01b825416179055565b612bf564ffffffffff8260d01c163360ff8416613d5a565b83613338565b1561339e57565b60405162461bcd60e51b815260206004820152601760248201527621b0b63632b91034b9903737ba103a34329037bbb732b960491b6044820152606490fd5b156133e457565b60405162461bcd60e51b8152602060048201526019602482015278141bdbdb081a5b99195e081b9bdd081c9959da5cdd195c9959603a1b6044820152606490fd5b926135399261349a91613441603c61ffff8860201c16146127ef565b6134556001600160a01b0385161515613560565b6040805160208101888152606087901b6001600160601b031916928201929092526134838160548101612b41565b519020610135546001600160a01b031692906142fa565b60d083901c64ffffffffff169061352b60ff8516926134c4605887901c64ffffffffff168261295f565b936134ee602882901b60ff60281b1660011765ffffffffffff16600052609b602052604060002090565b6134f9838254612e03565b9055600160ff60281b601089901b16176000908152609b6020526040902061352286825461295f565b90553390613d5a565b336119cc601886901c6104f1565b7ffa628b578e095243f0544bfad9255f49d79d03a5bbf6c85875d05a215e247ad2600080a2565b1561356757565b606460405162461bcd60e51b815260206004820152602060248201527f526563697069656e742063616e6e6f74206265207a65726f20616464726573736044820152fd5b156135b257565b60405162461bcd60e51b815260206004820152601d60248201527f506f6f6c20696e64657820616c726561647920726567697374657265640000006044820152606490fd5b156135fe57565b60405162461bcd60e51b815260206004820152602160248201527f5369676e6572206164647265737320616c7265616479207265676973746572656044820152601960fa1b6064820152608490fd5b1561365457565b60405162461bcd60e51b815260206004820152602260248201527f43616e6e6f742062652063616c6c6564207468726f75676820636f6e74726163604482015261747360f01b6064820152608490fd5b156136ab57565b60405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f742072656c656173652062656361757365206578706972656400006044820152606490fd5b909161370860018060a01b0361013454163314613397565b815183510361376a5760005b825160ff82169081101561376357906122158261375861375161374a61373d61375e978a6137d7565b516001600160a01b031690565b92896137d7565b5160ff1690565b90614a25565b613714565b5050915050565b60405162461bcd60e51b815260206004820152602e60248201527f546f6b656e7320616e6420696e64657865732073686f756c642068617665207460448201526d0d0ca40e6c2daca40d8cadccee8d60931b6064820152608490fd5b60ff1660ff811461142a5760010190565b80518210156137eb5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b9391839161380f938661456d565b600082815260ce6020526040902080546001600160d01b031916600117905564ffffffffff8260d01c1660ff83169165ffffffffffff6138598460ff60281b60019160281b161790565b16600052609b602052604060002092835483810180911161142a57612e7b9455613d5a565b60ff60019116019060ff821161142a57565b9061389a82611d48565b6138a76040519182610d3a565b82815280926138b8601f1991611d48565b0190602036910137565b6001600160a01b0390811660009081526066602090815260408083205494909316825260999052205464ffffffffff169060ff168115801561392d575b6139265761392291610fc1919064ffffffffff60ff60281b91169160281b161790565b5490565b5050600090565b5080156138ff565b1561393c57565b60405162461bcd60e51b815260206004820152601260248201527153776170207374696c6c20696e206c6f636b60701b6044820152606490fd5b1561397d57565b60405162461bcd60e51b815260206004820152602360248201527f4164647220697320617574686f72697a656420666f7220616e6f7468657220706044820152621bdbdb60ea1b6064820152608490fd5b60ff604f199116019060ff821161142a57565b60ff601f199116019060ff821161142a57565b60ff811660c08110613a0d575060021c603f1690565b90565b60408111613a1c575050600090565b60708111613a425750613a3d613a34613a0a9261387e565b60011c607f1690565b6139e1565b60801015613a9b5760405162461bcd60e51b8152602060048201526024808201527f546f6b656e20696e646578206e6f7420616c6c6f77656420666f72207377617060448201526370696e6760e01b6064820152608490fd5b613a0a906139ce565b60d01c64ffffffffff1690565b15613ab857565b60405162461bcd60e51b815260206004820152601e60248201527f5369676e65722063616e6e6f7420626520656d707479206164647265737300006044820152606490fd5b15613b0457565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b6040513d6000823e3d90fd5b15613b5057565b606460405162461bcd60e51b815260206004820152602060248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152fd5b15613b9b57565b60405162461bcd60e51b8152602060048201526013602482015272151bdad95b881b9bdd081cdd5c1c1bdc9d1959606a1b6044820152606490fd5b15613bdd57565b60405162461bcd60e51b815260206004820152602960248201527f54686520676976656e20746f6b656e2061646472657373206973206e6f7420616044820152680818dbdb9d1c9858dd60ba1b6064820152608490fd5b9064e8d4a5100082029180830464e8d4a51000149015171561142a57565b9060058202918083046005149015171561142a57565b8181029291811591840414171561142a57565b3d15613ca6573d90613c8c82610d60565b91613c9a6040519384610d3a565b82523d6000602084013e565b606090565b908160209103126102f25751613a0a81611527565b15613cc757565b60405162461bcd60e51b81526020600482015260136024820152721d1c985b9cd9995c919c9bdb4819985a5b1959606a1b6044820152606490fd5b15613d0957565b60405162461bcd60e51b815260206004820152602360248201527f6d73672e76616c756520646f6573206e6f74206d617463682074686520616d6f6044820152621d5b9d60ea1b6064820152608490fd5b90613d66831515613b49565b613d6f82613068565b15613d89575050613d8261306691613c34565b3414613d02565b816000929183612b41613e1b613de161306698613ddb613dba6106f4879a60ff166000526065602052604060002090565b97613dcf6001600160a01b038a161515613b94565b611289893b1515613bd6565b90613c68565b6040516323b872dd60e01b602082019081526001600160a01b03909616602482015230604482015260648101919091529182906084820190565b51925af1613e27613c7b565b81613e33575b50613cc0565b8051801592508215613e48575b505038613e2d565b613e5b9250602080918301019101613cab565b3880613e40565b15613e6957565b60405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b919091613eac81613068565b15613ebb57506130669161488a565b80613066936000612b41613f33613eff8397613ddb613ee8869960ff166000526065602052604060002090565b546001600160a01b031697611289893b1515613bd6565b60405163a9059cbb60e01b602082019081526001600160a01b03909616602482015260448101919091529182906064820190565b51925af1613f3f613c7b565b81613f4b575b50613e62565b8051801592508215613f60575b505038613f45565b613f739250602080918301019101613cab565b3880613f58565b908160209103126102f2575190565b15613f9057565b60405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608490fd5b60809060208152602e60208201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960408201526d6f6e206973206e6f74205555505360901b60608201520190565b906140627f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1690565b15614071575061306690614c42565b6040516352d1902d60e01b8152906020826004816001600160a01b0387165afa600092816140d7575b506140b85760405162461bcd60e51b81528061317360048201613fe7565b61306692613196600080516020614edf83398151915260009414613f89565b6140f191935060203d6020116131c5576131b68183610d3a565b913861409a565b6001600160a01b0316801561414c5761013480546001600160a01b0319811683179091556001600160a01b03167f8934ce4adea8d9ce0d714d2c22b86790e41b7731c84b926fbbdc1d40ff6533c9600080a3565b606460405162461bcd60e51b815260206004820152602060248201527f4e6577206f776e65722063616e6e6f74206265207a65726f20616464726573736044820152fd5b6001600160a01b031680156141e45761013580546001600160a01b0319811683179091556001600160a01b03167f4798f31ad3d0ccde6359edf35fc39b882e4e1cff2968ca749b72074d373db27a600080a3565b60405162461bcd60e51b815260206004820152602360248201527f4e6577207072656d69756d206d616e61676572206265207a65726f206164647260448201526265737360e81b6064820152608490fd5b604080516020810192835260609390931b6001600160601b03191690830152906142628160548101612b41565b51902090565b64ffffffffff8160d01c169064ffffffffff8160581c16820391821161142a5761429190614cd3565b810390811161142a5790565b6142a681614cd3565b90811580156142b757505050600090565b612710830292830461271014171561142a5761ffff6142d99160b01c16614d5a565b9081156142e4570490565b634e487b7160e01b600052601260045260246000fd5b6001600160a01b03909316929190614313841515613ab1565b60018060ff1b0382169160ff1c601b810180911161142a5760209360009360ff936143829261435a6fa2a8918ca85bafe22016d0b997e4df60600160ff1b03841115613afd565b6040519586951690859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15612c1c57600051613066916001600160a01b0390911614613afd565b600160cf1b81166145555760801c6001600160401b0316936143d9906143d0853b1515614dc1565b613ddb8361328a565b906143e381613068565b1561446a575060405163bff4163f60e01b815260006004820152602481018290526001600160a01b0392831660448201526001600160401b03949094166064850152602092849260849284929091165af18015612c1c57614442575b50565b61443f9060203d602011614463575b61445b8183610d3a565b810190613cab565b503d614451565b6106f46144879194929460ff166000526065602052604060002090565b92614494843b1515613bd6565b60405163095ea7b360e01b81526001600160a01b038316600482015260248101829052936020858060448101038160006001600160a01b0386165af1908115612c1c5760209560009261453a575b5060405163bff4163f60e01b81526001600160a01b039182166004820152602481019390935293841660448301526001600160401b03959095166064820152938492608492849291165af18015612c1c576144425750565b61455090873d89116144635761445b8183610d3a565b6144e2565b50928092915061456457505050565b61306692613ea0565b6001600160a01b03909416936020936000939161465a9190614590881515613ab1565b6001600160ff1b038216916145ab906104f19060ff1c612df5565b946145ce6fa2a8918ca85bafe22016d0b997e4df60600160ff1b03841115613afd565b600160cb1b8216151560c361ffff6145e96104bc8660081c90565b161488146146a557871461467e57780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d051a998560391b91612b4f905b612b416040519384928c8401968791604d939166ffffffffffffff1916835260198301526bffffffffffffffffffffffff199060601b1660398201520190565b838052039060015afa15612c1c5760005161306691906001600160a01b0316612ba7565b780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519990560391b91612b4f9061461a565b87146146ff576040517f19457468657265756d205369676e6564204d6573736167653a0a353200000000898201908152601c81019390935260609190911b6001600160601b031916603c830152612c888160508401612b41565b9060c36147126104bc6104bc8460201c90565b148714614753577f28cf5b919ed55db2b14d9e8b261a523eafb98bab117d3a8a56e559791415d17c915b601452865260348620875285526040852092612b54565b7f743e50106a7f059b52151dd4ba27a5f6c87b925ddfbdcf1c332e800da4b3df929161473c565b60ff811660fc81106147c057506147ae6147a66147a16101f49360d01c64ffffffffff1690565b613c52565b612710900490565b90808211156147bb575090565b905090565b60f881106147e357506147ae6147a66147a16113889360d01c64ffffffffff1690565b60f481106147fe57506147ae6147a66147a16101f493613aa4565b60f01161481e576147ae6147a66147a1600a9360d01c64ffffffffff1690565b6147ae6147a66147a16207a1209360d01c64ffffffffff1690565b61484281614e23565b61484c5750600090565b61ffff613a0a9160a01c16614d5a565b61486581614e23565b61486f5750600090565b60b01c61ffff16620100000164ffffffffff811161142a5790565b64e8d4a5100082029180830464e8d4a51000149015171561142a57600080809381935af16148b6613c7b565b50156148be57565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b156148fc57565b60405162461bcd60e51b815260206004820152601b60248201527f43616e6e6f7420757365203020617320746f6b656e20696e64657800000000006044820152606490fd5b1561494857565b60405162461bcd60e51b815260206004820152601b60248201527f546f6b656e20686173206265656e206164646564206265666f726500000000006044820152606490fd5b1561499457565b60405162461bcd60e51b8152602060048201526013602482015272125b99195e081a185cc81899595b881d5cd959606a1b6044820152606490fd5b156149d657565b60405162461bcd60e51b815260206004820152602160248201527f436f726520746f6b656e207265717569726573206164646472657373283078316044820152602960f81b6064820152608490fd5b614a3360ff831615156148f5565b6001600160a01b0381168015614ae757613066926108b691614a76614a706104f1610fa48760018060a01b03166000526066602052604060002090565b15614941565b614a9c614a966103b76106f48560ff166000526065602052604060002090565b1561498d565b614aa582613068565b614ad5575b506001600160a01b0383166000908152606660205260409020805460ff191660ff8316179055611f9a565b6001614ae191146149cf565b38614aaa565b60405162461bcd60e51b815260206004820152601760248201527643616e6e6f7420757365207a65726f206164647265737360481b6044820152606490fd5b9091614b3182614c42565b604051906001600160a01b0383167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a283511590811591614c3a575b50614b7a57505050565b813b15614be957506000828192602061443f95519201905af4614b9b613c7b565b60405191614baa606084610d3a565b602783527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c6020840152660819985a5b195960ca1b6040840152614e47565b62461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608490fd5b905038614b70565b803b15614c7857600080516020614edf83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b614cdc81614d9e565b614ce65750600090565b61ffff8160a01c1661ffff8114614d1957614d019150614d5a565b6103e88102908082046103e8149015171561142a5790565b5060d081901c64ffffffffff1690605881901c64ffffffffff16820391821161142a57600160ce1b811615614d4c575090565b614d559061477a565b614291565b6103e8811115613a0a576103e719810190811161142a576123288106906103e8820180921161142a57612328900490604d821161142a57613a0a91600a0a90613c68565b60bf60ff8260181c16109081614db2575090565b61084160c41b90811614919050565b15614dc857565b60405162461bcd60e51b815260206004820152602d60248201527f54686520676976656e20726563697069656e742061646472657373206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b600160cf1b811615159081614e36575090565b600360c91b16600160c91b14919050565b90919015614e53575090565b815115614e635750805190602001fd5b6040519062461bcd60e51b8252602060048301528181519182602483015260005b838110614ea65750508160006044809484010152601f80199101168101030190fd5b60208282018101516044878401015285935001614e8456fee34b8b74e1cdcaa1b90aa77af7dd89e496ad9a4ae4a4d4759712101c7da2dce6360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca164736f6c634300081c000a

Deployed Bytecode

0x6080604052600436101561001257600080fd5b60003560e01c8063051119f5146102d75780630ffad9c0146102d257806316f35d23146102cd5780631e2a6075146102c85780632335093c146102c3578063264849e7146102be57806330f00f3a146102b957806335eff30f146102b45780633659cfe6146102af57806337b90a4f146102aa578063485cc955146102a55780634a2377e2146102a05780634f1ef2861461029b578063515147ab1461029657806352d1902d1461029157806354d6a2b71461028c57806358d9b4e11461028757806360a2da98146102825780636484396e1461027d5780636f9b41fd146102785780637234cd9514610273578063741c8e2d1461026e5780637fe0282b14610269578063827c87cc1461026457806389a734c01461025f5780638b0a77651461025a5780638f487dc914610255578063a5c9c66c14610250578063ab115fd81461024b578063b805f32114610246578063c11d9ecb14610241578063c8173c441461023c578063cb4f999b14610237578063ce7f79b914610232578063d3c7c2c71461022d578063d3e95ea414610228578063d4f8232214610223578063decf2a481461021e578063eaf250b514610219578063eba7fb7714610214578063f1d2ec1d1461020f578063f2fde38b1461020a578063ff22f272146102055763ff3787191461020057600080fd5b612658565b6125af565b612578565b612447565b612427565b6123ae565b6122cb565b612286565b61225a565b612149565b61200d565b611f16565b611e76565b611dc7565b611d0f565b611aa8565b6118c3565b61172a565b6116e8565b6116a5565b611531565b6114e6565b61142f565b61137b565b611296565b61126b565b6111b8565b611196565b6110a1565b610fe1565b610df2565b610d7b565b610cf7565b610bf5565b610add565b610a0a565b6108f5565b610800565b61075e565b610721565b610651565b610587565b61046d565b610337565b600435906001600160a01b03821682036102f257565b600080fd5b606435906001600160a01b03821682036102f257565b602435906001600160a01b03821682036102f257565b35906001600160a01b03821682036102f257565b346102f25760203660031901126102f2576103506102dc565b3360005260996020527f475b83c893df40ee19fd0783cf26478cdb58478dff65bb62560e1e7c36e0f22f61042c64ffffffffff6040600020541692610396841515612694565b6000848152609a60205260409020546103ca906103c3906001600160a01b03165b6001600160a01b031690565b33146126ec565b6103f8846103f26103e86103dd85610707565b5464ffffffffff1690565b64ffffffffff1690565b14612742565b61041261040482610707565b805464ffffffffff19169055565b6040516001600160a01b0390911681529081906020820190565b0390a2005b6084359064ffffffffff821682036102f257565b6024359064ffffffffff821682036102f257565b6044359064ffffffffff821682036102f257565b346102f25760a03660031901126102f2576105856004356024356044356104926102f7565b9161049b610431565b936104ab60018260f81c146127a3565b6104ca603c61ffff6104c3600885901c5b61ffff1690565b16146127ef565b6104ff6104de60ff83166139f4565b6139f4565b60ff6104f76104f16104d9601887901c82565b60ff1690565b911614612835565b600081815260ce60205260409020610533906001600160d01b039061052c905b546001600160d01b031690565b161561288b565b61055064174876e80060d083901c64ffffffffff165b11156128cd565b610580611c2061056d603084901c64ffffffffff165b429061295f565b61057a610e10821161296c565b106129ae565b612a5c565b005b346102f25760403660031901126102f25760043561062a6105a661030d565b610135546105be906001600160a01b03163314612cfc565b8260005260ce6020526105df6001808060d01b036040600020541611612d52565b6105f6603084901c64ffffffffff165b4211612d94565b600083815260ce6020526040902080546001600160d01b031916905560ff83169060d084901c64ffffffffff165b91613ea0565b7ff6b6b4f7a13f02512c1b3aa8dcc4a07d7775a6a4becbd439efcbd37c5408e67f600080a2005b346102f25760203660031901126102f257600435600090815260ce60205260409020546001600160a01b03602882901c16906001600160d01b03811690826106cc57506106c86000925b604080516001600160a01b0392831681529490911660208501529115159183019190915281906060820190565b0390f35b6107016106f464ffffffffff6106c8931664ffffffffff16600052609a602052604060002090565b546001600160a01b031690565b9261069b565b6001600160a01b0316600090815260996020526040902090565b346102f25760203660031901126102f2576001600160a01b036107426102dc565b166000526066602052602060ff60406000205416604051908152f35b60203660031901126102f25761058560043561077f60018260f81c146127a3565b610794603c61ffff6104c3600885901c6104bc565b6107a36104de60ff83166139f4565b600081815260ce602052604090206107c7906001600160d01b039061052c9061051f565b6107e164174876e80060d083901c64ffffffffff16610549565b6107fb611c2061056d603084901c64ffffffffff16610566565b612e10565b346102f25760203660031901126102f2576108196102dc565b3360005260996020527fc94089e0c0b1b79fdecc6e64fb759cdd390590a15c7e50d281e681ea8273261c61042c64ffffffffff604060002054169261085f841515612694565b6000848152609a6020526040902054610884906103c3906001600160a01b03166103b7565b610897846103f26103e86103dd85610707565b6108d5816108b68664ffffffffff16600052609a602052604060002090565b80546001600160a01b0319166001600160a01b03909216919091179055565b604080513381526001600160a01b03909216602083015290918291820190565b346102f25760403660031901126102f257600435610911610445565b600082815260ce60205260409020546001600160d01b038116919064ffffffffff9061093f60018511612d52565b166109c55761099e9161096a64ffffffffff928361095f6103dd33610707565b9116931683146129ef565b1761097f8360005260ce602052604060002090565b80546001600160d01b0319166001600160d01b03909216919091179055565b7f60a99b51ae498c44acbbe11031aed2a06a32be66d2122e6e2a7a16c087865cc9600080a2005b60405162461bcd60e51b815260206004820152601b60248201527f5377617020626f6e64656420746f20616e6f7468657220706f6f6c00000000006044820152606490fd5b346102f25760203660031901126102f257610585610a266102dc565b610a7e7f000000000000000000000000370634e1064b945e9010ddfa6077f321eca431cf6001600160a01b0316610a5f30821415612ea2565b600080516020614edf833981519152546001600160a01b031614612f03565b610a9460018060a01b0361013454163314613397565b604051906020610aa48184610d3a565b60008352601f198101903690840137614036565b60409060031901126102f2576004359060243565ffffffffffff811681036102f25790565b610ae636610ab8565b610af1821515612f64565b64ffffffffff8116610b04811515612faa565b33600052609960205264ffffffffff80604060002054161603610b9f5765ffffffffffff81610b667f7d7d1df74ef3a6434d8d63dc0a25d13d5fa94dbe738c38a3cce26e6f892e2a769365ffffffffffff16600052609b602052604060002090565b610b71858254612e03565b9055610b8d8433610b88602885901c60ff166104f1565b613d5a565b6040519384521691806020810161042c565b60405162461bcd60e51b815260206004820152602860248201527f4e65656420616e20617574686f72697a65642061646472657373206173207468604482015267329039b4b3b732b960c11b6064820152608490fd5b346102f25760403660031901126102f257610c0e6102dc565b610c5b610c1961030d565b60005492610c3f60ff600886901c161580958196610cd9575b8115610cb9575b50612ff6565b83610c52600160ff196000541617600055565b610ca057613059565b610c6157005b610c7161ff001960005416600055565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602090a1005b610cb461010061ff00196000541617600055565b613059565b303b15915081610ccb575b5038610c39565b60ff16600114905038610cc4565b600160ff8216109150610c32565b6004359060ff821682036102f257565b346102f25760203660031901126102f2576020610d1a610d15610ce7565b613068565b6040519015158152f35b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b03821117610d5b57604052565b610d24565b6001600160401b038111610d5b57601f01601f191660200190565b60403660031901126102f257610d8f6102dc565b602435906001600160401b0382116102f257366023830112156102f257816004013590610dbb82610d60565b91610dc96040519384610d3a565b80835236602482860101116102f2576020816000926024610585970183870137840101526130a8565b346102f25760803660031901126102f257600435610f56610e3c610e146102f7565b610e2360018560f81c146127a3565b610e36603c61ffff8660201c16146127ef565b83614235565b610e6c6001600160501b0361052c610e5f84600052610101602052604060002090565b546001600160501b031690565b610f3b610f29610e7e6103dd33610707565b610e9064ffffffffff821615156131cc565b610e9942612dd7565b610eb7610eb0603089901c64ffffffffff1661294f565b8210613230565b601087901b60ff60281b1664ffffffffff831617610efb610ef3610eda8a614268565b9265ffffffffffff16600052609b602052604060002090565b91825461295f565b9055610f068761429d565b80610f7d575b5060281b69ffffffffff00000000001664ffffffffff9091161790565b91600052610101602052604060002090565b906001600160501b03166001600160501b0319825416179055565b7fbfb879c34323c5601fafe832c3a8a1e31e12c288695838726ddeada86034edb4600080a2005b60016000526066602052610fd9610ef3610fc185610fab600080516020614ebf8339815191525b5460ff1690565b60281b60ff60281b1664ffffffffff9091161790565b65ffffffffffff16600052609b602052604060002090565b905538610f0c565b346102f25760003660031901126102f2577f000000000000000000000000370634e1064b945e9010ddfa6077f321eca431cf6001600160a01b0316300361103b57604051600080516020614edf8339815191528152602090f35b60405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152608490fd5b346102f25760203660031901126102f257600435600081815260ce60205260409020546001600160d01b03166110d960018211612d52565b6110ed603083901c64ffffffffff166105ef565b60ff60c882901c166111515761062a906111246111148460005260ce602052604060002090565b80546001600160d01b0319169055565b60ff831690611140906103b79060281c6001600160a81b031681565b60d084901c64ffffffffff16610624565b60405162461bcd60e51b815260206004820152601d60248201527f5377617020746f6b656e206e6f742066726f6d20696e69746961746f720000006044820152606490fd5b346102f25760403660031901126102f257600435610f56610e3c610e1461030d565b346102f25760403660031901126102f2576004356111df6111d761030d565b600092614235565b815261010160205260408120546001600160501b03811691906001830361122c5750505060016000905b604080516001600160a01b0392909216825264ffffffffff929092166020820152f35b64ffffffffff9081168252609a6020526040909120546001600160a01b031691611265916103e89160281c165b6001600160501b031690565b90611209565b346102f25760203660031901126102f257602061128e611289610ce7565b61328a565b604051908152f35b60603660031901126102f2576105856004356112b061030d565b6112b8610459565b916112c860018260f81c146127a3565b6112dd603c61ffff6104c3600885901c6104bc565b6112ec6104de60ff83166139f4565b600081815260ce60205260409020611310906001600160d01b039061052c9061051f565b61132a64174876e80060d083901c64ffffffffff16610549565b611344611c2061056d603084901c64ffffffffff16610566565b613311565b60609060031901126102f25760043560ff811681036102f257906024359060443564ffffffffff811681036102f25790565b346102f25761138936611349565b6113a260018060a09594951b0361013454163314613397565b64ffffffffff81166000908152609a60205260409020546113cd906001600160a01b031615156133dd565b65ffffffffffff602883901b60ff60281b1616600052609b602052604060002080549184830392831161142a576114269361141e93610fc193559064ffffffffff60ff60281b91169160281b161790565b918254612e03565b9055005b612939565b346102f25760803660031901126102f25761058560043561144e61030d565b604435906064359261146560018260f81c146127a3565b61147a603c61ffff6104c3600885901c6104bc565b6114896104de60ff83166139f4565b600081815260ce602052604090206114ad906001600160d01b039061052c9061051f565b6114c764174876e80060d083901c64ffffffffff16610549565b6114e1611c2061056d603084901c64ffffffffff16610566565b613425565b346102f25760203660031901126102f2576001600160a01b036115076102dc565b166000526099602052602064ffffffffff60406000205416604051908152f35b801515036102f257565b346102f25760a03660031901126102f2576004356024356044356115e06115566102f7565b6084359261156384611527565b61157a61051f8760005260ce602052604060002090565b9461159060016001600160d01b03881611612d52565b603087901c64ffffffffff166115a542612de6565b1115611676576115c26111148860005260ce602052604060002090565b6115d96103b76001600160a81b03602889901c1681565b928761456d565b60ff83169164ffffffffff16901561164f5761141e610fc16116259261160e8664ffffffffff9060d01c1690565b9460281b60ff60281b1664ffffffffff9091161790565b90555b7f8d92c805c252261fcfff21ee60740eb8a38922469a7e6ee396976d57c22fc1c9600080a2005b906111406106f46116719364ffffffffff16600052609a602052604060002090565b611628565b6116a061168d8860005260ce602052604060002090565b80546001600160d01b0319166001179055565b6115c2565b346102f25760203660031901126102f25760043564ffffffffff81168091036102f257600052609a602052602060018060a01b0360406000205416604051908152f35b346102f25760203660031901126102f25765ffffffffffff60ff60281b61170d610ce7565b60281b1616600052609b6020526020604060002054604051908152f35b65ffffffffffff7f7d7d1df74ef3a6434d8d63dc0a25d13d5fa94dbe738c38a3cce26e6f892e2a7661175b36610ab8565b6117688294921515612f64565b64ffffffffff81166118058161177f811515612faa565b6117ae60018060a01b036117a76106f48464ffffffffff16600052609a602052604060002090565b16156135ab565b6117c66117c06103e86103dd33610707565b156135f7565b6117e5336108b68364ffffffffff16600052609a602052604060002090565b6117ee33610707565b9064ffffffffff1664ffffffffff19825416179055565b6118218265ffffffffffff16600052609b602052604060002090565b61182c868254612e03565b90556118438533610b88602886901c60ff166104f1565b6040513381527fb8d9c35a714d4e29eaf036b9bf8183a093c5573ac809453b4e8434e25c9126d290602090a26040519384521691806020810161042c565b60a09060031901126102f2576004359060243590604435906064356001600160a01b03811681036102f257906084356001600160a01b03811681036102f25790565b346102f25761198f6119d26119796118da36611881565b9396919490926118eb32331461364d565b611902603089901c64ffffffffff165b42106136a4565b6119166001600160a01b0386161515613560565b61196884600160ce1b8a1615159788611a8b575b611934828c614235565b9361196160016001600160501b0361195a610e5f89600052610101602052604060002090565b1611612d52565b888c61456d565b600052610101602052604060002090565b805469ffffffffffffffffffff19166001179055565b61199885614268565b9215611a47575b6119a885614839565b80611a09575b506119b88561429d565b806119f9575b506119cc601886901c6104f1565b856143a8565b7ffa628b578e095243f0544bfad9255f49d79d03a5bbf6c85875d05a215e247ad2600080a2005b611a03908361488a565b386119be565b9283611a149161295f565b92611a3f61141e610fc1611a278961485c565b899064ffffffffff60ff60281b91169160101b161790565b9055386119ae565b611a5a611a538661477a565b809461295f565b92611a8461141e601088901b60ff60281b1665ffffffffffff16600052609b602052604060002090565b905561199f565b61013554611aa3906001600160a01b03163314612cfc565b61192a565b346102f2576119d2611ab936611881565b9192611acd60018660f89897981c146127a3565b611ae0603c61ffff8860201c16146127ef565b611aeb32331461364d565b611aff6001600160a01b0384161515613560565b611b88611979600160ce1b881615159586611cf2575b8885611b218183614235565b92611b456001600160501b0361052c610e5f87600052610101602052604060002090565b611b516103dd33610707565b96611b6464ffffffffff891615156131cc565b8015611ccc5761196893611b819060301c64ffffffffff166118fb565b898d61456d565b611b9186614268565b93611bc1601088901b60ff60281b1664ffffffffff84161765ffffffffffff16600052609b602052604060002090565b611bcc86825461295f565b905515611c88575b611bdd86614839565b80611c4a575b50611bed8661429d565b80611c03575b506119cc9050601886901c6104f1565b60016000526066602052611c4391611c3090610fc190610fab600080516020614ebf833981519152610fa4565b611c3b82825461295f565b90558361488a565b3880611bf3565b9384611c559161295f565b93611c8061141e610fc1611c688a61485c565b8a9064ffffffffff60ff60281b91169160101b161790565b905538611be3565b611c9b611c948761477a565b809561295f565b93611cc561141e601089901b60ff60281b1665ffffffffffff16600052609b602052604060002090565b9055611bd4565b50505050866119685761013554611ced906001600160a01b03163314612cfc565b611968565b61013554611d0a906001600160a01b03163314612cfc565b611b15565b346102f25760203660031901126102f257610585611d2b6102dc565b61013554611d43906001600160a01b03163314612cfc565b614190565b6001600160401b038111610d5b5760051b60200190565b9080601f830112156102f257813590611d7782611d48565b92611d856040519485610d3a565b82845260208085019360051b8201019182116102f257602001915b818310611dad5750505090565b823560ff811681036102f257815260209283019201611da0565b346102f25760403660031901126102f2576004356001600160401b0381116102f257366023820112156102f257806004013590611e0382611d48565b91611e116040519384610d3a565b8083526024602084019160051b830101913683116102f257602401905b828210611e5e57602435846001600160401b0382116102f257611e58610585923690600401611d5f565b906136f0565b60208091611e6b84610323565b815201910190611e2e565b610585611e8236611881565b93611e9560018260f89694961c146127a3565b611eaa603c61ffff6104c3600885901c6104bc565b611eb96104de60ff83166139f4565b600081815260ce60205260409020611edd906001600160d01b039061052c9061051f565b611ef764174876e80060d083901c64ffffffffff16610549565b611f11611c2061056d603084901c64ffffffffff16610566565b613801565b346102f25760203660031901126102f257611f2f610ce7565b611f4560018060a01b0361013454163314613397565b60ff8116611f548115156148f5565b6000908152606560205260409020546001600160a01b03168015611fbd576001600160a01b03166000908152606660205260409020805460ff1916905561058590611fad905b60ff166000526065602052604060002090565b80546001600160a01b0319169055565b60405162461bcd60e51b815260206004820152602260248201527f546f6b656e20666f722074686520696e64657820646f6573206e6f74206578696044820152611cdd60f21b6064820152608490fd5b346102f25765ffffffffffff7f34c3d1c46f89307d63d8818fcc5c2a9c07a5f7a01ea4319bfba1899f40c6f40061204336610ab8565b6120508294921515612f64565b64ffffffffff8116612063811515612faa565b6000908152609a6020526040902054612086906001600160a01b031633146126ec565b6120a28165ffffffffffff16600052609b602052604060002090565b6120ad85825461295f565b9055610b8d84336120c4602885901c60ff166104f1565b613ea0565b6040810160408252825180915260206060830193019060005b81811061212a5750505060208183039101526020808351928381520192019060005b8181106121115750505090565b825160ff16845260209384019390920191600101612104565b82516001600160a01b03168552602094850194909201916001016120e2565b346102f25760003660031901126102f25760ff6000805b828082161061222357501661217d61217782613890565b91613890565b906000805b60ff8082161061219d5750506106c8604051928392836120c9565b6121af6103b76106f4611f9a8461387e565b6121bf575b60010160ff16612182565b90600161221a60ff926122156121da6106f4611f9a8861387e565b6121fa868416916121eb838b6137d7565b6001600160a01b039091169052565b61220d6122068861387e565b918a6137d7565b9060ff169052565b6137c6565b929150506121b4565b6122356103b76106f4611f9a8461387e565b612244575b6001018216612160565b90600161225184926137c6565b9291505061223a565b346102f25760403660031901126102f257602061128e6122786102dc565b61228061030d565b906138c2565b346102f25760403660031901126102f25761229f6102dc565b60243560ff811681036102f257610585916122c660018060a01b0361013454163314613397565b614a25565b60403660031901126102f2576004356024356001600160c81b03811691908281036102f2576105859260281c6001600160a01b03169064ffffffffff9061231860f885901c6001146127a3565b61232d603c61ffff6104c3600888901c6104bc565b61234f61233c60ff86166139f4565b60ff6104f76104f16104d960188a901c82565b600084815260ce60205260409020612373906001600160d01b039061052c9061051f565b61238d64174876e80060d086901c64ffffffffff16610549565b6123a7611c2061056d603087901c64ffffffffff16610566565b1691613311565b346102f25761240a65ffffffffffff6123c636611349565b9093916123df60018060a01b0361013454163314613397565b64ffffffffff82166000908152609a6020526040902054610fab906001600160a01b031615156133dd565b16600052609b6020526040600020805491820180921161142a5755005b346102f25760003660031901126102f257604051600f60f21b8152602090f35b346102f25760403660031901126102f25760043561251b61250861247261246c61030d565b84614235565b6124c061248d610e5f83600052610101602052604060002090565b6124a260016001600160501b03831611612d52565b6103e86124b964ffffffffff602884901c16611259565b4211613935565b601085901b60ff60281b1664ffffffffff8216176124e361141e610eda88614268565b90556124ee8561429d565b9081612542575b5050600052610101602052604060002090565b805469ffffffffffffffffffff19169055565b7fac7d23c4f0137a4cc35b0e4b4bc8061ea6cb65805e87ceb0a77ca0c85814858c600080a2005b6001600052606660205261256f9061141e90610fc190610fab600080516020614ebf833981519152610fa4565b905538806124f5565b346102f25760203660031901126102f2576105856125946102dc565b6125aa60018060a01b0361013454163314613397565b6140f8565b346102f25760203660031901126102f2576125c86102dc565b3360005260996020527fd49cde4f679ccef3d23ff07aae4f6845e1c661e23e9fe6a54da26f0723fb695f61042c64ffffffffff604060002054169261260e841515612694565b6000848152609a6020526040902054612633906103c3906001600160a01b03166103b7565b61264b6126456103e86103dd84610707565b15613976565b610412846117ee83610707565b346102f25760203660031901126102f25760ff612673610ce7565b166000526065602052602060018060a01b0360406000205416604051908152f35b1561269b57565b60405162461bcd60e51b815260206004820152602360248201527f546865207369676e657220646f6573206e6f74207265676973746572206120706044820152621bdbdb60ea1b6064820152608490fd5b156126f357565b60405162461bcd60e51b815260206004820152602160248201527f4e6565642074686520706f6f6c206f776e657220617320746865207369676e656044820152603960f91b6064820152608490fd5b1561274957565b60405162461bcd60e51b815260206004820152602c60248201527f41646472206973206e6f7420617574686f72697a656420666f7220746865207360448201526b1a59db995c89dcc81c1bdbdb60a21b6064820152608490fd5b156127aa57565b60405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420656e636f64696e672076657273696f6e0000000000006044820152606490fd5b156127f657565b60405162461bcd60e51b815260206004820152601760248201527629bbb0b8103737ba103337b9103a3434b99031b430b4b760491b6044820152606490fd5b1561283c57565b60405162461bcd60e51b815260206004820152602160248201527f496e2026206f757420746f6b656e20747970657320646f206e6f74206d6174636044820152600d60fb1b6064820152608490fd5b1561289257565b60405162461bcd60e51b81526020600482015260136024820152725377617020616c72656164792065786973747360681b6044820152606490fd5b156128d457565b60405162461bcd60e51b815260206004820152603760248201527f466f7220736563757269747920726561736f6e2c20616d6f756e742063616e6e6044820152766f742062652067726561746572207468616e203130306b60481b6064820152608490fd5b634e487b7160e01b600052601160045260246000fd5b61012b1981019190821161142a57565b9190820391821161142a57565b1561297357565b60405162461bcd60e51b815260206004820152601360248201527245787069726520747320746f6f206561726c7960681b6044820152606490fd5b156129b557565b60405162461bcd60e51b815260206004820152601260248201527145787069726520747320746f6f206c61746560701b6044820152606490fd5b156129f657565b60405162461bcd60e51b815260206004820152603860248201527f5369676e65722073686f756c6420626520616e20617574686f72697a6564206160448201527719191c995cdcc81bd9881d1a194819da5d995b881c1bdbdb60421b6064820152608490fd5b93909291600060209164ffffffffff841680151580612ce9575b612cc6575b506001600160a01b03851695612a92871515613ab1565b6001600160ff1b03821691612b7a90612ab1906104f19060ff1c612df5565b92612ad46fa2a8918ca85bafe22016d0b997e4df60600160ff1b03821115613afd565b600160cb1b8a16151560c361ffff612aef60088e901c6104bc565b16148614612c43578514612c2157780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519998560391b5b60405166ffffffffffffff19909116878201908152601981018c905290612b4f81603984015b03601f198101835282610d3a565b519020925b604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15612c1c57600051612bf593612bdf92612bcb929091612bad916001600160a01b03165b14613afd565b64ffffffffff1665010000000000600160c81b03602885901b161790565b61097f8560005260ce602052604060002090565b64ffffffffff60d084901c169060ff8416613d5a565b7f5ce4019f772fda6cb703b26bce3ec3006eb36b73f1d3a0eb441213317d9f5e9d600080a2565b613b3d565b780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519990560391b612b1b565b8514612c915789604051612c8881612b418a82019485603c917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008252601c8201520190565b51902092612b54565b89855285852086527f9862d877599564bcd97c37305a7b0fdbe621d9c2a125026f2ad601f754a75abc85526040852092612b54565b612ce3903384526099855264ffffffffff604085205416146129ef565b38612a7b565b50336001600160a01b0387161415612a76565b15612d0357565b60405162461bcd60e51b815260206004820152602160248201527f43616c6c6572206973206e6f7420746865207072656d69756d206d616e6167656044820152603960f91b6064820152608490fd5b15612d5957565b60405162461bcd60e51b815260206004820152601360248201527214ddd85c08191bd95cc81b9bdd08195e1a5cdd606a1b6044820152606490fd5b15612d9b57565b60405162461bcd60e51b815260206004820152601460248201527314ddd85c081a5cc81cdd1a5b1b081b1bd8dad95960621b6044820152606490fd5b90610960820180921161142a57565b90610e10820180921161142a57565b90601b820180921161142a57565b9190820180921161142a57565b600081815260ce6020526040902080546001600160d01b031916600117905560ff811660d082901c64ffffffffff1665ffffffffffff602884901b60ff60281b1660011716600052609b602052604060002091825482810180911161142a57612e7b93553390613d5a565b7f8d92c805c252261fcfff21ee60740eb8a38922469a7e6ee396976d57c22fc1c9600080a2565b15612ea957565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b15612f0a57565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b6064820152608490fd5b15612f6b57565b60405162461bcd60e51b8152602060048201526017602482015276416d6f756e74206d75737420626520706f73697469766560481b6044820152606490fd5b15612fb157565b60405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f7420757365203020617320706f6f6c20696e6465780000000000006044820152606490fd5b15612ffd57565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b90611d43613066926140f8565b565b60ff8116906031821015918261309c575b821561308457505090565b60be10915081613092575090565b6003915081161490565b60408111159250613079565b906130e27f000000000000000000000000370634e1064b945e9010ddfa6077f321eca431cf6001600160a01b0316610a5f30821415612ea2565b6130f860018060a01b0361013454163314613397565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561312c575061306690614c42565b6040516352d1902d60e01b8152906020826004816001600160a01b0387165afa6000928161319b575b506131775760405162461bcd60e51b81528061317360048201613fe7565b0390fd5b61306692613196600080516020614edf83398151915260019414613f89565b614b26565b6131be91935060203d6020116131c5575b6131b68183610d3a565b810190613f7a565b9138613155565b503d6131ac565b156131d357565b60405162461bcd60e51b815260206004820152602f60248201527f43616c6c6572206e6f7420726567697374657265642e2043616c6c206465706f60448201526e39b4ba20b7322932b3b4b9ba32b91760891b6064820152608490fd5b1561323757565b60405162461bcd60e51b815260206004820152602560248201527f43616e6e6f74206c6f636b20626563617573652065787069726554732069732060448201526439b7b7b71760d91b6064820152608490fd5b60ff166020811161329b5750600190565b60f2811480613309575b80613301575b156132b65750606490565b60708111806132f6575b156132cb5750606490565b607b811190816132ea575b506132e45764e8d4a5100090565b6103e890565b608091501115386132d6565b50607b8111156132c0565b5060016132ab565b5060016132a5565b91613379916000919064ffffffffff906001600160a01b031633811461339157600160c81b935b5065010000000000600160d01b039060281b1691169117178260005260ce60205260406000209060018060d01b031665ffffffffffff60d01b825416179055565b612bf564ffffffffff8260d01c163360ff8416613d5a565b83613338565b1561339e57565b60405162461bcd60e51b815260206004820152601760248201527621b0b63632b91034b9903737ba103a34329037bbb732b960491b6044820152606490fd5b156133e457565b60405162461bcd60e51b8152602060048201526019602482015278141bdbdb081a5b99195e081b9bdd081c9959da5cdd195c9959603a1b6044820152606490fd5b926135399261349a91613441603c61ffff8860201c16146127ef565b6134556001600160a01b0385161515613560565b6040805160208101888152606087901b6001600160601b031916928201929092526134838160548101612b41565b519020610135546001600160a01b031692906142fa565b60d083901c64ffffffffff169061352b60ff8516926134c4605887901c64ffffffffff168261295f565b936134ee602882901b60ff60281b1660011765ffffffffffff16600052609b602052604060002090565b6134f9838254612e03565b9055600160ff60281b601089901b16176000908152609b6020526040902061352286825461295f565b90553390613d5a565b336119cc601886901c6104f1565b7ffa628b578e095243f0544bfad9255f49d79d03a5bbf6c85875d05a215e247ad2600080a2565b1561356757565b606460405162461bcd60e51b815260206004820152602060248201527f526563697069656e742063616e6e6f74206265207a65726f20616464726573736044820152fd5b156135b257565b60405162461bcd60e51b815260206004820152601d60248201527f506f6f6c20696e64657820616c726561647920726567697374657265640000006044820152606490fd5b156135fe57565b60405162461bcd60e51b815260206004820152602160248201527f5369676e6572206164647265737320616c7265616479207265676973746572656044820152601960fa1b6064820152608490fd5b1561365457565b60405162461bcd60e51b815260206004820152602260248201527f43616e6e6f742062652063616c6c6564207468726f75676820636f6e74726163604482015261747360f01b6064820152608490fd5b156136ab57565b60405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f742072656c656173652062656361757365206578706972656400006044820152606490fd5b909161370860018060a01b0361013454163314613397565b815183510361376a5760005b825160ff82169081101561376357906122158261375861375161374a61373d61375e978a6137d7565b516001600160a01b031690565b92896137d7565b5160ff1690565b90614a25565b613714565b5050915050565b60405162461bcd60e51b815260206004820152602e60248201527f546f6b656e7320616e6420696e64657865732073686f756c642068617665207460448201526d0d0ca40e6c2daca40d8cadccee8d60931b6064820152608490fd5b60ff1660ff811461142a5760010190565b80518210156137eb5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b9391839161380f938661456d565b600082815260ce6020526040902080546001600160d01b031916600117905564ffffffffff8260d01c1660ff83169165ffffffffffff6138598460ff60281b60019160281b161790565b16600052609b602052604060002092835483810180911161142a57612e7b9455613d5a565b60ff60019116019060ff821161142a57565b9061389a82611d48565b6138a76040519182610d3a565b82815280926138b8601f1991611d48565b0190602036910137565b6001600160a01b0390811660009081526066602090815260408083205494909316825260999052205464ffffffffff169060ff168115801561392d575b6139265761392291610fc1919064ffffffffff60ff60281b91169160281b161790565b5490565b5050600090565b5080156138ff565b1561393c57565b60405162461bcd60e51b815260206004820152601260248201527153776170207374696c6c20696e206c6f636b60701b6044820152606490fd5b1561397d57565b60405162461bcd60e51b815260206004820152602360248201527f4164647220697320617574686f72697a656420666f7220616e6f7468657220706044820152621bdbdb60ea1b6064820152608490fd5b60ff604f199116019060ff821161142a57565b60ff601f199116019060ff821161142a57565b60ff811660c08110613a0d575060021c603f1690565b90565b60408111613a1c575050600090565b60708111613a425750613a3d613a34613a0a9261387e565b60011c607f1690565b6139e1565b60801015613a9b5760405162461bcd60e51b8152602060048201526024808201527f546f6b656e20696e646578206e6f7420616c6c6f77656420666f72207377617060448201526370696e6760e01b6064820152608490fd5b613a0a906139ce565b60d01c64ffffffffff1690565b15613ab857565b60405162461bcd60e51b815260206004820152601e60248201527f5369676e65722063616e6e6f7420626520656d707479206164647265737300006044820152606490fd5b15613b0457565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b6040513d6000823e3d90fd5b15613b5057565b606460405162461bcd60e51b815260206004820152602060248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152fd5b15613b9b57565b60405162461bcd60e51b8152602060048201526013602482015272151bdad95b881b9bdd081cdd5c1c1bdc9d1959606a1b6044820152606490fd5b15613bdd57565b60405162461bcd60e51b815260206004820152602960248201527f54686520676976656e20746f6b656e2061646472657373206973206e6f7420616044820152680818dbdb9d1c9858dd60ba1b6064820152608490fd5b9064e8d4a5100082029180830464e8d4a51000149015171561142a57565b9060058202918083046005149015171561142a57565b8181029291811591840414171561142a57565b3d15613ca6573d90613c8c82610d60565b91613c9a6040519384610d3a565b82523d6000602084013e565b606090565b908160209103126102f25751613a0a81611527565b15613cc757565b60405162461bcd60e51b81526020600482015260136024820152721d1c985b9cd9995c919c9bdb4819985a5b1959606a1b6044820152606490fd5b15613d0957565b60405162461bcd60e51b815260206004820152602360248201527f6d73672e76616c756520646f6573206e6f74206d617463682074686520616d6f6044820152621d5b9d60ea1b6064820152608490fd5b90613d66831515613b49565b613d6f82613068565b15613d89575050613d8261306691613c34565b3414613d02565b816000929183612b41613e1b613de161306698613ddb613dba6106f4879a60ff166000526065602052604060002090565b97613dcf6001600160a01b038a161515613b94565b611289893b1515613bd6565b90613c68565b6040516323b872dd60e01b602082019081526001600160a01b03909616602482015230604482015260648101919091529182906084820190565b51925af1613e27613c7b565b81613e33575b50613cc0565b8051801592508215613e48575b505038613e2d565b613e5b9250602080918301019101613cab565b3880613e40565b15613e6957565b60405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b919091613eac81613068565b15613ebb57506130669161488a565b80613066936000612b41613f33613eff8397613ddb613ee8869960ff166000526065602052604060002090565b546001600160a01b031697611289893b1515613bd6565b60405163a9059cbb60e01b602082019081526001600160a01b03909616602482015260448101919091529182906064820190565b51925af1613f3f613c7b565b81613f4b575b50613e62565b8051801592508215613f60575b505038613f45565b613f739250602080918301019101613cab565b3880613f58565b908160209103126102f2575190565b15613f9057565b60405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608490fd5b60809060208152602e60208201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960408201526d6f6e206973206e6f74205555505360901b60608201520190565b906140627f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1690565b15614071575061306690614c42565b6040516352d1902d60e01b8152906020826004816001600160a01b0387165afa600092816140d7575b506140b85760405162461bcd60e51b81528061317360048201613fe7565b61306692613196600080516020614edf83398151915260009414613f89565b6140f191935060203d6020116131c5576131b68183610d3a565b913861409a565b6001600160a01b0316801561414c5761013480546001600160a01b0319811683179091556001600160a01b03167f8934ce4adea8d9ce0d714d2c22b86790e41b7731c84b926fbbdc1d40ff6533c9600080a3565b606460405162461bcd60e51b815260206004820152602060248201527f4e6577206f776e65722063616e6e6f74206265207a65726f20616464726573736044820152fd5b6001600160a01b031680156141e45761013580546001600160a01b0319811683179091556001600160a01b03167f4798f31ad3d0ccde6359edf35fc39b882e4e1cff2968ca749b72074d373db27a600080a3565b60405162461bcd60e51b815260206004820152602360248201527f4e6577207072656d69756d206d616e61676572206265207a65726f206164647260448201526265737360e81b6064820152608490fd5b604080516020810192835260609390931b6001600160601b03191690830152906142628160548101612b41565b51902090565b64ffffffffff8160d01c169064ffffffffff8160581c16820391821161142a5761429190614cd3565b810390811161142a5790565b6142a681614cd3565b90811580156142b757505050600090565b612710830292830461271014171561142a5761ffff6142d99160b01c16614d5a565b9081156142e4570490565b634e487b7160e01b600052601260045260246000fd5b6001600160a01b03909316929190614313841515613ab1565b60018060ff1b0382169160ff1c601b810180911161142a5760209360009360ff936143829261435a6fa2a8918ca85bafe22016d0b997e4df60600160ff1b03841115613afd565b6040519586951690859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15612c1c57600051613066916001600160a01b0390911614613afd565b600160cf1b81166145555760801c6001600160401b0316936143d9906143d0853b1515614dc1565b613ddb8361328a565b906143e381613068565b1561446a575060405163bff4163f60e01b815260006004820152602481018290526001600160a01b0392831660448201526001600160401b03949094166064850152602092849260849284929091165af18015612c1c57614442575b50565b61443f9060203d602011614463575b61445b8183610d3a565b810190613cab565b503d614451565b6106f46144879194929460ff166000526065602052604060002090565b92614494843b1515613bd6565b60405163095ea7b360e01b81526001600160a01b038316600482015260248101829052936020858060448101038160006001600160a01b0386165af1908115612c1c5760209560009261453a575b5060405163bff4163f60e01b81526001600160a01b039182166004820152602481019390935293841660448301526001600160401b03959095166064820152938492608492849291165af18015612c1c576144425750565b61455090873d89116144635761445b8183610d3a565b6144e2565b50928092915061456457505050565b61306692613ea0565b6001600160a01b03909416936020936000939161465a9190614590881515613ab1565b6001600160ff1b038216916145ab906104f19060ff1c612df5565b946145ce6fa2a8918ca85bafe22016d0b997e4df60600160ff1b03841115613afd565b600160cb1b8216151560c361ffff6145e96104bc8660081c90565b161488146146a557871461467e57780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d051a998560391b91612b4f905b612b416040519384928c8401968791604d939166ffffffffffffff1916835260198301526bffffffffffffffffffffffff199060601b1660398201520190565b838052039060015afa15612c1c5760005161306691906001600160a01b0316612ba7565b780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519990560391b91612b4f9061461a565b87146146ff576040517f19457468657265756d205369676e6564204d6573736167653a0a353200000000898201908152601c81019390935260609190911b6001600160601b031916603c830152612c888160508401612b41565b9060c36147126104bc6104bc8460201c90565b148714614753577f28cf5b919ed55db2b14d9e8b261a523eafb98bab117d3a8a56e559791415d17c915b601452865260348620875285526040852092612b54565b7f743e50106a7f059b52151dd4ba27a5f6c87b925ddfbdcf1c332e800da4b3df929161473c565b60ff811660fc81106147c057506147ae6147a66147a16101f49360d01c64ffffffffff1690565b613c52565b612710900490565b90808211156147bb575090565b905090565b60f881106147e357506147ae6147a66147a16113889360d01c64ffffffffff1690565b60f481106147fe57506147ae6147a66147a16101f493613aa4565b60f01161481e576147ae6147a66147a1600a9360d01c64ffffffffff1690565b6147ae6147a66147a16207a1209360d01c64ffffffffff1690565b61484281614e23565b61484c5750600090565b61ffff613a0a9160a01c16614d5a565b61486581614e23565b61486f5750600090565b60b01c61ffff16620100000164ffffffffff811161142a5790565b64e8d4a5100082029180830464e8d4a51000149015171561142a57600080809381935af16148b6613c7b565b50156148be57565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b156148fc57565b60405162461bcd60e51b815260206004820152601b60248201527f43616e6e6f7420757365203020617320746f6b656e20696e64657800000000006044820152606490fd5b1561494857565b60405162461bcd60e51b815260206004820152601b60248201527f546f6b656e20686173206265656e206164646564206265666f726500000000006044820152606490fd5b1561499457565b60405162461bcd60e51b8152602060048201526013602482015272125b99195e081a185cc81899595b881d5cd959606a1b6044820152606490fd5b156149d657565b60405162461bcd60e51b815260206004820152602160248201527f436f726520746f6b656e207265717569726573206164646472657373283078316044820152602960f81b6064820152608490fd5b614a3360ff831615156148f5565b6001600160a01b0381168015614ae757613066926108b691614a76614a706104f1610fa48760018060a01b03166000526066602052604060002090565b15614941565b614a9c614a966103b76106f48560ff166000526065602052604060002090565b1561498d565b614aa582613068565b614ad5575b506001600160a01b0383166000908152606660205260409020805460ff191660ff8316179055611f9a565b6001614ae191146149cf565b38614aaa565b60405162461bcd60e51b815260206004820152601760248201527643616e6e6f7420757365207a65726f206164647265737360481b6044820152606490fd5b9091614b3182614c42565b604051906001600160a01b0383167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a283511590811591614c3a575b50614b7a57505050565b813b15614be957506000828192602061443f95519201905af4614b9b613c7b565b60405191614baa606084610d3a565b602783527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c6020840152660819985a5b195960ca1b6040840152614e47565b62461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608490fd5b905038614b70565b803b15614c7857600080516020614edf83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b614cdc81614d9e565b614ce65750600090565b61ffff8160a01c1661ffff8114614d1957614d019150614d5a565b6103e88102908082046103e8149015171561142a5790565b5060d081901c64ffffffffff1690605881901c64ffffffffff16820391821161142a57600160ce1b811615614d4c575090565b614d559061477a565b614291565b6103e8811115613a0a576103e719810190811161142a576123288106906103e8820180921161142a57612328900490604d821161142a57613a0a91600a0a90613c68565b60bf60ff8260181c16109081614db2575090565b61084160c41b90811614919050565b15614dc857565b60405162461bcd60e51b815260206004820152602d60248201527f54686520676976656e20726563697069656e742061646472657373206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b600160cf1b811615159081614e36575090565b600360c91b16600160c91b14919050565b90919015614e53575090565b815115614e635750805190602001fd5b6040519062461bcd60e51b8252602060048301528181519182602483015260005b838110614ea65750508160006044809484010152601f80199101168101030190fd5b60208282018101516044878401015285935001614e8456fee34b8b74e1cdcaa1b90aa77af7dd89e496ad9a4ae4a4d4759712101c7da2dce6360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca164736f6c634300081c000a

Deployed Bytecode Sourcemap

165:295:33:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;;;-1:-1:-1;;;;;165:295:33;;;;;;:::o;:::-;;;;;;;;-1:-1:-1;;;;;165:295:33;;;;;;:::o;:::-;;;;-1:-1:-1;;;;;165:295:33;;;;;;:::o;:::-;;;-1:-1:-1;;;;;165:295:33;;;;;;:::o;:::-;;;;;;-1:-1:-1;;165:295:33;;;;;;:::i;:::-;719:10:20;-1:-1:-1;165:295:33;5672:20:25;165:295:33;;6011:42:25;;165:295:33;;-1:-1:-1;165:295:33;;;5717:14:25;5709:62;5717:14;;;5709:62;:::i;:::-;-1:-1:-1;165:295:33;;;5798:11:25;165:295:33;;;;;;5777:81:25;;5785:35;;-1:-1:-1;;;;;165:295:33;5798:22:25;-1:-1:-1;;;;;165:295:33;;;5785:35:25;719:10:20;5785:35:25;5777:81;:::i;:::-;5864:96;5872:26;:39;:26;;;;:::i;:::-;165:295:33;;;;;5872:26:25;165:295:33;;;;5872:39:25;;5864:96;:::i;:::-;165:295:33;5973:26:25;;;:::i;:::-;165:295:33;;-1:-1:-1;;165:295:33;;;;;;;-1:-1:-1;;;;;165:295:33;;;;;;;;;;;;;6011:42:25;;;;165:295:33;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;-1:-1:-1;;165:295:33;;;;12834:1:29;165:295:33;;;;;;;;:::i;:::-;;;;:::i;:::-;;341:90:44;184:1:43;165:295:33;1116:3:44;165:295:33;349:51:44;341:90;:::i;:::-;12204:80:29;295:6:43;165:295:33;6556:24:44;6578:1;165:295:33;;;6563:16:44;165:295:33;;;;6556:24:44;165:295:33;12212:44:29;12204:80;:::i;:::-;12290:153;12305:42;165:295:33;;;12305:42:29;:::i;6854:18:44:-;12305:42:29;:::i;:::-;165:295:33;12305:89:29;12351:43;7428:24:44;7449:2;165:295:33;;;12351:43:29;165:295:33;7434:17:44;165:295:33;;;;12305:89:29;165:295:33;;12305:89:29;12290:153;:::i;:::-;295:6:43;;;;12457:12:29;295:6:43;;;;;12449:62:29;;-1:-1:-1;;;;;295:6:43;12457:25:29;;;295:6:43;-1:-1:-1;;;;;295:6:43;;;12457:25:29;295:6:43;12457:30:29;12449:62;:::i;:::-;12518:111;341:4:43;1370:3:44;165:295:33;;;1377:12:44;1354:35;12526:24:29;:43;;12518:111;:::i;:::-;12768:59;817:7:43;12652:44:29;6228:2:44;165:295:33;;;6234:12:44;6212:34;12652:26:29;12681:15;12652:44;;:::i;:::-;12702:60;766:7:43;12710:28:29;;12702:60;:::i;:::-;12776:28;12768:59;:::i;:::-;12834:1;:::i;:::-;165:295:33;;;;;;;-1:-1:-1;;165:295:33;;;;;;8637:24:29;165:295:33;;:::i;:::-;3242:15:23;165:295:33;8191:65:29;;-1:-1:-1;;;;;165:295:33;719:10:20;3242:31:23;8191:65:29;:::i;:::-;295:6:43;-1:-1:-1;295:6:43;8284:12:29;165:295:33;295:6:43;8315:46:29;8336:1;295:6:43;;;;;165:295:33;-1:-1:-1;295:6:43;;;8323:14:29;8315:46;:::i;:::-;8367:77;6228:2:44;165:295:33;;;6234:12:44;6212:34;8375:26:29;8404:15;-1:-1:-1;8367:77:29;:::i;:::-;-1:-1:-1;295:6:43;;;8284:12:29;165:295:33;295:6:43;165:295:33;295:6:43;;165:295:33;;-1:-1:-1;;;;;;165:295:33;;;;;;8637:24:29;1370:3:44;165:295:33;;;1377:12:44;1354:35;8637:24:29;;;:::i;:::-;8674:26;-1:-1:-1;8674:26:29;;165:295:33;;;;;;;-1:-1:-1;;165:295:33;;;;;;-1:-1:-1;295:6:43;;;11889:12:29;165:295:33;295:6:43;;;;;-1:-1:-1;;;;;165:295:33;;;;;;-1:-1:-1;;;;;295:6:43;;;12002:23:29;165:295:33;;12035:22:29;165:295:33;-1:-1:-1;11998:144:29;;295:6:43;165:295:33;;-1:-1:-1;;;;;165:295:33;;;;;;;;;;;;;11978:14:29;;;165:295:33;;;;;;;;;;;;;;;;;;11998:144:29;12090:45;;165:295:33;;;;;;;;12090:11:29;165:295:33;;;;;;;12090:45:29;165:295:33;-1:-1:-1;;;;;165:295:33;;;12090:45:29;11998:144;;;165:295:33;-1:-1:-1;;;;;165:295:33;;;;;5672:20:25;165:295:33;;;;;;:::o;:::-;;;;;;-1:-1:-1;;165:295:33;;;;-1:-1:-1;;;;;165:295:33;;:::i;:::-;;-1:-1:-1;165:295:33;3372:45:46;165:295:33;;;;;-1:-1:-1;165:295:33;;;;;;;;;;;;-1:-1:-1;;165:295:33;;;;12834:1:29;165:295:33;;341:90:44;184:1:43;165:295:33;1116:3:44;165:295:33;349:51:44;341:90;:::i;:::-;12204:80:29;295:6:43;165:295:33;6556:24:44;6578:1;165:295:33;;;6563:16:44;165:295:33;12204:80:29;12290:153;12305:42;165:295:33;;;12305:42:29;:::i;12290:153::-;295:6:43;;;;12457:12:29;295:6:43;;;;;12449:62:29;;-1:-1:-1;;;;;295:6:43;12457:25:29;;;295:6:43;12449:62:29;12518:111;341:4:43;1370:3:44;165:295:33;;;1377:12:44;1354:35;12526:24:29;1267:127:44;12518:111:29;12768:59;817:7:43;12652:44:29;6228:2:44;165:295:33;;;6234:12:44;6212:34;12652:26:29;6123:183:44;12768:59:29;12834:1;:::i;165:295:33:-;;;;;;-1:-1:-1;;165:295:33;;;;;;:::i;:::-;719:10:20;-1:-1:-1;165:295:33;6348:20:25;165:295:33;;6683:48:25;;165:295:33;;-1:-1:-1;165:295:33;;;6393:14:25;6385:62;6393:14;;;6385:62;:::i;:::-;-1:-1:-1;165:295:33;;;6474:11:25;165:295:33;;;;;;6453:81:25;;6461:35;;-1:-1:-1;;;;;165:295:33;6474:22:25;165:295:33;6453:81:25;6540:96;6548:26;:39;:26;;;;:::i;6540:96::-;6642:29;:22;;;165:295:33;;;;12090:11:29;165:295:33;;;;;;;6642:22:25;165:295:33;;-1:-1:-1;;;;;;165:295:33;-1:-1:-1;;;;;165:295:33;;;;;;;;;;6642:29:25;165:295:33;;;719:10:20;165:295:33;;-1:-1:-1;;;;;165:295:33;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;165:295:33;;;;;;;;:::i;:::-;-1:-1:-1;295:6:43;;;6872:12:29;165:295:33;295:6:43;165:295:33;295:6:43;;;-1:-1:-1;;;;;295:6:43;;;;165:295:33;;6903:46:29;165:295:33;6911:14:29;;6903:46;:::i;:::-;165:295:33;;;7161:50:29;719:10:20;7038:116:29;165:295:33;719:10:20;;7046:34:29;;719:10:20;7046:34:29;:::i;:::-;165:295:33;;;;7046:47:29;;7038:116;:::i;:::-;7189:22;7161:25;;295:6:43;;12457:12:29;295:6:43;;;;;;;7161:25:29;165:295:33;;-1:-1:-1;;;;;;165:295:33;-1:-1:-1;;;;;295:6:43;;;165:295:33;;;;;;;7161:50:29;7222:23;-1:-1:-1;7222:23:29;;165:295:33;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;165:295:33;;;;3499:5:4;165:295:33;;:::i;:::-;1963:87:4;1898:6;-1:-1:-1;;;;;165:295:33;1873:80:4;1889:4;1881:23;;;1873:80;:::i;:::-;-1:-1:-1;;;;;;;;;;;165:295:33;-1:-1:-1;;;;;165:295:33;1971:30:4;1963:87;:::i;:::-;2848:58:23;165:295:33;;;;;2856:6:23;165:295:33;;719:10:20;2856:22:23;2848:58;:::i;:::-;165:295:33;;;;;;;;:::i;:::-;-1:-1:-1;165:295:33;;-1:-1:-1;;165:295:33;;;;;;;;3499:5:4;:::i;165:295:33:-;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;:::i;:::-;3293:46:25;3301:10;;;3293:46;:::i;:::-;165:295:33;;;3401:53:25;3409:14;;;3401:53;:::i;:::-;719:10:20;3310:1:25;165:295:33;3525:20:25;165:295:33;;;;;3310:1:25;165:295:33;;;;3512:47:25;165:295:33;;;3610:35:25;;3782:37;3610:35;165:295:33;;;;3610:19:25;165:295:33;;;;;;;3610:35:25;:45;165:295:33;;;3610:45:25;:::i;:::-;165:295:33;;3763:6:25;719:10:20;;10755:27:44;10779:2;165:295:33;;;;;10761:20:44;165:295:33;10755:27:44;3763:6:25;:::i;:::-;165:295:33;;;;;;;;;;;3782:37:25;165:295:33;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;-1:-1:-1;;165:295:33;;;;;;:::i;:::-;3468:1:3;165:295:33;;:::i;:::-;-1:-1:-1;165:295:33;;3157:201:3;165:295:33;;;;;;3133:14:3;;;;3179:34;;;165:295:33;3178:108:3;;;;165:295:33;3157:201:3;;:::i;:::-;3368:16;;165:295:33;;;3134:13:3;165:295:33;;;3134:13:3;165:295:33;;3368:16:3;3394:65;;3468:1;:::i;:::-;3479:99;;165:295:33;3479:99:3;3513:21;165:295:33;;3134:13:3;165:295:33;;3134:13:3;165:295:33;;3513:21:3;165:295:33;;3383:1:3;165:295:33;;3553:14:3;;165:295:33;;3553:14:3;165:295:33;3394:65:3;3428:20;165:295:33;;;3134:13:3;165:295:33;;;3134:13:3;165:295:33;;3428:20:3;3468:1;:::i;3178:108::-;3258:4;1476:19:8;:23;;-1:-1:-1;1476:23:8;3219:66:3;;3178:108;;;;;3219:66;165:295:33;;3284:1:3;3268:17;;-1:-1:-1;3219:66:3;;;3179:34;3212:1;165:295:33;;;3197:16:3;;-1:-1:-1;3179:34:3;;165:295:33;;;;;;;;;;;:::o;:::-;;;;;;-1:-1:-1;;165:295:33;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;165:295:33;;;;;;;:::o;:::-;;:::i;:::-;-1:-1:-1;;;;;165:295:33;;;;;;-1:-1:-1;;165:295:33;;;;:::o;:::-;;;-1:-1:-1;;165:295:33;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;165:295:33;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1;165:295:33;;3761:222:4;165:295:33;;;;;;;;;;3761:222:4;:::i;165:295:33:-;;;;;;-1:-1:-1;;165:295:33;;;;;;8315:56:25;7526:34;165:295:33;;:::i;:::-;341:90:44;184:1:43;165:295:33;1116:3:44;165:295:33;349:51:44;341:90;:::i;:::-;16576:81:25;295:6:43;165:295:33;;;;;16584:45:25;16576:81;:::i;:::-;7526:34;;:::i;:::-;7566:57;-1:-1:-1;;;;;7574:20:25;;;295:6:43;;7574:12:25;295:6:43;;;;;;;7574:20:25;165:295:33;-1:-1:-1;;;;;165:295:33;;;7566:57:25;8315:20;8338:33;7649:34;;719:10:20;7649:34:25;:::i;:::-;7689:74;165:295:33;;;7697:14:25;;7689:74;:::i;:::-;7786:34;:15;:34;:::i;:::-;7826:96;7842:38;6228:2:44;165:295:33;;;6234:12:44;6212:34;7842:38:25;:::i;:::-;7834:46;;7826:96;:::i;:::-;8386:2:44;165:295:33;;;-1:-1:-1;;;165:295:33;;;;8349:52:44;8009:65:25;:35;8048:26;;;:::i;:::-;8009:35;165:295:33;;;;3610:19:25;165:295:33;;;;;;;8009:35:25;165:295:33;;;8009:65:25;:::i;:::-;165:295:33;;8148:29:25;;;:::i;:::-;8187:14;8183:126;;165:295:33;-1:-1:-1;9634:2:44;165:295:33;;;;;;;9616:33:44;;9514:140;8338:33:25;8315:20;295:6:43;;7574:12:25;295:6:43;;;;;;;8315:20:25;864:10:43;-1:-1:-1;;;;;165:295:33;-1:-1:-1;;;;;864:10:43;;;;;;;;8315:56:25;8383:23;-1:-1:-1;8383:23:25;;165:295:33;8183:126:25;165:295:33;;;8251:12:25;165:295:33;;8211:91:25;:77;8231:56;8251:24;;-1:-1:-1;;;;;;;;;;;8251:24:25;165:295:33;;;;;8251:24:25;10483:2:44;165:295:33;-1:-1:-1;;;165:295:33;;;;;10460:38:44;;10351:152;8231:56:25;165:295:33;;;;3610:19:25;165:295:33;;;;;;;8211:91:25;165:295:33;;8183:126:25;;;165:295:33;;;;;;-1:-1:-1;;165:295:33;;;;2333:6:4;-1:-1:-1;;;;;165:295:33;2324:4:4;2316:23;165:295:33;;;;-1:-1:-1;;;;;;;;;;;165:295:33;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;-1:-1:-1;;165:295:33;;;;;;-1:-1:-1;295:6:43;;;7594:12:29;165:295:33;295:6:43;;;;;-1:-1:-1;;;;;295:6:43;7625:46:29;165:295:33;7633:14:29;;7625:46;:::i;:::-;7677:77;6228:2:44;165:295:33;;;6234:12:44;6212:34;7685:26:29;6123:183:44;7677:77:29;165:295:33;;;;;;;;8042:24:29;7840:25;165:295:33;7840:25:29;;295:6:43;;12457:12:29;295:6:43;;;;;;;7840:25:29;165:295:33;;-1:-1:-1;;;;;;165:295:33;;;;;;;;;9057:34:44;;9065:25;;10779:2;165:295:33;-1:-1:-1;;;;;165:295:33;9065:25:44;165:295:33;9057:34:44;1370:3;165:295:33;;;1377:12:44;1354:35;8042:24:29;1267:127:44;165:295:33;295:6:43;165:295:33;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;165:295:33;;;;;;8315:56:25;7526:34;165:295:33;;:::i;:::-;;;;;;-1:-1:-1;;165:295:33;;;;;;16226:34:25;165:295:33;;:::i;:::-;-1:-1:-1;165:295:33;16226:34:25;:::i;:::-;295:6:43;;16286:12:25;165:295:33;295:6:43;165:295:33;295:6:43;;165:295:33;-1:-1:-1;;;;;165:295:33;;;295:6:43;16330:1:25;16316:15;;16330:1;;16341:22;;;16330:1;-1:-1:-1;16312:205:25;;165:295:33;;;-1:-1:-1;;;;;165:295:33;;;;;;;;;;;;;;;;16312:205:25;165:295:33;;;;;;16413:11:25;165:295:33;;;;;;;-1:-1:-1;;;;;165:295:33;;16474:36:25;;10144:25:44;;10779:2;165:295:33;;10152:16:44;-1:-1:-1;;;;;165:295:33;;;16474:36:25;16312:205;;;165:295:33;;;;;;-1:-1:-1;;165:295:33;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;-1:-1:-1;;165:295:33;;;;12834:1:29;165:295:33;;;;:::i;:::-;;;:::i;:::-;;341:90:44;184:1:43;165:295:33;1116:3:44;165:295:33;349:51:44;341:90;:::i;:::-;12204:80:29;295:6:43;165:295:33;6556:24:44;6578:1;165:295:33;;;6563:16:44;165:295:33;12204:80:29;12290:153;12305:42;165:295:33;;;12305:42:29;:::i;12290:153::-;295:6:43;;;;12457:12:29;295:6:43;;;;;12449:62:29;;-1:-1:-1;;;;;295:6:43;12457:25:29;;;295:6:43;12449:62:29;12518:111;341:4:43;1370:3:44;165:295:33;;;1377:12:44;1354:35;12526:24:29;1267:127:44;12518:111:29;12768:59;817:7:43;12652:44:29;6228:2:44;165:295:33;;;6234:12:44;6212:34;12652:26:29;6123:183:44;12768:59:29;12834:1;:::i;165:295:33:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;2848:58:23;165:295:33;;;;;;;;2856:6:23;165:295:33;;719:10:20;2856:22:23;2848:58;:::i;:::-;165:295:33;;;-1:-1:-1;165:295:33;;;2325:11:23;165:295:33;;;;;;2317:76:23;;-1:-1:-1;;;;;165:295:33;2325:38:23;;2317:76;:::i;:::-;165:295:33;10483:2:44;165:295:33;;;-1:-1:-1;;;165:295:33;;-1:-1:-1;165:295:33;2399:19:23;165:295:33;;;-1:-1:-1;165:295:33;;;341:4:43;;;;;;;;;2470:75:23;165:295:33;2470:65:23;165:295:33;2490:44:23;165:295:33;;10351:152:44;165:295:33;-1:-1:-1;;;10351:152:44;165:295:33;;10483:2:44;165:295:33;;10460:38:44;10351:152;;2470:65:23;165:295:33;;;2470:75:23;:::i;:::-;165:295:33;;;341:4:43;;:::i;165:295:33:-;;;;;;-1:-1:-1;;165:295:33;;;;12834:1:29;165:295:33;;;;:::i;:::-;;;;;;;341:90:44;184:1:43;165:295:33;1116:3:44;165:295:33;349:51:44;341:90;:::i;:::-;12204:80:29;295:6:43;165:295:33;6556:24:44;6578:1;165:295:33;;;6563:16:44;165:295:33;12204:80:29;12290:153;12305:42;165:295:33;;;12305:42:29;:::i;12290:153::-;295:6:43;;;;12457:12:29;295:6:43;;;;;12449:62:29;;-1:-1:-1;;;;;295:6:43;12457:25:29;;;295:6:43;12449:62:29;12518:111;341:4:43;1370:3:44;165:295:33;;;1377:12:44;1354:35;12526:24:29;1267:127:44;12518:111:29;12768:59;817:7:43;12652:44:29;6228:2:44;165:295:33;;;6234:12:44;6212:34;12652:26:29;6123:183:44;12768:59:29;12834:1;:::i;165:295:33:-;;;;;;-1:-1:-1;;165:295:33;;;;-1:-1:-1;;;;;165:295:33;;:::i;:::-;;-1:-1:-1;165:295:33;1593:54:45;165:295:33;;;;;-1:-1:-1;165:295:33;;;;;;;;;;;;;;;;:::o;:::-;;;;;;-1:-1:-1;;165:295:33;;;;;;;;;;10205:32:29;165:295:33;;:::i;:::-;;;;;;;:::i;:::-;9589:25:29;;;295:6:43;;12457:12:29;295:6:43;;;;;;;9589:25:29;295:6:43;9620:46:29;9641:1;-1:-1:-1;;;;;295:6:43;;9628:14:29;9620:46;:::i;:::-;6228:2:44;165:295:33;;;6234:12:44;6212:34;9761:38:29;:15;:38;:::i;:::-;-1:-1:-1;9761:15:29;;;165:295:33;9948:25:29;;295:6:43;;12457:12:29;295:6:43;;;;;;;165:295:33;9057:34:44;9065:25;-1:-1:-1;;;;;10779:2:44;165:295:33;;;;9065:25:44;165:295:33;9057:34:44;10205:32:29;;;:::i;:::-;165:295:33;;;;;;10357:221:29;;;;10384:63;10404:42;10384:91;10451:24;;;1377:12:44;1267:127;1370:3;165:295:33;1354:35:44;1267:127;;10451:24:29;10404:42;10483:2:44;165:295:33;-1:-1:-1;;;165:295:33;;;;;10460:38:44;;10351:152;10384:91:29;165:295:33;;10357:221:29;10589:25;-1:-1:-1;10589:25:29;;165:295:33;10357:221:29;10522:22;;;10546:24;10522:22;165:295:33;;;;12090:11:29;165:295:33;;;;;;;10546:24:29;10357:221;;9728:408;10100:29;:25;;295:6:43;;12457:12:29;295:6:43;;;;;;;10100:25:29;165:295:33;;-1:-1:-1;;;;;;165:295:33;295:6:43;165:295:33;;;;10100:29:29;9728:408;;165:295:33;;;;;;-1:-1:-1;;165:295:33;;;;;;;;;;;;;;-1:-1:-1;165:295:33;2197:45:45;165:295:33;;;;;;;;;-1:-1:-1;165:295:33;;;;;;;;;;;;;;;-1:-1:-1;;165:295:33;;;;;-1:-1:-1;;;165:295:33;;:::i;:::-;10483:2:44;165:295:33;;;-1:-1:-1;165:295:33;4088:19:45;165:295:33;;;;-1:-1:-1;165:295:33;;;;;;;;;;2631:37:25;165:295:33;;;:::i;:::-;1904:46:25;1912:10;;;;;1904:46;:::i;:::-;165:295:33;;;2365:43:25;165:295:33;2050:53:25;2058:14;;;2050:53;:::i;:::-;2153:78;165:295:33;;;;;2161:22:25;;;165:295:33;;;;12090:11:29;165:295:33;;;;;;;2161:22:25;165:295:33;2161:36:25;2153:78;:::i;:::-;2237:82;2245:36;:31;;719:10:20;2245:31:25;:::i;:36::-;;2237:82;:::i;:::-;2325:34;719:10:20;2325:22:25;;165:295:33;;;;12090:11:29;165:295:33;;;;;;;2325:34:25;2365:31;719:10:20;2365:31:25;:::i;:::-;165:295:33;;;;;;;;;;;;2365:43:25;2415:35;;165:295:33;;;;3610:19:25;165:295:33;;;;;;;2415:35:25;:45;165:295:33;;;2415:45:25;:::i;:::-;165:295:33;;2565:6:25;719:10:20;;10755:27:44;10779:2;165:295:33;;;;;10761:20:44;165:295:33;2565:6:25;165:295:33;;719:10:20;165:295:33;;2584:36:25;;165:295:33;;2584:36:25;165:295:33;;;;;;;;;;;2631:37:25;165:295:33;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;165:295:33;;;;;;;;;-1:-1:-1;;;;;165:295:33;;;;;;;:::o;:::-;;;;11166:24:25;12404:13;11166:20;165:295:33;;;:::i;:::-;10454:9:25;;;;;;10430:72;10454:9;719:10:20;10438:25:25;10430:72;:::i;:::-;10508:87;6228:2:44;165:295:33;;;6234:12:44;6212:34;10516:26:25;10545:15;-1:-1:-1;10508:87:25;:::i;:::-;10601:68;-1:-1:-1;;;;;165:295:33;;10609:23:25;;10601:68;:::i;:::-;11150:9;10693:23;-1:-1:-1;;;3745:68:44;;3744:74;;10722:181:25;;;;165:295:33;10984:34:25;;;;:::i;:::-;11032:20;11024:56;11055:1;-1:-1:-1;;;;;11032:20:25;;;295:6:43;;7574:12:25;295:6:43;;;;;;;11032:20:25;165:295:33;11032:24:25;11024:56;:::i;:::-;11150:9;;;:::i;:::-;295:6:43;;7574:12:25;295:6:43;;;;;;;11166:20:25;864:10:43;;-1:-1:-1;;864:10:43;165:295:33;864:10:43;;;;11166:24:25;11275:26;;;:::i;:::-;11311:10;;11307:629;;165:295:33;11966:27:25;;;:::i;:::-;12003:17;11999:185;;165:295:33;12211:29:25;;;;:::i;:::-;12250:14;12246:76;;165:295:33;-1:-1:-1;7428:24:44;7449:2;165:295:33;;;7434:17:44;165:295:33;7428:24:44;12404:13:25;;:::i;:::-;12430:25;10630:1;12430:25;;165:295:33;12246:76:25;12304:10;;;;:::i;:::-;12246:76;;;11999:185;12030:30;;;;;:::i;:::-;12128;12068:109;:92;12088:71;12128:30;;;:::i;:::-;12088:71;8230:176:44;165:295:33;-1:-1:-1;;;8230:176:44;165:295:33;;8386:2:44;165:295:33;;8349:52:44;8230:176;;12068:109:25;165:295:33;;11999:185:25;;;11307:629;11504:27;11418:24;;;:::i;:::-;11504:27;;;:::i;:::-;11872:42;11852:77;:63;8386:2:44;165:295:33;;;-1:-1:-1;;;165:295:33;;;;;3610:19:25;165:295:33;;;;;;;11852:77:25;165:295:33;;11307:629:25;;10722:181;3242:15:23;165:295:33;10831:65:25;;-1:-1:-1;;;;;165:295:33;719:10:20;3242:31:23;8191:65:29;:::i;10831::25:-;10722:181;;165:295:33;;;;14498:13:25;165:295:33;;;:::i;:::-;;;341:90:44;184:1:43;165:295:33;1116:3:44;165:295:33;;;;349:51:44;341:90;:::i;:::-;16576:81:25;295:6:43;165:295:33;;7150:2:44;165:295:33;;16584:45:25;16576:81;:::i;:::-;12679:72;12703:9;719:10:20;12687:25:25;12679:72;:::i;:::-;12757:68;-1:-1:-1;;;;;165:295:33;;12765:23:25;;12757:68;:::i;:::-;13553:24;:20;-1:-1:-1;;;3745:68:44;;3744:74;;12878:95:25;;;;165:295:33;12996:34:25;;;;;;:::i;:::-;13044:20;13036:57;-1:-1:-1;;;;;13044:20:25;;;295:6:43;;7574:12:25;295:6:43;;;;;;;13036:57:25;13119:34;;719:10:20;13119:34:25;:::i;:::-;165:295:33;13159:74:25;165:295:33;;;13167:14:25;;13159:74;:::i;:::-;13244:17;;;;13429:9;;13271:87;;6228:2:44;165:295:33;6234:12:44;6212:34;13279:26:25;6123:183:44;13271:87:25;13429:9;;;:::i;13553:24::-;13608:26;;;:::i;:::-;13660:50;13640:71;8386:2:44;165:295:33;;;-1:-1:-1;;;165:295:33;;;;8349:52:44;165:295:33;;;;3610:19:25;165:295:33;;;;;;;13640:71:25;:88;165:295:33;;;13640:88:25;:::i;:::-;165:295:33;;13739:10:25;13735:196;;13240:308;13961:27;;;:::i;:::-;13998:17;13994:185;;13240:308;14206:29;;;;:::i;:::-;14245:14;14241:175;;13240:308;-1:-1:-1;7428:24:44;;-1:-1:-1;7449:2:44;165:295:33;;;7434:17:44;165:295:33;14241:175:25;165:295:33;;;8251:12:25;165:295:33;;14398:10:25;;14269:77;;14289:56;;14309:24;-1:-1:-1;;;;;;;;;;;14309:24:25;165:295:33;14269:77:25;:91;165:295:33;;;14269:91:25;:::i;:::-;165:295:33;;14398:10:25;;:::i;:::-;14241:175;;;;13994:185;14025:30;;;;;:::i;:::-;14123;14063:109;:92;14083:71;14123:30;;;:::i;:::-;14083:71;8230:176:44;165:295:33;-1:-1:-1;;;8230:176:44;165:295:33;;8386:2:44;165:295:33;;8349:52:44;8230:176;;14063:109:25;165:295:33;;13994:185:25;;;13735:196;13812:27;13780:24;;;:::i;:::-;13812:27;;;:::i;:::-;13867:42;13847:77;:63;8386:2:44;165:295:33;;;-1:-1:-1;;;165:295:33;;;;;3610:19:25;165:295:33;;;;;;;13847:77:25;165:295:33;;13735:196:25;;13240:308;13456:10;;;;;13553:20;13452:96;3242:15:23;165:295:33;13476:65:25;;-1:-1:-1;;;;;165:295:33;719:10:20;3242:31:23;8191:65:29;:::i;13476::25:-;13240:308;;12878:95;3242:15:23;165:295:33;12901:65:25;;-1:-1:-1;;;;;165:295:33;719:10:20;3242:31:23;8191:65:29;:::i;12901::25:-;12878:95;;165:295:33;;;;;;-1:-1:-1;;165:295:33;;;;2183:17:23;165:295:33;;:::i;:::-;3242:15:23;165:295:33;2088:65:23;;-1:-1:-1;;;;;165:295:33;719:10:20;3242:31:23;8191:65:29;:::i;2088::23:-;2183:17;:::i;165:295:33:-;-1:-1:-1;;;;;165:295:33;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;165:295:33;;;;;;-1:-1:-1;;;;;165:295:33;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;165:295:33;;;;;1601:306:23;165:295:33;;;;;;:::i;:::-;1601:306:23;;:::i;165:295:33:-;;;;;;;:::i;:::-;;;;;;;;;;12834:1:29;165:295:33;;;:::i;:::-;;341:90:44;184:1:43;165:295:33;1116:3:44;165:295:33;;;;349:51:44;341:90;:::i;:::-;12204:80:29;295:6:43;165:295:33;6556:24:44;6578:1;165:295:33;;;6563:16:44;165:295:33;12204:80:29;12290:153;12305:42;165:295:33;;;12305:42:29;:::i;12290:153::-;295:6:43;;;;12457:12:29;295:6:43;;;;;12449:62:29;;-1:-1:-1;;;;;295:6:43;12457:25:29;;;295:6:43;12449:62:29;12518:111;341:4:43;1370:3:44;165:295:33;;;1377:12:44;1354:35;12526:24:29;1267:127:44;12518:111:29;12768:59;817:7:43;12652:44:29;6228:2:44;165:295:33;;;6234:12:44;6212:34;12652:26:29;6123:183:44;12768:59:29;12834:1;:::i;165:295:33:-;;;;;;-1:-1:-1;;165:295:33;;;;;;:::i;:::-;2848:58:23;165:295:33;;;;;2856:6:23;165:295:33;;719:10:20;2856:22:23;2848:58;:::i;:::-;165:295:33;;;5097:50:46;5105:10;;;5097:50;:::i;:::-;-1:-1:-1;165:295:33;;;5169:13:46;165:295:33;;;;;;-1:-1:-1;;;;;165:295:33;5203:19:46;;165:295:33;;-1:-1:-1;;;;;165:295:33;;;;;5274:12:46;165:295:33;;;;;;;-1:-1:-1;;165:295:33;;;;;5306:20:46;;165:295:33;;;;;5169:13:46;165:295:33;;;;;;;5306:20:46;165:295:33;;-1:-1:-1;;;;;;165:295:33;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;4720:37:25;165:295:33;;;:::i;:::-;4253:46:25;4261:10;;;;;4253:46;:::i;:::-;165:295:33;;;4361:53:25;4369:14;;;4361:53;:::i;:::-;4270:1;165:295:33;;;4472:11:25;165:295:33;;;;;;4464:84:25;;-1:-1:-1;;;;;165:295:33;719:10:20;4472:38:25;4464:84;:::i;:::-;4554:35;;165:295:33;;;;3610:19:25;165:295:33;;;;;;;4554:35:25;:45;165:295:33;;;4554:45:25;:::i;:::-;165:295:33;;4701:6:25;719:10:20;;10755:27:44;10779:2;165:295:33;;;;;10761:20:44;165:295:33;10755:27:44;4701:6:25;:::i;165:295:33:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;165:295:33;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;165:295:33;;;;;;4152:9:46;4179:7;165:295:33;;;;4179:7:46;;;165:295:33;;4317:16:46;4283:18;;;:::i;:::-;4317:16;;:::i;:::-;4339:11;165:295:33;;4368:7:46;165:295:33;;;;4368:7:46;;;165:295:33;;;;;;;;;;:::i;4377:3:46:-;4394:32;:18;;4408:3;;;:::i;4394:32::-;4390:126;;4377:3;4221:1;165:295:33;;;4361:5:46;;4390:126;4464:3;4221:1;4504:3;165:295:33;4464:3:46;4478:16;4450:18;;4464:3;;;:::i;4450:18::-;4438:30;165:295:33;;;4438:30:46;;;;;:::i;:::-;-1:-1:-1;;;;;165:295:33;;;;;;4438:30:46;4478:16;4491:3;;;:::i;:::-;4478:16;;;:::i;:::-;165:295:33;;;;;;4478:16:46;4504:3;:::i;:::-;4390:126;;;;;;4188:3;4205:32;:18;;4219:3;;;:::i;4205:32::-;4201:62;;4188:3;4221:1;165:295:33;;;4172:5:46;;4201:62;4249:5;4221:1;4249:5;;;;:::i;:::-;4201:62;;;;;;165:295:33;;;;;;-1:-1:-1;;165:295:33;;;;;;;;:::i;:::-;;;:::i;:::-;;;:::i;:::-;;;;;;-1:-1:-1;;165:295:33;;;;;;:::i;:::-;;;;;;;;;;1368:5:23;165:295:33;2848:58:23;165:295:33;;;;;2856:6:23;165:295:33;;719:10:20;2856:22:23;2848:58;:::i;:::-;1368:5;:::i;165:295:33:-;;;-1:-1:-1;;165:295:33;;;;;;;;-1:-1:-1;;;;;165:295:33;;;;;;;;;12834:1:29;;165:295:33;;-1:-1:-1;;;;;165:295:33;;;;341:90:44;1116:3;165:295:33;;;184:1:43;349:51:44;341:90;:::i;:::-;12204:80:29;295:6:43;165:295:33;6556:24:44;6578:1;165:295:33;;;6563:16:44;165:295:33;12204:80:29;12290:153;12305:42;165:295:33;;;12305:42:29;:::i;:::-;165:295:33;12305:89:29;12351:43;7428:24:44;7449:2;165:295:33;;;12351:43:29;165:295:33;12290:153:29;295:6:43;;;;12457:12:29;295:6:43;;;;;12449:62:29;;-1:-1:-1;;;;;295:6:43;12457:25:29;;;295:6:43;12449:62:29;12518:111;341:4:43;1370:3:44;165:295:33;;;1377:12:44;1354:35;12526:24:29;1267:127:44;12518:111:29;12768:59;817:7:43;12652:44:29;6228:2:44;165:295:33;;;6234:12:44;6212:34;12652:26:29;6123:183:44;12768:59:29;165:295:33;12834:1:29;;:::i;165:295:33:-;;;;2757:44:23;165:295:33;;;;:::i;:::-;;;;2848:58:23;165:295:33;;;;;2856:6:23;165:295:33;;719:10:20;2856:22:23;2848:58;:::i;:::-;165:295:33;;;-1:-1:-1;165:295:33;;;2663:11:23;165:295:33;;;;;;2655:76:23;;-1:-1:-1;;;;;165:295:33;2663:38:23;;2655:76;:::i;2757:44::-;165:295:33;-1:-1:-1;165:295:33;2737:19:23;165:295:33;;;-1:-1:-1;165:295:33;;;;;;;;;;;;;;;;;;;-1:-1:-1;;165:295:33;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;-1:-1:-1;;165:295:33;;;;;;;9485:20:25;8859:34;165:295:33;;:::i;:::-;8859:34:25;;:::i;:::-;9891:18:44;8919:20:25;;;295:6:43;;7574:12:25;295:6:43;;;;;;;8919:20:25;8945:46;8966:1;-1:-1:-1;;;;;165:295:33;;8953:14:25;8945:46;:::i;:::-;8997:77;10144:25:44;165:295:33;10779:2:44;165:295:33;;;;10152:16:44;165:295:33;10144:25:44;9036:15:25;-1:-1:-1;8997:77:25;:::i;9891:18:44:-;8386:2;165:295:33;;;-1:-1:-1;;;165:295:33;;;;8349:52:44;9218:65:25;:35;9257:26;;;:::i;9218:65::-;165:295:33;;9311:29:25;;;:::i;:::-;9350:14;;9346:126;;165:295:33;9485:20:25;;295:6:43;;7574:12:25;295:6:43;;;;;;;9485:20:25;165:295:33;;-1:-1:-1;;165:295:33;;;;;9517:25:25;-1:-1:-1;9517:25:25;;165:295:33;9346:126:25;165:295:33;;;8251:12:25;165:295:33;;9374:91:25;;:77;;9394:56;;9414:24;-1:-1:-1;;;;;;;;;;;9414:24:25;165:295:33;9374:91:25;165:295:33;;9346:126:25;;;;165:295:33;;;;;;-1:-1:-1;;165:295:33;;;;1998:8:23;165:295:33;;:::i;:::-;2848:58:23;165:295:33;;;;;2856:6:23;165:295:33;;719:10:20;2856:22:23;2848:58;:::i;:::-;1998:8;:::i;165:295:33:-;;;;;;-1:-1:-1;;165:295:33;;;;;;:::i;:::-;719:10:20;-1:-1:-1;165:295:33;5025:20:25;165:295:33;;5352:40:25;;165:295:33;;-1:-1:-1;165:295:33;;;5070:14:25;5062:62;5070:14;;;5062:62;:::i;:::-;-1:-1:-1;165:295:33;;;5151:11:25;165:295:33;;;;;;5130:81:25;;5138:35;;-1:-1:-1;;;;;165:295:33;5151:22:25;165:295:33;5130:81:25;5217:79;5225:31;:26;;;;:::i;:31::-;;5217:79;:::i;:::-;5302:38;:26;;;;:::i;165:295:33:-;;;;;;-1:-1:-1;;165:295:33;;;;;;;:::i;:::-;;-1:-1:-1;165:295:33;3088:46:46;165:295:33;;;;;;;;;-1:-1:-1;165:295:33;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;184:1:43;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;184:1:43;;;;;;;;;;;165:295:33;184:1:43;165:295:33;;;184:1:43;;;;295:6;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;295:6:43;;;;;;;;;;;165:295:33;-1:-1:-1;;;165:295:33;;;295:6:43;;;;;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;295:6:43;;;;;;;;;;;165:295:33;295:6:43;165:295:33;;;295:6:43;-1:-1:-1;;;295:6:43;;;;;;;;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;295:6:43;;;;;;;;;;;165:295:33;-1:-1:-1;;;165:295:33;;;295:6:43;;;;341:4;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;341:4:43;;;;;;;;;;;165:295:33;341:4:43;165:295:33;;;341:4:43;-1:-1:-1;;;341:4:43;;;;;;;;165:295:33;;;341:4:43;;;;;;;;;-1:-1:-1;;341:4:43;;;;;;;;:::o;:::-;;;;;;;;;;:::o;766:7::-;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;766:7:43;;;;;;;;;;;165:295:33;-1:-1:-1;;;165:295:33;;;766:7:43;;;;817;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;817:7:43;;;;;;;;;;;165:295:33;-1:-1:-1;;;165:295:33;;;817:7:43;;;;165:295:33;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;5215:893:29;;;;;5438:1;12687:26:44;5215:893:29;165:295:33;;;5426:13:29;;;:42;;;5215:893;5422:272;;5215:893;-1:-1:-1;;;;;;165:295:33;;;11776:63:44;11784:20;;;11776:63;:::i;:::-;-1:-1:-1;;;;;11857:89:44;;;12687:26;;11962:41;;11968:34;;11879:66;165:295:33;11968:34:44;:::i;11962:41::-;12031:66;12009:110;-1:-1:-1;;;;;12017:80:44;;;12009:110;:::i;:::-;-1:-1:-1;;;4012:68:44;;4011:74;;12227:6;165:295:33;6556:24:44;165:295:33;;;;6563:16:44;165:295:33;6556:24:44;165:295:33;12198:35:44;12227:6;;;;12279:49;;;;-1:-1:-1;;;12279:49:44;165:295:33;;-1:-1:-1;;1166:41:43;;;12262:80:44;;;1166:41:43;;;;;;165:295:33;;;12262:80:44;;165:295:33;1166:41:43;;;12262:80:44;;165:295:33;;12262:80:44;;;;;;:::i;:::-;165:295:33;12252:91:44;;12194:470;;165:295:33;;12687:26:44;;;;1166:41:43;;;;165:295:33;1166:41:43;;;;;165:295:33;;;;1166:41:43;;;165:295:33;1166:41:43;;;165:295:33;1166:41:43;165:295:33;1166:41:43;12687:26:44;;;;;;;;;;;;5438:1:29;12687:26:44;6043:24:29;;5866:72;;5894:44;;12687:26:44;;12669:66;;-1:-1:-1;;;;;165:295:33;12677:36:44;;12669:66;:::i;:::-;165:295:33;;-1:-1:-1;;;;;165:295:33;;;;;8706:108:44;;8565:254;5894:44:29;5866:25;;295:6:43;;12457:12:29;295:6:43;;;;;;;5866:72:29;1377:12:44;1370:3;165:295:33;;;1354:35:44;;165:295:33;;;6043:24:29;:::i;:::-;6080:23;5438:1;6080:23;;5215:893::o;12687:26:44:-;;:::i;12279:49::-;-1:-1:-1;;;12279:49:44;;12194:470;12356:308;;;;165:295:33;;;12397:46:44;;;;;;;;914:43:43;;1333:52;914:43;;;;;165:295:33;914:43:43;;;12397:46:44;165:295:33;12387:57:44;;12356:308;12194:470;;12356:308;12509:149;;;;;;;;1333:52:43;12509:149:44;;;;;12356:308;12194:470;;5422:272:29;5571:116;719:10:20;;165:295:33;;5579:20:29;165:295:33;;;;;;;;5579:47:29;5571:116;:::i;:::-;5422:272;;;5426:42;-1:-1:-1;719:10:20;-1:-1:-1;;;;;165:295:33;;5443:25:29;;5426:42;;165:295:33;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;864:10:43;165:295:33;;;;;;;:::o;:::-;;766:7:43;165:295:33;;;;;;;:::o;:::-;;12000:2:44;165:295:33;;;;;;;:::o;:::-;;;;;;;;;;:::o;11239:447:29:-;-1:-1:-1;295:6:43;;;11381:12:29;295:6:43;;;;;165:295:33;;-1:-1:-1;;;;;;165:295:33;295:6:43;165:295:33;;;;;;1370:3:44;165:295:33;;;1377:12:44;1354:35;165:295:33;10483:2:44;165:295:33;;;-1:-1:-1;;;165:295:33;;10460:38:44;165:295:33;-1:-1:-1;165:295:33;11519:19:29;295:6:43;165:295:33;295:6:43;-1:-1:-1;165:295:33;;;;;;;;;;;;11637:6:29;165:295:33;;719:10:20;11637:6:29;;:::i;:::-;11656:25;-1:-1:-1;11656:25:29;;11239:447::o;165:295:33:-;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;227:161;;332:5;368:14;227:161;332:5;:::i;368:14::-;227:161::o;3692:174:46:-;165:295:33;;;3773:16:46;3787:2;3773:16;;;:36;;;;3692:174;3772:89;;;;3765:96;;3692:174;:::o;3772:89::-;3829:3;-1:-1:-1;3816:16:46;-1:-1:-1;3816:16:46;3815:45;;3772:89;3692:174;:::o;3815:45::-;3858:1;165:295:33;;;;3838:21:46;3692:174;:::o;3773:36::-;3807:2;3793:16;;;;-1:-1:-1;3773:36:46;;1842:226:4;;1963:87;1898:6;-1:-1:-1;;;;;165:295:33;1873:80:4;1889:4;1881:23;;;1873:80;:::i;1963:87::-;2848:58:23;165:295:33;;;;;2856:6:23;165:295:33;;719:10:20;2856:22:23;2848:58;:::i;:::-;951:66:1;;165:295:33;;951:66:1;;;3478:17;;;;:::i;3380:526::-;165:295:33;;-1:-1:-1;;;3531:63:1;;165:295:33;3531:63:1;165:295:33;3531:63:1;165:295:33;-1:-1:-1;;;;;165:295:33;;3531:63:1;;3384:59;;3531:63;;;3380:526;-1:-1:-1;3527:302:1;;165:295:33;;-1:-1:-1;;;3758:56:1;;165:295:33;3758:56:1;3531:63;3758:56;;;:::i;:::-;;;;3527:302;3885:9;3644:28;3636:82;-1:-1:-1;;;;;;;;;;;3971:4:4;3644:28:1;;3636:82;:::i;:::-;3885:9;:::i;3531:63::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;165:295:33;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;864:10:43;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;864:10:43;;;;;;;;;;;165:295:33;864:10:43;165:295:33;;;864:10:43;-1:-1:-1;;;864:10:43;;;;;;;8261:404:45;165:295:33;;8356:2:45;8342:16;;8356:2;;8368:8;8375:1;8368:8;:::o;8338:306::-;8407:3;8393:17;;:46;;;8338:306;8393:75;;;8338:306;8389:255;;;8478:10;8485:3;8478:10;:::o;8389:255::-;8518:3;8505:16;;:37;;;8389:255;8501:143;;;8552:10;8559:3;8552:10;:::o;8501:143::-;8592:3;8579:16;;:37;;;;8501:143;8575:69;;;8656:4;8261:404;:::o;8575:69::-;8633:4;8626:11;:::o;8579:37::-;8613:3;8599:17;;;;8579:37;;;8505;8525:17;8539:3;8525:17;;;8505:37;;8393:75;;8443:25;8393:75;;:46;;8414:25;8393:46;;3548:433:29;;3716:92;;-1:-1:-1;;3548:433:29;165:295:33;;-1:-1:-1;;;;;165:295:33;719:10:20;3782:25:29;;165:295:33;;-1:-1:-1;;;165:295:33;8707:56:44;295:6:43;;165:295:33;295:6:43;;;165:295:33;;;295:6:43;165:295:33;;8706:96:44;;:108;295:6:43;-1:-1:-1;295:6:43;3716:12:29;295:6:43;;;-1:-1:-1;295:6:43;165:295:33;;295:6:43;;;;;165:295:33;;;;;;;;;;3716:92:29;3916:24;1377:12:44;165:295:33;1370:3:44;165:295:33;1354:35:44;719:10:20;165:295:33;;;3916:24:29;:::i;8707:56:44:-;;;;165:295:33;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;16525:144:25;;4496:13:23;16525:144:25;4006:15:23;16525:144:25;16576:81;295:6:43;165:295:33;;7150:2:44;165:295:33;;16584:45:25;16576:81;:::i;:::-;3817:68:23;-1:-1:-1;;;;;165:295:33;;3825:23:23;;3817:68;:::i;:::-;165:295:33;;;7150:2:44;3919:40:23;;165:295:33;;;;;;;-1:-1:-1;;;;;;165:295:33;;;;;;;;3919:40:23;165:295:33;;;;3919:40:23;165:295:33;3919:40:23;165:295:33;3909:51:23;;4006:15;165:295:33;-1:-1:-1;;;;;165:295:33;;3909:51:23;4006:15;:::i;:::-;1370:3:44;165:295:33;;;1377:12:44;1354:35;6854:18;4403:6:23;165:295:33;;;4166:22:23;4157:31;2657:2:44;165:295:33;;;2663:12:44;2641:34;4157:31:23;;:::i;:::-;4215:36;4195:57;10483:2:44;165:295:33;;;-1:-1:-1;;;165:295:33;;10460:38:44;165:295:33;;;;3610:19:25;165:295:33;;;;;;;4195:57:23;:67;165:295:33;;;4195:67:23;:::i;:::-;165:295:33;;;-1:-1:-1;;;8386:2:44;165:295:33;;;;8349:52:44;165:295:33;;;;3610:19:25;165:295:33;;;;;4268:80:23;165:295:33;;;4268:80:23;:::i;:::-;165:295:33;;719:10:20;4403:6:23;;:::i;:::-;719:10:20;7428:24:44;7449:2;165:295:33;;;7434:17:44;165:295:33;4496:13:23;4522:25;-1:-1:-1;4522:25:23;;16525:144:25:o;165:295:33:-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;;;;2821:97:23;;;2848:58;165:295:33;;;;;2856:6:23;165:295:33;;719:10:20;2856:22:23;2848:58;:::i;:::-;165:295:33;;;;1719:31:23;165:295:33;;-1:-1:-1;1844:3:23;165:295:33;;;;;1825:17:23;;;;;;1874:9;1885:10;1874:9;1885:10;;1874:9;;1844:3;1874:9;;;:::i;:::-;165:295:33;-1:-1:-1;;;;;165:295:33;;;1874:9:23;1885:10;;;:::i;:::-;165:295:33;;;;;1885:10:23;;;:::i;1844:3::-;1812:11;;1825:17;;;;;;2821:97::o;165:295:33:-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;10623:612:29;;;;;10916:9;10623:612;10916:9;;:::i;:::-;-1:-1:-1;295:6:43;;;10933:12:29;295:6:43;;;;;165:295:33;;-1:-1:-1;;;;;;165:295:33;295:6:43;165:295:33;;;1377:12:44;165:295:33;1370:3:44;165:295:33;1354:35:44;165:295:33;;;11091:34:29;165:295:33;11091:34:29;;-1:-1:-1;;;165:295:33;10351:152:44;10483:2;165:295:33;;10460:38:44;10351:152;;11091:34:29;165:295:33;-1:-1:-1;165:295:33;11071:19:29;295:6:43;165:295:33;295:6:43;-1:-1:-1;165:295:33;;;;;;;;;;;;11186:6:29;165:295:33;;11186:6:29;:::i;165:295:33:-;;;;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;:::o;3502:330:45:-;-1:-1:-1;;;;;165:295:33;;;;;;;3614:12:45;165:295:33;;;;;;;;;;;;;;;3658:20:45;165:295:33;;;;;;;;;3694:14:45;;:33;;;;3502:330;3690:62;;3764:63;3784:42;;;10351:152:44;165:295:33;-1:-1:-1;;;10351:152:44;165:295:33;;10483:2:44;165:295:33;;10460:38:44;10351:152;;3764:63:45;165:295:33;3502:330:45;:::o;3690:62::-;3737:8;;165:295:33;3737:8:45;:::o;3694:33::-;3712:15;;;3694:33;;165:295:33;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;:::o;7461:560:44:-;165:295:33;;;7553:3:44;7539:17;;7553:3;;-1:-1:-1;165:295:33;;;;7614:21:44;:::o;7621:14::-;7614:21;:::o;7535:430::-;7666:2;7652:16;;7666:2;;7712:8;;165:295:33;7712:8:44;:::o;7648:317::-;7751:3;7737:17;;7751:3;;7819:14;7818:20;7819:14;7818:25;7819:14;;:::i;:::-;165:295:33;;;;;;7818:20:44;:25;:::i;7733:232::-;7874:3;-1:-1:-1;7860:17:44;7856:109;;165:295:33;;-1:-1:-1;;;7970:46:44;;165:295:33;7970:46:44;;;165:295:33;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;3758:56:1;7856:109:44;7943:15;;;:::i;1267:127::-;1370:3;165:295:33;1377:12:44;1354:35;;1267:127::o;165:295:33:-;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;1166:41:43;165:295:33;;1166:41:43;;;;;;;165:295:33;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;4696:4:45;165:295:33;;;;;;4696:4:45;165:295:33;;;;;;;:::o;:::-;;410:1:43;165:295:33;;;;;;410:1:43;165:295:33;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::o;550:58:45:-;;;;;;165:295:33;;;;:::i;:::-;;;;;;;;:::i;:::-;;;550:58:45;-1:-1:-1;550:58:45;;;;:::o;:::-;165:295:33;550:58:45;:::o;:::-;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;550:58:45;;;;;;;;;;;165:295:33;-1:-1:-1;;;165:295:33;;;550:58:45;;;;;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;550:58:45;;;;;;;;;;;165:295:33;550:58:45;165:295:33;;;550:58:45;-1:-1:-1;;;550:58:45;;;;;;;4430:884;;4540:55;4548:10;;;4540:55;:::i;:::-;4606:24;;;:::i;:::-;;;;4687:13;;;4679:74;4687:13;;:::i;:::-;4704:9;4687:26;4679:74;:::i;4602:708::-;4811:25;4557:1;4811:25;;;5082:123;;4992:35;5214:89;4811:25;5002;4811;;;;165:295:33;;;;5169:13:46;165:295:33;;;;;;;4811:25:45;165:295:33;4845:51:45;-1:-1:-1;;;;;165:295:33;;4853:19:45;;4845:51;:::i;:::-;4904:79;1476:19:8;;:23;;4904:79:45;:::i;5002:25::-;4992:35;;:::i;:::-;165:295:33;;-1:-1:-1;;;5082:123:45;;;;;;-1:-1:-1;;;;;165:295:33;;;5082:123:45;;;165:295:33;5176:4:45;550:58;;;165:295:33;550:58:45;;;165:295:33;;;;;;;550:58:45;;;;;5082:123;5071:135;;;;;;:::i;:::-;5222:57;;;4602:708;5214:89;;:::i;5222:57::-;165:295:33;;5234:16:45;;;-1:-1:-1;5234:44:45;;;;5222:57;;;;;;5234:44;5254:24;;;5082:123;5254:24;;;;;;;;:::i;:::-;5234:44;;;;445:46;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;445:46:45;;;;;;;;;;;165:295:33;-1:-1:-1;;;165:295:33;;;445:46:45;;;;5678:864;;;;5789:24;;;:::i;:::-;;;;5892:6;;;;:::i;5785:753::-;5957:25;6438:85;5957:25;6126;6321:106;;6079:35;5957:25;;6089;5957;;;165:295:33;;;;5169:13:46;165:295:33;;;;;;;5957:25:45;165:295:33;-1:-1:-1;;;;;165:295:33;;5991:79:45;1476:19:8;;:23;;4904:79:45;:::i;6079:35::-;165:295:33;;-1:-1:-1;;;6321:106:45;;;;;;-1:-1:-1;;;;;165:295:33;;;6321:106:45;;;165:295:33;445:46:45;;;165:295:33;;;;;;;445:46:45;;;;;6321:106;6310:118;;;;;;:::i;:::-;6446:57;;;5785:753;6438:85;;:::i;6446:57::-;165:295:33;;6458:16:45;;;-1:-1:-1;6458:44:45;;;;6446:57;;;;;;6458:44;6478:24;;;6321:106;6478:24;;;;;;;;:::i;:::-;6458:44;;;;951:66:1;;;;;;;;;;;:::o;:::-;;;;:::o;:::-;165:295:33;;-1:-1:-1;;;951:66:1;;;;;;;;;;;165:295:33;951:66:1;165:295:33;;;951:66:1;-1:-1:-1;;;951:66:1;;;;;;;;;;;;;;;;;165:295:33;951:66:1;165:295:33;;;951:66:1;-1:-1:-1;;;951:66:1;;;;;;:::o;2938:974::-;;951:66;;;165:295:33;;;;951:66:1;;;;3478:17;;;;:::i;3380:526::-;165:295:33;;-1:-1:-1;;;3531:63:1;;165:295:33;3531:63:1;165:295:33;3531:63:1;165:295:33;-1:-1:-1;;;;;165:295:33;;3531:63:1;;3495:1:4;;3531:63:1;;;3380:526;-1:-1:-1;3527:302:1;;165:295:33;;-1:-1:-1;;;3758:56:1;;165:295:33;3758:56:1;3531:63;3758:56;;;:::i;3527:302::-;3885:9;3644:28;3636:82;-1:-1:-1;;;;;;;;;;;3495:1:4;3644:28:1;;3636:82;:::i;3531:63::-;;;;;;;;;;;;;;;:::i;:::-;;;;;2922:236:23;-1:-1:-1;;;;;165:295:33;2991:22:23;;165:295:33;;3076:6:23;165:295:33;;-1:-1:-1;;;;;;165:295:33;;;;;;;-1:-1:-1;;;;;165:295:33;3116:37:23;-1:-1:-1;;3116:37:23;2922:236::o;165:295:33:-;;;;;;;;;;;;;;;;;;;;;;;;;3282:325:23;-1:-1:-1;;;;;165:295:33;3365:31:23;;165:295:33;;3471:15:23;165:295:33;;-1:-1:-1;;;;;;165:295:33;;;;;;;-1:-1:-1;;;;;165:295:33;3538:64:23;-1:-1:-1;;3538:64:23;3282:325::o;165:295:33:-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;705:161:44;165:295:33;;;820:40:44;;;165:295:33;;;;;;;;-1:-1:-1;;;;;;165:295:33;;;;;820:40:44;;165:295:33;;;;820:40:44;165:295:33;820:40:44;165:295:33;810:51:44;;705:161;:::o;1398:182::-;1377:12;165:295:33;1370:3:44;165:295:33;1354:35:44;1514:22;2663:12;165:295:33;2657:2:44;165:295:33;2641:34:44;341:4:43;;;;;;;1539:36:44;;;:::i;:::-;341:4:43;;;;;;;1398:182:44;:::o;4785:292::-;4894:36;;;:::i;:::-;4940:17;;;;;4936:123;;5064:8;;;165:295:33;4785:292:44;:::o;4936:123::-;4990:3;165:295:33;;;;;4990:3:44;165:295:33;;;;;5045:6:44;4996:56;165:295:33;5038:3:44;165:295:33;5022:29:44;4996:56;:::i;:::-;165:295:33;;;;;;4967:85:44;:::o;165:295:33:-;;;;;;;;;;;;14626:530:44;-1:-1:-1;;;;;165:295:33;;;;14626:530:44;;14735:63;14743:20;;;14735:63;:::i;:::-;165:295:33;11879:66:44;;;;14816:89;;165:295:33;;;14959:2:44;165:295:33;;;;;;;15103:26:44;;14761:1;;165:295:33;;15103:26:44;;14968:110;-1:-1:-1;;;;;14976:80:44;;;14968:110;:::i;:::-;165:295:33;;;;;;15103:26:44;;1166:41:43;;;;165:295:33;1166:41:43;;;;;165:295:33;;;;1166:41:43;;;165:295:33;1166:41:43;;;165:295:33;1166:41:43;165:295:33;1166:41:43;15103:26:44;;;;;;;;;;;;14761:1;15103:26;15085:66;;-1:-1:-1;;;;;165:295:33;;;15093:36:44;15085:66;:::i;14558:535:25:-;-1:-1:-1;;;3436:68:44;;165:295:33;;3176:3:44;165:295:33;-1:-1:-1;;;;;165:295:33;;7428:35:45;;7331:90;1476:19:8;;:23;;7331:90:45;:::i;:::-;7438:25;;;:::i;7428:35::-;7473:24;;;;:::i;:::-;;;;-1:-1:-1;165:295:33;;-1:-1:-1;;;7546:154:45;;165:295:33;7546:154:45;;;165:295:33;;;;;;;-1:-1:-1;;;;;165:295:33;;;;;;;-1:-1:-1;;;;;165:295:33;;;;;;;;7546:154:45;;165:295:33;;;;;;;;;7546:154:45;;;;;;;;7469:615;;14558:535:25:o;7546:154:45:-;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;7469:615;7758:25;;;;;;165:295:33;;;;5169:13:46;165:295:33;;;;;;;7758:25:45;7799;7791:79;1476:19:8;;:23;;4904:79:45;:::i;7791:::-;165:295:33;;-1:-1:-1;;;7885:50:45;;-1:-1:-1;;;;;165:295:33;;7885:50:45;;;165:295:33;445:46:45;;;165:295:33;;;;7885:50:45;165:295:33;;445:46:45;;;7885:50;165:295:33;-1:-1:-1;;;;;;165:295:33;;7885:50:45;;;;;;;;;-1:-1:-1;7885:50:45;;;7469:615;-1:-1:-1;165:295:33;;-1:-1:-1;;;7943:134:45;;-1:-1:-1;;;;;165:295:33;;;7885:50:45;7943:134;;165:295:33;;;;;;;;;;;;;;;-1:-1:-1;;;;;165:295:33;;;;;;;;;;;;;;;;;7943:134:45;;;;;;;;7469:615;227:161:33:o;7885:50:45:-;;;;;;;;;;;;;:::i;:::-;;;14684:405:25;14840:10;;;;;;14836:253;;14684:405;;;14558:535::o;14836:253::-;14897:6;;;:::i;13372:1250:44:-;-1:-1:-1;;;;;165:295:33;;;;14569:26:44;;13562:1;;13372:1250;14569:26;;13372:1250;13536:63;13544:20;;;13536:63;:::i;:::-;-1:-1:-1;;;;;13617:89:44;;;13722:41;;13728:34;;11879:66;165:295:33;11968:34:44;:::i;13722:41::-;12031:66;13769:110;-1:-1:-1;;;;;13777:80:44;;;13769:110;:::i;:::-;-1:-1:-1;;;4012:68:44;;4011:74;;13987:6;165:295:33;6556:24:44;6563:16;;165:295:33;;;;6556:24:44;165:295:33;13958:35:44;13987:6;;;;14039:49;;;;-1:-1:-1;;;999:43:43;14022:91:44;;14039:49;14022:91;165:295:33;;14022:91:44;;;;;;;;1250:41:43;;;;1166;;;;;1250;;;165:295:33;;;;;;;1250:41:43;;;165:295:33;1250:41:43;;;14569:26:44;;;;;;;;;;;;13562:1;14569:26;14551:66;;14569:26;-1:-1:-1;;;;;165:295:33;14559:36:44;165:295:33;14039:49:44;-1:-1:-1;;;914:43:43;14022:91:44;;14039:49;;13954:592;14127:419;;;;165:295:33;;1545:98:43;14168:60:44;;;914:43:43;;;999;;;165:295:33;;;;;;;;;-1:-1:-1;;;;;;165:295:33;999:43:43;;;165:295:33;14168:60:44;165:295:33;999:43:43;;;14168:60:44;999:43:43;14127:419:44;7135:17;13987:6;14269:36;7128:25;7135:17;;165:295:33;;;;14269:36:44;;:84;;;;1545:98:43;14269:84:44;;14361:179;;;;;;;;;;;;;;14127:419;13954:592;;14269:84;1426:69:43;14269:84:44;;;1732:667;165:295:33;;;1905:3:44;1891:17;;1905:3;;1918:32;2303:51;:43;:24;555:3:43;1887:347:44;1370:3;165:295:33;1377:12:44;1354:35;;1267:127;2303:24;:43;:::i;:::-;2349:5;165:295:33;;;;2303:51:44;2367:27;:12;;;;;;:27;1732:667;:::o;2367:27::-;;;1732:667;:::o;1887:347::-;1981:3;1967:17;;1981:3;;1994:32;2303:51;:43;:24;632:4:43;1963:271:44;1370:3;165:295:33;1377:12:44;1354:35;;1267:127;1963:271;2057:3;2043:17;;2057:3;;2070:32;2303:51;:43;:24;555:3:43;2039:195:44;1887:347;;2039:195;2133:3;-1:-1:-1;2133:3:44;;2303:51;:43;:24;700:2:43;2115:119:44;1370:3;165:295:33;1377:12:44;1354:35;;1267:127;2115:119;2303:51;:43;:24;489:7:43;2115:119:44;1370:3;165:295:33;1377:12:44;1354:35;;1267:127;5357:215;5444:30;;;:::i;:::-;5440:114;;5559:8;165:295:33;5357:215:44;:::o;5440:114::-;5540:6;5491:56;165:295:33;5533:3:44;165:295:33;5517:29:44;5491:56;:::i;5773:206::-;5862:30;;;:::i;:::-;5858:103;;5966:8;165:295:33;5773:206:44;:::o;5858:103::-;5932:3;165:295:33;5939:6:44;5910:35;5949:5;165:295:33;;;;;;5902:52:44;:::o;6546:183:45:-;6674:4;165:295:33;;;;;;6674:4:45;165:295:33;;;;;;;-1:-1:-1;6643:40:45;;;;;;;;;:::i;:::-;;165:295:33;;;6546:183:45:o;165:295:33:-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;4530:506:46;4599:50;165:295:33;;;4607:10:46;;4599:50;:::i;:::-;-1:-1:-1;;;;;165:295:33;;4663:19:46;;165:295:33;;5003:28:46;4724:19;5003:20;4724:19;4716:64;4724:24;:19;;;165:295:33;;;;;;;;5274:12:46;165:295:33;;;;;;;4724:24:46;;4716:64;:::i;:::-;4786:66;4794:34;:20;;;165:295:33;;;;5169:13:46;165:295:33;;;;;;;4794:34:46;;4786:66;:::i;:::-;4862:19;;;:::i;:::-;4858:107;;4530:506;-1:-1:-1;;;;;;165:295:33;;;;;;5274:12:46;165:295:33;;;;;;;-1:-1:-1;;165:295:33;;;;;;;4970:27:46;165:295:33;4858:107:46;4916:3;4891:67;4899:21;;4891:67;:::i;:::-;4858:107;;;165:295:33;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;2478:288:1;;;2277:17;;;:::i;:::-;165:295:33;;;-1:-1:-1;;;;;165:295:33;;2310:27:1;;;;165:295:33;;2659:15:1;;;;:28;;;2478:288;2655:105;;;2478:288;;;:::o;2655:105::-;1476:19:8;;:23;165:295:33;;7395:25:1;2310:27;7395:25;;;;7437:99;7395:25;;;;;;;;;:::i;:::-;165:295:33;;;;;;;:::i;:::-;;;;;7395:25:1;165:295:33;;;-1:-1:-1;;;165:295:33;;;;7437:99:1;:::i;165:295:33:-;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;2659:28:1;;;;;;1805:281;1476:19:8;;:23;165:295:33;;-1:-1:-1;;;;;;;;;;;165:295:33;;-1:-1:-1;;;;;;165:295:33;-1:-1:-1;;;;;165:295:33;;;;;;;;;;1805:281:1:o;165:295:33:-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;4372:409:44;4468:30;;;:::i;:::-;4464:299;;4768:8;165:295:33;4372:409:44;:::o;4464:299::-;4543:6;165:295:33;4536:3:44;165:295:33;4520:29:44;4543:6;4561:11;;4557:151;;4722:28;;;;:::i;:::-;4753:3;165:295:33;;;;;;4753:3:44;165:295:33;;;;;;;4715:41:44;:::o;4557:151::-;-1:-1:-1;1370:3:44;165:295:33;;;1377:12:44;1354:35;4618:22;2657:2;165:295:33;;;2663:12:44;2641:34;341:4:43;;;;;;;-1:-1:-1;;;3745:68:44;;3744:74;165:295:33;;-1:-1:-1;4584:115:44;:::o;4644:54::-;4674:24;;;:::i;:::-;4644:54;;5576:193;5669:4;5664:9;;;5660:38;;-1:-1:-1;;341:4:43;;;;;;;5724::44;165:295:33;;;5669:4:44;165:295:33;;;;;;;5724:4:44;341::43;165:295:33;;;;;;;5710:54:44;165:295:33;;;5710:54:44;;:::i;4094:274::-;4219:3;165:295:33;;7449:2:44;165:295:33;;4185:37:44;4184:179;;;;4177:186;4094:274;:::o;4184:179::-;-1:-1:-1;;;4235:68:44;;;4234:128;;4094:274;-1:-1:-1;4094:274:44:o;165:295:33:-;;;;:::o;:::-;;;-1:-1:-1;;;165:295:33;;;;;;;;;;;;;;;;;-1:-1:-1;;;165:295:33;;;;;;;5081:272:44;-1:-1:-1;;;3436:68:44;;3435:75;5171:37;;;:177;;5164:184;5081:272;:::o;5171:177::-;-1:-1:-1;;;5220:68:44;-1:-1:-1;;;5219:128:44;;5081:272;-1:-1:-1;5081:272:44:o;6622:742:8:-;;;;6792:566;;;6819:17;;:::o;6792:566::-;165:295:33;;6937:21:8;:17;;7121:154;;;;;;;6933:415;165:295:33;;;;;;7313:20:8;;165:295:33;7313:20:8;;;165:295:33;;;;;;;;;;6957:1:8;165:295:33;;;;;;;;;6957:1:8;165:295:33;;;;;;;;;;;;;;;7313:20:8;;;;165:295:33;;;;;;;;;;;;;;;;-1:-1:-1;165:295:33;;

Swarm Source

none

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

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.