ETH Price: $2,190.87 (-5.54%)

Transaction Decoder

Block:
20558340 at Aug-18-2024 09:56:11 PM +UTC
Transaction Fee:
0.000164989183880604 ETH $0.36
Gas Used:
186,062 Gas / 0.886743042 Gwei

Emitted Events:

201 ERC1967Proxy.0x3080b7bd2c324f74c283a191b34a0be31e6120cc0e3ab396119bb28365424cb8( 0x3080b7bd2c324f74c283a191b34a0be31e6120cc0e3ab396119bb28365424cb8, 0x000000000000000000000000b56ded72348cde2704d189e95a4d8194994a1003, 000000000000000000000000000000000000000000000000000eb06cb5990af0, 0000000000000000000000000000000000000000000000000000000066c26dfb )
202 ERC1967Proxy.0xbdb350188e9b2a4891f35e6dd30e2edc2663e108b92b7b862873de3c59cba2b5( 0xbdb350188e9b2a4891f35e6dd30e2edc2663e108b92b7b862873de3c59cba2b5, 0x000000000000000000000000b56ded72348cde2704d189e95a4d8194994a1003, 00000000000000000000000000000000000000000000000000000444c48d0f93 )
203 ERC1967Proxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000f965671dec4c8f902083e8e0845cf86aac44fd80, 0x000000000000000000000000b56ded72348cde2704d189e95a4d8194994a1003, 0000000000000000000000000000000000000000000000000000b61914066100 )
204 ERC1967Proxy.0x3627975b28b74f1965a80e230770993136e2e9486705755206c93917dee8581f( 0x3627975b28b74f1965a80e230770993136e2e9486705755206c93917dee8581f, 0x000000000000000000000000b56ded72348cde2704d189e95a4d8194994a1003, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000b61914066100, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
(beaverbuild)
6.084962262994726608 Eth6.084970121332971832 Eth0.000007858338245224
0xb56DeD72...4994A1003
0.001320259823069263 Eth
Nonce: 2
0.001155270639188659 Eth
Nonce: 3
0.000164989183880604
0xD1e64bcc...69b4bcdAe
0xF965671D...aac44FD80
(Pikamoon: Staking Pool)

Execution Trace

ERC1967Proxy.2e17de78( )
  • PikaStakingPool.unstake( _stakeId=0 )
    • ERC1967Proxy.STATICCALL( )
      • PoolController.DELEGATECALL( )
      • ERC1967Proxy.STATICCALL( )
        • PoolController.DELEGATECALL( )
        • ERC1967Proxy.a9059cbb( )
          • PikaMoon.transfer( to=0xb56DeD72348CDE2704d189e95a4D8194994A1003, value=200218826400000 ) => ( True )
            File 1 of 6: ERC1967Proxy
            // SPDX-License-Identifier: MIT
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/utils/StorageSlot.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            
            pragma solidity ^0.8.20;
            
            /**
             * @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:
             * ```solidity
             * 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(newImplementation.code.length > 0);
             *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
             *     }
             * }
             * ```
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
            
                struct BooleanSlot {
                    bool value;
                }
            
                struct Bytes32Slot {
                    bytes32 value;
                }
            
                struct Uint256Slot {
                    uint256 value;
                }
            
                struct StringSlot {
                    string value;
                }
            
                struct BytesSlot {
                    bytes 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
                    }
                }
            
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
            
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
            
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/utils/Address.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @dev Collection of functions related to the address type
             */
            library Address {
                /**
                 * @dev The ETH balance of the account is not enough to perform the operation.
                 */
                error AddressInsufficientBalance(address account);
            
                /**
                 * @dev There's no code at `target` (it is not a contract).
                 */
                error AddressEmptyCode(address target);
            
                /**
                 * @dev A call to an address target failed. The target may have reverted.
                 */
                error FailedInnerCall();
            
                /**
                 * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                 */
                function sendValue(address payable recipient, uint256 amount) internal {
                    if (address(this).balance < amount) {
                        revert AddressInsufficientBalance(address(this));
                    }
            
                    (bool success, ) = recipient.call{value: amount}("");
                    if (!success) {
                        revert FailedInnerCall();
                    }
                }
            
                /**
                 * @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 or custom error, it is bubbled
                 * up by this function (like regular Solidity function calls). However, if
                 * the call reverted with no returned reason, this function reverts with a
                 * {FailedInnerCall} error.
                 *
                 * 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.
                 */
                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, 0);
                }
            
                /**
                 * @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`.
                 */
                function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                    if (address(this).balance < value) {
                        revert AddressInsufficientBalance(address(this));
                    }
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a static call.
                 */
                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a delegate call.
                 */
                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
            
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
                 * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
                 * unsuccessful call.
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata
                ) internal view returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        // only check if target is a contract if the call was successful and the return data is empty
                        // otherwise we already know that it was a contract
                        if (returndata.length == 0 && target.code.length == 0) {
                            revert AddressEmptyCode(target);
                        }
                        return returndata;
                    }
                }
            
                /**
                 * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
                 * revert reason or with a default {FailedInnerCall} error.
                 */
                function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        return returndata;
                    }
                }
            
                /**
                 * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
                 */
                function _revert(bytes memory returndata) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert FailedInnerCall();
                    }
                }
            }
            
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @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.
                 *
                 * {UpgradeableBeacon} will check that this address is a contract.
                 */
                function implementation() external view returns (address);
            }
            
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
            
            pragma solidity ^0.8.20;
            
            
            
            
            /**
             * @dev This abstract contract provides getters and event emitting update functions for
             * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
             */
            library ERC1967Utils {
                // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
                // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
            
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
            
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
            
                /**
                 * @dev Storage slot with the address of the current implementation.
                 * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
            
                /**
                 * @dev The `implementation` of the proxy is invalid.
                 */
                error ERC1967InvalidImplementation(address implementation);
            
                /**
                 * @dev The `admin` of the proxy is invalid.
                 */
                error ERC1967InvalidAdmin(address admin);
            
                /**
                 * @dev The `beacon` of the proxy is invalid.
                 */
                error ERC1967InvalidBeacon(address beacon);
            
                /**
                 * @dev An upgrade function sees `msg.value > 0` that may be lost.
                 */
                error ERC1967NonPayable();
            
                /**
                 * @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 {
                    if (newImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(newImplementation);
                    }
                    StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
                }
            
                /**
                 * @dev Performs implementation upgrade with additional setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-Upgraded} event.
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) internal {
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
            
                    if (data.length > 0) {
                        Address.functionDelegateCall(newImplementation, data);
                    } else {
                        _checkNonPayable();
                    }
                }
            
                /**
                 * @dev Storage slot with the admin of the contract.
                 * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
            
                /**
                 * @dev Returns the current admin.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
                 * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                 */
                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 {
                    if (newAdmin == address(0)) {
                        revert ERC1967InvalidAdmin(address(0));
                    }
                    StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
                }
            
                /**
                 * @dev Changes the admin of the proxy.
                 *
                 * Emits an {IERC1967-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 the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
            
                /**
                 * @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 {
                    if (newBeacon.code.length == 0) {
                        revert ERC1967InvalidBeacon(newBeacon);
                    }
            
                    StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
            
                    address beaconImplementation = IBeacon(newBeacon).implementation();
                    if (beaconImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(beaconImplementation);
                    }
                }
            
                /**
                 * @dev Change the beacon and trigger a setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-BeaconUpgraded} event.
                 *
                 * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
                 * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
                 * efficiency.
                 */
                function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
                    _setBeacon(newBeacon);
                    emit BeaconUpgraded(newBeacon);
            
                    if (data.length > 0) {
                        Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                    } else {
                        _checkNonPayable();
                    }
                }
            
                /**
                 * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
                 * if an upgrade doesn't perform an initialization call.
                 */
                function _checkNonPayable() private {
                    if (msg.value > 0) {
                        revert ERC1967NonPayable();
                    }
                }
            }
            
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/proxy/Proxy.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @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 {
                    _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();
                }
            }
            
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)
            
            pragma solidity ^0.8.20;
            
            
            
            /**
             * @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 {
                /**
                 * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
                 *
                 * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
                 * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
                 *
                 * Requirements:
                 *
                 * - If `data` is empty, `msg.value` must be zero.
                 */
                constructor(address implementation, bytes memory _data) payable {
                    ERC1967Utils.upgradeToAndCall(implementation, _data);
                }
            
                /**
                 * @dev Returns the current implementation address.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
                 * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                 */
                function _implementation() internal view virtual override returns (address) {
                    return ERC1967Utils.getImplementation();
                }
            }

            File 2 of 6: ERC1967Proxy
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)
            pragma solidity ^0.8.20;
            import {Proxy} from "../Proxy.sol";
            import {ERC1967Utils} from "./ERC1967Utils.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 {
                /**
                 * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
                 *
                 * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
                 * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
                 *
                 * Requirements:
                 *
                 * - If `data` is empty, `msg.value` must be zero.
                 */
                constructor(address implementation, bytes memory _data) payable {
                    ERC1967Utils.upgradeToAndCall(implementation, _data);
                }
                /**
                 * @dev Returns the current implementation address.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
                 * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                 */
                function _implementation() internal view virtual override returns (address) {
                    return ERC1967Utils.getImplementation();
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
            pragma solidity ^0.8.20;
            import {IBeacon} from "../beacon/IBeacon.sol";
            import {Address} from "../../utils/Address.sol";
            import {StorageSlot} from "../../utils/StorageSlot.sol";
            /**
             * @dev This abstract contract provides getters and event emitting update functions for
             * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
             */
            library ERC1967Utils {
                // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
                // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
                /**
                 * @dev Storage slot with the address of the current implementation.
                 * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                /**
                 * @dev The `implementation` of the proxy is invalid.
                 */
                error ERC1967InvalidImplementation(address implementation);
                /**
                 * @dev The `admin` of the proxy is invalid.
                 */
                error ERC1967InvalidAdmin(address admin);
                /**
                 * @dev The `beacon` of the proxy is invalid.
                 */
                error ERC1967InvalidBeacon(address beacon);
                /**
                 * @dev An upgrade function sees `msg.value > 0` that may be lost.
                 */
                error ERC1967NonPayable();
                /**
                 * @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 {
                    if (newImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(newImplementation);
                    }
                    StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
                }
                /**
                 * @dev Performs implementation upgrade with additional setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-Upgraded} event.
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) internal {
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
                    if (data.length > 0) {
                        Address.functionDelegateCall(newImplementation, data);
                    } else {
                        _checkNonPayable();
                    }
                }
                /**
                 * @dev Storage slot with the admin of the contract.
                 * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                /**
                 * @dev Returns the current admin.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
                 * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                 */
                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 {
                    if (newAdmin == address(0)) {
                        revert ERC1967InvalidAdmin(address(0));
                    }
                    StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
                }
                /**
                 * @dev Changes the admin of the proxy.
                 *
                 * Emits an {IERC1967-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 the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                /**
                 * @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 {
                    if (newBeacon.code.length == 0) {
                        revert ERC1967InvalidBeacon(newBeacon);
                    }
                    StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
                    address beaconImplementation = IBeacon(newBeacon).implementation();
                    if (beaconImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(beaconImplementation);
                    }
                }
                /**
                 * @dev Change the beacon and trigger a setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-BeaconUpgraded} event.
                 *
                 * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
                 * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
                 * efficiency.
                 */
                function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
                    _setBeacon(newBeacon);
                    emit BeaconUpgraded(newBeacon);
                    if (data.length > 0) {
                        Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                    } else {
                        _checkNonPayable();
                    }
                }
                /**
                 * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
                 * if an upgrade doesn't perform an initialization call.
                 */
                function _checkNonPayable() private {
                    if (msg.value > 0) {
                        revert ERC1967NonPayable();
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)
            pragma solidity ^0.8.20;
            /**
             * @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 {
                    _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();
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            pragma solidity ^0.8.20;
            /**
             * @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:
             * ```solidity
             * 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(newImplementation.code.length > 0);
             *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
             *     }
             * }
             * ```
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                struct StringSlot {
                    string value;
                }
                struct BytesSlot {
                    bytes 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
                    }
                }
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
            pragma solidity ^0.8.20;
            /**
             * @dev Collection of functions related to the address type
             */
            library Address {
                /**
                 * @dev The ETH balance of the account is not enough to perform the operation.
                 */
                error AddressInsufficientBalance(address account);
                /**
                 * @dev There's no code at `target` (it is not a contract).
                 */
                error AddressEmptyCode(address target);
                /**
                 * @dev A call to an address target failed. The target may have reverted.
                 */
                error FailedInnerCall();
                /**
                 * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                 */
                function sendValue(address payable recipient, uint256 amount) internal {
                    if (address(this).balance < amount) {
                        revert AddressInsufficientBalance(address(this));
                    }
                    (bool success, ) = recipient.call{value: amount}("");
                    if (!success) {
                        revert FailedInnerCall();
                    }
                }
                /**
                 * @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 or custom error, it is bubbled
                 * up by this function (like regular Solidity function calls). However, if
                 * the call reverted with no returned reason, this function reverts with a
                 * {FailedInnerCall} error.
                 *
                 * 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.
                 */
                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, 0);
                }
                /**
                 * @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`.
                 */
                function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                    if (address(this).balance < value) {
                        revert AddressInsufficientBalance(address(this));
                    }
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a static call.
                 */
                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a delegate call.
                 */
                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
                 * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
                 * unsuccessful call.
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata
                ) internal view returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        // only check if target is a contract if the call was successful and the return data is empty
                        // otherwise we already know that it was a contract
                        if (returndata.length == 0 && target.code.length == 0) {
                            revert AddressEmptyCode(target);
                        }
                        return returndata;
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
                 * revert reason or with a default {FailedInnerCall} error.
                 */
                function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        return returndata;
                    }
                }
                /**
                 * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
                 */
                function _revert(bytes memory returndata) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert FailedInnerCall();
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
            pragma solidity ^0.8.20;
            /**
             * @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.
                 *
                 * {UpgradeableBeacon} will check that this address is a contract.
                 */
                function implementation() external view returns (address);
            }
            

            File 3 of 6: PikaStakingPool
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.20;
            import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
            import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
            import "./CorePool.sol";
            contract PikaStakingPool is Initializable, UUPSUpgradeable, CorePool {
                /// @custom:oz-upgrades-unsafe-allow constructor
                constructor() {
                    _disableInitializers();
                }
                function initialize(
                    address _poolToken,
                    address _rewardToken,
                    address _poolController,
                    uint256 _weight
                ) external initializer {
                    __Ownable_init(msg.sender);
                    __Pausable_init();
                    __UUPSUpgradeable_init();
                    __CorePool_init(
                        _poolToken,
                        _rewardToken,
                        _poolController,
                        _weight
                    );
                }
                /**
                 * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                 * {upgradeToAndCall}.
                 */
                function _authorizeUpgrade(
                    address newImplementation
                ) internal override onlyOwner {}
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.20;
            import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
            import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
            import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
            import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
            import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
            import {IPikaMoon} from "./interfaces/IPikaMoon.sol";
            import {Stake} from "./libraries/Stake.sol";
            import {CommonErrors} from "./libraries/Errors.sol";
            import {ICorePool} from "./interfaces/ICorePool.sol";
            import {IPoolController} from "./interfaces/IPoolController.sol";
            contract CorePool is
                OwnableUpgradeable,
                PausableUpgradeable,
                ICorePool,
                ReentrancyGuardUpgradeable
            {
                using Stake for Stake.Data;
                using Stake for uint256;
                using SafeERC20 for IPikaMoon;
                /// @dev Data structure representing token holder.
                struct User {
                    /// @dev pending rewards rewards to be claimed
                    uint256 pendingRewards;
                    /// @dev Total weight
                    uint256 userTotalWeight;
                    /// @dev Checkpoint variable for rewards calculation
                    uint256 rewardsPerWeightPaid;
                    /// @dev An array of holder's stakes
                    Stake.Data[] stakes;
                }
                /// @dev Used to calculate rewards.
                /// @dev Note: stakes are different in duration and "weight" reflects that.
                /// @dev updates in the _sync function
                uint256 public rewardsPerWeight;
                /// @dev Timestamp of the last rewards distribution event.
                uint256 public lastRewardsDistribution;
                /// @dev Link to the pool token instance, for example PIKA or PIKA/USDT pair LP token.
                address public poolToken;
                /// @dev Link to the reward token instance, for example PIKA
                address public rewardToken;
                /// @dev Link to the pool controller IPoolController instance.
                address public poolController;
                /// @dev verifier Address for ECDSA claim verification.
                address public verifierAddress;
                /**  @notice you can lock your tokens for a period between 1 and 12 months.
                 * This changes your token weight. By increasing the duration of your lock,
                 * you will increase the token weight of the locked tokens.
                 * The maximum weight of a locked token is 2 ,
                 * which occurs when you lock for a period of 12 months.
                 * @dev Pool weight, initial values are 200 for PIKA pool and 800 for PIKA/USDT.
                 */
                uint256 public weight;
                /// @dev Used to calculate rewards, keeps track of the tokens weight locked in staking.
                uint256 public globalStakeWeight;
                /// @dev total pool token reserve. PIKA or PIKA/USDT pair LP token.
                uint256 public totalTokenStaked;
                /// @dev upper Bound percentage for early unstake penalty.
                uint256 public upperBoundSlash;
                /// @dev lower Bound percentage for early unstake penalty.
                uint256 public lowerBoundSlash;
                uint256 private multiplier; // 1000 = 100%
                uint32 private constant COOLDOWN_PERIOD = 30 days;
                /// @dev Token holder storage, maps token holder address to their data record.
                mapping(address => User) public users;
                /// @dev mapping to prevent signature replay
                mapping(bytes32 => bool) public signatureUsed;
                mapping(address => uint256) public coolOffPeriod;
                function __CorePool_init(
                    address _poolToken,
                    address _rewardToken,
                    address _poolController,
                    uint256 _weight
                ) internal onlyInitializing {
                    if (_poolToken == address(0)) {
                        revert CommonErrors.ZeroAddress();
                    }
                    if (_rewardToken == address(0)) {
                        revert CommonErrors.ZeroAddress();
                    }
                    if (_poolController == address(0)) {
                        revert CommonErrors.ZeroAddress();
                    }
                    verifierAddress = owner();
                    //PIKA or PIKA/USDT pair LP token address.
                    poolToken = _poolToken;
                    //PIKA token address.
                    rewardToken = _rewardToken;
                    /// pool controller IPoolController instance.
                    poolController = _poolController;
                    // init the dependent state variables
                    lastRewardsDistribution = _now256();
                    // direct staking weight 200 and lp staking 800
                    weight = _weight;
                    upperBoundSlash = 900; // 90%
                    lowerBoundSlash = 100; // 10%
                    multiplier = 1000; // 100%
                }
                /**
                 * @notice Stakes specified value of tokens for the specified value of time,
                 *      and pays pending rewards rewards if any.
                 *
                 * @dev Requires value to stake and lock duration to be greater than zero.
                 *
                 * @param _value value of tokens to stake
                 * @param _lockDuration stake duration as unix timestamp
                 */
                function stake(
                    uint256 _value,
                    uint256 _lockDuration
                ) external nonReentrant {
                    // checks if the contract is in a paused state
                    if (paused()) revert CommonErrors.ContractIsPaused();
                    // validate the _value
                    if (_value == 0) revert CommonErrors.ZeroAmount();
                    // validate the _lockDuration
                    if (
                        !(_lockDuration >= Stake.MIN_STAKE_PERIOD &&
                            _lockDuration <= Stake.MAX_STAKE_PERIOD)
                    ) {
                        revert CommonErrors.InvalidLockDuration();
                    }
                    // get a link to user data struct, we will write to it later
                    User storage user = users[msg.sender];
                    // update user state
                    _updateReward(msg.sender);
                    // calculates until when a stake is going to be locked
                    uint256 lockUntil = _now256() + _lockDuration;
                    // calculate stake weight. same as weight function in stake.sol library
                    uint256 stakeWeight = (((lockUntil - _now256()) *
                        Stake.WEIGHT_MULTIPLIER) /
                        Stake.MAX_STAKE_PERIOD +
                        Stake.BASE_WEIGHT) * _value;
                    // makes sure stakeWeight is valid
                    require(stakeWeight > 0);
                    // create and save the stake (append it to stakes array)
                    Stake.Data memory userStake = Stake.Data({
                        stakeId: user.stakes.length,
                        value: _value,
                        lockedFrom: _now256(),
                        lockedUntil: lockUntil,
                        isUnstaked: false
                    });
                    // pushes new stake to `stakes` array
                    user.stakes.push(userStake);
                    // update user weight
                    user.userTotalWeight += stakeWeight;
                    // update global weight value
                    globalStakeWeight += stakeWeight;
                    // update pool reserve
                    totalTokenStaked += _value;
                    // transfer `_value` to this contract
                    IPikaMoon(poolToken).safeTransferFrom(
                        msg.sender,
                        address(this),
                        _value
                    );
                    // emits an event
                    emit LogStake(msg.sender, (user.stakes.length - 1), _value, lockUntil);
                }
                function stakeAsPool(
                    address _staker,
                    uint256 _value
                ) external nonReentrant {
                    // checks if the contract is in a paused state
                    if (paused()) revert CommonErrors.ContractIsPaused();
                    IPoolController _controller = IPoolController(poolController);
                    if (!_controller.poolExists(msg.sender)) {
                        revert CommonErrors.UnAuthorized();
                    }
                    // gets storage pointer to user
                    User storage user = users[_staker];
                    // update user state
                    _updateReward(_staker);
                    uint256 lockUntil = _now256() + Stake.MAX_STAKE_PERIOD;
                    uint256 stakeWeight = (((lockUntil - _now256()) *
                        Stake.WEIGHT_MULTIPLIER) /
                        Stake.MAX_STAKE_PERIOD +
                        Stake.BASE_WEIGHT) * _value;
                    // initialize new yield stake being created in memory
                    Stake.Data memory newStake = Stake.Data({
                        stakeId: user.stakes.length,
                        value: _value,
                        lockedFrom: _now256(),
                        lockedUntil: lockUntil,
                        isUnstaked: false
                    });
                    // sum new yield stake weight to user's total weight
                    user.userTotalWeight += stakeWeight;
                    // add the new yield stake to storage
                    user.stakes.push(newStake);
                    // update global weight and global pool token count
                    globalStakeWeight += stakeWeight;
                    totalTokenStaked += _value;
                    IPoolController(poolController).transferRewardTokens(
                        rewardToken,
                        address(this),
                        _value
                    );
                    // emits an event
                    emit LogStake(_staker, (user.stakes.length - 1), _value, lockUntil);
                }
                /**
                 * @dev Unstakes a stake that has been previously locked, and is now in an unlocked
                 *      state if user tries to early unstake he is slashed according to percentage of time calculations
                 *      restricted by upper and lower bound
                 *
                 * @param _stakeId stake ID to unstake from, zero-indexed
                 */
                function unstake(uint256 _stakeId) external {
                    // checks if the contract is in a paused state
                    if (paused()) revert CommonErrors.ContractIsPaused();
                    // get a link to user data struct, we will write to it later
                    User storage user = users[msg.sender];
                    // update user state
                    _updateReward(msg.sender);
                    // get a link to the corresponding stake, we may write to it later
                    Stake.Data storage userStake = user.stakes[_stakeId];
                    uint256 stakeValue = userStake.value;
                    if (user.stakes[_stakeId].isUnstaked) {
                        revert CommonErrors.AlreadyUnstaked();
                    }
                    // store stake weight
                    uint256 previousWeight = userStake.weight();
                    // update user record
                    user.userTotalWeight = user.userTotalWeight - previousWeight;
                    // update global weight variable
                    globalStakeWeight = globalStakeWeight - previousWeight;
                    // update global pool token count
                    totalTokenStaked -= stakeValue;
                    // mark stake struct as unstaked
                    user.stakes[_stakeId].isUnstaked = true;
                    // checks if stake is unlocked already
                    if (_now256() < userStake.lockedUntil) {
                        uint256 earlyUnstakePercentage = calculateEarlyUnstakePercentage(
                            userStake.lockedFrom,
                            _now256(),
                            userStake.lockedUntil
                        );
                        uint256 unstakeValue = stakeValue -
                            ((stakeValue * earlyUnstakePercentage) / multiplier);
                        // transfer slash amount
                        IPikaMoon(poolToken).safeTransfer(
                            poolController,
                            stakeValue - unstakeValue
                        );
                        // return user stake
                        IPikaMoon(poolToken).safeTransfer(msg.sender, unstakeValue);
                        // emits an event
                        emit LogUnstake(
                            msg.sender,
                            _stakeId,
                            unstakeValue,
                            earlyUnstakePercentage,
                            true
                        );
                    } else {
                        // return user stake
                        IPikaMoon(poolToken).safeTransfer(msg.sender, stakeValue);
                        // emits an event
                        emit LogUnstake(msg.sender, _stakeId, stakeValue, 0, false);
                    }
                }
                /**
                 * @notice Calculates the penalty percentage for early unstaking based on the remaining locked time
                 * @dev This function returns a penalty percentage scaled by `multiplier`. The function applies bounds to the penalty, ensuring it does not fall below `lowerBoundSlash` or exceed `upperBoundSlash`.
                 * @param lockedFrom The timestamp when the stake was locked
                 * @param nowTime The current timestamp, representing the moment of the unstaking request
                 * @param lockedUntil The timestamp until which the stake was meant to be locked
                 * @return penaltyPercentage The penalty percentage for unstaking early, scaled by `multiplier`. If the stake period has ended, returns 0.
                 */
                function calculateEarlyUnstakePercentage(
                    uint256 lockedFrom,
                    uint256 nowTime,
                    uint256 lockedUntil
                ) public view returns (uint256) {
                    if (nowTime <= lockedUntil) {
                        uint256 percentageToSlash = (((lockedUntil - nowTime)) *
                            multiplier) / (lockedUntil - lockedFrom);
                        if (percentageToSlash < lowerBoundSlash) {
                            return lowerBoundSlash;
                        } else if (percentageToSlash > upperBoundSlash) {
                            return upperBoundSlash;
                        } else {
                            return percentageToSlash;
                        }
                    } else {
                        return 0;
                    }
                }
                /**
                 * @dev Prefixes a bytes32 hash with the string "\\x19Ethereum Signed Message:\
            32" and then hashes the result.
                 * This is used to conform with the Ethereum signing standard (EIP-191).
                 * @param hash The original hash that needs to be prefixed and rehashed.
                 * @return The prefixed and rehashed bytes32 value.
                 */
                function prefixed(bytes32 hash) internal pure returns (bytes32) {
                    return
                        keccak256(
                            abi.encodePacked("\\x19Ethereum Signed Message:\
            32", hash)
                        );
                }
                /**
                 * @notice Claims a percentage of the accrued rewards for the caller
                 * @dev This function handles the claim process by validating the signature and calculating the reward percentage
                 * @param _claimPercentage The percentage of the pending rewards to claim, scaled by the MULTIPLIER
                 * @param _signature Cryptographic signature to verify the authenticity of the claim
                 * @param nonce A unique identifier to prevent replay attacks
                 */
                function claimRewards(
                    uint256 _claimPercentage,
                    bool _restakeLeftOver,
                    bytes calldata _signature,
                    uint256 nonce
                ) external {
                    // lock duration recommended to be of 1 year to mitigate protocol abuse
                    // checks if the contract is in a paused state
                    if (paused()) revert CommonErrors.ContractIsPaused();
                    require(_claimPercentage <= multiplier);
                    if (!_restakeLeftOver && _claimPercentage != 0) {
                        if (_now256() < coolOffPeriod[msg.sender] + COOLDOWN_PERIOD) {
                            revert CommonErrors.CoolOffPeriodIsNotOver();
                        }
                    }
                    coolOffPeriod[msg.sender] = _now256(); // Update the last claim time
                    bytes32 message = prefixed(
                        keccak256(
                            abi.encodePacked(
                                msg.sender,
                                _claimPercentage,
                                _restakeLeftOver,
                                nonce
                            )
                        )
                    );
                    require(!signatureUsed[message]);
                    signatureUsed[message] = true;
                    if (ECDSA.recover(message, _signature) != verifierAddress) {
                        revert CommonErrors.WrongHash();
                    }
                    // update user state
                    _updateReward(msg.sender);
                    // get link to a user data structure, we will write into it later
                    User storage user = users[msg.sender];
                    // if pending rewards is zero revert
                    if (user.pendingRewards == 0) return;
                    if (_claimPercentage == 0 && !_restakeLeftOver) {
                        revert CommonErrors.InvalidOperation();
                    }
                    if (_claimPercentage != 0) {
                        uint256 toClaim = (user.pendingRewards * _claimPercentage) /
                            multiplier;
                        user.pendingRewards -= toClaim;
                        // transfer pending rewards to staker
                        IPoolController(poolController).transferRewardTokens(
                            rewardToken,
                            msg.sender,
                            toClaim
                        );
                        // emits an event
                        emit LogClaimRewards(msg.sender, toClaim);
                    }
                    if (_restakeLeftOver && _claimPercentage < multiplier) {
                        if (poolToken == rewardToken) {
                            uint256 pendingRewardsToClaim = user.pendingRewards;
                            user.pendingRewards = 0;
                            // calculates until when a stake is going to be locked
                            uint256 lockUntil = _now256() + Stake.MAX_STAKE_PERIOD;
                            // calculate stake weight. same as weight function in stake.sol library
                            uint256 stakeWeight = (((lockUntil - _now256()) *
                                Stake.WEIGHT_MULTIPLIER) /
                                Stake.MAX_STAKE_PERIOD +
                                Stake.BASE_WEIGHT) * pendingRewardsToClaim;
                            // makes sure stakeWeight is valid
                            require(stakeWeight > 0);
                            // create and save the stake (append it to stakes array)
                            Stake.Data memory userStake = Stake.Data({
                                stakeId: user.stakes.length,
                                value: pendingRewardsToClaim,
                                lockedFrom: _now256(),
                                lockedUntil: lockUntil,
                                isUnstaked: false
                            });
                            // pushes new stake to `stakes` array
                            user.stakes.push(userStake);
                            // update user weight
                            user.userTotalWeight += stakeWeight;
                            // update global weight value
                            globalStakeWeight += stakeWeight;
                            // update pool reserve
                            totalTokenStaked += pendingRewardsToClaim;
                            IPoolController(poolController).transferRewardTokens(
                                rewardToken,
                                address(this),
                                pendingRewardsToClaim
                            );
                            // emits an event
                            emit LogStake(
                                msg.sender,
                                (user.stakes.length - 1),
                                pendingRewardsToClaim,
                                lockUntil
                            );
                        } else {
                            uint256 pendingRewardsToClaim = user.pendingRewards;
                            user.pendingRewards = 0;
                            address poolAddress = IPoolController(poolController).pools(rewardToken);
                            ICorePool(poolAddress)
                                .stakeAsPool(msg.sender, pendingRewardsToClaim);
                        }
                    }
                }
                /**
                 * @notice Calculates current rewards rewards value available for address specified.
                 * @param _staker an address to calculate rewards rewards value for
                 */
                function pendingRewards(
                    address _staker
                ) external view returns (uint256 _pendingRewards) {
                    if (_staker == address(0)) revert CommonErrors.ZeroAddress();
                    // `newrewardsPerWeight` will be the stored or recalculated value for `rewardsPerWeight`
                    uint256 newrewardsPerWeight;
                    // gas savings
                    uint256 _lastRewardsDistribution = lastRewardsDistribution;
                    // based on the rewards per weight value, calculate pending rewards;
                    // storage takes less gas
                    User storage user = users[_staker];
                    // initializes both variables from one storage slot
                    uint256 userWeight = user.userTotalWeight;
                    // if smart contract state was not updated recently, `rewardsPerWeight` value
                    // is outdated and we need to recalculate it in order to calculate pending rewards correctly
                    if (_now256() > _lastRewardsDistribution && globalStakeWeight != 0) {
                        IPoolController _controller = IPoolController(poolController);
                        uint256 secondsPassed = _now256() - _lastRewardsDistribution;
                        uint256 pikaRewards = (secondsPassed *
                            _controller.pikaPerSecond() *
                            weight) / _controller.totalWeight();
                        // recalculated value for `rewardsPerWeight`
                        newrewardsPerWeight =
                            pikaRewards.getRewardPerWeight((globalStakeWeight)) +
                            rewardsPerWeight;
                    } else {
                        // if smart contract state is up to date, we don't recalculate
                        newrewardsPerWeight = rewardsPerWeight;
                    }
                    _pendingRewards =
                        (userWeight).earned(
                            newrewardsPerWeight,
                            user.rewardsPerWeightPaid
                        ) +
                        user.pendingRewards;
                }
                /**
                 * @dev Must be called every time user.userTotalWeight is changed.
                 * @dev Syncs the global pool state, processes the user pending rewards (if any),
                 *      and updates check points values stored in the user struct.
                 * @dev If user is coming from v1 pool, it expects to receive this v1 user weight
                 *      to include in rewards calculations.
                 *
                 * @param _staker user address
                 */
                function _updateReward(address _staker) internal {
                    // update pool state
                    _sync();
                    // gets storage reference to the user
                    User storage user = users[_staker];
                    // gas savings
                    uint256 userTotalWeight = user.userTotalWeight;
                    // calculates pending rewards to be added
                    uint256 _rewards = userTotalWeight.earned(
                        rewardsPerWeight,
                        user.rewardsPerWeightPaid
                    );
                    // calculates pending reenue distribution to be added
                    // increases stored user.rewards with value returned
                    user.pendingRewards += _rewards;
                    // updates user checkpoint values for future calculations
                    user.rewardsPerWeightPaid = rewardsPerWeight;
                    // emits an event
                    emit LogUpdateRewards(_staker, _rewards);
                }
                /**
                 *
                 * @dev Updates smart contract state (`rewardsPerWeight`, `lastRewardsDistribution`),
                 *      updates state via `updatePIKAPerSecond`
                 */
                function _sync() internal {
                    IPoolController _poolController = IPoolController(poolController);
                    if (_now256() <= lastRewardsDistribution) {
                        return;
                    }
                    // if globalStakeWeight is zero - update only `lastRewardsDistribution` and exit
                    if (globalStakeWeight == 0) {
                        lastRewardsDistribution = _now256();
                        return;
                    }
                    // to calculate the reward we need to know how many seconds passed, and reward per second
                    uint256 currentTimestamp = _now256();
                    uint256 secondsPassed = currentTimestamp - lastRewardsDistribution;
                    // calculate the reward
                    uint256 pikaReward = (secondsPassed *
                        _poolController.pikaPerSecond() *
                        weight) / _poolController.totalWeight();
                    // update rewards per weight and `lastRewardsDistribution`
                    rewardsPerWeight += pikaReward.getRewardPerWeight(globalStakeWeight);
                    lastRewardsDistribution = currentTimestamp;
                    // emits an event
                    emit LogSync(msg.sender, rewardsPerWeight, lastRewardsDistribution);
                }
                /**
                 * @notice Service function to synchronize pool state with current time.
                 *
                 * @dev Can be executed by anyone at any time, but has an effect only when
                 *      at least one second passes between synchronizations.
                 * @dev Executed internally when staking, unstaking, processing rewards in order
                 *      for calculations to be correct and to reflect state progress of the contract.
                 * @dev When timing conditions are not met (executed too frequently, or after pool Controller
                 *      end time), function doesn't throw and exits silently.
                 */
                function sync() external {
                    // checks if the contract is in a paused state
                    if (paused()) revert CommonErrors.ContractIsPaused();
                    // calls internal function
                    _sync();
                }
                /**
                 * @dev Executed by the pool Controller to modify pool weight; the pool Controller is expected
                 *      to keep track of the total pools weight when updating.
                 *
                 * @dev Set weight to zero to disable the pool.
                 *
                 * @param _weight new weight to set for the pool
                 */
                function setWeight(uint256 _weight) external {
                    if (msg.sender != poolController) {
                        revert CommonErrors.OnlyFactory();
                    }
                    // update pool state using current weight value
                    _sync();
                    // set the new weight value
                    weight = _weight;
                }
                /**
                 * @dev Set paused/unpaused state in the staking contract.
                 * @param _shouldPause whether the contract should be paused/unpausd
                 */
                function pause(bool _shouldPause) external onlyOwner {
                    if (_shouldPause) {
                        _pause();
                    } else {
                        _unpause();
                    }
                }
                /**
                 * @dev set verification address for ECDSA claim verification.
                 * @param _verifierAddress verifier Address
                 */
                function setVerifierAddress(address _verifierAddress) external onlyOwner {
                    if (_verifierAddress == address(0)) revert CommonErrors.ZeroAddress();
                    emit LogVerificationAddress(_verifierAddress, verifierAddress);
                    verifierAddress = _verifierAddress;
                }
                /**
                 * @notice Returns total staked token balance for the given address.
                 * @dev Loops through stakes and returns total balance.
                 * @notice Expected to be called externally through `eth_call`. Gas shouldn't
                 *         be an issue here.
                 *
                 * @param _user an address to query balance for
                 * @return balance total staked token balance
                 */
                function balanceOf(address _user) external view returns (uint256 balance) {
                    // gets storage pointer to _user
                    // storage takes less gas
                    User storage user = users[_user];
                    // calculate length
                    uint256 len = user.stakes.length;
                    // loops over each user stake and adds to the total balance.
                    for (uint256 i; i < len; i++) {
                        if (!user.stakes[i].isUnstaked) {
                            balance += user.stakes[i].value;
                        }
                    }
                }
                /**
                 * @notice Returns number of stakes for the given address. Allows iteration over stakes.
                 *
                 * @dev See `getStake()`.
                 *
                 * @param _user an address to query stake length for
                 * @return number of stakes for the given address
                 */
                function getStakesLength(address _user) external view returns (uint256) {
                    // read stakes array length and return
                    return users[_user].stakes.length;
                }
                /**
                 * @notice Returns information on the given stake for the given address.
                 *
                 * @dev See getStakesLength.
                 *
                 * @param _user an address to query stake for
                 * @param _stakeId zero-indexed stake ID for the address specified
                 * @return stake info as Stake structure
                 */
                function getStake(
                    address _user,
                    uint256 _stakeId
                ) external view returns (Stake.Data memory) {
                    // read stake at specified index and return
                    return users[_user].stakes[_stakeId];
                }
                /**
                 * @dev Get paginated stake information for a specific user
                 *
                 * This function allows querying stake information for a specific user in a paginated manner.
                 * Users can specify a start index and a count to retrieve a subset of the user's stakes.
                 *
                 * @param _user The address of the user to query stake information for
                 * @param startIndex The start index of the paginated results (zero-indexed)
                 * @param count The number of stake entries to retrieve
                 *
                 * @return result An array of Stake.Data structures containing paginated stake information
                 */
                function getPaginatedStake(
                    address _user,
                    uint startIndex,
                    uint count
                ) external view returns (Stake.Data[] memory result) {
                    // storage takes less gas
                    Stake.Data[] storage data = users[_user].stakes;
                    uint len = data.length;
                    // Ensure that we are not starting the pagination out of the bounds of the array
                    if (startIndex >= len) return result;
                    // Calculate the actual number of items we can return
                    uint length = count;
                    if (startIndex + count > len) {
                        length = len - startIndex;
                    }
                    // Allocate memory for the result array
                    result = new Stake.Data[](length);
                    // Populate the result array with the relevant data
                    for (uint i = 0; i < length; ) {
                        result[i] = data[startIndex + i];
                        unchecked {
                            ++i;
                        }
                    }
                    return result;
                }
                /**
                 * @dev Testing time-dependent functionality is difficult and the best way of
                 *      doing it is to override time in helper test smart contracts.
                 *
                 * @return `block.timestamp` in mainnet, custom values in testnets (if overridden).
                 */
                function _now256() internal view virtual returns (uint256) {
                    // return current block timestamp
                    return block.timestamp;
                }
                /**
                 * @dev Empty reserved space in storage. The size of the __gap array is calculated so that
                 *      the amount of storage used by a contract always adds up to the 50.
                 *      See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[37] private __gap;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
            pragma solidity ^0.8.20;
            import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
            import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
            import {Initializable} from "./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.
             */
            abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
                /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
                address private immutable __self = address(this);
                /**
                 * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
                 * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
                 * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
                 * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
                 * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
                 * during an upgrade.
                 */
                string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
                /**
                 * @dev The call is from an unauthorized context.
                 */
                error UUPSUnauthorizedCallContext();
                /**
                 * @dev The storage `slot` is unsupported as a UUID.
                 */
                error UUPSUnsupportedProxiableUUID(bytes32 slot);
                /**
                 * @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() {
                    _checkProxy();
                    _;
                }
                /**
                 * @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() {
                    _checkNotDelegated();
                    _;
                }
                function __UUPSUpgradeable_init() internal onlyInitializing {
                }
                function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
                }
                /**
                 * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
                 * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
                 *
                 * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                 * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                 * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
                 */
                function proxiableUUID() external view virtual notDelegated returns (bytes32) {
                    return ERC1967Utils.IMPLEMENTATION_SLOT;
                }
                /**
                 * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
                 * encoded in `data`.
                 *
                 * Calls {_authorizeUpgrade}.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
                    _authorizeUpgrade(newImplementation);
                    _upgradeToAndCallUUPS(newImplementation, data);
                }
                /**
                 * @dev Reverts if the execution is not performed via delegatecall or the execution
                 * context is not of a proxy with an ERC1967-compliant implementation pointing to self.
                 * See {_onlyProxy}.
                 */
                function _checkProxy() internal view virtual {
                    if (
                        address(this) == __self || // Must be called through delegatecall
                        ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
                    ) {
                        revert UUPSUnauthorizedCallContext();
                    }
                }
                /**
                 * @dev Reverts if the execution is performed via delegatecall.
                 * See {notDelegated}.
                 */
                function _checkNotDelegated() internal view virtual {
                    if (address(this) != __self) {
                        // Must not be called through delegatecall
                        revert UUPSUnauthorizedCallContext();
                    }
                }
                /**
                 * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                 * {upgradeToAndCall}.
                 *
                 * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                 *
                 * ```solidity
                 * function _authorizeUpgrade(address) internal onlyOwner {}
                 * ```
                 */
                function _authorizeUpgrade(address newImplementation) internal virtual;
                /**
                 * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
                 *
                 * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
                 * is expected to be the implementation slot in ERC1967.
                 *
                 * Emits an {IERC1967-Upgraded} event.
                 */
                function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
                    try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                        if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
                            revert UUPSUnsupportedProxiableUUID(slot);
                        }
                        ERC1967Utils.upgradeToAndCall(newImplementation, data);
                    } catch {
                        // The implementation is not UUPS
                        revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
            pragma solidity ^0.8.20;
            /**
             * @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]
             * ```solidity
             * 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 Storage of the initializable contract.
                 *
                 * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
                 * when using with upgradeable contracts.
                 *
                 * @custom:storage-location erc7201:openzeppelin.storage.Initializable
                 */
                struct InitializableStorage {
                    /**
                     * @dev Indicates that the contract has been initialized.
                     */
                    uint64 _initialized;
                    /**
                     * @dev Indicates that the contract is in the process of being initialized.
                     */
                    bool _initializing;
                }
                // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
                bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
                /**
                 * @dev The contract is already initialized.
                 */
                error InvalidInitialization();
                /**
                 * @dev The contract is not initializing.
                 */
                error NotInitializing();
                /**
                 * @dev Triggered when the contract has been initialized or reinitialized.
                 */
                event Initialized(uint64 version);
                /**
                 * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                 * `onlyInitializing` functions can be used to initialize parent contracts.
                 *
                 * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
                 * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
                 * production.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier initializer() {
                    // solhint-disable-next-line var-name-mixedcase
                    InitializableStorage storage $ = _getInitializableStorage();
                    // Cache values to avoid duplicated sloads
                    bool isTopLevelCall = !$._initializing;
                    uint64 initialized = $._initialized;
                    // Allowed calls:
                    // - initialSetup: the contract is not in the initializing state and no previous version was
                    //                 initialized
                    // - construction: the contract is initialized at version 1 (no reininitialization) and the
                    //                 current contract is just being deployed
                    bool initialSetup = initialized == 0 && isTopLevelCall;
                    bool construction = initialized == 1 && address(this).code.length == 0;
                    if (!initialSetup && !construction) {
                        revert InvalidInitialization();
                    }
                    $._initialized = 1;
                    if (isTopLevelCall) {
                        $._initializing = true;
                    }
                    _;
                    if (isTopLevelCall) {
                        $._initializing = false;
                        emit Initialized(1);
                    }
                }
                /**
                 * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                 * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                 * used to initialize parent contracts.
                 *
                 * A reinitializer may be used after the original initialization step. This is essential to configure modules that
                 * are added through upgrades and that require initialization.
                 *
                 * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
                 * cannot be nested. If one is invoked in the context of another, execution will revert.
                 *
                 * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                 * a contract, executing them in the right order is up to the developer or operator.
                 *
                 * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier reinitializer(uint64 version) {
                    // solhint-disable-next-line var-name-mixedcase
                    InitializableStorage storage $ = _getInitializableStorage();
                    if ($._initializing || $._initialized >= version) {
                        revert InvalidInitialization();
                    }
                    $._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() {
                    _checkInitializing();
                    _;
                }
                /**
                 * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
                 */
                function _checkInitializing() internal view virtual {
                    if (!_isInitializing()) {
                        revert NotInitializing();
                    }
                }
                /**
                 * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                 * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                 * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                 * through proxies.
                 *
                 * Emits an {Initialized} event the first time it is successfully executed.
                 */
                function _disableInitializers() internal virtual {
                    // solhint-disable-next-line var-name-mixedcase
                    InitializableStorage storage $ = _getInitializableStorage();
                    if ($._initializing) {
                        revert InvalidInitialization();
                    }
                    if ($._initialized != type(uint64).max) {
                        $._initialized = type(uint64).max;
                        emit Initialized(type(uint64).max);
                    }
                }
                /**
                 * @dev Returns the highest version that has been initialized. See {reinitializer}.
                 */
                function _getInitializedVersion() internal view returns (uint64) {
                    return _getInitializableStorage()._initialized;
                }
                /**
                 * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
                 */
                function _isInitializing() internal view returns (bool) {
                    return _getInitializableStorage()._initializing;
                }
                /**
                 * @dev Returns a pointer to the storage namespace.
                 */
                // solhint-disable-next-line var-name-mixedcase
                function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
                    assembly {
                        $.slot := INITIALIZABLE_STORAGE
                    }
                }
            }
            // SPDX-License-Identifier: UNLICENSED
            pragma solidity 0.8.20;
            interface IPoolController {
                function owner() external view returns (address);
                function pikaPerSecond() external view returns (uint192);
                function totalWeight() external view returns (uint32);
                function transferRewardTokens(
                    address _token,
                    address _to,
                    uint256 _value
                ) external;
                function changePoolWeight(address pool, uint32 weight) external;
                function pools(address _poolToken) external view returns (address);
                function poolExists(address _poolAddress) external view returns (bool);
            }
            // SPDX-License-Identifier: UNLICENSED
            pragma solidity 0.8.20;
            import "../libraries/Stake.sol";
            interface ICorePool {
                /* ========== MUTATIVE FUNCTIONS ========== */
                function stake(uint256 _value, uint256 _lockDuration) external;
                    function poolToken() external view returns (address);
            function stakeAsPool(address _staker, uint256 _value) external ;
                function unstake(uint256 _stakeId) external;
                function claimRewards(
                    uint256 _claimPercentage,
                    bool _restakeLeftOver,
                    bytes memory _signature,
                    uint256 _nonce
                ) external;
                function sync() external;
                function setWeight(uint256 _weight) external;
                /* ========== RESTRICTED FUNCTIONS ========== */
                function pause(bool _shouldPause) external;
                /* ========== READ FUNCTIONS ========== */
                function pendingRewards(
                    address _staker
                ) external view returns (uint256 pendingYield);
                function balanceOf(address _user) external view returns (uint256 balance);
                function getStakesLength(address _user) external view returns (uint256);
                function getStake(
                    address _user,
                    uint256 _stakeId
                ) external view returns (Stake.Data memory);
                function weight() external view returns (uint256);
                /* ========== EVENTS ========== */
                /**
                 * @dev Fired in _stake() and stakeAsPool() in PIKAPool contract.
                 * @param from token holder address, the tokens will be returned to that address
                 * @param stakeId id of the new stake created
                 * @param value value of tokens staked
                 * @param lockUntil timestamp indicating when tokens should unlock (max 2 years)
                 */
                event LogStake(
                    address indexed from,
                    uint256 stakeId,
                    uint256 value,
                    uint256 lockUntil
                );
                /**
                 * @dev Fired in `_updateRewards()`.
                 *
                 * @param from an address which received the yield
                 * @param yieldValue value of yield processed
                 */
                event LogUpdateRewards(address indexed from, uint256 yieldValue);
                /**
                 * @dev Fired in `unstake()`.
                 *
                 * @param to address receiving the tokens (user)
                 * @param stakeId id value of the stake
                 * @param value number of tokens unstaked
                 */
                event LogUnstake(
                    address indexed to,
                    uint256 stakeId,
                    uint256 value,
                    uint256 earlyUnstakePercentage,
                    bool isEarlyUnstake
                );
                /**
                 * @dev Fired in `updatePIKAPerSecond()`.
                 *
                 * @param by an address which executed an action
                 * @param newPIKAPerSecond new PIKA/second value
                 */
                event LogUpdatePikaPerSecond(address indexed by, uint256 newPIKAPerSecond);
                /**
                 * @dev Fired in `_sync()` and dependent functions (stake, unstake, etc.).
                 *
                 * @param by an address which performed an operation
                 * @param yieldRewardsPerWeight updated yield rewards per weight value
                 * @param lastYieldDistribution usually, current timestamp
                 */
                event LogSync(
                    address indexed by,
                    uint256 yieldRewardsPerWeight,
                    uint256 lastYieldDistribution
                );
                /**
                 * @dev Fired in `updatePIKAPerSecond()`.
                 *
                 * @param by an address which executed an action
                 * @param newPikaPerSecond new PIKA/second value
                 */
                event LogUpdatePIKAPerSecond(address indexed by, uint256 newPikaPerSecond);
                /**
                 * @dev Fired in `_claimYieldRewards()`.
                 *
                 * @param from an address which received the yield
                 * @param value value of yield paid
                 */
                event LogClaimRewards(address indexed from, uint256 value);
                /**
                 * @dev Fired in `setEndTime()`.
                 *
                 * @param by an address which executed the action
                 * @param endTime new endTime value
                 */
                event LogSetEndTime(address indexed by, uint256 endTime);
                /**
                 * @dev Fired in `setsetVerifierAddress()`.
                 *
                 * @param newVerificationAddress new Verification Address
                 * @param oldVerificationAddress old Verification Address
                 */
                event LogVerificationAddress(address indexed newVerificationAddress,address indexed oldVerificationAddress);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.20;
            /**
             * @dev This smart contract defines custom errors that can be thrown during specific conditions in contracts.
             * @notice Pre-defined errors instead of string error messages to reduce gas costs.
             */
            library CommonErrors {
                error ZeroAmount();
                error ZeroAddress();
                error ContractIsPaused();
                error InvalidLockDuration();
                error OnlyFactory();
                error AlreadyRegistered();
                error WrongHash();
                error AlreadyUnstaked();
                error UnAuthorized();
                error CoolOffPeriodIsNotOver();
                error InvalidOperation();
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.20;
            /**
             * @dev Stake library used by PIKA pool and PIKA/USDT LP Pool.
             *
             * @dev Responsible to manage weight calculation and store important constants
             *      related to stake period, base weight and multipliers utilized.
             */
            library Stake {
                struct Data {
                    /// @dev token amount staked
                    uint256 value;
                    /// @dev locking period - from
                    uint256 lockedFrom;
                    /// @dev locking period - until
                    uint256 lockedUntil;
                    /// @dev whether the entry is unstaked 
                    bool isUnstaked;
                     /// @dev stakeId same as the array index 
                    uint256 stakeId;
                }
                /**
                 * @dev Stake weight is proportional to stake value and time locked, precisely
                 *      "stake value wei multiplied by (fraction of the year locked plus one)".
                 * @dev To avoid significant precision loss due to multiplication by "fraction of the year" [0, 1],
                 *      weight is stored multiplied by 1e6 constant, as an integer.
                 * @dev Corner case 1: if time locked is zero, weight is stake value multiplied by 1e6 + base weight
                 * @dev Corner case 2: if time locked is two years, division of
                        (lockedUntil - lockedFrom) / MAX_STAKE_PERIOD is 1e6, and
                 *      weight is a stake value multiplied by 2 * 1e6.
                 */
                uint256 internal constant WEIGHT_MULTIPLIER = 1e6;
                /**
                 * @dev Minimum weight value, if result of multiplication using WEIGHT_MULTIPLIER
                 *      is 0 (e.g stake flexible), then BASE_WEIGHT is used.
                 */
                uint256 internal constant BASE_WEIGHT = 1e6;
                /**
                 * @dev Minimum period that someone can lock a stake for.
                 */
                uint256 internal constant MIN_STAKE_PERIOD = 30 days;
                /**
                 * @dev Maximum period that someone can lock a stake for.
                 */
                uint256 internal constant MAX_STAKE_PERIOD = 365 days;
                /**
                 * @dev Rewards per weight are stored multiplied by 1e20 as uint.
                 */
                uint256 internal constant REWARD_PER_WEIGHT_MULTIPLIER = 1e20;
              
                function weight(Data storage _self) internal view returns (uint256) {
                    return
                        uint256(
                            (((_self.lockedUntil - _self.lockedFrom) * WEIGHT_MULTIPLIER) / MAX_STAKE_PERIOD + BASE_WEIGHT) *
                                _self.value
                        );
                }
                /**
                 * @dev Converts stake weight (not to be mixed with the pool weight) to
                 *      PIKA reward value, applying the 10^12 division on weight
                 *
                 * @param _weight stake weight
                 * @param _rewardPerWeight PIKA reward per weight
                 * @param _rewardPerWeightPaid last reward per weight value used for user earnings
                 * @return reward value normalized to 10^12
                 */
                function earned(
                    uint256 _weight,
                    uint256 _rewardPerWeight,
                    uint256 _rewardPerWeightPaid
                ) internal pure returns (uint256) {
                    // apply the formula and return
                    return (_weight * (_rewardPerWeight - _rewardPerWeightPaid)) / REWARD_PER_WEIGHT_MULTIPLIER;
                }
                /**
                 * @dev Converts reward PIKA value to stake weight (not to be mixed with the pool weight),
                 *      applying the 10^12 multiplication on the reward.
                 *      - OR -
                 * @dev Converts reward PIKA value to reward/weight if stake weight is supplied as second
                 *      function parameter instead of reward/weight.
                 *
                 * @param _reward yield reward
                 * @param _globalWeight total weight in the pool
                 * @return reward per weight value
                 */
                function getRewardPerWeight(uint256 _reward, uint256 _globalWeight) internal pure returns (uint256) {
                    // apply the reverse formula and return
                    return (_reward * REWARD_PER_WEIGHT_MULTIPLIER) / _globalWeight;
                }
            }
            // SPDX-License-Identifier: UNLICENSED
            pragma solidity 0.8.20;
            import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
            interface IPikaMoon is IERC20 {
                function mint(address to, uint amount) external;
                function burn(address owner, uint amount) external;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
            pragma solidity ^0.8.20;
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module that helps prevent reentrant calls to a function.
             *
             * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
             * available, which can be applied to functions to make sure there are no nested
             * (reentrant) calls to them.
             *
             * Note that because there is a single `nonReentrant` guard, functions marked as
             * `nonReentrant` may not call one another. This can be worked around by making
             * those functions `private`, and then adding `external` `nonReentrant` entry
             * points to them.
             *
             * TIP: If you would like to learn more about reentrancy and alternative ways
             * to protect against it, check out our blog post
             * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
             */
            abstract contract ReentrancyGuardUpgradeable is Initializable {
                // Booleans are more expensive than uint256 or any type that takes up a full
                // word because each write operation emits an extra SLOAD to first read the
                // slot's contents, replace the bits taken up by the boolean, and then write
                // back. This is the compiler's defense against contract upgrades and
                // pointer aliasing, and it cannot be disabled.
                // The values being non-zero value makes deployment a bit more expensive,
                // but in exchange the refund on every call to nonReentrant will be lower in
                // amount. Since refunds are capped to a percentage of the total
                // transaction's gas, it is best to keep them low in cases like this one, to
                // increase the likelihood of the full refund coming into effect.
                uint256 private constant NOT_ENTERED = 1;
                uint256 private constant ENTERED = 2;
                /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
                struct ReentrancyGuardStorage {
                    uint256 _status;
                }
                // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
                bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
                function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
                    assembly {
                        $.slot := ReentrancyGuardStorageLocation
                    }
                }
                /**
                 * @dev Unauthorized reentrant call.
                 */
                error ReentrancyGuardReentrantCall();
                function __ReentrancyGuard_init() internal onlyInitializing {
                    __ReentrancyGuard_init_unchained();
                }
                function __ReentrancyGuard_init_unchained() internal onlyInitializing {
                    ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
                    $._status = NOT_ENTERED;
                }
                /**
                 * @dev Prevents a contract from calling itself, directly or indirectly.
                 * Calling a `nonReentrant` function from another `nonReentrant`
                 * function is not supported. It is possible to prevent this from happening
                 * by making the `nonReentrant` function external, and making it call a
                 * `private` function that does the actual work.
                 */
                modifier nonReentrant() {
                    _nonReentrantBefore();
                    _;
                    _nonReentrantAfter();
                }
                function _nonReentrantBefore() private {
                    ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
                    // On the first call to nonReentrant, _status will be NOT_ENTERED
                    if ($._status == ENTERED) {
                        revert ReentrancyGuardReentrantCall();
                    }
                    // Any calls to nonReentrant after this point will fail
                    $._status = ENTERED;
                }
                function _nonReentrantAfter() private {
                    ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
                    // By storing the original value once again, a refund is triggered (see
                    // https://eips.ethereum.org/EIPS/eip-2200)
                    $._status = NOT_ENTERED;
                }
                /**
                 * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
                 * `nonReentrant` function in the call stack.
                 */
                function _reentrancyGuardEntered() internal view returns (bool) {
                    ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
                    return $._status == ENTERED;
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
            pragma solidity ^0.8.20;
            import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module which provides a basic access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * The initial owner is set to the address provided by the deployer. This can
             * later be changed with {transferOwnership}.
             *
             * This module is used through inheritance. It will make available the modifier
             * `onlyOwner`, which can be applied to your functions to restrict their use to
             * the owner.
             */
            abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
                /// @custom:storage-location erc7201:openzeppelin.storage.Ownable
                struct OwnableStorage {
                    address _owner;
                }
                // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
                bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
                function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
                    assembly {
                        $.slot := OwnableStorageLocation
                    }
                }
                /**
                 * @dev The caller account is not authorized to perform an operation.
                 */
                error OwnableUnauthorizedAccount(address account);
                /**
                 * @dev The owner is not a valid owner account. (eg. `address(0)`)
                 */
                error OwnableInvalidOwner(address owner);
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
                 */
                function __Ownable_init(address initialOwner) internal onlyInitializing {
                    __Ownable_init_unchained(initialOwner);
                }
                function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
                    if (initialOwner == address(0)) {
                        revert OwnableInvalidOwner(address(0));
                    }
                    _transferOwnership(initialOwner);
                }
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    _checkOwner();
                    _;
                }
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    OwnableStorage storage $ = _getOwnableStorage();
                    return $._owner;
                }
                /**
                 * @dev Throws if the sender is not the owner.
                 */
                function _checkOwner() internal view virtual {
                    if (owner() != _msgSender()) {
                        revert OwnableUnauthorizedAccount(_msgSender());
                    }
                }
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby disabling any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    _transferOwnership(address(0));
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    if (newOwner == address(0)) {
                        revert OwnableInvalidOwner(address(0));
                    }
                    _transferOwnership(newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual {
                    OwnableStorage storage $ = _getOwnableStorage();
                    address oldOwner = $._owner;
                    $._owner = newOwner;
                    emit OwnershipTransferred(oldOwner, newOwner);
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
            pragma solidity ^0.8.20;
            import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module which allows children to implement an emergency stop
             * mechanism that can be triggered by an authorized account.
             *
             * This module is used through inheritance. It will make available the
             * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
             * the functions of your contract. Note that they will not be pausable by
             * simply including this module, only once the modifiers are put in place.
             */
            abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
                /// @custom:storage-location erc7201:openzeppelin.storage.Pausable
                struct PausableStorage {
                    bool _paused;
                }
                // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
                bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
                function _getPausableStorage() private pure returns (PausableStorage storage $) {
                    assembly {
                        $.slot := PausableStorageLocation
                    }
                }
                /**
                 * @dev Emitted when the pause is triggered by `account`.
                 */
                event Paused(address account);
                /**
                 * @dev Emitted when the pause is lifted by `account`.
                 */
                event Unpaused(address account);
                /**
                 * @dev The operation failed because the contract is paused.
                 */
                error EnforcedPause();
                /**
                 * @dev The operation failed because the contract is not paused.
                 */
                error ExpectedPause();
                /**
                 * @dev Initializes the contract in unpaused state.
                 */
                function __Pausable_init() internal onlyInitializing {
                    __Pausable_init_unchained();
                }
                function __Pausable_init_unchained() internal onlyInitializing {
                    PausableStorage storage $ = _getPausableStorage();
                    $._paused = false;
                }
                /**
                 * @dev Modifier to make a function callable only when the contract is not paused.
                 *
                 * Requirements:
                 *
                 * - The contract must not be paused.
                 */
                modifier whenNotPaused() {
                    _requireNotPaused();
                    _;
                }
                /**
                 * @dev Modifier to make a function callable only when the contract is paused.
                 *
                 * Requirements:
                 *
                 * - The contract must be paused.
                 */
                modifier whenPaused() {
                    _requirePaused();
                    _;
                }
                /**
                 * @dev Returns true if the contract is paused, and false otherwise.
                 */
                function paused() public view virtual returns (bool) {
                    PausableStorage storage $ = _getPausableStorage();
                    return $._paused;
                }
                /**
                 * @dev Throws if the contract is paused.
                 */
                function _requireNotPaused() internal view virtual {
                    if (paused()) {
                        revert EnforcedPause();
                    }
                }
                /**
                 * @dev Throws if the contract is not paused.
                 */
                function _requirePaused() internal view virtual {
                    if (!paused()) {
                        revert ExpectedPause();
                    }
                }
                /**
                 * @dev Triggers stopped state.
                 *
                 * Requirements:
                 *
                 * - The contract must not be paused.
                 */
                function _pause() internal virtual whenNotPaused {
                    PausableStorage storage $ = _getPausableStorage();
                    $._paused = true;
                    emit Paused(_msgSender());
                }
                /**
                 * @dev Returns to normal state.
                 *
                 * Requirements:
                 *
                 * - The contract must be paused.
                 */
                function _unpause() internal virtual whenPaused {
                    PausableStorage storage $ = _getPausableStorage();
                    $._paused = false;
                    emit Unpaused(_msgSender());
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
            pragma solidity ^0.8.20;
            /**
             * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
             *
             * These functions can be used to verify that a message was signed by the holder
             * of the private keys of a given address.
             */
            library ECDSA {
                enum RecoverError {
                    NoError,
                    InvalidSignature,
                    InvalidSignatureLength,
                    InvalidSignatureS
                }
                /**
                 * @dev The signature derives the `address(0)`.
                 */
                error ECDSAInvalidSignature();
                /**
                 * @dev The signature has an invalid length.
                 */
                error ECDSAInvalidSignatureLength(uint256 length);
                /**
                 * @dev The signature has an S value that is in the upper half order.
                 */
                error ECDSAInvalidSignatureS(bytes32 s);
                /**
                 * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
                 * return address(0) without also returning an error description. Errors are documented using an enum (error type)
                 * and a bytes32 providing additional information about the error.
                 *
                 * If no error is returned, then the address can be used for verification purposes.
                 *
                 * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
                 * this function rejects them by requiring the `s` value to be in the lower
                 * half order, and the `v` value to be either 27 or 28.
                 *
                 * IMPORTANT: `hash` _must_ be the result of a hash operation for the
                 * verification to be secure: it is possible to craft signatures that
                 * recover to arbitrary addresses for non-hashed data. A safe way to ensure
                 * this is by receiving a hash of the original message (which may otherwise
                 * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
                 *
                 * Documentation for signature generation:
                 * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
                 * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
                 */
                function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
                    if (signature.length == 65) {
                        bytes32 r;
                        bytes32 s;
                        uint8 v;
                        // ecrecover takes the signature parameters, and the only way to get them
                        // currently is to use assembly.
                        /// @solidity memory-safe-assembly
                        assembly {
                            r := mload(add(signature, 0x20))
                            s := mload(add(signature, 0x40))
                            v := byte(0, mload(add(signature, 0x60)))
                        }
                        return tryRecover(hash, v, r, s);
                    } else {
                        return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
                    }
                }
                /**
                 * @dev Returns the address that signed a hashed message (`hash`) with
                 * `signature`. This address can then be used for verification purposes.
                 *
                 * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
                 * this function rejects them by requiring the `s` value to be in the lower
                 * half order, and the `v` value to be either 27 or 28.
                 *
                 * IMPORTANT: `hash` _must_ be the result of a hash operation for the
                 * verification to be secure: it is possible to craft signatures that
                 * recover to arbitrary addresses for non-hashed data. A safe way to ensure
                 * this is by receiving a hash of the original message (which may otherwise
                 * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
                 */
                function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
                    (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
                    _throwError(error, errorArg);
                    return recovered;
                }
                /**
                 * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
                 *
                 * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
                 */
                function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
                    unchecked {
                        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
                        // We do not check for an overflow here since the shift operation results in 0 or 1.
                        uint8 v = uint8((uint256(vs) >> 255) + 27);
                        return tryRecover(hash, v, r, s);
                    }
                }
                /**
                 * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
                 */
                function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
                    (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
                    _throwError(error, errorArg);
                    return recovered;
                }
                /**
                 * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
                 * `r` and `s` signature fields separately.
                 */
                function tryRecover(
                    bytes32 hash,
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                ) internal pure returns (address, RecoverError, bytes32) {
                    // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
                    // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
                    // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
                    // signatures from current libraries generate a unique signature with an s-value in the lower half order.
                    //
                    // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
                    // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
                    // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
                    // these malleable signatures as well.
                    if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
                        return (address(0), RecoverError.InvalidSignatureS, s);
                    }
                    // If the signature is valid (and not malleable), return the signer address
                    address signer = ecrecover(hash, v, r, s);
                    if (signer == address(0)) {
                        return (address(0), RecoverError.InvalidSignature, bytes32(0));
                    }
                    return (signer, RecoverError.NoError, bytes32(0));
                }
                /**
                 * @dev Overload of {ECDSA-recover} that receives the `v`,
                 * `r` and `s` signature fields separately.
                 */
                function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
                    (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
                    _throwError(error, errorArg);
                    return recovered;
                }
                /**
                 * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
                 */
                function _throwError(RecoverError error, bytes32 errorArg) private pure {
                    if (error == RecoverError.NoError) {
                        return; // no error: do nothing
                    } else if (error == RecoverError.InvalidSignature) {
                        revert ECDSAInvalidSignature();
                    } else if (error == RecoverError.InvalidSignatureLength) {
                        revert ECDSAInvalidSignatureLength(uint256(errorArg));
                    } else if (error == RecoverError.InvalidSignatureS) {
                        revert ECDSAInvalidSignatureS(errorArg);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
            pragma solidity ^0.8.20;
            import {IERC20} from "../IERC20.sol";
            import {IERC20Permit} from "../extensions/IERC20Permit.sol";
            import {Address} from "../../../utils/Address.sol";
            /**
             * @title SafeERC20
             * @dev Wrappers around ERC20 operations that throw on failure (when the token
             * contract returns false). Tokens that return no value (and instead revert or
             * throw on failure) are also supported, non-reverting calls are assumed to be
             * successful.
             * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
             * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
             */
            library SafeERC20 {
                using Address for address;
                /**
                 * @dev An operation with an ERC20 token failed.
                 */
                error SafeERC20FailedOperation(address token);
                /**
                 * @dev Indicates a failed `decreaseAllowance` request.
                 */
                error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
                /**
                 * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
                 * non-reverting calls are assumed to be successful.
                 */
                function safeTransfer(IERC20 token, address to, uint256 value) internal {
                    _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
                }
                /**
                 * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
                 * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
                 */
                function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                    _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
                }
                /**
                 * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
                 * non-reverting calls are assumed to be successful.
                 */
                function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                    uint256 oldAllowance = token.allowance(address(this), spender);
                    forceApprove(token, spender, oldAllowance + value);
                }
                /**
                 * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
                 * value, non-reverting calls are assumed to be successful.
                 */
                function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
                    unchecked {
                        uint256 currentAllowance = token.allowance(address(this), spender);
                        if (currentAllowance < requestedDecrease) {
                            revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
                        }
                        forceApprove(token, spender, currentAllowance - requestedDecrease);
                    }
                }
                /**
                 * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
                 * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
                 * to be set to zero before setting it to a non-zero value, such as USDT.
                 */
                function forceApprove(IERC20 token, address spender, uint256 value) internal {
                    bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
                    if (!_callOptionalReturnBool(token, approvalCall)) {
                        _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
                        _callOptionalReturn(token, approvalCall);
                    }
                }
                /**
                 * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                 * on the return value: the return value is optional (but if data is returned, it must not be false).
                 * @param token The token targeted by the call.
                 * @param data The call data (encoded using abi.encode or one of its variants).
                 */
                function _callOptionalReturn(IERC20 token, bytes memory data) private {
                    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                    // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
                    // the target address contains contract code and also asserts for success in the low-level call.
                    bytes memory returndata = address(token).functionCall(data);
                    if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
                        revert SafeERC20FailedOperation(address(token));
                    }
                }
                /**
                 * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                 * on the return value: the return value is optional (but if data is returned, it must not be false).
                 * @param token The token targeted by the call.
                 * @param data The call data (encoded using abi.encode or one of its variants).
                 *
                 * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
                 */
                function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
                    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                    // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
                    // and not revert is the subcall reverts.
                    (bool success, bytes memory returndata) = address(token).call(data);
                    return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
            pragma solidity ^0.8.20;
            import {IBeacon} from "../beacon/IBeacon.sol";
            import {Address} from "../../utils/Address.sol";
            import {StorageSlot} from "../../utils/StorageSlot.sol";
            /**
             * @dev This abstract contract provides getters and event emitting update functions for
             * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
             */
            library ERC1967Utils {
                // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
                // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
                /**
                 * @dev Storage slot with the address of the current implementation.
                 * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                /**
                 * @dev The `implementation` of the proxy is invalid.
                 */
                error ERC1967InvalidImplementation(address implementation);
                /**
                 * @dev The `admin` of the proxy is invalid.
                 */
                error ERC1967InvalidAdmin(address admin);
                /**
                 * @dev The `beacon` of the proxy is invalid.
                 */
                error ERC1967InvalidBeacon(address beacon);
                /**
                 * @dev An upgrade function sees `msg.value > 0` that may be lost.
                 */
                error ERC1967NonPayable();
                /**
                 * @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 {
                    if (newImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(newImplementation);
                    }
                    StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
                }
                /**
                 * @dev Performs implementation upgrade with additional setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-Upgraded} event.
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) internal {
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
                    if (data.length > 0) {
                        Address.functionDelegateCall(newImplementation, data);
                    } else {
                        _checkNonPayable();
                    }
                }
                /**
                 * @dev Storage slot with the admin of the contract.
                 * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                /**
                 * @dev Returns the current admin.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
                 * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                 */
                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 {
                    if (newAdmin == address(0)) {
                        revert ERC1967InvalidAdmin(address(0));
                    }
                    StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
                }
                /**
                 * @dev Changes the admin of the proxy.
                 *
                 * Emits an {IERC1967-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 the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                /**
                 * @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 {
                    if (newBeacon.code.length == 0) {
                        revert ERC1967InvalidBeacon(newBeacon);
                    }
                    StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
                    address beaconImplementation = IBeacon(newBeacon).implementation();
                    if (beaconImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(beaconImplementation);
                    }
                }
                /**
                 * @dev Change the beacon and trigger a setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-BeaconUpgraded} event.
                 *
                 * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
                 * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
                 * efficiency.
                 */
                function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
                    _setBeacon(newBeacon);
                    emit BeaconUpgraded(newBeacon);
                    if (data.length > 0) {
                        Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                    } else {
                        _checkNonPayable();
                    }
                }
                /**
                 * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
                 * if an upgrade doesn't perform an initialization call.
                 */
                function _checkNonPayable() private {
                    if (msg.value > 0) {
                        revert ERC1967NonPayable();
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
            pragma solidity ^0.8.20;
            /**
             * @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 (last updated v5.0.0) (token/ERC20/IERC20.sol)
            pragma solidity ^0.8.20;
            /**
             * @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 value of tokens in existence.
                 */
                function totalSupply() external view returns (uint256);
                /**
                 * @dev Returns the value of tokens owned by `account`.
                 */
                function balanceOf(address account) external view returns (uint256);
                /**
                 * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
                /**
                 * @dev Moves a `value` amount of tokens from `from` to `to` using the
                 * allowance mechanism. `value` 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 value) external returns (bool);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
            pragma solidity ^0.8.20;
            /**
             * @dev Collection of functions related to the address type
             */
            library Address {
                /**
                 * @dev The ETH balance of the account is not enough to perform the operation.
                 */
                error AddressInsufficientBalance(address account);
                /**
                 * @dev There's no code at `target` (it is not a contract).
                 */
                error AddressEmptyCode(address target);
                /**
                 * @dev A call to an address target failed. The target may have reverted.
                 */
                error FailedInnerCall();
                /**
                 * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                 */
                function sendValue(address payable recipient, uint256 amount) internal {
                    if (address(this).balance < amount) {
                        revert AddressInsufficientBalance(address(this));
                    }
                    (bool success, ) = recipient.call{value: amount}("");
                    if (!success) {
                        revert FailedInnerCall();
                    }
                }
                /**
                 * @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 or custom error, it is bubbled
                 * up by this function (like regular Solidity function calls). However, if
                 * the call reverted with no returned reason, this function reverts with a
                 * {FailedInnerCall} error.
                 *
                 * 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.
                 */
                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, 0);
                }
                /**
                 * @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`.
                 */
                function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                    if (address(this).balance < value) {
                        revert AddressInsufficientBalance(address(this));
                    }
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a static call.
                 */
                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a delegate call.
                 */
                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
                 * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
                 * unsuccessful call.
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata
                ) internal view returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        // only check if target is a contract if the call was successful and the return data is empty
                        // otherwise we already know that it was a contract
                        if (returndata.length == 0 && target.code.length == 0) {
                            revert AddressEmptyCode(target);
                        }
                        return returndata;
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
                 * revert reason or with a default {FailedInnerCall} error.
                 */
                function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        return returndata;
                    }
                }
                /**
                 * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
                 */
                function _revert(bytes memory returndata) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert FailedInnerCall();
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
            pragma solidity ^0.8.20;
            /**
             * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
             * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
             *
             * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
             * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
             * need to send a transaction, and thus is not required to hold Ether at all.
             *
             * ==== Security Considerations
             *
             * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
             * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
             * considered as an intention to spend the allowance in any specific way. The second is that because permits have
             * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
             * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
             * generally recommended is:
             *
             * ```solidity
             * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
             *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
             *     doThing(..., value);
             * }
             *
             * function doThing(..., uint256 value) public {
             *     token.safeTransferFrom(msg.sender, address(this), value);
             *     ...
             * }
             * ```
             *
             * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
             * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
             * {SafeERC20-safeTransferFrom}).
             *
             * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
             * contracts should have entry points that don't rely on permit.
             */
            interface IERC20Permit {
                /**
                 * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
                 * given ``owner``'s signed approval.
                 *
                 * IMPORTANT: The same issues {IERC20-approve} has related to transaction
                 * ordering also apply here.
                 *
                 * Emits an {Approval} event.
                 *
                 * Requirements:
                 *
                 * - `spender` cannot be the zero address.
                 * - `deadline` must be a timestamp in the future.
                 * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
                 * over the EIP712-formatted function arguments.
                 * - the signature must use ``owner``'s current nonce (see {nonces}).
                 *
                 * For more information on the signature format, see the
                 * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
                 * section].
                 *
                 * CAUTION: See Security Considerations above.
                 */
                function permit(
                    address owner,
                    address spender,
                    uint256 value,
                    uint256 deadline,
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                ) external;
                /**
                 * @dev Returns the current nonce for `owner`. This value must be
                 * included whenever a signature is generated for {permit}.
                 *
                 * Every successful call to {permit} increases ``owner``'s nonce by one. This
                 * prevents a signature from being used multiple times.
                 */
                function nonces(address owner) external view returns (uint256);
                /**
                 * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
                 */
                // solhint-disable-next-line func-name-mixedcase
                function DOMAIN_SEPARATOR() external view returns (bytes32);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            pragma solidity ^0.8.20;
            /**
             * @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:
             * ```solidity
             * 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(newImplementation.code.length > 0);
             *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
             *     }
             * }
             * ```
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                struct StringSlot {
                    string value;
                }
                struct BytesSlot {
                    bytes 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
                    }
                }
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
            pragma solidity ^0.8.20;
            /**
             * @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.
                 *
                 * {UpgradeableBeacon} will check that this address is a contract.
                 */
                function implementation() external view returns (address);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
            pragma solidity ^0.8.20;
            import {Initializable} from "../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;
                }
                function _contextSuffixLength() internal view virtual returns (uint256) {
                    return 0;
                }
            }
            

            File 4 of 6: ERC1967Proxy
            // SPDX-License-Identifier: MIT
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/utils/StorageSlot.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            
            pragma solidity ^0.8.20;
            
            /**
             * @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:
             * ```solidity
             * 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(newImplementation.code.length > 0);
             *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
             *     }
             * }
             * ```
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
            
                struct BooleanSlot {
                    bool value;
                }
            
                struct Bytes32Slot {
                    bytes32 value;
                }
            
                struct Uint256Slot {
                    uint256 value;
                }
            
                struct StringSlot {
                    string value;
                }
            
                struct BytesSlot {
                    bytes 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
                    }
                }
            
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
            
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
            
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/utils/Address.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @dev Collection of functions related to the address type
             */
            library Address {
                /**
                 * @dev The ETH balance of the account is not enough to perform the operation.
                 */
                error AddressInsufficientBalance(address account);
            
                /**
                 * @dev There's no code at `target` (it is not a contract).
                 */
                error AddressEmptyCode(address target);
            
                /**
                 * @dev A call to an address target failed. The target may have reverted.
                 */
                error FailedInnerCall();
            
                /**
                 * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                 */
                function sendValue(address payable recipient, uint256 amount) internal {
                    if (address(this).balance < amount) {
                        revert AddressInsufficientBalance(address(this));
                    }
            
                    (bool success, ) = recipient.call{value: amount}("");
                    if (!success) {
                        revert FailedInnerCall();
                    }
                }
            
                /**
                 * @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 or custom error, it is bubbled
                 * up by this function (like regular Solidity function calls). However, if
                 * the call reverted with no returned reason, this function reverts with a
                 * {FailedInnerCall} error.
                 *
                 * 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.
                 */
                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, 0);
                }
            
                /**
                 * @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`.
                 */
                function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                    if (address(this).balance < value) {
                        revert AddressInsufficientBalance(address(this));
                    }
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a static call.
                 */
                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a delegate call.
                 */
                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
            
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
                 * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
                 * unsuccessful call.
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata
                ) internal view returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        // only check if target is a contract if the call was successful and the return data is empty
                        // otherwise we already know that it was a contract
                        if (returndata.length == 0 && target.code.length == 0) {
                            revert AddressEmptyCode(target);
                        }
                        return returndata;
                    }
                }
            
                /**
                 * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
                 * revert reason or with a default {FailedInnerCall} error.
                 */
                function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        return returndata;
                    }
                }
            
                /**
                 * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
                 */
                function _revert(bytes memory returndata) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert FailedInnerCall();
                    }
                }
            }
            
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @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.
                 *
                 * {UpgradeableBeacon} will check that this address is a contract.
                 */
                function implementation() external view returns (address);
            }
            
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
            
            pragma solidity ^0.8.20;
            
            
            
            
            /**
             * @dev This abstract contract provides getters and event emitting update functions for
             * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
             */
            library ERC1967Utils {
                // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
                // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
            
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
            
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
            
                /**
                 * @dev Storage slot with the address of the current implementation.
                 * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
            
                /**
                 * @dev The `implementation` of the proxy is invalid.
                 */
                error ERC1967InvalidImplementation(address implementation);
            
                /**
                 * @dev The `admin` of the proxy is invalid.
                 */
                error ERC1967InvalidAdmin(address admin);
            
                /**
                 * @dev The `beacon` of the proxy is invalid.
                 */
                error ERC1967InvalidBeacon(address beacon);
            
                /**
                 * @dev An upgrade function sees `msg.value > 0` that may be lost.
                 */
                error ERC1967NonPayable();
            
                /**
                 * @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 {
                    if (newImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(newImplementation);
                    }
                    StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
                }
            
                /**
                 * @dev Performs implementation upgrade with additional setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-Upgraded} event.
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) internal {
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
            
                    if (data.length > 0) {
                        Address.functionDelegateCall(newImplementation, data);
                    } else {
                        _checkNonPayable();
                    }
                }
            
                /**
                 * @dev Storage slot with the admin of the contract.
                 * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
            
                /**
                 * @dev Returns the current admin.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
                 * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                 */
                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 {
                    if (newAdmin == address(0)) {
                        revert ERC1967InvalidAdmin(address(0));
                    }
                    StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
                }
            
                /**
                 * @dev Changes the admin of the proxy.
                 *
                 * Emits an {IERC1967-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 the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
            
                /**
                 * @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 {
                    if (newBeacon.code.length == 0) {
                        revert ERC1967InvalidBeacon(newBeacon);
                    }
            
                    StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
            
                    address beaconImplementation = IBeacon(newBeacon).implementation();
                    if (beaconImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(beaconImplementation);
                    }
                }
            
                /**
                 * @dev Change the beacon and trigger a setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-BeaconUpgraded} event.
                 *
                 * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
                 * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
                 * efficiency.
                 */
                function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
                    _setBeacon(newBeacon);
                    emit BeaconUpgraded(newBeacon);
            
                    if (data.length > 0) {
                        Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                    } else {
                        _checkNonPayable();
                    }
                }
            
                /**
                 * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
                 * if an upgrade doesn't perform an initialization call.
                 */
                function _checkNonPayable() private {
                    if (msg.value > 0) {
                        revert ERC1967NonPayable();
                    }
                }
            }
            
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/proxy/Proxy.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @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 {
                    _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();
                }
            }
            
            // File: .deps/github/OpenZeppelin/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)
            
            pragma solidity ^0.8.20;
            
            
            
            /**
             * @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 {
                /**
                 * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
                 *
                 * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
                 * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
                 *
                 * Requirements:
                 *
                 * - If `data` is empty, `msg.value` must be zero.
                 */
                constructor(address implementation, bytes memory _data) payable {
                    ERC1967Utils.upgradeToAndCall(implementation, _data);
                }
            
                /**
                 * @dev Returns the current implementation address.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
                 * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                 */
                function _implementation() internal view virtual override returns (address) {
                    return ERC1967Utils.getImplementation();
                }
            }

            File 5 of 6: PoolController
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.20;
            import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
            import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
            import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
            import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
            import {ICorePool} from "./interfaces/ICorePool.sol";
            import {CommonErrors} from "./libraries/Errors.sol";
            import {IPikaMoon} from "./interfaces/IPikaMoon.sol";
            contract PoolController is Initializable, UUPSUpgradeable, OwnableUpgradeable {
                using SafeERC20 for IPikaMoon;
                /**
                 * @dev PIKA/second determines rewards farming reward base
                 */
                uint256 public pikaPerSecond;
                /**
                 * @dev The yield is distributed proportionally to pool weights;
                 *      total weight is here to help in determining the proportion.
                 */
                uint256 public totalWeight;
                /// @dev Keeps track of registered pool addresses, maps pool address -> exists flag.
                mapping(address => bool) public poolExists;
                // @dev pool token to pool address
                mapping(address => address) public pools;
                /**
                 * @dev Fired in `changePoolWeight()`.
                 *
                 * @param by an address which executed an action
                 * @param poolAddress deployed pool instance address
                 * @param weight new pool weight
                 */
                event LogChangePoolWeight(
                    address indexed by,
                    address indexed poolAddress,
                    uint256 weight
                );
                /**
                 * @dev Fired in `updatePikaPerSecond()`.
                 *
                 * @param newPikaPerSecond new Pika/second value
                 */
                event LogUpdatePikaPerSecond(uint256 newPikaPerSecond);
                /**
                 * @dev Fired in registerPool()
                 * @param addr an address of pool
                 */
                event LogRegisterPool(address indexed addr);
                /// @custom:oz-upgrades-unsafe-allow constructor
                constructor() {
                    _disableInitializers();
                }
                function initialize() external initializer {
                    __Ownable_init(msg.sender);
                    __UUPSUpgradeable_init();
                    pikaPerSecond = 25.3678335870 gwei; // pika has 9 decimals, so gwei = 10**9
                    totalWeight = 1000; //(direct staking)200 + (pool staking)800
                }
                /// @notice Registers a new pool
                /// @dev Only callable by the owner; emits LogRegisterPool on success
                /// @param _poolAddress The address of the pool to register
                function registerPool(address _poolAddress) external onlyOwner {
                    if (poolExists[_poolAddress]) {
                        revert CommonErrors.AlreadyRegistered();
                    }
                    address poolToken= ICorePool(_poolAddress).poolToken();
                    
                    pools[poolToken] = _poolAddress;
                    poolExists[_poolAddress] = true;
                    emit LogRegisterPool(_poolAddress);
                }
                // @dev add pool token to pool address
                 function addPool() external onlyOwner {
                    pools[0xD1e64bcc904Cfdc19d0FABA155a9EdC69b4bcdAe] = 0xF965671DeC4C8f902083e8E0845cf86aac44FD80; // pika staking
                    pools[0x43a68A9f1F234e639B142F0ABa946B7Add26418d] = 0xFCf12ADF9Dc9967701596A12D1c7F5E447e34736; // lp staking
                }
               
                /// @notice Updates the rate of PIKA distribution per second
                /// @dev Only callable by the owner; emits LogUpdatePikaPerSecond on success
                /// @param _pikaPerSecond The new rate of PIKA distribution per second
                function updatePikaPerSecond(uint256 _pikaPerSecond) external onlyOwner {
                    if (_pikaPerSecond == 0) revert CommonErrors.ZeroAmount();
                    pikaPerSecond = _pikaPerSecond;
                    emit LogUpdatePikaPerSecond(_pikaPerSecond);
                }
                /// @notice Transfers reward tokens from a registered pool
                /// @dev Only callable by a registered pool
                /// @param _token The token address to transfer
                /// @param _to The recipient address
                /// @param _value The amount of tokens to transfer
                function transferRewardTokens(
                    address _token,
                    address _to,
                    uint256 _value
                ) public {
                    if (!poolExists[msg.sender]) {
                        revert CommonErrors.UnAuthorized();
                    }
                    IPikaMoon(_token).safeTransfer(_to, _value);
                }
                /**
                 * @dev Changes the weight of the pool;
                 *      executed by the pool itself or by the factory owner.
                 *
                 * @param pool address of the pool to change weight for
                 * @param weight new weight value to set to
                 */
                function changePoolWeight(address pool, uint256 weight) external onlyOwner {
                    // recalculate total weight
                    totalWeight = totalWeight + weight - ICorePool(pool).weight();
                    // set the new pool weight
                    ICorePool(pool).setWeight(weight);
                    // emit an event
                    emit LogChangePoolWeight(msg.sender, address(pool), weight);
                }
                /**
                 * @dev Overrides `Ownable.renounceOwnership()`, to avoid accidentally
                 *      renouncing ownership of the PoolControllers contract.
                 */
                function renounceOwnership() public virtual override {}
                /**
                 * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                 * {upgradeToAndCall}.
                 */
                function _authorizeUpgrade(
                    address newImplementation
                ) internal override onlyOwner {}
                 /**
                 * @dev Empty reserved space in storage. The size of the __gap array is calculated so that
                 *      the amount of storage used by a contract always adds up to the 50.
                 *      See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[44] private __gap;
            }
            // SPDX-License-Identifier: UNLICENSED
            pragma solidity 0.8.20;
            import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
            interface IPikaMoon is IERC20 {
                function mint(address to, uint amount) external;
                function burn(address owner, uint amount) external;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.20;
            /**
             * @dev This smart contract defines custom errors that can be thrown during specific conditions in contracts.
             * @notice Pre-defined errors instead of string error messages to reduce gas costs.
             */
            library CommonErrors {
                error ZeroAmount();
                error ZeroAddress();
                error ContractIsPaused();
                error InvalidLockDuration();
                error OnlyFactory();
                error AlreadyRegistered();
                error WrongHash();
                error AlreadyUnstaked();
                error UnAuthorized();
                error CoolOffPeriodIsNotOver();
                error InvalidOperation();
            }
            // SPDX-License-Identifier: UNLICENSED
            pragma solidity 0.8.20;
            import "../libraries/Stake.sol";
            interface ICorePool {
                /* ========== MUTATIVE FUNCTIONS ========== */
                function stake(uint256 _value, uint256 _lockDuration) external;
                    function poolToken() external view returns (address);
            function stakeAsPool(address _staker, uint256 _value) external ;
                function unstake(uint256 _stakeId) external;
                function claimRewards(
                    uint256 _claimPercentage,
                    bool _restakeLeftOver,
                    bytes memory _signature,
                    uint256 _nonce
                ) external;
                function sync() external;
                function setWeight(uint256 _weight) external;
                /* ========== RESTRICTED FUNCTIONS ========== */
                function pause(bool _shouldPause) external;
                /* ========== READ FUNCTIONS ========== */
                function pendingRewards(
                    address _staker
                ) external view returns (uint256 pendingYield);
                function balanceOf(address _user) external view returns (uint256 balance);
                function getStakesLength(address _user) external view returns (uint256);
                function getStake(
                    address _user,
                    uint256 _stakeId
                ) external view returns (Stake.Data memory);
                function weight() external view returns (uint256);
                /* ========== EVENTS ========== */
                /**
                 * @dev Fired in _stake() and stakeAsPool() in PIKAPool contract.
                 * @param from token holder address, the tokens will be returned to that address
                 * @param stakeId id of the new stake created
                 * @param value value of tokens staked
                 * @param lockUntil timestamp indicating when tokens should unlock (max 2 years)
                 */
                event LogStake(
                    address indexed from,
                    uint256 stakeId,
                    uint256 value,
                    uint256 lockUntil
                );
                /**
                 * @dev Fired in `_updateRewards()`.
                 *
                 * @param from an address which received the yield
                 * @param yieldValue value of yield processed
                 */
                event LogUpdateRewards(address indexed from, uint256 yieldValue);
                /**
                 * @dev Fired in `unstake()`.
                 *
                 * @param to address receiving the tokens (user)
                 * @param stakeId id value of the stake
                 * @param value number of tokens unstaked
                 */
                event LogUnstake(
                    address indexed to,
                    uint256 stakeId,
                    uint256 value,
                    uint256 earlyUnstakePercentage,
                    bool isEarlyUnstake
                );
                /**
                 * @dev Fired in `updatePIKAPerSecond()`.
                 *
                 * @param by an address which executed an action
                 * @param newPIKAPerSecond new PIKA/second value
                 */
                event LogUpdatePikaPerSecond(address indexed by, uint256 newPIKAPerSecond);
                /**
                 * @dev Fired in `_sync()` and dependent functions (stake, unstake, etc.).
                 *
                 * @param by an address which performed an operation
                 * @param yieldRewardsPerWeight updated yield rewards per weight value
                 * @param lastYieldDistribution usually, current timestamp
                 */
                event LogSync(
                    address indexed by,
                    uint256 yieldRewardsPerWeight,
                    uint256 lastYieldDistribution
                );
                /**
                 * @dev Fired in `updatePIKAPerSecond()`.
                 *
                 * @param by an address which executed an action
                 * @param newPikaPerSecond new PIKA/second value
                 */
                event LogUpdatePIKAPerSecond(address indexed by, uint256 newPikaPerSecond);
                /**
                 * @dev Fired in `_claimYieldRewards()`.
                 *
                 * @param from an address which received the yield
                 * @param value value of yield paid
                 */
                event LogClaimRewards(address indexed from, uint256 value);
                /**
                 * @dev Fired in `setEndTime()`.
                 *
                 * @param by an address which executed the action
                 * @param endTime new endTime value
                 */
                event LogSetEndTime(address indexed by, uint256 endTime);
                /**
                 * @dev Fired in `setsetVerifierAddress()`.
                 *
                 * @param newVerificationAddress new Verification Address
                 * @param oldVerificationAddress old Verification Address
                 */
                event LogVerificationAddress(address indexed newVerificationAddress,address indexed oldVerificationAddress);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
            pragma solidity ^0.8.20;
            import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module which provides a basic access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * The initial owner is set to the address provided by the deployer. This can
             * later be changed with {transferOwnership}.
             *
             * This module is used through inheritance. It will make available the modifier
             * `onlyOwner`, which can be applied to your functions to restrict their use to
             * the owner.
             */
            abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
                /// @custom:storage-location erc7201:openzeppelin.storage.Ownable
                struct OwnableStorage {
                    address _owner;
                }
                // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
                bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
                function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
                    assembly {
                        $.slot := OwnableStorageLocation
                    }
                }
                /**
                 * @dev The caller account is not authorized to perform an operation.
                 */
                error OwnableUnauthorizedAccount(address account);
                /**
                 * @dev The owner is not a valid owner account. (eg. `address(0)`)
                 */
                error OwnableInvalidOwner(address owner);
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
                 */
                function __Ownable_init(address initialOwner) internal onlyInitializing {
                    __Ownable_init_unchained(initialOwner);
                }
                function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
                    if (initialOwner == address(0)) {
                        revert OwnableInvalidOwner(address(0));
                    }
                    _transferOwnership(initialOwner);
                }
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    _checkOwner();
                    _;
                }
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    OwnableStorage storage $ = _getOwnableStorage();
                    return $._owner;
                }
                /**
                 * @dev Throws if the sender is not the owner.
                 */
                function _checkOwner() internal view virtual {
                    if (owner() != _msgSender()) {
                        revert OwnableUnauthorizedAccount(_msgSender());
                    }
                }
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby disabling any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    _transferOwnership(address(0));
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    if (newOwner == address(0)) {
                        revert OwnableInvalidOwner(address(0));
                    }
                    _transferOwnership(newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual {
                    OwnableStorage storage $ = _getOwnableStorage();
                    address oldOwner = $._owner;
                    $._owner = newOwner;
                    emit OwnershipTransferred(oldOwner, newOwner);
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
            pragma solidity ^0.8.20;
            import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
            import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
            import {Initializable} from "./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.
             */
            abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
                /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
                address private immutable __self = address(this);
                /**
                 * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
                 * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
                 * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
                 * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
                 * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
                 * during an upgrade.
                 */
                string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
                /**
                 * @dev The call is from an unauthorized context.
                 */
                error UUPSUnauthorizedCallContext();
                /**
                 * @dev The storage `slot` is unsupported as a UUID.
                 */
                error UUPSUnsupportedProxiableUUID(bytes32 slot);
                /**
                 * @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() {
                    _checkProxy();
                    _;
                }
                /**
                 * @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() {
                    _checkNotDelegated();
                    _;
                }
                function __UUPSUpgradeable_init() internal onlyInitializing {
                }
                function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
                }
                /**
                 * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
                 * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
                 *
                 * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                 * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                 * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
                 */
                function proxiableUUID() external view virtual notDelegated returns (bytes32) {
                    return ERC1967Utils.IMPLEMENTATION_SLOT;
                }
                /**
                 * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
                 * encoded in `data`.
                 *
                 * Calls {_authorizeUpgrade}.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
                    _authorizeUpgrade(newImplementation);
                    _upgradeToAndCallUUPS(newImplementation, data);
                }
                /**
                 * @dev Reverts if the execution is not performed via delegatecall or the execution
                 * context is not of a proxy with an ERC1967-compliant implementation pointing to self.
                 * See {_onlyProxy}.
                 */
                function _checkProxy() internal view virtual {
                    if (
                        address(this) == __self || // Must be called through delegatecall
                        ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
                    ) {
                        revert UUPSUnauthorizedCallContext();
                    }
                }
                /**
                 * @dev Reverts if the execution is performed via delegatecall.
                 * See {notDelegated}.
                 */
                function _checkNotDelegated() internal view virtual {
                    if (address(this) != __self) {
                        // Must not be called through delegatecall
                        revert UUPSUnauthorizedCallContext();
                    }
                }
                /**
                 * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                 * {upgradeToAndCall}.
                 *
                 * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                 *
                 * ```solidity
                 * function _authorizeUpgrade(address) internal onlyOwner {}
                 * ```
                 */
                function _authorizeUpgrade(address newImplementation) internal virtual;
                /**
                 * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
                 *
                 * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
                 * is expected to be the implementation slot in ERC1967.
                 *
                 * Emits an {IERC1967-Upgraded} event.
                 */
                function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
                    try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                        if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
                            revert UUPSUnsupportedProxiableUUID(slot);
                        }
                        ERC1967Utils.upgradeToAndCall(newImplementation, data);
                    } catch {
                        // The implementation is not UUPS
                        revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
            pragma solidity ^0.8.20;
            /**
             * @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]
             * ```solidity
             * 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 Storage of the initializable contract.
                 *
                 * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
                 * when using with upgradeable contracts.
                 *
                 * @custom:storage-location erc7201:openzeppelin.storage.Initializable
                 */
                struct InitializableStorage {
                    /**
                     * @dev Indicates that the contract has been initialized.
                     */
                    uint64 _initialized;
                    /**
                     * @dev Indicates that the contract is in the process of being initialized.
                     */
                    bool _initializing;
                }
                // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
                bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
                /**
                 * @dev The contract is already initialized.
                 */
                error InvalidInitialization();
                /**
                 * @dev The contract is not initializing.
                 */
                error NotInitializing();
                /**
                 * @dev Triggered when the contract has been initialized or reinitialized.
                 */
                event Initialized(uint64 version);
                /**
                 * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                 * `onlyInitializing` functions can be used to initialize parent contracts.
                 *
                 * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
                 * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
                 * production.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier initializer() {
                    // solhint-disable-next-line var-name-mixedcase
                    InitializableStorage storage $ = _getInitializableStorage();
                    // Cache values to avoid duplicated sloads
                    bool isTopLevelCall = !$._initializing;
                    uint64 initialized = $._initialized;
                    // Allowed calls:
                    // - initialSetup: the contract is not in the initializing state and no previous version was
                    //                 initialized
                    // - construction: the contract is initialized at version 1 (no reininitialization) and the
                    //                 current contract is just being deployed
                    bool initialSetup = initialized == 0 && isTopLevelCall;
                    bool construction = initialized == 1 && address(this).code.length == 0;
                    if (!initialSetup && !construction) {
                        revert InvalidInitialization();
                    }
                    $._initialized = 1;
                    if (isTopLevelCall) {
                        $._initializing = true;
                    }
                    _;
                    if (isTopLevelCall) {
                        $._initializing = false;
                        emit Initialized(1);
                    }
                }
                /**
                 * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                 * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                 * used to initialize parent contracts.
                 *
                 * A reinitializer may be used after the original initialization step. This is essential to configure modules that
                 * are added through upgrades and that require initialization.
                 *
                 * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
                 * cannot be nested. If one is invoked in the context of another, execution will revert.
                 *
                 * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                 * a contract, executing them in the right order is up to the developer or operator.
                 *
                 * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier reinitializer(uint64 version) {
                    // solhint-disable-next-line var-name-mixedcase
                    InitializableStorage storage $ = _getInitializableStorage();
                    if ($._initializing || $._initialized >= version) {
                        revert InvalidInitialization();
                    }
                    $._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() {
                    _checkInitializing();
                    _;
                }
                /**
                 * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
                 */
                function _checkInitializing() internal view virtual {
                    if (!_isInitializing()) {
                        revert NotInitializing();
                    }
                }
                /**
                 * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                 * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                 * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                 * through proxies.
                 *
                 * Emits an {Initialized} event the first time it is successfully executed.
                 */
                function _disableInitializers() internal virtual {
                    // solhint-disable-next-line var-name-mixedcase
                    InitializableStorage storage $ = _getInitializableStorage();
                    if ($._initializing) {
                        revert InvalidInitialization();
                    }
                    if ($._initialized != type(uint64).max) {
                        $._initialized = type(uint64).max;
                        emit Initialized(type(uint64).max);
                    }
                }
                /**
                 * @dev Returns the highest version that has been initialized. See {reinitializer}.
                 */
                function _getInitializedVersion() internal view returns (uint64) {
                    return _getInitializableStorage()._initialized;
                }
                /**
                 * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
                 */
                function _isInitializing() internal view returns (bool) {
                    return _getInitializableStorage()._initializing;
                }
                /**
                 * @dev Returns a pointer to the storage namespace.
                 */
                // solhint-disable-next-line var-name-mixedcase
                function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
                    assembly {
                        $.slot := INITIALIZABLE_STORAGE
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
            pragma solidity ^0.8.20;
            import {IERC20} from "../IERC20.sol";
            import {IERC20Permit} from "../extensions/IERC20Permit.sol";
            import {Address} from "../../../utils/Address.sol";
            /**
             * @title SafeERC20
             * @dev Wrappers around ERC20 operations that throw on failure (when the token
             * contract returns false). Tokens that return no value (and instead revert or
             * throw on failure) are also supported, non-reverting calls are assumed to be
             * successful.
             * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
             * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
             */
            library SafeERC20 {
                using Address for address;
                /**
                 * @dev An operation with an ERC20 token failed.
                 */
                error SafeERC20FailedOperation(address token);
                /**
                 * @dev Indicates a failed `decreaseAllowance` request.
                 */
                error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
                /**
                 * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
                 * non-reverting calls are assumed to be successful.
                 */
                function safeTransfer(IERC20 token, address to, uint256 value) internal {
                    _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
                }
                /**
                 * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
                 * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
                 */
                function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                    _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
                }
                /**
                 * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
                 * non-reverting calls are assumed to be successful.
                 */
                function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                    uint256 oldAllowance = token.allowance(address(this), spender);
                    forceApprove(token, spender, oldAllowance + value);
                }
                /**
                 * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
                 * value, non-reverting calls are assumed to be successful.
                 */
                function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
                    unchecked {
                        uint256 currentAllowance = token.allowance(address(this), spender);
                        if (currentAllowance < requestedDecrease) {
                            revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
                        }
                        forceApprove(token, spender, currentAllowance - requestedDecrease);
                    }
                }
                /**
                 * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
                 * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
                 * to be set to zero before setting it to a non-zero value, such as USDT.
                 */
                function forceApprove(IERC20 token, address spender, uint256 value) internal {
                    bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
                    if (!_callOptionalReturnBool(token, approvalCall)) {
                        _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
                        _callOptionalReturn(token, approvalCall);
                    }
                }
                /**
                 * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                 * on the return value: the return value is optional (but if data is returned, it must not be false).
                 * @param token The token targeted by the call.
                 * @param data The call data (encoded using abi.encode or one of its variants).
                 */
                function _callOptionalReturn(IERC20 token, bytes memory data) private {
                    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                    // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
                    // the target address contains contract code and also asserts for success in the low-level call.
                    bytes memory returndata = address(token).functionCall(data);
                    if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
                        revert SafeERC20FailedOperation(address(token));
                    }
                }
                /**
                 * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                 * on the return value: the return value is optional (but if data is returned, it must not be false).
                 * @param token The token targeted by the call.
                 * @param data The call data (encoded using abi.encode or one of its variants).
                 *
                 * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
                 */
                function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
                    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                    // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
                    // and not revert is the subcall reverts.
                    (bool success, bytes memory returndata) = address(token).call(data);
                    return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
            pragma solidity ^0.8.20;
            /**
             * @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 value of tokens in existence.
                 */
                function totalSupply() external view returns (uint256);
                /**
                 * @dev Returns the value of tokens owned by `account`.
                 */
                function balanceOf(address account) external view returns (uint256);
                /**
                 * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
                /**
                 * @dev Moves a `value` amount of tokens from `from` to `to` using the
                 * allowance mechanism. `value` 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 value) external returns (bool);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.20;
            /**
             * @dev Stake library used by PIKA pool and PIKA/USDT LP Pool.
             *
             * @dev Responsible to manage weight calculation and store important constants
             *      related to stake period, base weight and multipliers utilized.
             */
            library Stake {
                struct Data {
                    /// @dev token amount staked
                    uint256 value;
                    /// @dev locking period - from
                    uint256 lockedFrom;
                    /// @dev locking period - until
                    uint256 lockedUntil;
                    /// @dev whether the entry is unstaked 
                    bool isUnstaked;
                     /// @dev stakeId same as the array index 
                    uint256 stakeId;
                }
                /**
                 * @dev Stake weight is proportional to stake value and time locked, precisely
                 *      "stake value wei multiplied by (fraction of the year locked plus one)".
                 * @dev To avoid significant precision loss due to multiplication by "fraction of the year" [0, 1],
                 *      weight is stored multiplied by 1e6 constant, as an integer.
                 * @dev Corner case 1: if time locked is zero, weight is stake value multiplied by 1e6 + base weight
                 * @dev Corner case 2: if time locked is two years, division of
                        (lockedUntil - lockedFrom) / MAX_STAKE_PERIOD is 1e6, and
                 *      weight is a stake value multiplied by 2 * 1e6.
                 */
                uint256 internal constant WEIGHT_MULTIPLIER = 1e6;
                /**
                 * @dev Minimum weight value, if result of multiplication using WEIGHT_MULTIPLIER
                 *      is 0 (e.g stake flexible), then BASE_WEIGHT is used.
                 */
                uint256 internal constant BASE_WEIGHT = 1e6;
                /**
                 * @dev Minimum period that someone can lock a stake for.
                 */
                uint256 internal constant MIN_STAKE_PERIOD = 30 days;
                /**
                 * @dev Maximum period that someone can lock a stake for.
                 */
                uint256 internal constant MAX_STAKE_PERIOD = 365 days;
                /**
                 * @dev Rewards per weight are stored multiplied by 1e20 as uint.
                 */
                uint256 internal constant REWARD_PER_WEIGHT_MULTIPLIER = 1e20;
              
                function weight(Data storage _self) internal view returns (uint256) {
                    return
                        uint256(
                            (((_self.lockedUntil - _self.lockedFrom) * WEIGHT_MULTIPLIER) / MAX_STAKE_PERIOD + BASE_WEIGHT) *
                                _self.value
                        );
                }
                /**
                 * @dev Converts stake weight (not to be mixed with the pool weight) to
                 *      PIKA reward value, applying the 10^12 division on weight
                 *
                 * @param _weight stake weight
                 * @param _rewardPerWeight PIKA reward per weight
                 * @param _rewardPerWeightPaid last reward per weight value used for user earnings
                 * @return reward value normalized to 10^12
                 */
                function earned(
                    uint256 _weight,
                    uint256 _rewardPerWeight,
                    uint256 _rewardPerWeightPaid
                ) internal pure returns (uint256) {
                    // apply the formula and return
                    return (_weight * (_rewardPerWeight - _rewardPerWeightPaid)) / REWARD_PER_WEIGHT_MULTIPLIER;
                }
                /**
                 * @dev Converts reward PIKA value to stake weight (not to be mixed with the pool weight),
                 *      applying the 10^12 multiplication on the reward.
                 *      - OR -
                 * @dev Converts reward PIKA value to reward/weight if stake weight is supplied as second
                 *      function parameter instead of reward/weight.
                 *
                 * @param _reward yield reward
                 * @param _globalWeight total weight in the pool
                 * @return reward per weight value
                 */
                function getRewardPerWeight(uint256 _reward, uint256 _globalWeight) internal pure returns (uint256) {
                    // apply the reverse formula and return
                    return (_reward * REWARD_PER_WEIGHT_MULTIPLIER) / _globalWeight;
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
            pragma solidity ^0.8.20;
            /**
             * @dev Collection of functions related to the address type
             */
            library Address {
                /**
                 * @dev The ETH balance of the account is not enough to perform the operation.
                 */
                error AddressInsufficientBalance(address account);
                /**
                 * @dev There's no code at `target` (it is not a contract).
                 */
                error AddressEmptyCode(address target);
                /**
                 * @dev A call to an address target failed. The target may have reverted.
                 */
                error FailedInnerCall();
                /**
                 * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                 */
                function sendValue(address payable recipient, uint256 amount) internal {
                    if (address(this).balance < amount) {
                        revert AddressInsufficientBalance(address(this));
                    }
                    (bool success, ) = recipient.call{value: amount}("");
                    if (!success) {
                        revert FailedInnerCall();
                    }
                }
                /**
                 * @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 or custom error, it is bubbled
                 * up by this function (like regular Solidity function calls). However, if
                 * the call reverted with no returned reason, this function reverts with a
                 * {FailedInnerCall} error.
                 *
                 * 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.
                 */
                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, 0);
                }
                /**
                 * @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`.
                 */
                function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                    if (address(this).balance < value) {
                        revert AddressInsufficientBalance(address(this));
                    }
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a static call.
                 */
                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a delegate call.
                 */
                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
                 * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
                 * unsuccessful call.
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata
                ) internal view returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        // only check if target is a contract if the call was successful and the return data is empty
                        // otherwise we already know that it was a contract
                        if (returndata.length == 0 && target.code.length == 0) {
                            revert AddressEmptyCode(target);
                        }
                        return returndata;
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
                 * revert reason or with a default {FailedInnerCall} error.
                 */
                function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        return returndata;
                    }
                }
                /**
                 * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
                 */
                function _revert(bytes memory returndata) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert FailedInnerCall();
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
            pragma solidity ^0.8.20;
            /**
             * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
             * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
             *
             * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
             * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
             * need to send a transaction, and thus is not required to hold Ether at all.
             *
             * ==== Security Considerations
             *
             * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
             * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
             * considered as an intention to spend the allowance in any specific way. The second is that because permits have
             * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
             * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
             * generally recommended is:
             *
             * ```solidity
             * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
             *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
             *     doThing(..., value);
             * }
             *
             * function doThing(..., uint256 value) public {
             *     token.safeTransferFrom(msg.sender, address(this), value);
             *     ...
             * }
             * ```
             *
             * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
             * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
             * {SafeERC20-safeTransferFrom}).
             *
             * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
             * contracts should have entry points that don't rely on permit.
             */
            interface IERC20Permit {
                /**
                 * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
                 * given ``owner``'s signed approval.
                 *
                 * IMPORTANT: The same issues {IERC20-approve} has related to transaction
                 * ordering also apply here.
                 *
                 * Emits an {Approval} event.
                 *
                 * Requirements:
                 *
                 * - `spender` cannot be the zero address.
                 * - `deadline` must be a timestamp in the future.
                 * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
                 * over the EIP712-formatted function arguments.
                 * - the signature must use ``owner``'s current nonce (see {nonces}).
                 *
                 * For more information on the signature format, see the
                 * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
                 * section].
                 *
                 * CAUTION: See Security Considerations above.
                 */
                function permit(
                    address owner,
                    address spender,
                    uint256 value,
                    uint256 deadline,
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                ) external;
                /**
                 * @dev Returns the current nonce for `owner`. This value must be
                 * included whenever a signature is generated for {permit}.
                 *
                 * Every successful call to {permit} increases ``owner``'s nonce by one. This
                 * prevents a signature from being used multiple times.
                 */
                function nonces(address owner) external view returns (uint256);
                /**
                 * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
                 */
                // solhint-disable-next-line func-name-mixedcase
                function DOMAIN_SEPARATOR() external view returns (bytes32);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
            pragma solidity ^0.8.20;
            import {IBeacon} from "../beacon/IBeacon.sol";
            import {Address} from "../../utils/Address.sol";
            import {StorageSlot} from "../../utils/StorageSlot.sol";
            /**
             * @dev This abstract contract provides getters and event emitting update functions for
             * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
             */
            library ERC1967Utils {
                // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
                // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
                /**
                 * @dev Storage slot with the address of the current implementation.
                 * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                /**
                 * @dev The `implementation` of the proxy is invalid.
                 */
                error ERC1967InvalidImplementation(address implementation);
                /**
                 * @dev The `admin` of the proxy is invalid.
                 */
                error ERC1967InvalidAdmin(address admin);
                /**
                 * @dev The `beacon` of the proxy is invalid.
                 */
                error ERC1967InvalidBeacon(address beacon);
                /**
                 * @dev An upgrade function sees `msg.value > 0` that may be lost.
                 */
                error ERC1967NonPayable();
                /**
                 * @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 {
                    if (newImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(newImplementation);
                    }
                    StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
                }
                /**
                 * @dev Performs implementation upgrade with additional setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-Upgraded} event.
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) internal {
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
                    if (data.length > 0) {
                        Address.functionDelegateCall(newImplementation, data);
                    } else {
                        _checkNonPayable();
                    }
                }
                /**
                 * @dev Storage slot with the admin of the contract.
                 * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                /**
                 * @dev Returns the current admin.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
                 * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                 */
                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 {
                    if (newAdmin == address(0)) {
                        revert ERC1967InvalidAdmin(address(0));
                    }
                    StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
                }
                /**
                 * @dev Changes the admin of the proxy.
                 *
                 * Emits an {IERC1967-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 the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                /**
                 * @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 {
                    if (newBeacon.code.length == 0) {
                        revert ERC1967InvalidBeacon(newBeacon);
                    }
                    StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
                    address beaconImplementation = IBeacon(newBeacon).implementation();
                    if (beaconImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(beaconImplementation);
                    }
                }
                /**
                 * @dev Change the beacon and trigger a setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-BeaconUpgraded} event.
                 *
                 * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
                 * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
                 * efficiency.
                 */
                function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
                    _setBeacon(newBeacon);
                    emit BeaconUpgraded(newBeacon);
                    if (data.length > 0) {
                        Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                    } else {
                        _checkNonPayable();
                    }
                }
                /**
                 * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
                 * if an upgrade doesn't perform an initialization call.
                 */
                function _checkNonPayable() private {
                    if (msg.value > 0) {
                        revert ERC1967NonPayable();
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
            pragma solidity ^0.8.20;
            /**
             * @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 (last updated v5.0.1) (utils/Context.sol)
            pragma solidity ^0.8.20;
            import {Initializable} from "../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;
                }
                function _contextSuffixLength() internal view virtual returns (uint256) {
                    return 0;
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            pragma solidity ^0.8.20;
            /**
             * @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:
             * ```solidity
             * 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(newImplementation.code.length > 0);
             *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
             *     }
             * }
             * ```
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                struct StringSlot {
                    string value;
                }
                struct BytesSlot {
                    bytes 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
                    }
                }
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
            pragma solidity ^0.8.20;
            /**
             * @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.
                 *
                 * {UpgradeableBeacon} will check that this address is a contract.
                 */
                function implementation() external view returns (address);
            }
            

            File 6 of 6: PikaMoon
            // SPDX-License-Identifier: UNLICENSED
            
            pragma solidity 0.8.20;
            
            /**
             * @dev This smart contract defines custom errors that can be thrown during specific conditions in contracts.
             */
            
            library CommanErrors {
                error ZeroAmount();
                error ZeroAddress();
                error WrongTax();
                error PairIsAlreadyGivenValue();
            }
            
            // File: @openzeppelin/contracts/utils/StorageSlot.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            
            pragma solidity ^0.8.20;
            
            /**
             * @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:
             * ```solidity
             * 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(newImplementation.code.length > 0);
             *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
             *     }
             * }
             * ```
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
            
                struct BooleanSlot {
                    bool value;
                }
            
                struct Bytes32Slot {
                    bytes32 value;
                }
            
                struct Uint256Slot {
                    uint256 value;
                }
            
                struct StringSlot {
                    string value;
                }
            
                struct BytesSlot {
                    bytes 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
                    }
                }
            
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
            
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
            
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            
            // File: @openzeppelin/contracts/utils/Address.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @dev Collection of functions related to the address type
             */
            library Address {
                /**
                 * @dev The ETH balance of the account is not enough to perform the operation.
                 */
                error AddressInsufficientBalance(address account);
            
                /**
                 * @dev There's no code at `target` (it is not a contract).
                 */
                error AddressEmptyCode(address target);
            
                /**
                 * @dev A call to an address target failed. The target may have reverted.
                 */
                error FailedInnerCall();
            
                /**
                 * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                 */
                function sendValue(address payable recipient, uint256 amount) internal {
                    if (address(this).balance < amount) {
                        revert AddressInsufficientBalance(address(this));
                    }
            
                    (bool success, ) = recipient.call{value: amount}("");
                    if (!success) {
                        revert FailedInnerCall();
                    }
                }
            
                /**
                 * @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 or custom error, it is bubbled
                 * up by this function (like regular Solidity function calls). However, if
                 * the call reverted with no returned reason, this function reverts with a
                 * {FailedInnerCall} error.
                 *
                 * 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.
                 */
                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, 0);
                }
            
                /**
                 * @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`.
                 */
                function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                    if (address(this).balance < value) {
                        revert AddressInsufficientBalance(address(this));
                    }
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a static call.
                 */
                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a delegate call.
                 */
                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata);
                }
            
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
                 * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
                 * unsuccessful call.
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata
                ) internal view returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        // only check if target is a contract if the call was successful and the return data is empty
                        // otherwise we already know that it was a contract
                        if (returndata.length == 0 && target.code.length == 0) {
                            revert AddressEmptyCode(target);
                        }
                        return returndata;
                    }
                }
            
                /**
                 * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
                 * revert reason or with a default {FailedInnerCall} error.
                 */
                function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                    if (!success) {
                        _revert(returndata);
                    } else {
                        return returndata;
                    }
                }
            
                /**
                 * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
                 */
                function _revert(bytes memory returndata) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert FailedInnerCall();
                    }
                }
            }
            
            // File: @openzeppelin/contracts/proxy/beacon/IBeacon.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @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.
                 *
                 * {UpgradeableBeacon} will check that this address is a contract.
                 */
                function implementation() external view returns (address);
            }
            
            // File: @openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
            
            pragma solidity ^0.8.20;
            
            
            
            
            /**
             * @dev This abstract contract provides getters and event emitting update functions for
             * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
             */
            library ERC1967Utils {
                // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
                // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
            
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
            
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
            
                /**
                 * @dev Storage slot with the address of the current implementation.
                 * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
            
                /**
                 * @dev The `implementation` of the proxy is invalid.
                 */
                error ERC1967InvalidImplementation(address implementation);
            
                /**
                 * @dev The `admin` of the proxy is invalid.
                 */
                error ERC1967InvalidAdmin(address admin);
            
                /**
                 * @dev The `beacon` of the proxy is invalid.
                 */
                error ERC1967InvalidBeacon(address beacon);
            
                /**
                 * @dev An upgrade function sees `msg.value > 0` that may be lost.
                 */
                error ERC1967NonPayable();
            
                /**
                 * @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 {
                    if (newImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(newImplementation);
                    }
                    StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
                }
            
                /**
                 * @dev Performs implementation upgrade with additional setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-Upgraded} event.
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) internal {
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
            
                    if (data.length > 0) {
                        Address.functionDelegateCall(newImplementation, data);
                    } else {
                        _checkNonPayable();
                    }
                }
            
                /**
                 * @dev Storage slot with the admin of the contract.
                 * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
            
                /**
                 * @dev Returns the current admin.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
                 * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                 */
                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 {
                    if (newAdmin == address(0)) {
                        revert ERC1967InvalidAdmin(address(0));
                    }
                    StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
                }
            
                /**
                 * @dev Changes the admin of the proxy.
                 *
                 * Emits an {IERC1967-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 the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
                 */
                // solhint-disable-next-line private-vars-leading-underscore
                bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
            
                /**
                 * @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 {
                    if (newBeacon.code.length == 0) {
                        revert ERC1967InvalidBeacon(newBeacon);
                    }
            
                    StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
            
                    address beaconImplementation = IBeacon(newBeacon).implementation();
                    if (beaconImplementation.code.length == 0) {
                        revert ERC1967InvalidImplementation(beaconImplementation);
                    }
                }
            
                /**
                 * @dev Change the beacon and trigger a setup call if data is nonempty.
                 * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                 * to avoid stuck value in the contract.
                 *
                 * Emits an {IERC1967-BeaconUpgraded} event.
                 *
                 * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
                 * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
                 * efficiency.
                 */
                function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
                    _setBeacon(newBeacon);
                    emit BeaconUpgraded(newBeacon);
            
                    if (data.length > 0) {
                        Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                    } else {
                        _checkNonPayable();
                    }
                }
            
                /**
                 * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
                 * if an upgrade doesn't perform an initialization call.
                 */
                function _checkNonPayable() private {
                    if (msg.value > 0) {
                        revert ERC1967NonPayable();
                    }
                }
            }
            
            // File: @openzeppelin/contracts/interfaces/draft-IERC1822.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @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);
            }
            
            // File: @openzeppelin/contracts/utils/introspection/IERC165.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @dev Interface of the ERC165 standard, as defined in the
             * https://eips.ethereum.org/EIPS/eip-165[EIP].
             *
             * Implementers can declare support of contract interfaces, which can then be
             * queried by others ({ERC165Checker}).
             *
             * For an implementation, see {ERC165}.
             */
            interface IERC165 {
                /**
                 * @dev Returns true if this contract implements the interface defined by
                 * `interfaceId`. See the corresponding
                 * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                 * to learn more about how these ids are created.
                 *
                 * This function call must use less than 30 000 gas.
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool);
            }
            
            // File: @openzeppelin/contracts/access/IAccessControl.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @dev External interface of AccessControl declared to support ERC165 detection.
             */
            interface IAccessControl {
                /**
                 * @dev The `account` is missing a role.
                 */
                error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
            
                /**
                 * @dev The caller of a function is not the expected one.
                 *
                 * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
                 */
                error AccessControlBadConfirmation();
            
                /**
                 * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                 *
                 * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                 * {RoleAdminChanged} not being emitted signaling this.
                 */
                event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
            
                /**
                 * @dev Emitted when `account` is granted `role`.
                 *
                 * `sender` is the account that originated the contract call, an admin role
                 * bearer except when using {AccessControl-_setupRole}.
                 */
                event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
            
                /**
                 * @dev Emitted when `account` is revoked `role`.
                 *
                 * `sender` is the account that originated the contract call:
                 *   - if using `revokeRole`, it is the admin role bearer
                 *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                 */
                event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
            
                /**
                 * @dev Returns `true` if `account` has been granted `role`.
                 */
                function hasRole(bytes32 role, address account) external view returns (bool);
            
                /**
                 * @dev Returns the admin role that controls `role`. See {grantRole} and
                 * {revokeRole}.
                 *
                 * To change a role's admin, use {AccessControl-_setRoleAdmin}.
                 */
                function getRoleAdmin(bytes32 role) external view returns (bytes32);
            
                /**
                 * @dev Grants `role` to `account`.
                 *
                 * If `account` had not been already granted `role`, emits a {RoleGranted}
                 * event.
                 *
                 * Requirements:
                 *
                 * - the caller must have ``role``'s admin role.
                 */
                function grantRole(bytes32 role, address account) external;
            
                /**
                 * @dev Revokes `role` from `account`.
                 *
                 * If `account` had been granted `role`, emits a {RoleRevoked} event.
                 *
                 * Requirements:
                 *
                 * - the caller must have ``role``'s admin role.
                 */
                function revokeRole(bytes32 role, address account) external;
            
                /**
                 * @dev Revokes `role` from the calling account.
                 *
                 * Roles are often managed via {grantRole} and {revokeRole}: this function's
                 * purpose is to provide a mechanism for accounts to lose their privileges
                 * if they are compromised (such as when a trusted device is misplaced).
                 *
                 * If the calling account had been granted `role`, emits a {RoleRevoked}
                 * event.
                 *
                 * Requirements:
                 *
                 * - the caller must be `callerConfirmation`.
                 */
                function renounceRole(bytes32 role, address callerConfirmation) external;
            }
            
            // File: @openzeppelin/contracts/interfaces/draft-IERC6093.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
            pragma solidity ^0.8.20;
            
            /**
             * @dev Standard ERC20 Errors
             * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
             */
            interface IERC20Errors {
                /**
                 * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
                 * @param sender Address whose tokens are being transferred.
                 * @param balance Current balance for the interacting account.
                 * @param needed Minimum amount required to perform a transfer.
                 */
                error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
            
                /**
                 * @dev Indicates a failure with the token `sender`. Used in transfers.
                 * @param sender Address whose tokens are being transferred.
                 */
                error ERC20InvalidSender(address sender);
            
                /**
                 * @dev Indicates a failure with the token `receiver`. Used in transfers.
                 * @param receiver Address to which tokens are being transferred.
                 */
                error ERC20InvalidReceiver(address receiver);
            
                /**
                 * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
                 * @param spender Address that may be allowed to operate on tokens without being their owner.
                 * @param allowance Amount of tokens a `spender` is allowed to operate with.
                 * @param needed Minimum amount required to perform a transfer.
                 */
                error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
            
                /**
                 * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
                 * @param approver Address initiating an approval operation.
                 */
                error ERC20InvalidApprover(address approver);
            
                /**
                 * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
                 * @param spender Address that may be allowed to operate on tokens without being their owner.
                 */
                error ERC20InvalidSpender(address spender);
            }
            
            /**
             * @dev Standard ERC721 Errors
             * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
             */
            interface IERC721Errors {
                /**
                 * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
                 * Used in balance queries.
                 * @param owner Address of the current owner of a token.
                 */
                error ERC721InvalidOwner(address owner);
            
                /**
                 * @dev Indicates a `tokenId` whose `owner` is the zero address.
                 * @param tokenId Identifier number of a token.
                 */
                error ERC721NonexistentToken(uint256 tokenId);
            
                /**
                 * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
                 * @param sender Address whose tokens are being transferred.
                 * @param tokenId Identifier number of a token.
                 * @param owner Address of the current owner of a token.
                 */
                error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
            
                /**
                 * @dev Indicates a failure with the token `sender`. Used in transfers.
                 * @param sender Address whose tokens are being transferred.
                 */
                error ERC721InvalidSender(address sender);
            
                /**
                 * @dev Indicates a failure with the token `receiver`. Used in transfers.
                 * @param receiver Address to which tokens are being transferred.
                 */
                error ERC721InvalidReceiver(address receiver);
            
                /**
                 * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
                 * @param operator Address that may be allowed to operate on tokens without being their owner.
                 * @param tokenId Identifier number of a token.
                 */
                error ERC721InsufficientApproval(address operator, uint256 tokenId);
            
                /**
                 * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
                 * @param approver Address initiating an approval operation.
                 */
                error ERC721InvalidApprover(address approver);
            
                /**
                 * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
                 * @param operator Address that may be allowed to operate on tokens without being their owner.
                 */
                error ERC721InvalidOperator(address operator);
            }
            
            /**
             * @dev Standard ERC1155 Errors
             * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
             */
            interface IERC1155Errors {
                /**
                 * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
                 * @param sender Address whose tokens are being transferred.
                 * @param balance Current balance for the interacting account.
                 * @param needed Minimum amount required to perform a transfer.
                 * @param tokenId Identifier number of a token.
                 */
                error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
            
                /**
                 * @dev Indicates a failure with the token `sender`. Used in transfers.
                 * @param sender Address whose tokens are being transferred.
                 */
                error ERC1155InvalidSender(address sender);
            
                /**
                 * @dev Indicates a failure with the token `receiver`. Used in transfers.
                 * @param receiver Address to which tokens are being transferred.
                 */
                error ERC1155InvalidReceiver(address receiver);
            
                /**
                 * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
                 * @param operator Address that may be allowed to operate on tokens without being their owner.
                 * @param owner Address of the current owner of a token.
                 */
                error ERC1155MissingApprovalForAll(address operator, address owner);
            
                /**
                 * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
                 * @param approver Address initiating an approval operation.
                 */
                error ERC1155InvalidApprover(address approver);
            
                /**
                 * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
                 * @param operator Address that may be allowed to operate on tokens without being their owner.
                 */
                error ERC1155InvalidOperator(address operator);
            
                /**
                 * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
                 * Used in batch transfers.
                 * @param idsLength Length of the array of token identifiers
                 * @param valuesLength Length of the array of token amounts
                 */
                error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
            }
            
            // File: @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @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]
             * ```solidity
             * 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 Storage of the initializable contract.
                 *
                 * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
                 * when using with upgradeable contracts.
                 *
                 * @custom:storage-location erc7201:openzeppelin.storage.Initializable
                 */
                struct InitializableStorage {
                    /**
                     * @dev Indicates that the contract has been initialized.
                     */
                    uint64 _initialized;
                    /**
                     * @dev Indicates that the contract is in the process of being initialized.
                     */
                    bool _initializing;
                }
            
                // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
                bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
            
                /**
                 * @dev The contract is already initialized.
                 */
                error InvalidInitialization();
            
                /**
                 * @dev The contract is not initializing.
                 */
                error NotInitializing();
            
                /**
                 * @dev Triggered when the contract has been initialized or reinitialized.
                 */
                event Initialized(uint64 version);
            
                /**
                 * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                 * `onlyInitializing` functions can be used to initialize parent contracts.
                 *
                 * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
                 * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
                 * production.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier initializer() {
                    // solhint-disable-next-line var-name-mixedcase
                    InitializableStorage storage $ = _getInitializableStorage();
            
                    // Cache values to avoid duplicated sloads
                    bool isTopLevelCall = !$._initializing;
                    uint64 initialized = $._initialized;
            
                    // Allowed calls:
                    // - initialSetup: the contract is not in the initializing state and no previous version was
                    //                 initialized
                    // - construction: the contract is initialized at version 1 (no reininitialization) and the
                    //                 current contract is just being deployed
                    bool initialSetup = initialized == 0 && isTopLevelCall;
                    bool construction = initialized == 1 && address(this).code.length == 0;
            
                    if (!initialSetup && !construction) {
                        revert InvalidInitialization();
                    }
                    $._initialized = 1;
                    if (isTopLevelCall) {
                        $._initializing = true;
                    }
                    _;
                    if (isTopLevelCall) {
                        $._initializing = false;
                        emit Initialized(1);
                    }
                }
            
                /**
                 * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                 * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                 * used to initialize parent contracts.
                 *
                 * A reinitializer may be used after the original initialization step. This is essential to configure modules that
                 * are added through upgrades and that require initialization.
                 *
                 * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
                 * cannot be nested. If one is invoked in the context of another, execution will revert.
                 *
                 * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                 * a contract, executing them in the right order is up to the developer or operator.
                 *
                 * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier reinitializer(uint64 version) {
                    // solhint-disable-next-line var-name-mixedcase
                    InitializableStorage storage $ = _getInitializableStorage();
            
                    if ($._initializing || $._initialized >= version) {
                        revert InvalidInitialization();
                    }
                    $._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() {
                    _checkInitializing();
                    _;
                }
            
                /**
                 * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
                 */
                function _checkInitializing() internal view virtual {
                    if (!_isInitializing()) {
                        revert NotInitializing();
                    }
                }
            
                /**
                 * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                 * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                 * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                 * through proxies.
                 *
                 * Emits an {Initialized} event the first time it is successfully executed.
                 */
                function _disableInitializers() internal virtual {
                    // solhint-disable-next-line var-name-mixedcase
                    InitializableStorage storage $ = _getInitializableStorage();
            
                    if ($._initializing) {
                        revert InvalidInitialization();
                    }
                    if ($._initialized != type(uint64).max) {
                        $._initialized = type(uint64).max;
                        emit Initialized(type(uint64).max);
                    }
                }
            
                /**
                 * @dev Returns the highest version that has been initialized. See {reinitializer}.
                 */
                function _getInitializedVersion() internal view returns (uint64) {
                    return _getInitializableStorage()._initialized;
                }
            
                /**
                 * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
                 */
                function _isInitializing() internal view returns (bool) {
                    return _getInitializableStorage()._initializing;
                }
            
                /**
                 * @dev Returns a pointer to the storage namespace.
                 */
                // solhint-disable-next-line var-name-mixedcase
                function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
                    assembly {
                        $.slot := INITIALIZABLE_STORAGE
                    }
                }
            }
            
            // File: @openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
            
            pragma solidity ^0.8.20;
            
            
            
            
            /**
             * @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.
             */
            abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
                /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
                address private immutable __self = address(this);
            
                /**
                 * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
                 * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
                 * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
                 * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
                 * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
                 * during an upgrade.
                 */
                string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
            
                /**
                 * @dev The call is from an unauthorized context.
                 */
                error UUPSUnauthorizedCallContext();
            
                /**
                 * @dev The storage `slot` is unsupported as a UUID.
                 */
                error UUPSUnsupportedProxiableUUID(bytes32 slot);
            
                /**
                 * @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() {
                    _checkProxy();
                    _;
                }
            
                /**
                 * @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() {
                    _checkNotDelegated();
                    _;
                }
            
                function __UUPSUpgradeable_init() internal onlyInitializing {
                }
            
                function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
                }
                /**
                 * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
                 * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
                 *
                 * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                 * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                 * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
                 */
                function proxiableUUID() external view virtual notDelegated returns (bytes32) {
                    return ERC1967Utils.IMPLEMENTATION_SLOT;
                }
            
                /**
                 * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
                 * encoded in `data`.
                 *
                 * Calls {_authorizeUpgrade}.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
                    _authorizeUpgrade(newImplementation);
                    _upgradeToAndCallUUPS(newImplementation, data);
                }
            
                /**
                 * @dev Reverts if the execution is not performed via delegatecall or the execution
                 * context is not of a proxy with an ERC1967-compliant implementation pointing to self.
                 * See {_onlyProxy}.
                 */
                function _checkProxy() internal view virtual {
                    if (
                        address(this) == __self || // Must be called through delegatecall
                        ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
                    ) {
                        revert UUPSUnauthorizedCallContext();
                    }
                }
            
                /**
                 * @dev Reverts if the execution is performed via delegatecall.
                 * See {notDelegated}.
                 */
                function _checkNotDelegated() internal view virtual {
                    if (address(this) != __self) {
                        // Must not be called through delegatecall
                        revert UUPSUnauthorizedCallContext();
                    }
                }
            
                /**
                 * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                 * {upgradeToAndCall}.
                 *
                 * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                 *
                 * ```solidity
                 * function _authorizeUpgrade(address) internal onlyOwner {}
                 * ```
                 */
                function _authorizeUpgrade(address newImplementation) internal virtual;
            
                /**
                 * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
                 *
                 * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
                 * is expected to be the implementation slot in ERC1967.
                 *
                 * Emits an {IERC1967-Upgraded} event.
                 */
                function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
                    try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                        if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
                            revert UUPSUnsupportedProxiableUUID(slot);
                        }
                        ERC1967Utils.upgradeToAndCall(newImplementation, data);
                    } catch {
                        // The implementation is not UUPS
                        revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
                    }
                }
            }
            
            // File: @openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
            
            pragma solidity ^0.8.20;
            
            
            
            /**
             * @dev Implementation of the {IERC165} interface.
             *
             * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
             * for the additional interface id that will be supported. For example:
             *
             * ```solidity
             * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
             *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
             * }
             * ```
             */
            abstract contract ERC165Upgradeable is Initializable, IERC165 {
                function __ERC165_init() internal onlyInitializing {
                }
            
                function __ERC165_init_unchained() internal onlyInitializing {
                }
                /**
                 * @dev See {IERC165-supportsInterface}.
                 */
                function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
                    return interfaceId == type(IERC165).interfaceId;
                }
            }
            
            // File: @openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
            
            pragma solidity ^0.8.20;
            
            
            /**
             * @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;
                }
            
                function _contextSuffixLength() internal view virtual returns (uint256) {
                    return 0;
                }
            }
            
            // File: @openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
            
            pragma solidity ^0.8.20;
            
            
            
            
            
            /**
             * @dev Contract module that allows children to implement role-based access
             * control mechanisms. This is a lightweight version that doesn't allow enumerating role
             * members except through off-chain means by accessing the contract event logs. Some
             * applications may benefit from on-chain enumerability, for those cases see
             * {AccessControlEnumerable}.
             *
             * Roles are referred to by their `bytes32` identifier. These should be exposed
             * in the external API and be unique. The best way to achieve this is by
             * using `public constant` hash digests:
             *
             * ```solidity
             * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
             * ```
             *
             * Roles can be used to represent a set of permissions. To restrict access to a
             * function call, use {hasRole}:
             *
             * ```solidity
             * function foo() public {
             *     require(hasRole(MY_ROLE, msg.sender));
             *     ...
             * }
             * ```
             *
             * Roles can be granted and revoked dynamically via the {grantRole} and
             * {revokeRole} functions. Each role has an associated admin role, and only
             * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
             *
             * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
             * that only accounts with this role will be able to grant or revoke other
             * roles. More complex role relationships can be created by using
             * {_setRoleAdmin}.
             *
             * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
             * grant and revoke this role. Extra precautions should be taken to secure
             * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
             * to enforce additional security measures for this role.
             */
            abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
                struct RoleData {
                    mapping(address account => bool) hasRole;
                    bytes32 adminRole;
                }
            
                bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
            
            
                /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
                struct AccessControlStorage {
                    mapping(bytes32 role => RoleData) _roles;
                }
            
                // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
                bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
            
                function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
                    assembly {
                        $.slot := AccessControlStorageLocation
                    }
                }
            
                /**
                 * @dev Modifier that checks that an account has a specific role. Reverts
                 * with an {AccessControlUnauthorizedAccount} error including the required role.
                 */
                modifier onlyRole(bytes32 role) {
                    _checkRole(role);
                    _;
                }
            
                function __AccessControl_init() internal onlyInitializing {
                }
            
                function __AccessControl_init_unchained() internal onlyInitializing {
                }
                /**
                 * @dev See {IERC165-supportsInterface}.
                 */
                function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                    return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
                }
            
                /**
                 * @dev Returns `true` if `account` has been granted `role`.
                 */
                function hasRole(bytes32 role, address account) public view virtual returns (bool) {
                    AccessControlStorage storage $ = _getAccessControlStorage();
                    return $._roles[role].hasRole[account];
                }
            
                /**
                 * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
                 * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
                 */
                function _checkRole(bytes32 role) internal view virtual {
                    _checkRole(role, _msgSender());
                }
            
                /**
                 * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
                 * is missing `role`.
                 */
                function _checkRole(bytes32 role, address account) internal view virtual {
                    if (!hasRole(role, account)) {
                        revert AccessControlUnauthorizedAccount(account, role);
                    }
                }
            
                /**
                 * @dev Returns the admin role that controls `role`. See {grantRole} and
                 * {revokeRole}.
                 *
                 * To change a role's admin, use {_setRoleAdmin}.
                 */
                function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
                    AccessControlStorage storage $ = _getAccessControlStorage();
                    return $._roles[role].adminRole;
                }
            
                /**
                 * @dev Grants `role` to `account`.
                 *
                 * If `account` had not been already granted `role`, emits a {RoleGranted}
                 * event.
                 *
                 * Requirements:
                 *
                 * - the caller must have ``role``'s admin role.
                 *
                 * May emit a {RoleGranted} event.
                 */
                function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
                    _grantRole(role, account);
                }
            
                /**
                 * @dev Revokes `role` from `account`.
                 *
                 * If `account` had been granted `role`, emits a {RoleRevoked} event.
                 *
                 * Requirements:
                 *
                 * - the caller must have ``role``'s admin role.
                 *
                 * May emit a {RoleRevoked} event.
                 */
                function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
                    _revokeRole(role, account);
                }
            
                /**
                 * @dev Revokes `role` from the calling account.
                 *
                 * Roles are often managed via {grantRole} and {revokeRole}: this function's
                 * purpose is to provide a mechanism for accounts to lose their privileges
                 * if they are compromised (such as when a trusted device is misplaced).
                 *
                 * If the calling account had been revoked `role`, emits a {RoleRevoked}
                 * event.
                 *
                 * Requirements:
                 *
                 * - the caller must be `callerConfirmation`.
                 *
                 * May emit a {RoleRevoked} event.
                 */
                function renounceRole(bytes32 role, address callerConfirmation) public virtual {
                    if (callerConfirmation != _msgSender()) {
                        revert AccessControlBadConfirmation();
                    }
            
                    _revokeRole(role, callerConfirmation);
                }
            
                /**
                 * @dev Sets `adminRole` as ``role``'s admin role.
                 *
                 * Emits a {RoleAdminChanged} event.
                 */
                function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                    AccessControlStorage storage $ = _getAccessControlStorage();
                    bytes32 previousAdminRole = getRoleAdmin(role);
                    $._roles[role].adminRole = adminRole;
                    emit RoleAdminChanged(role, previousAdminRole, adminRole);
                }
            
                /**
                 * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
                 *
                 * Internal function without access restriction.
                 *
                 * May emit a {RoleGranted} event.
                 */
                function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
                    AccessControlStorage storage $ = _getAccessControlStorage();
                    if (!hasRole(role, account)) {
                        $._roles[role].hasRole[account] = true;
                        emit RoleGranted(role, account, _msgSender());
                        return true;
                    } else {
                        return false;
                    }
                }
            
                /**
                 * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
                 *
                 * Internal function without access restriction.
                 *
                 * May emit a {RoleRevoked} event.
                 */
                function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
                    AccessControlStorage storage $ = _getAccessControlStorage();
                    if (hasRole(role, account)) {
                        $._roles[role].hasRole[account] = false;
                        emit RoleRevoked(role, account, _msgSender());
                        return true;
                    } else {
                        return false;
                    }
                }
            }
            
            // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
            
            pragma solidity ^0.8.20;
            
            /**
             * @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 value of tokens in existence.
                 */
                function totalSupply() external view returns (uint256);
            
                /**
                 * @dev Returns the value of tokens owned by `account`.
                 */
                function balanceOf(address account) external view returns (uint256);
            
                /**
                 * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
            
                /**
                 * @dev Moves a `value` amount of tokens from `from` to `to` using the
                 * allowance mechanism. `value` 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 value) external returns (bool);
            }
            
            // File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
            
            pragma solidity ^0.8.20;
            
            
            /**
             * @dev Interface for the optional metadata functions from the ERC20 standard.
             */
            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);
            }
            
            // File: @openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
            
            pragma solidity ^0.8.20;
            
            
            
            
            
            
            /**
             * @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}.
             *
             * TIP: For a detailed writeup see our guide
             * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
             * to implement supply mechanisms].
             *
             * The default value of {decimals} is 18. To change this, you should override
             * this function so it returns a different value.
             *
             * 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.
             */
            abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors {
                /// @custom:storage-location erc7201:openzeppelin.storage.ERC20
                struct ERC20Storage {
                    mapping(address account => uint256) _balances;
            
                    mapping(address account => mapping(address spender => uint256)) _allowances;
            
                    uint256 _totalSupply;
            
                    string _name;
                    string _symbol;
                }
            
                // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff))
                bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;
            
                function _getERC20Storage() private pure returns (ERC20Storage storage $) {
                    assembly {
                        $.slot := ERC20StorageLocation
                    }
                }
            
                /**
                 * @dev Sets the values for {name} and {symbol}.
                 *
                 * 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 {
                    ERC20Storage storage $ = _getERC20Storage();
                    $._name = name_;
                    $._symbol = symbol_;
                }
            
                /**
                 * @dev Returns the name of the token.
                 */
                function name() public view virtual returns (string memory) {
                    ERC20Storage storage $ = _getERC20Storage();
                    return $._name;
                }
            
                /**
                 * @dev Returns the symbol of the token, usually a shorter version of the
                 * name.
                 */
                function symbol() public view virtual returns (string memory) {
                    ERC20Storage storage $ = _getERC20Storage();
                    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 default value returned by this function, unless
                 * it's 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 returns (uint8) {
                    return 18;
                }
            
                /**
                 * @dev See {IERC20-totalSupply}.
                 */
                function totalSupply() public view virtual returns (uint256) {
                    ERC20Storage storage $ = _getERC20Storage();
                    return $._totalSupply;
                }
            
                /**
                 * @dev See {IERC20-balanceOf}.
                 */
                function balanceOf(address account) public view virtual returns (uint256) {
                    ERC20Storage storage $ = _getERC20Storage();
                    return $._balances[account];
                }
            
                /**
                 * @dev See {IERC20-transfer}.
                 *
                 * Requirements:
                 *
                 * - `to` cannot be the zero address.
                 * - the caller must have a balance of at least `value`.
                 */
                function transfer(address to, uint256 value) public virtual returns (bool) {
                    address owner = _msgSender();
                    _transfer(owner, to, value);
                    return true;
                }
            
                /**
                 * @dev See {IERC20-allowance}.
                 */
                function allowance(address owner, address spender) public view virtual returns (uint256) {
                    ERC20Storage storage $ = _getERC20Storage();
                    return $._allowances[owner][spender];
                }
            
                /**
                 * @dev See {IERC20-approve}.
                 *
                 * NOTE: If `value` 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 value) public virtual returns (bool) {
                    address owner = _msgSender();
                    _approve(owner, spender, value);
                    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 `value`.
                 * - the caller must have allowance for ``from``'s tokens of at least
                 * `value`.
                 */
                function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
                    address spender = _msgSender();
                    _spendAllowance(from, spender, value);
                    _transfer(from, to, value);
                    return true;
                }
            
                /**
                 * @dev Moves a `value` 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.
                 *
                 * NOTE: This function is not virtual, {_update} should be overridden instead.
                 */
                function _transfer(address from, address to, uint256 value) internal {
                    if (from == address(0)) {
                        revert ERC20InvalidSender(address(0));
                    }
                    if (to == address(0)) {
                        revert ERC20InvalidReceiver(address(0));
                    }
                    _update(from, to, value);
                }
            
                /**
                 * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
                 * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
                 * this function.
                 *
                 * Emits a {Transfer} event.
                 */
                function _update(address from, address to, uint256 value) internal virtual {
                    ERC20Storage storage $ = _getERC20Storage();
                    if (from == address(0)) {
                        // Overflow check required: The rest of the code assumes that totalSupply never overflows
                        $._totalSupply += value;
                    } else {
                        uint256 fromBalance = $._balances[from];
                        if (fromBalance < value) {
                            revert ERC20InsufficientBalance(from, fromBalance, value);
                        }
                        unchecked {
                            // Overflow not possible: value <= fromBalance <= totalSupply.
                            $._balances[from] = fromBalance - value;
                        }
                    }
            
                    if (to == address(0)) {
                        unchecked {
                            // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                            $._totalSupply -= value;
                        }
                    } else {
                        unchecked {
                            // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                            $._balances[to] += value;
                        }
                    }
            
                    emit Transfer(from, to, value);
                }
            
                /**
                 * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
                 * Relies on the `_update` mechanism
                 *
                 * Emits a {Transfer} event with `from` set to the zero address.
                 *
                 * NOTE: This function is not virtual, {_update} should be overridden instead.
                 */
                function _mint(address account, uint256 value) internal {
                    if (account == address(0)) {
                        revert ERC20InvalidReceiver(address(0));
                    }
                    _update(address(0), account, value);
                }
            
                /**
                 * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
                 * Relies on the `_update` mechanism.
                 *
                 * Emits a {Transfer} event with `to` set to the zero address.
                 *
                 * NOTE: This function is not virtual, {_update} should be overridden instead
                 */
                function _burn(address account, uint256 value) internal {
                    if (account == address(0)) {
                        revert ERC20InvalidSender(address(0));
                    }
                    _update(account, address(0), value);
                }
            
                /**
                 * @dev Sets `value` 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.
                 *
                 * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
                 */
                function _approve(address owner, address spender, uint256 value) internal {
                    _approve(owner, spender, value, true);
                }
            
                /**
                 * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
                 *
                 * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
                 * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
                 * `Approval` event during `transferFrom` operations.
                 *
                 * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
                 * true using the following override:
                 * ```
                 * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
                 *     super._approve(owner, spender, value, true);
                 * }
                 * ```
                 *
                 * Requirements are the same as {_approve}.
                 */
                function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
                    ERC20Storage storage $ = _getERC20Storage();
                    if (owner == address(0)) {
                        revert ERC20InvalidApprover(address(0));
                    }
                    if (spender == address(0)) {
                        revert ERC20InvalidSpender(address(0));
                    }
                    $._allowances[owner][spender] = value;
                    if (emitEvent) {
                        emit Approval(owner, spender, value);
                    }
                }
            
                /**
                 * @dev Updates `owner` s allowance for `spender` based on spent `value`.
                 *
                 * Does not update the allowance value in case of infinite allowance.
                 * Revert if not enough allowance is available.
                 *
                 * Does not emit an {Approval} event.
                 */
                function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
                    uint256 currentAllowance = allowance(owner, spender);
                    if (currentAllowance != type(uint256).max) {
                        if (currentAllowance < value) {
                            revert ERC20InsufficientAllowance(spender, currentAllowance, value);
                        }
                        unchecked {
                            _approve(owner, spender, currentAllowance - value, false);
                        }
                    }
                }
            }
            
            // File: @openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20CappedUpgradeable.sol
            
            
            // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Capped.sol)
            
            pragma solidity ^0.8.20;
            
            
            
            /**
             * @dev Extension of {ERC20} that adds a cap to the supply of tokens.
             */
            abstract contract ERC20CappedUpgradeable is Initializable, ERC20Upgradeable {
                /// @custom:storage-location erc7201:openzeppelin.storage.ERC20Capped
                struct ERC20CappedStorage {
                    uint256 _cap;
                }
            
                // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20Capped")) - 1)) & ~bytes32(uint256(0xff))
                bytes32 private constant ERC20CappedStorageLocation = 0x0f070392f17d5f958cc1ac31867dabecfc5c9758b4a419a200803226d7155d00;
            
                function _getERC20CappedStorage() private pure returns (ERC20CappedStorage storage $) {
                    assembly {
                        $.slot := ERC20CappedStorageLocation
                    }
                }
            
                /**
                 * @dev Total supply cap has been exceeded.
                 */
                error ERC20ExceededCap(uint256 increasedSupply, uint256 cap);
            
                /**
                 * @dev The supplied cap is not a valid cap.
                 */
                error ERC20InvalidCap(uint256 cap);
            
                /**
                 * @dev Sets the value of the `cap`. This value is immutable, it can only be
                 * set once during construction.
                 */
                function __ERC20Capped_init(uint256 cap_) internal onlyInitializing {
                    __ERC20Capped_init_unchained(cap_);
                }
            
                function __ERC20Capped_init_unchained(uint256 cap_) internal onlyInitializing {
                    ERC20CappedStorage storage $ = _getERC20CappedStorage();
                    if (cap_ == 0) {
                        revert ERC20InvalidCap(0);
                    }
                    $._cap = cap_;
                }
            
                /**
                 * @dev Returns the cap on the token's total supply.
                 */
                function cap() public view virtual returns (uint256) {
                    ERC20CappedStorage storage $ = _getERC20CappedStorage();
                    return $._cap;
                }
            
                /**
                 * @dev See {ERC20-_update}.
                 */
                function _update(address from, address to, uint256 value) internal virtual override {
                    super._update(from, to, value);
            
                    if (from == address(0)) {
                        uint256 maxSupply = cap();
                        uint256 supply = totalSupply();
                        if (supply > maxSupply) {
                            revert ERC20ExceededCap(supply, maxSupply);
                        }
                    }
                }
            }
            
            // File: contracts/PikaMoon.sol
            
            
            pragma solidity 0.8.20;
            
            
            
            
            
            
            
            /**
             * @title PikaMoon Token
             * @dev A simple ERC20 token contract that allows minting and burning of tokens.
             */
            contract PikaMoon is
                Initializable,
                ERC20CappedUpgradeable,
                AccessControlUpgradeable,
                UUPSUpgradeable
            {
                //storage
                bytes32 private constant OWNER_ROLE = keccak256("OWNER_ROLE");
                uint32 public constant feeMultiply = 1000;
                uint16 constant public marketingTax = 10; 
                uint16 constant public ecosystemTax = 10; 
                uint16 constant public burnTax = 5; 
                address public ecoSystemWallet;
                address public marketingWallet;
                mapping(address => bool) public isExcludeFromTax;
                mapping(address => bool) public automatedMarketMakerPairs;
            
                bool public isTaxEnabled;
            
                // events
                event SetAutomatedMarketMakerPair(address pair, bool value);
                event ToggleTax(bool tax);
                event ExcludeFromTax(address _user, bool _isExcludeFromTax);
                event EventEcoSystemWallet(
                    address ecoSystemWallet,
                    address _ecoSystemWallet
                );
                event EventMarketingWallet(
                    address marketingWallet,
                    address _marketingWallet
                );
            
                /// @custom:oz-upgrades-unsafe-allow constructor
                constructor() {
                    _disableInitializers();
                }
            
                /**
                 * @dev Initializer function to initialize the contract.
                 * @param _name The name of the token.
                 * @param _symbol The symbol of the token.
                 * @param _ecosystemdevelopment ecosystem wallet.
                 * @param _marketing marketing wallet.
                 */
                function initialize(
                    string memory _name, // Pikamoon
                    string memory _symbol, // PIKA
                    address _ecosystemdevelopment,
                    address _marketing
                ) external initializer {
                    __ERC20_init(_name, _symbol);
                    __ERC20Capped_init(50_000_000_000 * 10 ** decimals());
                    __AccessControl_init();
                    __UUPSUpgradeable_init();
            
                    _grantRole(OWNER_ROLE, _msgSender());
                    _setRoleAdmin(OWNER_ROLE, OWNER_ROLE);
            
                    if (_ecosystemdevelopment == address(0)) {
                        revert CommanErrors.ZeroAddress();
                    }
                    if (_marketing == address(0)) {
                        revert CommanErrors.ZeroAddress();
                    }
            
                    isTaxEnabled = true;
                   
                    //set marketing and ecosystem wallet
                    ecoSystemWallet = _ecosystemdevelopment;
                    marketingWallet = _marketing;
                    // exclude owner & this contract from tax
                    isExcludeFromTax[address(this)] = true;
                }
            
                /**
                 * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                 * {upgradeToAndCall}.
                 */
                function _authorizeUpgrade(
                    address newImplementation
                ) internal override onlyRole(OWNER_ROLE) {}
            
                /**
                 * @dev function for setting Automated MarketMaker Pair
                 * @param pair address for pair.
                 * @param value boolean true or false.
                 */
                function setAutomatedMarketMakerPair(
                    address pair,
                    bool value
                ) external onlyRole(OWNER_ROLE) {
                    _setAutomatedMarketMakerPair(pair, value);
                }
            
                /**
                 * @dev private function for setting Automated MarketMaker Pair
                 * @param pair address for pair.
                 * @param value boolean true or false.
                 */
                function _setAutomatedMarketMakerPair(address pair, bool value) private {
                    if (automatedMarketMakerPairs[pair] == value) {
                        revert CommanErrors.PairIsAlreadyGivenValue();
                    }
            
                    automatedMarketMakerPairs[pair] = value;
                    emit SetAutomatedMarketMakerPair(pair, value);
                }
            
                /**
                 * @dev Function to get decimals.
                 */
                function decimals() public pure override returns (uint8) {
                    return 9;
                }
            
                /**
                 * @dev Function to mint new tokens and assign them to a specified address.
                 * @param to The address to which the new tokens are minted.
                 * @param amount The amount of tokens to be minted.
                 */
                function mint(address to, uint amount) external onlyRole(OWNER_ROLE) {
                    // Call the internal _mint function from ERC20 to create new tokens
                    _mint(to, amount);
                }
            
                /**
                 * @dev Function for user to burn there balance.
                 * @param amount The amount of tokens to be burned.
                 */
                function burn(uint amount) external {
                    // Call the internal _burn function from ERC20 to destroy tokens
                    _burn(_msgSender(), amount);
                }
            
                /**
                 * @dev Function to set ecosystem address.
                 * @param _ecoSystemWallet The address to ecosystem wallet.
                 */
                function changeEcoSystemWallet(
                    address _ecoSystemWallet
                ) external onlyRole(OWNER_ROLE) {
                    if (_ecoSystemWallet == address(0)) {
                        revert CommanErrors.ZeroAddress();
                    }
                    emit EventEcoSystemWallet(ecoSystemWallet, _ecoSystemWallet);
                    ecoSystemWallet = _ecoSystemWallet;
                }
            
                /**
                 * @dev Function to set marketing address.
                 * @param _marketing The address to  marketing wallet.
                 */
                function changeMarketingWallet(
                    address _marketing
                ) external onlyRole(OWNER_ROLE) {
                    if (_marketing == address(0)) {
                        revert CommanErrors.ZeroAddress();
                    }
                    emit EventMarketingWallet(marketingWallet, _marketing);
                    marketingWallet = _marketing;
                }
            
                /**
                 * @dev Function to update isExcludeFromTax mapping to exclude or include From Tax
                 * @param _user The address to be exclude or include From Tax
                 * @param _isExcludeFromTax true or false
                 */
                function excludeFromTax(
                    address _user,
                    bool _isExcludeFromTax
                ) external onlyRole(OWNER_ROLE) {
                    isExcludeFromTax[_user] = _isExcludeFromTax;
                    emit ExcludeFromTax(_user, _isExcludeFromTax);
                }
            
                /**
                 * @dev Function to toggle tax
                 */
                function toggleTax() external onlyRole(OWNER_ROLE) {
                    isTaxEnabled = !isTaxEnabled;
                    emit ToggleTax(isTaxEnabled);
                }
            
                /**
                 * @dev Moves a `value` amount of tokens from the caller's account to `to`.
                 * @param to The address to which the tokens are being transfered.
                 * @param value The amount of tokens to be transfered.
                 * @notice Pikamoon incorporates a small 2.5% transaction tax on Sell orders & Transfers.
                 * There is NO buy Tax when purchasing $PIKA. The Pikamoon token is used to support our metaverse
                 * and marketplace, therefore we want to reward hodlers of Pikamoon by punishing those leaving our ecosystem.
                 * 1% of the tax will go towards marketing, 1% towards the ecosystem development fund / P2E Rewards
                 * and 0.5% burned forever!
                 */
                function transfer(
                    address to,
                    uint256 value
                ) public override(ERC20Upgradeable) returns (bool) {
                    (
                        uint256 tax,
                        uint256 burnAmount,
                        uint256 marketingAmount,
                        uint256 ecosystemAmount
                    ) = calculateTax(_msgSender(), to, value);
                    if (tax > 0) {
                        unchecked {
                            value -= tax;
                        }
            
                        // deduct tax
                        if (marketingAmount > 0) {
                            super._transfer(_msgSender(), marketingWallet, marketingAmount);
                        }
                        if (ecosystemAmount > 0) {
                            super._transfer(_msgSender(), ecoSystemWallet, ecosystemAmount);
                        }
                        if (burnAmount > 0) {
                            super._burn(_msgSender(), burnAmount);
                        }
                    }
                    // normal transfer
                    super._transfer(_msgSender(), to, value);
                    return true;
                }
            
                /**
                 * @dev Moves a `value` amount of tokens from `from` to `to` using the
                 * allowance mechanism. `value` is then deducted from the caller's
                 * allowance.
                 * @param from The address from which the tokens are being transfered.
                 * @param to The address to which the tokens are being transfered.
                 * @param value The amount of tokens to be transfered.
                 * @notice Pikamoon incorporates a small 2.5% transaction tax on Sell orders & Transfers.
                 * There is NO buy Tax when purchasing $PIKA. The Pikamoon token is used to support our metaverse
                 * and marketplace, therefore we want to reward hodlers of Pikamoon by punishing those leaving our ecosystem.
                 * 1% of the tax will go towards marketing, 1% towards the ecosystem development fund / P2E Rewards
                 * and 0.5% burned forever!
                 */
                function transferFrom(
                    address from,
                    address to,
                    uint256 value
                ) public override(ERC20Upgradeable) returns (bool) {
                    _spendAllowance(from, _msgSender(), value);
                    (
                        uint256 tax,
                        uint256 burnAmount,
                        uint256 marketingAmount,
                        uint256 ecosystemAmount
                    ) = calculateTax(from, to, value);
                    if (tax > 0) {
                        unchecked {
                            value -= tax;
                        }
            
                        // deduct tax
                        if (marketingAmount > 0) {
                            super._transfer(from, marketingWallet, marketingAmount);
                        }
                        if (ecosystemAmount > 0) {
                            super._transfer(from, ecoSystemWallet, ecosystemAmount);
                        }
                        if (burnAmount > 0) {
                            super._burn(from, burnAmount);
                        }
                    }
                    // normal transfer
                    super._transfer(from, to, value);
                    return true;
                }
            
                /**
                 * @dev Function to calculate the tax
                 * @param from address on which tax is applied
                 * @param to address on which tax is applied
                 * @param value amount on which tax is calculated
                 */
                function calculateTax(
                    address from,
                    address to,
                    uint256 value
                )
                    public
                    view
                    returns (
                        uint256 tax,
                        uint256 burnAmount,
                        uint256 marketingAmount,
                        uint256 ecosystemAmount
                    )
                {
                    // calculate tax
                    if (
                        isTaxEnabled &&
                        !automatedMarketMakerPairs[from] &&
                        !isExcludeFromTax[from] &&
                        !isExcludeFromTax[to]
                    ) {
                        burnAmount = (value * burnTax) / feeMultiply;
                        marketingAmount = (value * marketingTax) / feeMultiply;
                        ecosystemAmount = (value * ecosystemTax) / feeMultiply;
                        unchecked {
                            tax = burnAmount + marketingAmount + ecosystemAmount;
                        }
                    }
                }
            }