ETH Price: $1,972.70 (+0.54%)
 

Overview

Max Total Supply

39,000 XGZ

Holders

191 (0.00%)

Market

Price

$163.24 @ 0.082750 ETH (+0.11%)

Onchain Market Cap

$6,366,400.11

Circulating Supply Market Cap

$0.00

Other Info

Token Contract (WITH 8 Decimals)

Filtered by Token Holder
1inch: Aggregation Executor 5
Balance
0.00000001 XGZ

Value
$0.00 ( ~0 Eth) [0.0000%]
0x990636ecb3ff04d33d92e970d3d588bf5cd8d086
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

GoldZip (XGZ), Gold-backed Token Powered by Hong Kong Gold Exchange (HKGX) Powered by the 115-year legacy, GoldZip offers seamless, real-time exposure to physical gold. Issued by a wholly owned HKGX subsidiary and pegged to the global spot price, GoldZip is Asia’s gold standard—on-chain.

Market

Volume (24H):$103.34
Market Capitalization:$0.00
Circulating Supply:0.00 XGZ
Market Data Source: Coinmarketcap

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
ERC1967Proxy

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 1337 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Proxy.sol)

pragma solidity ^0.8.22;

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[ERC-1967], 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 ERC-1967) 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) (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.3.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 reinitialization) 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 Pointer to storage slot. Allows integrators to override it with a custom storage location.
     *
     * NOTE: Consider following the ERC-7201 formula to derive storage locations.
     */
    function _initializableStorageSlot() internal pure virtual returns (bytes32) {
        return INITIALIZABLE_STORAGE;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        bytes32 slot = _initializableStorageSlot();
        assembly {
            $.slot := slot
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.22;

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 ERC-1967) 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 ERC-1167 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 ERC-1822 {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 ERC-1967 compliant implementation pointing to self.
     */
    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 ERC-1967.
     *
     * 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.3.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * 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 ERC-20
 * applications.
 */
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}.
     *
     * Both 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}.
     *
     * Skips emitting an {Approval} event indicating an allowance update. This is not
     * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
     *
     * 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:
     *
     * ```solidity
     * 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);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)

pragma solidity ^0.8.20;

import {ERC20Upgradeable} from "../ERC20Upgradeable.sol";
import {ContextUpgradeable} from "../../../utils/ContextUpgradeable.sol";
import {Initializable} from "../../../proxy/utils/Initializable.sol";

/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20BurnableUpgradeable is Initializable, ContextUpgradeable, ERC20Upgradeable {
    function __ERC20Burnable_init() internal onlyInitializing {
    }

    function __ERC20Burnable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Destroys a `value` amount of tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 value) public virtual {
        _burn(_msgSender(), value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, deducting from
     * the caller's allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `value`.
     */
    function burnFrom(address account, uint256 value) public virtual {
        _spendAllowance(account, _msgSender(), value);
        _burn(account, value);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/ERC20Pausable.sol)

pragma solidity ^0.8.20;

import {ERC20Upgradeable} from "../ERC20Upgradeable.sol";
import {PausableUpgradeable} from "../../../utils/PausableUpgradeable.sol";
import {Initializable} from "../../../proxy/utils/Initializable.sol";

/**
 * @dev ERC-20 token with pausable token transfers, minting and burning.
 *
 * Useful for scenarios such as preventing trades until the end of an evaluation
 * period, or having an emergency switch for freezing all token transfers in the
 * event of a large bug.
 *
 * IMPORTANT: This contract does not include public pause and unpause functions. In
 * addition to inheriting this contract, you must define both functions, invoking the
 * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
 * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
 * make the contract pause mechanism of the contract unreachable, and thus unusable.
 */
abstract contract ERC20PausableUpgradeable is Initializable, ERC20Upgradeable, PausableUpgradeable {
    function __ERC20Pausable_init() internal onlyInitializing {
    }

    function __ERC20Pausable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {ERC20-_update}.
     *
     * Requirements:
     *
     * - the contract must not be paused.
     */
    function _update(address from, address to, uint256 value) internal virtual override whenNotPaused {
        super._update(from, to, value);
    }
}

// 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.3.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 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();
        _;
    }

    function __Pausable_init() internal onlyInitializing {
    }

    function __Pausable_init_unchained() internal onlyInitializing {
    }
    /**
     * @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());
    }
}

File 10 of 42 : draft-IERC1822.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.20;

/**
 * @dev ERC-1822: 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.1.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC-20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 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 ERC-721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-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 ERC-1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 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 12 of 42 : IERC1967.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)

pragma solidity ^0.8.20;

/**
 * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
 */
interface IERC1967 {
    /**
     * @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);
}

// 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.2.0) (proxy/ERC1967/ERC1967Utils.sol)

pragma solidity ^0.8.22;

import {IBeacon} from "../beacon/IBeacon.sol";
import {IERC1967} from "../../interfaces/IERC1967.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";

/**
 * @dev This library provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots.
 */
library ERC1967Utils {
    /**
     * @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 ERC-1967 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 IERC1967.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 ERC-1967) 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 ERC-1967 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 IERC1967.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 ERC-1967 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 IERC1967.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.3.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * 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 ERC-20
 * applications.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * Both values are immutable: they can only be set once during construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

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

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

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the 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) {
        return _totalSupply;
    }

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

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `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) {
        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}.
     *
     * Skips emitting an {Approval} event indicating an allowance update. This is not
     * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
     *
     * 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 {
        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:
     *
     * ```solidity
     * 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 {
        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);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC-20 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);
}

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

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
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.2.0) (utils/Address.sol)

pragma solidity ^0.8.20;

import {Errors} from "./Errors.sol";

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @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 Errors.InsufficientBalance(address(this).balance, amount);
        }

        (bool success, bytes memory returndata) = recipient.call{value: amount}("");
        if (!success) {
            _revert(returndata);
        }
    }

    /**
     * @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
     * {Errors.FailedCall} 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 Errors.InsufficientBalance(address(this).balance, value);
        }
        (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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}.
     */
    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
            assembly ("memory-safe") {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert Errors.FailedCall();
        }
    }
}

// SPDX-License-Identifier: MIT
// 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 Context {
    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 21 of 42 : Errors.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedCall();

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * 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[ERC 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);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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 ERC-1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     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;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct Int256Slot {
        int256 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) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

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

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

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

    /**
     * @dev Returns a `Int256Slot` with member `value` located at `slot`.
     */
    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            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) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns a `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            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) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }
}

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

import {Context} from "@openzeppelin/contracts/utils/Context.sol";

abstract contract AccessControl is Context {
    /// @custom:storage-location erc7201:eth.storage.AccessControl
    struct AccessControlStorage {
        mapping(bytes32 => mapping(address => bool)) roles;
    }

    /// @dev the role that can manage the access control
    bytes32 public constant MANAGE_ROLE = keccak256("MANAGE_ROLE");

    /**
     * @dev Role grant event
     * @param role The role being granted
     * @param account The address of the account receiving the role
     * @param operator The address of the operator granting the role
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed operator);

    /**
     * @dev Role revocation event
     * @param role The role being revoked
     * @param account The address of the account whose role is being revoked
     * @param operator The address of the operator revoking the role
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed operator);

    /**
     * @dev Unauthorized account error
     * @param account The address of the account attempting to perform the operation
     * @param neededRole The required role permission
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev if the caller is not the owner, it will check if the caller has the specified role
     * @param role The role to check
     */
    modifier onlyRole(bytes32 role) {
        address sender = _msgSender();
        if (!hasRole(role, sender)) {
            revert AccessControlUnauthorizedAccount(sender, role);
        }
        _;
    }

    function _isOwner(address account) internal view virtual returns (bool);

    function _getAccessControlStorage() internal view virtual returns (AccessControlStorage storage);

    /**
     * @dev Checks if an account has a specific role
     * @param role The role identifier
     * @param account The address to check
     * @return Returns true if the account has the role, false otherwise
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        return _isOwner(account) || _getAccessControlStorage().roles[role][account];
    }

    /**
     * @dev Grants a role to an account
     * @param role The role identifier to grant
     * @param account The address of the account receiving the role
     * @notice Only accounts with the admin role can call this function
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(MANAGE_ROLE) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes a role from an account
     * @param role The role identifier to revoke
     * @param account The address of the account whose role is being revoked
     * @notice Only accounts with the admin role can call this function
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(MANAGE_ROLE) {
        _revokeRole(role, account);
    }

    function _grantRole(bytes32 role, address account) internal virtual {
        mapping(address => bool) storage roleMembers = _getAccessControlStorage().roles[role];
        if (roleMembers[account]) {
            return;
        }
        roleMembers[account] = true;
        emit RoleGranted(role, account, _msgSender());
    }

    function _revokeRole(bytes32 role, address account) internal virtual {
        mapping(address => bool) storage roleMembers = _getAccessControlStorage().roles[role];
        if (!roleMembers[account]) {
            return;
        }
        roleMembers[account] = false;
        emit RoleRevoked(role, account, _msgSender());
    }
}

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

import {AccessControl} from "./AccessControl.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

abstract contract AccessControlUpgradeable is AccessControl, Initializable {
    function __AccessControl_init() internal onlyInitializing {}

    function __AccessControl_init_unchained() internal onlyInitializing {}

    // keccak256(abi.encode(uint256(keccak256("eth.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessControlStorageLocation =
        0xc7718c714a4ea3787e76d937c7cf515450ac49586b94b576139798de290de800;

    function _getAccessControlStorage() internal view virtual override returns (AccessControlStorage storage $) {
        assembly {
            $.slot := AccessControlStorageLocation
        }
    }
}

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

import {AddressListLib, CommonErrors} from "../lib/AddressList.sol";
import {
    IBlacklistQueryExtension,
    IBlacklistCore
} from "../interfaces/IBlacklistable.sol";

/// @dev Provide blacklist function for Token
abstract contract BaseBlacklistable is IBlacklistCore, IBlacklistQueryExtension {
    using AddressListLib for AddressListLib.AddressList;

    /// @dev Raised if address is not in blacklist
    error Blacklistable__NotInBlacklist();
    /// @dev Raised if address is in blacklist
    error Blacklistable__AlreadyInBlacklist();

    uint256 private constant MAX_BATCH_SIZE = 100;

    function _getBlacklistStorage() internal view virtual returns (AddressListLib.AddressList storage);

    modifier onlyBlacklistController() {
        _validateBlacklistController();
        _;
    }

    function _validateBlacklistController() internal view virtual;

    /// @inheritdoc IBlacklistQueryExtension
    /// @notice Returns the complete list of blacklisted addresses. Be aware that this function
    /// may fail when the list grows too large (typically over 10,000 addresses) due to:
    /// 1. RPC node response size limitations
    /// 2. Block gas limits (for on-chain calls)
    /// 3. EVM stack depth restrictions
    /// If you encounter any issues retrieving the complete list, please use the paginated 
    /// alternative: `blacklistedAddressesPaginated(uint256 offset, uint256 limit)` instead,
    /// which allows retrieving the list in manageable chunks.
    function blacklistedAddresses() external view virtual returns (address[] memory) {
        return _getBlacklistStorage().getList();
    }

    /// @inheritdoc IBlacklistQueryExtension
    function blacklistedAddressesPaginated(uint256 offset, uint256 limit)
        external
        view
        virtual
        returns (address[] memory addresses)
    {
        return _getBlacklistStorage().getListPaginated(offset, limit);
    }

    /// @inheritdoc IBlacklistQueryExtension
    function blacklistedAddressCount() public view virtual returns (uint256) {
        return _getBlacklistStorage().count();
    }

    /// @inheritdoc IBlacklistCore
    function isBlacklisted(address account) public view virtual returns (bool) {
        return _isBlacklisted(account);
    }

    /// @inheritdoc IBlacklistCore
    function areBlacklisted(address[] calldata addresses) external view virtual returns (bool[] memory) {
        return _getBlacklistStorage().areInList(addresses);
    }

    /// @inheritdoc IBlacklistCore
    function addToBlacklist(address addr) external virtual onlyBlacklistController {
        _addToBlacklist(addr, true);
    }

    /// @inheritdoc IBlacklistCore
    /// @dev If the address is already in the blacklist, the function will not revert.
    /// This design choice improves usability by eliminating the need for callers to pre-check addresses,
    /// thus simplifying batch operations and reducing additional on-chain transactions and gas costs.
    function batchAddToBlacklist(address[] calldata addresses) public virtual onlyBlacklistController {
        uint256 len = addresses.length;
        if (len > MAX_BATCH_SIZE) {
            revert CommonErrors.ExceedsMaximumAmount(len, MAX_BATCH_SIZE);
        }

        for (uint256 i = 0; i < len;) {
            _addToBlacklist(addresses[i], false);
            unchecked {
                i++;
            }
        }
    }

    /// @inheritdoc IBlacklistCore
    function removeFromBlacklist(address addr) external virtual onlyBlacklistController {
        _removeFromBlacklist(addr, true);
    }

    /// @inheritdoc IBlacklistCore
    /// @dev If the address to remove is not in the list, it will not be reverted,
    /// This design choice improves usability by eliminating the need for callers to pre-check addresses,
    /// thus simplifying batch operations and reducing additional on-chain transactions and gas costs.
    function batchRemoveFromBlacklist(address[] calldata addresses) public virtual onlyBlacklistController {
        uint256 len = addresses.length;
        if (len > MAX_BATCH_SIZE) {
            revert CommonErrors.ExceedsMaximumAmount(len, MAX_BATCH_SIZE);
        }

        for (uint256 i = 0; i < len;) {
            _removeFromBlacklist(addresses[i], false);
            unchecked {
                i++;
            }
        }
    }

    /// @inheritdoc IBlacklistCore
    /// @dev If the address to remove is not in the list or the address to add is already in the list, it will not be reverted,
    /// This design choice improves usability by eliminating the need for callers to pre-check addresses,
    /// thus simplifying batch operations and reducing additional on-chain transactions and gas costs.
    function updateBlacklist(address[] calldata addressesToAdd, address[] calldata addressesToRemove)
        external
        virtual
        onlyBlacklistController
    {
        batchAddToBlacklist(addressesToAdd);
        batchRemoveFromBlacklist(addressesToRemove);
    }

    function _isBlacklisted(address account) internal view virtual returns (bool) {
        return _getBlacklistStorage().isInList(account);
    }

    function _addToBlacklist(address account, bool strict) internal virtual {
        if (!_getBlacklistStorage().addToList(account)) {
            if (strict) {
                revert Blacklistable__AlreadyInBlacklist();
            } else {
                return;
            }
        }
        emit Blacklisted(account);
    }

    function _removeFromBlacklist(address account, bool strict) internal virtual {
        if (!_getBlacklistStorage().removeFromList(account)) {
            if (strict) {
                revert Blacklistable__NotInBlacklist();
            } else {
                return;
            }
        }
        emit UnBlacklisted(account);
    }
}

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

import {IBlacklistToggleExtension} from "../interfaces/IBlacklistable.sol";
import {CommonErrors} from "../lib/AddressList.sol";

abstract contract BaseToggleBlacklistable is IBlacklistToggleExtension {
    /// @dev Emit when blacklist enabled
    event BlacklistEnabled();
    /// @dev Emit when blacklist disabled
    event BlacklistDisabled();

    /// @custom:storage-location erc7201:eth.storage.BlacklistToggle
    struct BlacklistToggleStorage {
        /// @dev Bool indicate blacklist is enabled or not
        bool blacklistEnabled;
    }

    /// @dev Get the blacklist toggle storage
    /// @return storage The blacklist toggle storage
    function _getBlacklistToggleStorage() internal view virtual returns (BlacklistToggleStorage storage);

    /// @inheritdoc IBlacklistToggleExtension
    function isBlacklistEnabled() public view virtual returns (bool) {
        return _getBlacklistToggleStorage().blacklistEnabled;
    }

    function _setBlacklistEnabled(bool enabled) internal virtual {
        BlacklistToggleStorage storage $ = _getBlacklistToggleStorage();
        if ($.blacklistEnabled == enabled) return;
        if (enabled) {
            emit BlacklistEnabled();
        } else {
            emit BlacklistDisabled();
        }
        $.blacklistEnabled = enabled;
    }

    function _requireBlacklistEnabled() internal view virtual {
        if (!isBlacklistEnabled()) {
            revert CommonErrors.Blacklistable__BlacklistNotEnabled();
        }
    }
}

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

import {IWhitelistToggleExtension} from "../interfaces/IWhitelistable.sol";
import {CommonErrors} from "../lib/AddressList.sol";

/// @dev Provide whitelist function for Token
abstract contract BaseToggleWhitelistable is IWhitelistToggleExtension {
    /// @dev Emit when whitelist enabled
    event WhitelistEnabled();
    /// @dev Emit when whitelist disabled
    event WhitelistDisabled();

    /// @custom:storage-location erc7201:eth.storage.WhitelistToggle
    struct WhitelistToggleStorage {
        /// @dev Bool indicate whitelist is enabled or not
        bool whitelistEnabled;
    }

    /// @dev Get the whitelist toggle storage
    /// @return storage The whitelist toggle storage
    function _getWhitelistToggleStorage() internal view virtual returns (WhitelistToggleStorage storage);

    /// @inheritdoc IWhitelistToggleExtension
    function isWhitelistEnabled() public view virtual returns (bool) {
        return _getWhitelistToggleStorage().whitelistEnabled;
    }

    function _setWhitelistEnabled(bool enabled) internal virtual {
        WhitelistToggleStorage storage $ = _getWhitelistToggleStorage();
        if ($.whitelistEnabled == enabled) return;
        if (enabled) {
            emit WhitelistEnabled();
        } else {
            emit WhitelistDisabled();
        }
        $.whitelistEnabled = enabled;
    }

    function _requireWhitelistEnabled() internal view virtual {
        if (!isWhitelistEnabled()) {
            revert CommonErrors.Whitelistable__WhitelistNotEnabled();
        }
    }
}

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

import {AddressListLib, CommonErrors} from "../lib/AddressList.sol";
import {
    IWhitelistQueryExtension,
    IWhitelistCore
} from "../interfaces/IWhitelistable.sol";

/// @dev Provide whitelist function for Token
abstract contract BaseWhitelistable is IWhitelistCore,IWhitelistQueryExtension {
    using AddressListLib for AddressListLib.AddressList;

    /// @dev Raised if address is not in whitelist
    error Whitelistable__NotInWhitelist();
    /// @dev Raised if address is in whitelist
    error Whitelistable__AlreadyInWhitelist();

    AddressListLib.AddressList private _whitelistStorage;
    uint256 private constant MAX_BATCH_SIZE = 100;

    function _getWhitelistStorage() internal view virtual returns (AddressListLib.AddressList storage);

    modifier onlyWhitelistController() {
        _validateWhitelistController();
        _;
    }

    function _validateWhitelistController() internal view virtual;

    /// @inheritdoc IWhitelistQueryExtension
    /// @notice Returns the complete list of whitelisted addresses. Be aware that this function
    /// may fail when the list grows too large (typically over 10,000 addresses) due to:
    /// 1. RPC node response size limitations
    /// 2. Block gas limits (for on-chain calls)
    /// 3. EVM stack depth restrictions
    /// If you encounter any issues retrieving the complete list, please use the paginated 
    /// alternative: `whitelistedAddressesPaginated(uint256 offset, uint256 limit)` instead,
    /// which allows retrieving the list in manageable chunks.
    function whitelistedAddresses() external view virtual returns (address[] memory) {
         return _getWhitelistStorage().getList();
    }

    /// @inheritdoc IWhitelistQueryExtension
    function whitelistedAddressesPaginated(uint256 offset, uint256 limit)
        external
        virtual
        view
        returns (address[] memory addresses)
    {
        return _getWhitelistStorage().getListPaginated(offset, limit);
    }

    /// @inheritdoc IWhitelistQueryExtension
    function whitelistedAddressCount() public view virtual returns (uint256) {
        return _getWhitelistStorage().count();
    }

    /// @inheritdoc IWhitelistCore
    function isWhitelisted(address account) public view virtual returns (bool) {
        return _isWhitelisted(account);
    }

    /// @inheritdoc IWhitelistCore
    function areWhitelisted(address[] calldata addresses) external view virtual returns (bool[] memory) {
        return _getWhitelistStorage().areInList(addresses);
    }

    /// @inheritdoc IWhitelistCore
    function addToWhitelist(address addr) external virtual onlyWhitelistController {
        _addToWhitelist(addr, true);
    }

    /// @inheritdoc IWhitelistCore
    /// @dev If the address is already in the list, the function will not revert.
    /// This design choice improves usability by eliminating the need for callers to pre-check addresses,
    /// thus simplifying batch operations and reducing additional on-chain transactions and gas costs.
    function batchAddToWhitelist(address[] calldata addresses) public virtual onlyWhitelistController {
        uint256 len = addresses.length;
        if (len > MAX_BATCH_SIZE) {
            revert CommonErrors.ExceedsMaximumAmount(len, MAX_BATCH_SIZE);
        }

        for (uint256 i = 0; i < len;) {
            _addToWhitelist(addresses[i], false);
            unchecked {
                i++;
            }
        }
    }

    /// @inheritdoc IWhitelistCore
    function removeFromWhitelist(address addr) external virtual onlyWhitelistController {
        _removeFromWhitelist(addr, true);
    }

    /// @inheritdoc IWhitelistCore
    /// @dev If the address to remove is not in the list, it will not be reverted,
    /// This design choice improves usability by eliminating the need for callers to pre-check addresses,
    /// thus simplifying batch operations and reducing additional on-chain transactions and gas costs.
    function batchRemoveFromWhitelist(address[] calldata addresses) public virtual onlyWhitelistController {
        uint256 len = addresses.length;
        if (len > MAX_BATCH_SIZE) {
            revert CommonErrors.ExceedsMaximumAmount(len, MAX_BATCH_SIZE);
        }

        for (uint256 i = 0; i < len;) {
            _removeFromWhitelist(addresses[i], false);
            unchecked {
                i++;
            }
        }
    }

    /// @inheritdoc IWhitelistCore
    /// @dev If the address to remove is not in the list or the address to add is already in the list, it will not be reverted,
    /// This design choice improves usability by eliminating the need for callers to pre-check addresses,
    /// thus simplifying batch operations and reducing additional on-chain transactions and gas costs.
    function updateWhitelist(address[] calldata addressesToAdd, address[] calldata addressesToRemove)
        external
        virtual
        onlyWhitelistController
    {
        batchAddToWhitelist(addressesToAdd);
        batchRemoveFromWhitelist(addressesToRemove);
    }

    function _isWhitelisted(address account) internal view virtual returns (bool) {
        return _getWhitelistStorage().isInList(account);
    }

    function _addToWhitelist(address account, bool strict) internal virtual {
        if (!_getWhitelistStorage().addToList(account)) {
            if (strict) {
                revert Whitelistable__AlreadyInWhitelist();
            } else {
                return;
            }
        }
        emit Whitelisted(account);
    }

    function _removeFromWhitelist(address account, bool strict) internal virtual {
        if (!_getWhitelistStorage().removeFromList(account)) {
            if (strict) {
                revert Whitelistable__NotInWhitelist();
            } else {
                return;
            }
        }
        emit UnWhitelisted(account);
    }
}

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

import {AddressListLib} from "../lib/AddressList.sol";
import {BaseBlacklistable} from "./BaseBlacklistable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

abstract contract BlacklistableV1Upgradeable is BaseBlacklistable, Initializable {
    function __BlacklistableV1_init() internal onlyInitializing {
        __BlacklistableV1_init_unchained();
    }

    function __BlacklistableV1_init_unchained() internal onlyInitializing {}

    // keccak256(abi.encode(uint256(keccak256("eth.storage.AddressList.blacklist")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant BlacklistStorageLocation =
        0xe324a5d682b26d0ea8420970e5277ed2e5a32b3840534fa099829ebe4cef1200;

    function _getBlacklistStorage() internal view virtual override returns (AddressListLib.AddressList storage $) {
        assembly {
            $.slot := BlacklistStorageLocation
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Capped.sol)

pragma solidity ^0.8.20;

import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

/**
 * @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 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 {
        if (cap_ > 0) {
            ERC20CappedStorage storage $ = _getERC20CappedStorage();
            $._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);

        uint256 maxSupply = cap();
        if (from == address(0) && maxSupply > 0) {
            uint256 supply = totalSupply();
            if (supply > maxSupply) {
                revert ERC20ExceededCap(supply, maxSupply);
            }
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/**
 * @dev Extension of {ERC20} that adds a cap to the supply of tokens.
 */
abstract contract ERC20Capped is ERC20 {
    uint256 private immutable _cap;

    /**
     * @dev Total supply cap has been exceeded.
     */
    error ERC20ExceededCap(uint256 increasedSupply, uint256 cap);

    /**
     * @dev Sets the value of the `cap`. This value is immutable, it can only be
     * set once during construction.
     */
    constructor(uint256 cap_) {
        _cap = cap_;
    }

    /**
     * @dev Returns the cap on the token's total supply.
     */
    function cap() public view virtual returns (uint256) {
        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) && _cap > 0) {
            uint256 maxSupply = cap();
            uint256 supply = totalSupply();
            if (supply > maxSupply) {
                revert ERC20ExceededCap(supply, maxSupply);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ~0.8.20;

contract Multicall {
    /// @notice Aggregate calls, ensuring each returns success if required
    /// @param calls An array of Call3 structs
    /// @return returnData An array of Result structs
    function aggregate(bytes[] calldata calls) public virtual returns (bytes[] memory returnData) {
        uint256 length = calls.length;
        returnData = new bytes[](length);
        for (uint256 i = 0; i < length;) {
            bool success;
            (success, returnData[i]) = address(this).delegatecall(calls[i]);
            require(success, "Multicall3: call failed");
            unchecked {
                ++i;
            }
        }
    }
}

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

import {AddressListLib} from "../lib/AddressList.sol";
import {BaseWhitelistable} from "./BaseWhitelistable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

abstract contract WhitelistableV1Upgradeable is BaseWhitelistable, Initializable {
    function __WhitelistableV1_init() internal onlyInitializing {
        __WhitelistableV1_init_unchained();
    }

    function __WhitelistableV1_init_unchained() internal onlyInitializing {}

    // keccak256(abi.encode(uint256(keccak256("eth.storage.AddressList.whitelist")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant WhitelistStorageLocation =
        0x1cfa5e7091c18064c617daf65974fb5d5c7430ad724797e7a06249adbc38f100;

    function _getWhitelistStorage() internal view virtual override returns (AddressListLib.AddressList storage $) {
        assembly {
            $.slot := WhitelistStorageLocation
        }
    }
}

File 35 of 42 : GLDBToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ~0.8.20;

import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import {ERC20PausableUpgradeable} from
    "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol";
import {ERC20BurnableUpgradeable} from
    "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import {ERC20CappedUpgradeable} from "./extensions/ERC20CappedUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {Helper} from "./lib/Helper.sol";
import {IWhitelistToggleExtension, IWhitelistCore} from "./interfaces/IWhitelistable.sol";
import {IBlacklistToggleExtension, IBlacklistCore} from "./interfaces/IBlacklistable.sol";
import {CommonErrors} from "./lib/AddressList.sol";
import {BaseToggleWhitelistable} from "./extensions/BaseToggleWhitelistable.sol";
import {BaseToggleBlacklistable} from "./extensions/BaseToggleBlacklistable.sol";
import {IExternalWhitelistImpl, IExternalBlacklistImpl} from "./interfaces/ExternalImpl.sol";
// Neet to import this for HH Ignition
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Multicall} from "./extensions/Multicall.sol";

error InvalidDecimals(uint8 decimals);
error MintingNotEnabled();
error BurningNotEnabled();
error PausingNotEnabled();
error AddrBalanceExceedsMaxAllowed(address addr, uint256 amount);
error RecipientBlacklisted(address addr);
error RecipientNotWhitelisted(address addr);
error MaxTokenAmountNotAllowed();
error MaxTokenAmountPerAddrLtPrevious();

error TransferFromSenderNotWhitelisted(address sender);
error TransferFromSenderBlacklisted(address sender);

error InvalidRecipientAndAmount();
error UnAuthorisedSender();
error AuthorisedSenderEnabled();

error InvalidTaxBPS(uint256 taxBPS);
error InvalidDeflationBPS(uint256 deflationBPS);
error TokenIsNotTaxable();
error TokenIsNotDeflationary();

contract GLDBToken is
    Multicall,
    Initializable,
    ERC20Upgradeable,
    ERC20PausableUpgradeable,
    ERC20BurnableUpgradeable,
    ERC20CappedUpgradeable,
    OwnableUpgradeable,
    UUPSUpgradeable,
    BaseToggleWhitelistable,
    BaseToggleBlacklistable,
    IExternalWhitelistImpl,
    IExternalBlacklistImpl,
    IERC165
{
    /// @dev Emit when new document uri set
    event DocumentUriSet(string documentUri);
    event MaxTokenAmountPerSet(uint256 maxTokenAmount);

    event TaxConfigSet(address addr, uint256 taxBPS);
    event DeflationConfigSet(uint256 deflationBPS);

    event WhitelistImplSet(address indexed whitelistImpl);
    event BlacklistImplSet(address indexed blacklistImpl);

    /// @dev MaxBPSAmount 10_000=100%
    uint256 private constant MAX_BPS_AMOUNT = 10_000;
    string public constant identifier = "GLDBToken";

    struct ConstructorParams {
        uint256 maxTokenAmountPerAddress;
        string metadata;
        string documentUri;
        /// tax config
        /// @dev Tax fee recipient address
        address taxAddress;
        /// @dev Tax fee BPS(100bps=1%)
        uint256 taxBPS;
        /// @dev Burn fee BPS(100bps=1%)
        uint256 deflationBPS;
        /// flags
        bool isBurnable;
        bool isMintable;
        bool isPausable;
        bool isBlacklistEnabled;
        bool isWhitelistEnabled;
        bool isMaxAmountPerAddressSet;
        bool isForceTransferAllowed;
        bool isTaxable;
        bool isDeflationary;
        bool authorisedSenderEnabled;
        /// whitelist implementation
        IWhitelistCore whitelistImpl;
        /// blacklist implementation
        IBlacklistCore blacklistImpl;
    }

    // Storage structures for ERC-7201 named storage pattern

    /// @dev Token features struct
    struct TokenFeatures {
        bool isBurnable;
        bool isMintable;
        bool isPausable;
        bool isMaxAmountPerAddressSet;
        bool isForceTransferAllowed;
        bool isTaxable;
        bool isDeflationary;
        bool authorisedSenderEnabled;
    }

    /// @custom:storage-location erc7201:eth.storage.Version
    struct VersionStorage {
        uint256 versionNumber;
        string version;
    }

    /// @custom:storage-location erc7201:eth.storage.TokenConfig
    struct TokenStorage {
        /// @dev Decimals of token
        uint8 decimals;
        /// @dev Initial supply of token will be mint during init
        uint256 initialSupply;
        /// @dev Max amount of token allowed per address
        uint256 maxTokenAmountPerAddress;
        /// @dev Metadata JSON
        string metadata;
        /// @dev Documentation of the security token
        string documentUri;
        /// @dev Token configuration
        TokenFeatures features;
    }

    /// @custom:storage-location erc7201:eth.storage.Tax
    struct TaxStorage {
        /// @dev Tax fee recipient address
        address taxAddress;
        /// @dev Tax fee BPS(100bps=1%)
        uint256 taxBPS;
        /// @dev Burn fee BPS(100bps=1%)
        uint256 deflationBPS;
    }

    /// @custom:storage-location erc7201:eth.storage.Auth
    struct AuthStorage {
        bool authorisedSenderEnabled;
        /// @dev Address who can send transaction
        mapping(address => bool) authorisedSender;
    }

    /// @custom:storage-location erc7201:eth.storage.WhiteBlackList
    struct WhiteBlackListStorage {
        IWhitelistCore whitelistImpl;
        IBlacklistCore blacklistImpl;
    }

    /**
     * @dev Modifier to check sender and recipient when transfer
     * @param sender - Transfer sender
     * @param recipient - Transfer recipient
     */
    modifier checkTransfer(address sender, address recipient) {
        _checkTransfer(sender, recipient);
        _;
    }

    /// @dev Modifier to check if the token is burnable
    modifier whenBurnable() {
        if (!isBurnable()) {
            revert BurningNotEnabled();
        }
        _;
    }

    /// @dev Modifier to check if the token is mintable
    modifier whenMintable() {
        if (!isMintable()) {
            revert MintingNotEnabled();
        }
        _;
    }

    function _checkTransfer(address sender, address recipient) private view {
        address msgSender = _msgSender();
        bool isOwner = msgSender == owner();

        // When the current caller is the contract owner and the contract permits forced transfers,
        // all transfer requests are released without any whitelist or blacklist checks.
        if (isForceTransferAllowed() && isOwner) {
            return;
        }

        if (isBlacklistEnabled()) {
            if (_isBlacklisted(sender)) {
                revert TransferFromSenderBlacklisted(sender);
            }
            if (_isBlacklisted(recipient)) {
                revert RecipientBlacklisted(recipient);
            }

            if (sender != msgSender && !isOwner && _isBlacklisted(msgSender)) {
                revert TransferFromSenderBlacklisted(msgSender);
            }
        }

        if (isWhitelistEnabled()) {
            if (!_isWhitelisted(sender)) {
                revert TransferFromSenderNotWhitelisted(sender);
            }
            if (!_isWhitelisted(recipient)) {
                revert RecipientNotWhitelisted(recipient);
            }

            if (sender != msgSender && !isOwner && !_isWhitelisted(msgSender)) {
                revert TransferFromSenderNotWhitelisted(msgSender);
            }
        }
    }

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /// @dev Initializes the contract
    function initialize(
        string memory name_,
        string memory symbol_,
        uint8 decimals_,
        uint256 maxSupply_,
        uint256 initialSupply_,
        address tokenOwner,
        ConstructorParams memory params
    ) public initializer {
        if (decimals_ > 18) {
            revert InvalidDecimals(decimals_);
        }
        __ERC20_init(name_, symbol_);
        __ERC20Pausable_init();
        __ERC20Burnable_init();
        __ERC20Capped_init(maxSupply_);
        __Ownable_init(tokenOwner);
        __UUPSUpgradeable_init();

        if (params.isWhitelistEnabled) {
            _setWhitelistImpl(params.whitelistImpl);
        }
        if (params.isBlacklistEnabled) {
            _setBlacklistImpl(params.blacklistImpl);
        }
        _setBlacklistEnabled(params.isBlacklistEnabled);
        _setWhitelistEnabled(params.isWhitelistEnabled);

        _setVersion("1.0.0", 1);

        TaxStorage storage taxStorage = _getTaxStorage();
        if (params.isTaxable) {
            if (params.taxBPS > MAX_BPS_AMOUNT) {
                revert InvalidTaxBPS(params.taxBPS);
            }
            Helper.checkAddress(params.taxAddress);
            taxStorage.taxAddress = params.taxAddress;
            taxStorage.taxBPS = params.taxBPS;
        }
        if (params.isDeflationary) {
            if (params.deflationBPS > MAX_BPS_AMOUNT) {
                revert InvalidDeflationBPS(params.deflationBPS);
            }
            taxStorage.deflationBPS = params.deflationBPS;
        }

        if (params.authorisedSenderEnabled) {
            AuthStorage storage authStorage = _getAuthStorage();
            authStorage.authorisedSenderEnabled = params.authorisedSenderEnabled;
            authStorage.authorisedSender[tokenOwner] = true;
        }

        TokenStorage storage tokenStorage = _getTokenStorage();
        tokenStorage.decimals = decimals_;
        tokenStorage.initialSupply = initialSupply_;
        tokenStorage.maxTokenAmountPerAddress = params.maxTokenAmountPerAddress;
        tokenStorage.metadata = params.metadata;
        tokenStorage.documentUri = params.documentUri;
        tokenStorage.features = TokenFeatures({
            isBurnable: params.isBurnable,
            isMintable: params.isMintable,
            isPausable: params.isPausable,
            isMaxAmountPerAddressSet: params.isMaxAmountPerAddressSet,
            isForceTransferAllowed: params.isForceTransferAllowed,
            isTaxable: params.isTaxable,
            isDeflationary: params.isDeflationary,
            authorisedSenderEnabled: params.authorisedSenderEnabled
        });

        if (initialSupply_ > 0) {
            super._mint(tokenOwner, initialSupply_);
        }
    }

    /// @dev Required override for UUPSUpgradeable to authorize upgrades
    function _authorizeUpgrade(address newImplementation) internal override onlyOwner whenNotPaused {
        // Authorization logic is just requiring the owner
    }

    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
        return interfaceId == type(IERC165).interfaceId || interfaceId == type(IExternalWhitelistImpl).interfaceId
            || interfaceId == type(IExternalBlacklistImpl).interfaceId
            || interfaceId == type(IWhitelistToggleExtension).interfaceId
            || interfaceId == type(IBlacklistToggleExtension).interfaceId;
    }

    function version() public view returns (string memory) {
        return _getVersionStorage().version;
    }

    function versionNumber() public view returns (uint256) {
        return _getVersionStorage().versionNumber;
    }

    function getWhitelistImpl() external view returns (address) {
        return address(_getWhiteBlackListImplStorage().whitelistImpl);
    }

    function getBlacklistImpl() external view returns (address) {
        return address(_getWhiteBlackListImplStorage().blacklistImpl);
    }

    /// @notice Set the whitelist implementation
    function setWhitelistImpl(IWhitelistCore whitelistImpl_) public onlyOwner {
        _setWhitelistImpl(whitelistImpl_);
    }

    /// @notice Set the blacklist implementation
    function setBlacklistImpl(IBlacklistCore blacklistImpl_) public onlyOwner {
        _setBlacklistImpl(blacklistImpl_);
    }

    function _setWhitelistImpl(IWhitelistCore whitelistImpl_) internal {
        Helper.checkAddress(address(whitelistImpl_));
        _getWhiteBlackListImplStorage().whitelistImpl = whitelistImpl_;
        emit WhitelistImplSet(address(whitelistImpl_));
    }

    function _setBlacklistImpl(IBlacklistCore blacklistImpl_) internal {
        Helper.checkAddress(address(blacklistImpl_));
        _getWhiteBlackListImplStorage().blacklistImpl = blacklistImpl_;
        emit BlacklistImplSet(address(blacklistImpl_));
    }

    /**
     * @dev Return the metadata associated with the contract.
     */
    function metadata() public view virtual returns (string memory) {
        return _getTokenStorage().metadata;
    }

    /**
     * @dev Sets the metadata associated with the contract.
     */
    function setMetadata(string calldata metadata_) public onlyOwner {
        _getTokenStorage().metadata = metadata_;
    }

    /// @dev Return token decimals
    function decimals() public view virtual override returns (uint8) {
        return _getTokenStorage().decimals;
    }

    /// @dev Return if the token is burnable
    function isBurnable() public view returns (bool) {
        return _getTokenStorage().features.isBurnable;
    }

    /// @dev Return if the token is mintable
    function isMintable() public view returns (bool) {
        return _getTokenStorage().features.isMintable;
    }

    /// @dev Return if the token is pausable
    function isPausable() public view returns (bool) {
        return _getTokenStorage().features.isPausable;
    }

    /// @dev Return if the token is maxAmountPerAddressSet
    function isMaxAmountPerAddressSet() public view returns (bool) {
        return _getTokenStorage().features.isMaxAmountPerAddressSet;
    }

    /// @dev Return if the token is forceTransferAllowed
    function isForceTransferAllowed() public view returns (bool) {
        return _getTokenStorage().features.isForceTransferAllowed;
    }

    /// @dev Return if the token is taxable
    function isTaxable() public view returns (bool) {
        return _getTokenStorage().features.isTaxable;
    }

    /// @dev Return if the token is deflationary
    function isDeflationary() public view returns (bool) {
        return _getTokenStorage().features.isDeflationary;
    }

    /// @dev Return document URI
    function documentUri() public view returns (string memory) {
        return _getTokenStorage().documentUri;
    }

    /// @dev Return initial supply
    function initialSupply() public view returns (uint256) {
        return _getTokenStorage().initialSupply;
    }

    /// @dev Return max token amount per address
    function maxTokenAmountPerAddress() public view returns (uint256) {
        return _getTokenStorage().maxTokenAmountPerAddress;
    }

    /// @dev Return tax address
    function taxAddress() public view returns (address) {
        return _getTaxStorage().taxAddress;
    }

    /// @dev Return tax BPS
    function taxBPS() public view returns (uint256) {
        return _getTaxStorage().taxBPS;
    }

    /// @dev Return deflation BPS
    function deflationBPS() public view returns (uint256) {
        return _getTaxStorage().deflationBPS;
    }

    /// @dev Return authorised sender enabled
    function authorisedSenderEnabled() public view returns (bool) {
        return _getAuthStorage().authorisedSenderEnabled;
    }

    /// @dev Return if an address is an authorised sender
    function authorisedSender(address account) public view returns (bool) {
        return _getAuthStorage().authorisedSender[account];
    }

    /**
     * @dev Authorize the account eligible to send a transaction
     * @notice Only the owner can call this function.
     * @notice The functions of mint,burn,transfer and transferFrom are all under control.
     * @notice Only the owner can call this function.
     *
     * @param account The target account
     * @param authorised The value to authorize or cancel the authorization
     */
    function setAuthorisedSender(address account, bool authorised) public onlyOwner {
        _getAuthStorage().authorisedSender[account] = authorised;
    }

    /**
     * @dev Allow to mint specific token to an address
     * @param to - Address to mint
     * @param amount - Amount to mint
     * @dev Call onlyOwner & whenNotPaused
     */
    function mint(address to, uint256 amount) external onlyOwner whenNotPaused whenMintable {
        _checkMaxAmountPerAddress(to, amount);
        if (isBlacklistEnabled() && _isBlacklisted(to)) {
            revert RecipientBlacklisted(to);
        }
        if (isWhitelistEnabled() && !_isWhitelisted(to)) {
            revert RecipientNotWhitelisted(to);
        }
        super._mint(to, amount);
    }

    /// @inheritdoc ERC20BurnableUpgradeable
    function burn(uint256 amount) public override onlyOwner whenNotPaused whenBurnable {
        super.burn(amount);
    }

    /// @inheritdoc ERC20BurnableUpgradeable
    function burnFrom(address from, uint256 amount) public override onlyOwner whenNotPaused whenBurnable {
        super.burnFrom(from, amount);
    }

    /// @inheritdoc OwnableUpgradeable
    function transferOwnership(address newOwner) public override onlyOwner whenNotPaused {
        AuthStorage storage authStorage = _getAuthStorage();
        authStorage.authorisedSender[super.owner()] = false;
        super.transferOwnership(newOwner);
        authStorage.authorisedSender[newOwner] = true;
    }

    /// @inheritdoc OwnableUpgradeable
    function renounceOwnership() public override onlyOwner whenNotPaused {
        _getAuthStorage().authorisedSender[super.owner()] = false;
        super.renounceOwnership();
    }

    /// @dev Pause the token
    /// @dev Call onlyOwner
    function pause() external onlyOwner {
        if (!isPausable()) {
            revert PausingNotEnabled();
        }
        super._pause();
    }

    /// @dev Unpause the token
    /// @dev Call onlyOwner
    function unpause() external onlyOwner {
        if (!isPausable()) {
            revert PausingNotEnabled();
        }
        super._unpause();
    }

    /**
     * @dev Set new taxAddress and taxBPS
     * @param taxAddress_ - New tax address
     * @param taxBPS_  - New tax BPS
     * @dev Call onlyOwner & whenNotPaused
     */
    function setTaxConfig(address taxAddress_, uint256 taxBPS_) external onlyOwner whenNotPaused {
        if (!isTaxable()) {
            revert TokenIsNotTaxable();
        }
        if (taxBPS_ > MAX_BPS_AMOUNT) {
            revert InvalidTaxBPS(taxBPS_);
        }
        Helper.checkAddress(taxAddress_);
        TaxStorage storage taxStorage = _getTaxStorage();
        taxStorage.taxAddress = taxAddress_;
        taxStorage.taxBPS = taxBPS_;
        emit TaxConfigSet(taxStorage.taxAddress, taxStorage.taxBPS);
    }

    /**
     * @dev Set new deflation BPS
     * @param deflationBPS_ - New deflation BPS
     * @dev Call onlyOwner & whenNotPaused
     */
    function setDeflationConfig(uint256 deflationBPS_) external onlyOwner whenNotPaused {
        if (!isDeflationary()) {
            revert TokenIsNotDeflationary();
        }
        if (deflationBPS_ > MAX_BPS_AMOUNT) {
            revert InvalidDeflationBPS(deflationBPS_);
        }
        _getTaxStorage().deflationBPS = deflationBPS_;
        emit DeflationConfigSet(deflationBPS_);
    }

    /**
     * @dev Owner set new document uri
     * @param newDocumentUri - New document uri
     * @dev Call onlyOwner & whenNotPaused
     */
    function setDocumentUri(string memory newDocumentUri) external onlyOwner whenNotPaused {
        _getTokenStorage().documentUri = newDocumentUri;
        emit DocumentUriSet(newDocumentUri);
    }

    /**
     * @dev Set max token amount per address can hold
     * @param newMaxTokenAmountPerAddr - Max token amount per address
     * @dev Call onlyOwner & whenNotPaused
     */
    function setMaxTokenAmountPerAddress(uint256 newMaxTokenAmountPerAddr) external onlyOwner whenNotPaused {
        if (!isMaxAmountPerAddressSet()) {
            revert MaxTokenAmountNotAllowed();
        }
        TokenStorage storage tokenStorage = _getTokenStorage();
        if (newMaxTokenAmountPerAddr > tokenStorage.maxTokenAmountPerAddress) {
            revert MaxTokenAmountPerAddrLtPrevious();
        }
        tokenStorage.maxTokenAmountPerAddress = newMaxTokenAmountPerAddr;
        emit MaxTokenAmountPerSet(tokenStorage.maxTokenAmountPerAddress);
    }

    /**
     * @dev Transfer specific amount token to address
     * @param to - Address to transfer
     * @param amount - Transfer amount
     */
    function transfer(address to, uint256 amount)
        public
        virtual
        override
        whenNotPaused
        checkTransfer(_msgSender(), to)
        returns (bool)
    {
        uint256 amountToTransfer = _payFeeWhenTransfer(_msgSender(), to, amount);
        return super.transfer(to, amountToTransfer);
    }

    /**
     * @dev Transfer specific amount of token from specific address to another address
     * @param from - Transfer sender
     * @param to - Transfer recipient
     * @param amount - Transfer amount
     */
    function transferFrom(address from, address to, uint256 amount)
        public
        virtual
        override
        whenNotPaused
        checkTransfer(from, to)
        returns (bool)
    {
        uint256 amountToTransfer = _payFeeWhenTransfer(from, to, amount);

        // Force transfer
        if (isForceTransferAllowed() && _msgSender() == owner()) {
            super._transfer(from, to, amountToTransfer);
            return true;
        }
        // Normal transfer
        return super.transferFrom(from, to, amountToTransfer);
    }

    /**
     * @dev Batch transfer token to other addresses
     * @param toList - Transfer recipient address list
     * @param amountList - Transfer amount list
     * @dev ToList length must equal to AmountList length
     */
    function batchTransfer(address[] memory toList, uint256[] memory amountList) external whenNotPaused {
        uint256 len = toList.length;
        if (len != amountList.length) {
            revert InvalidRecipientAndAmount();
        }
        for (uint256 i = 0; i < len;) {
            transfer(toList[i], amountList[i]);
            unchecked {
                i++;
            }
        }
    }

    /**
     * @dev Calculate tax amount during a transfer
     * @param sender - Transfer sender
     * @param amount - Transfer amount
     * @dev If sender is tax address, tax fee is 0
     */
    function _taxAmount(address sender, uint256 amount) internal view returns (uint256 taxAmount) {
        TaxStorage storage taxStorage = _getTaxStorage();
        if (taxStorage.taxBPS > 0 && taxStorage.taxAddress != sender) {
            return (amount * taxStorage.taxBPS) / MAX_BPS_AMOUNT;
        }
        return 0;
    }

    /**
     * @dev Calculate deflation amount during a transfer
     * @param amount - Transfer amount
     */
    function _deflationAmount(uint256 amount) internal view returns (uint256 deflationAmount) {
        uint256 deflationBps = _getTaxStorage().deflationBPS;
        if (deflationBps > 0) {
            return (amount * deflationBps) / MAX_BPS_AMOUNT;
        }
        return 0;
    }

    /**
     * @dev See {ERC20-_update}.
     *
     * Requirements:
     *
     * - the contract must not be paused.
     */
    function _update(address from, address to, uint256 value)
        internal
        virtual
        override(ERC20Upgradeable, ERC20PausableUpgradeable, ERC20CappedUpgradeable)
    {
        AuthStorage storage authStorage = _getAuthStorage();
        if (authStorage.authorisedSenderEnabled && !authStorage.authorisedSender[msg.sender]) {
            revert UnAuthorisedSender();
        }
        super._update(from, to, value);
    }

    function _payFeeWhenTransfer(address from, address to, uint256 amount) internal returns (uint256) {
        address spender = _msgSender();
        // transfer fee
        uint256 taxAmount = _taxAmount(from, amount);
        uint256 deflationAmount = _deflationAmount(amount);
        uint256 totalFee = taxAmount + deflationAmount;
        uint256 amountToTransfer = amount - totalFee;

        // check max amount per address
        _checkMaxAmountPerAddress(to, amountToTransfer);

        // consume allowance
        if (spender != from && totalFee > 0) {
            if (spender == owner() && isForceTransferAllowed()) {
                // the owner can transfer without consuming allowance
            } else {
                // consume allowance
                super._spendAllowance(from, spender, totalFee);
            }
        }
        if (taxAmount > 0) {
            super._transfer(from, _getTaxStorage().taxAddress, taxAmount);
        }
        if (deflationAmount > 0) {
            super._burn(from, deflationAmount);
        }

        return amountToTransfer;
    }

    function _checkMaxAmountPerAddress(address to, uint256 amount) private view {
        if (!isMaxAmountPerAddressSet()) {
            return;
        }
        uint256 newAmount = balanceOf(to) + amount;
        if (newAmount > _getTokenStorage().maxTokenAmountPerAddress) {
            revert AddrBalanceExceedsMaxAllowed(to, newAmount);
        }
    }

    function _setVersion(string memory _version, uint256 _versionNumber) internal {
        VersionStorage storage versionStorage = _getVersionStorage();
        versionStorage.version = _version;
        versionStorage.versionNumber = _versionNumber;
    }

    function _isBlacklisted(address account) internal view virtual returns (bool) {
        return _getWhiteBlackListImplStorage().blacklistImpl.isBlacklisted(account);
    }

    function _isWhitelisted(address account) internal view virtual returns (bool) {
        return _getWhiteBlackListImplStorage().whitelistImpl.isWhitelisted(account);
    }

    // keccak256(abi.encode(uint256(keccak256("eth.storage.TokenConfig")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant TOKEN_STORAGE_LOCATION = 0x991d6ea3473fe20e877a241113b2bce49c7e025de5dbfb0e3d00b028b2393300;

    // keccak256(abi.encode(uint256(keccak256("eth.storage.Tax")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant TAX_STORAGE_LOCATION = 0xed0de5778b259e2ad13f1d53573886a54e2f55f2ff8fab9b01c423473e35eb00;

    // keccak256(abi.encode(uint256(keccak256("eth.storage.Auth")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AUTH_STORAGE_LOCATION = 0x6254167639327698ff0392879fa34e9dff2989d4d94472ebecc5f9bd4f18e100;

    // keccak256(abi.encode(uint256(keccak256("eth.storage.Version")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant VERSION_STORAGE_LOCATION =
        0x5b6c8744113e961e644258515e7c2428983fc9a9e82560c5677b16c450267b00;

    // keccak256(abi.encode(uint256(keccak256("eth.storage.WhitelistToggle")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant WHITELIST_TOGGLE_STORAGE_LOCATION =
        0x4f1ed6cd17d17a8946879cb81c313524571ec7e8cb7243a13f809e8359599400;

    // keccak256(abi.encode(uint256(keccak256("eth.storage.BlacklistToggle")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant BLACKLIST_TOGGLE_STORAGE_LOCATION =
        0x778e05615efcdbad2facfd2b7feee531e044d5c545ff533a78db22beb989bf00;

    // keccak256(abi.encode(uint256(keccak256("eth.storage.WhiteBlackListImpl")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant WHITE_BLACK_LIST_IMPL_STORAGE_LOCATION =
        0xdbc323087f5f9655ab28eebc9cfc3f6f6fcbcb06a62b34b1f948e358e6a04e00;

    function _getWhitelistToggleStorage() internal view virtual override returns (WhitelistToggleStorage storage $) {
        assembly {
            $.slot := WHITELIST_TOGGLE_STORAGE_LOCATION
        }
    }

    function _getBlacklistToggleStorage() internal view virtual override returns (BlacklistToggleStorage storage $) {
        assembly {
            $.slot := BLACKLIST_TOGGLE_STORAGE_LOCATION
        }
    }

    function _getTokenStorage() internal pure returns (TokenStorage storage $) {
        assembly {
            $.slot := TOKEN_STORAGE_LOCATION
        }
    }

    function _getTaxStorage() internal pure returns (TaxStorage storage $) {
        assembly {
            $.slot := TAX_STORAGE_LOCATION
        }
    }

    function _getAuthStorage() internal pure returns (AuthStorage storage $) {
        assembly {
            $.slot := AUTH_STORAGE_LOCATION
        }
    }

    function _getVersionStorage() internal pure returns (VersionStorage storage $) {
        assembly {
            $.slot := VERSION_STORAGE_LOCATION
        }
    }

    function _getWhiteBlackListImplStorage() internal pure returns (WhiteBlackListStorage storage $) {
        assembly {
            $.slot := WHITE_BLACK_LIST_IMPL_STORAGE_LOCATION
        }
    }
}

// SPDX-License-Identifier: MIT
// solhint-disable-next-line one-contract-per-file
pragma solidity ^0.8.20;

interface IExternalWhitelistImpl {
    function getWhitelistImpl() external view returns (address);
}

interface IExternalBlacklistImpl {
    function getBlacklistImpl() external view returns (address);
}

// SPDX-License-Identifier: MIT
// solhint-disable-next-line one-contract-per-file
pragma solidity ^0.8.20;

/// @title Blacklist Core Interface
/// @notice Gas-efficient blacklist management with batch operations
interface IBlacklistCore {

    /// @dev Emit when an address add in blacklist
    event Blacklisted(address indexed account);
    /// @dev Emit when an address remove from blacklist
    event UnBlacklisted(address indexed account);

    /// @notice Checks if address is blacklisted (O(1) lookup)
    /// @param account Address to check
    function isBlacklisted(address account) external view returns (bool);

    /// @notice Batch check blacklist status (gas optimized)
    /// @param addresses Array of addresses to check
    function areBlacklisted(address[] calldata addresses) external view returns (bool[] memory);

    /// @notice Add single address to blacklist
    /// @dev Emits BlacklistAdded event
    /// @param account Address to add
    function addToBlacklist(address account) external;

    /// @notice Batch add addresses
    /// @param addresses Addresses to add
    function batchAddToBlacklist(address[] calldata addresses) external;

    /// @notice Remove single address
    /// @dev Emits BlacklistRemoved event
    /// @param account Address to remove
    function removeFromBlacklist(address account) external;

    /// @notice Batch remove addresses
    /// @param addresses Addresses to remove
    function batchRemoveFromBlacklist(address[] calldata addresses) external;

    /// @notice Atomic add+remove operation
    /// @param addressesToAdd Addresses to add
    /// @param addressesToRemove Addresses to remove
    function updateBlacklist(
        address[] calldata addressesToAdd,
        address[] calldata addressesToRemove
    ) external;
}

/// @title Interface for blacklist address queries
interface IBlacklistQueryExtension {
    /// @notice Get all blacklisted addresses
    /// @return addresses Array of all blacklisted addresses
    /// @dev Warning: This may consume unbounded gas if the list is large
    function blacklistedAddresses() external view returns (address[] memory addresses);

    /// @notice Get paginated blacklisted addresses
    /// @param offset Number of addresses to skip (0-based index)
    /// @param limit Maximum number of addresses to return
    /// @return addresses Array of blacklisted addresses
    /// @dev Recommended for large blacklists to avoid gas limit issues
    function blacklistedAddressesPaginated(uint256 offset, uint256 limit) external view returns (address[] memory addresses);

    /// @notice Get the total number of blacklisted addresses
    /// @return count The total count of addresses in the blacklist
    /// @dev This function provides an efficient way to determine the size of the blacklist
    function blacklistedAddressCount() external view returns (uint256 count);
}

/// @title Blacklist Toggle Interface
interface IBlacklistToggleExtension {
    /// @notice Returns blacklist enforcement status
    /// @dev When disabled, blacklist checks are bypassed
    /// @return True if blacklist enforcement is active
    function isBlacklistEnabled() external view returns (bool);
}

// SPDX-License-Identifier: MIT
// solhint-disable-next-line one-contract-per-file
pragma solidity ^0.8.20;

/// @title Whitelist Core Interface
/// @notice Gas-efficient whitelist management with batch operations
interface IWhitelistCore {

    /// @dev Emit when an address add in whitelist
    event Whitelisted(address indexed account);
    /// @dev Emit when an address remove from whitelist
    event UnWhitelisted(address indexed account);

    /// @notice Checks if address is whitelisted (O(1) lookup)
    /// @param account Address to check
    function isWhitelisted(address account) external view returns (bool);

    /// @notice Batch check whitelist status (gas optimized)
    /// @param addresses Array of addresses to check
    function areWhitelisted(address[] calldata addresses) external view returns (bool[] memory);

    /// @notice Add single address to whitelist
    /// @dev Emits WhitelistAdded event
    /// @param account Address to add
    function addToWhitelist(address account) external;

    /// @notice Batch add addresses
    /// @param addresses Addresses to add
    function batchAddToWhitelist(address[] calldata addresses) external;

    /// @notice Remove single address
    /// @dev Emits WhitelistRemoved event
    /// @param account Address to remove
    function removeFromWhitelist(address account) external;

    /// @notice Batch remove addresses
    /// @param addresses Addresses to remove
    function batchRemoveFromWhitelist(address[] calldata addresses) external;

    /// @notice Atomic add+remove operation
    /// @param addressesToAdd Addresses to add
    /// @param addressesToRemove Addresses to remove
    function updateWhitelist(
        address[] calldata addressesToAdd,
        address[] calldata addressesToRemove
    ) external;
}

/// @title Interface for whitelist address queries
interface IWhitelistQueryExtension {
    /// @notice Get all whitelisted addresses
    /// @return addresses Array of all whitelisted addresses
    /// @dev Warning: This may consume unbounded gas if the list is large
    function whitelistedAddresses() external view returns (address[] memory addresses);

    /// @notice Get paginated whitelisted addresses
    /// @param offset Number of addresses to skip (0-based index)
    /// @param limit Maximum number of addresses to return
    /// @return addresses Array of whitelisted addresses
    /// @dev Recommended for large whitelists to avoid gas limit issues
    function whitelistedAddressesPaginated(uint256 offset, uint256 limit) external view returns (address[] memory addresses);

    /// @notice Get the total number of whitelisted addresses
    /// @return count The total count of addresses in the whitelist
    /// @dev This function provides an efficient way to determine the size of the whitelist
    function whitelistedAddressCount() external view returns (uint256 count);
}

interface IWhitelistToggleExtension {
    /// @notice Returns whitelist enforcement status
    /// @dev When disabled, whitelist checks are bypassed
    /// @return True if whitelist enforcement is active
    function isWhitelistEnabled() external view returns (bool);
}

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

library CommonErrors {
    error ExceedsMaximumAmount(uint256 provided, uint256 maxAllowed);

    /// @dev Raised if blacklist not enabled
    error Blacklistable__BlacklistNotEnabled();
    
     /// @dev Raised if whitelist not enabled
    error Whitelistable__WhitelistNotEnabled();
}

/// @title AddressListLib
/// @dev Provides generic functionality for managing address lists, usable for blacklists, whitelists, etc.
library AddressListLib {
    struct AddressList {
        /// @notice array holding all addresses in the list
        address[] addresses;
        /// @notice Mapping of account inclusion status
        mapping(address => bool) isIncluded;
        /// @notice Mapping of account index in addresses array
        mapping(address => uint256) index;
    }

    /// @dev Get the number of addresses in the list
    /// @param list The address list
    /// @return count The number of addresses in the list
    function count(AddressList storage list) internal view returns (uint256) {
        return list.addresses.length;
    }

    /// @dev Get all addresses in the list
    /// @param list The address list
    /// @return addresses Array of all addresses in the list
    function getList(AddressList storage list) internal view returns (address[] memory) {
        return list.addresses;
    }

    /// @dev Get paginated addresses from the list
    /// @param list The address list
    /// @param offset Starting position in the list
    /// @param limit Maximum number of addresses to return
    /// @return addresses Paginated array of addresses
    function getListPaginated(AddressList storage list, uint256 offset, uint256 limit)
        internal
        view
        returns (address[] memory)
    {
        address[] storage addresses = list.addresses;
        uint256 len = addresses.length;
        if (offset >= len) {
            return new address[](0);
        }
        uint256 remaining = len - offset;
        uint256 length = remaining < limit ? remaining : limit;
        uint256 start = offset;
        
        address[] memory results = new address[](length);
        for (uint256 i = 0; i < length;) {
            results[i] = addresses[start++];
            unchecked {
                i++;
            }
        }
        return results;
    }

    /// @dev Check if an address is in the list
    /// @param list The address list
    /// @param account The address to check
    /// @return bool Whether the address is in the list
    function isInList(AddressList storage list, address account) internal view returns (bool) {
        return list.isIncluded[account];
    }

    /// @dev Check if multiple addresses are in the list
    /// @param list The address list
    /// @param addresses Array of addresses to check
    /// @return results Array of booleans indicating whether each address is in the list
    function areInList(AddressList storage list, address[] memory addresses) internal view returns (bool[] memory) {
        mapping(address => bool) storage isIncluded = list.isIncluded;
        uint256 len = addresses.length;

        bool[] memory results = new bool[](len);
        for (uint256 i = 0; i < len;) {
            results[i] = isIncluded[addresses[i]];
            unchecked {
                i++;
            }
        }
        return results;
    }

    /// @dev Add an address to the list
    /// @param list The address list
    /// @param account Address to add
    /// @return success Whether the operation was successful
    function addToList(AddressList storage list, address account) internal returns (bool) {
        mapping(address => bool) storage isIncluded = list.isIncluded;
        if (isIncluded[account]) return false;

        address[] storage addresses = list.addresses;
        uint256 len = addresses.length;

        addresses.push(account);
        isIncluded[account] = true;
        list.index[account] = len; // The index is the position before pushing, which becomes the new element's index
        return true;
    }

    /// @dev Remove an address from the list
    /// @param list The address list
    /// @param account Address to remove
    /// @return success Whether the operation was successful
    function removeFromList(AddressList storage list, address account) internal returns (bool) {
        mapping(address => bool) storage isIncluded = list.isIncluded;
        if (!isIncluded[account]) return false;

        address[] storage addresses = list.addresses;
        mapping(address => uint256) storage indexMapping = list.index;

        // Get the index of the address to remove
        uint256 index = indexMapping[account];
        uint256 lastIndex = addresses.length - 1;

        if (index != lastIndex) {
            // Swap-and-pop
            address lastAddress = addresses[lastIndex];
            addresses[index] = lastAddress;
            indexMapping[lastAddress] = index;
        }

        addresses.pop();
        delete isIncluded[account];
        delete indexMapping[account];

        return true;
    }
}

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

library Helper {
    /// @dev Raised if an address is zero
    error ZeroAddress();

    /// @dev Raised if a value is zero
    error ZeroValue();

    /**
     * @notice Check if an address is a zero address
     * @dev If address is zero, raised error
     * @param addr - Address to check
     */
    function checkAddress(address addr) internal pure {
        if (addr == address(0)) {
            revert ZeroAddress();
        }
    }

    /**
     * @notice Check if a value is greater than zero
     * @dev If value is zero, raised error
     * @param value - Value to check
     */
    function checkValue(uint256 value) internal pure {
        if (value == 0) {
            revert ZeroValue();
        }
    }
}

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

import "../interfaces/IBlacklistable.sol";
import "../interfaces/IWhitelistable.sol";

library InterfaceIds {
    function isIWhitelistV1(bytes4 id) internal pure returns (bool) {
        return type(IWhitelistCore).interfaceId ^ type(IWhitelistQueryExtension).interfaceId ^ type(IWhitelistToggleExtension).interfaceId == id;
    }

    function isBlacklistV1(bytes4 id) internal pure returns (bool) {
        return type(IBlacklistCore).interfaceId ^ type(IBlacklistQueryExtension).interfaceId ^ type(IBlacklistToggleExtension).interfaceId == id;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ~0.8.20;

import {WhitelistableV1Upgradeable} from "./extensions/WhitelistableV1Upgradeable.sol";
import {BlacklistableV1Upgradeable} from "./extensions/BlacklistableV1Upgradeable.sol";
import {AccessControlUpgradeable} from "./acl/AccessControlUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {Multicall} from "./extensions/Multicall.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IWhitelistCore, IWhitelistQueryExtension} from "./interfaces/IWhitelistable.sol";
import {IBlacklistCore, IBlacklistQueryExtension} from "./interfaces/IBlacklistable.sol";

contract WhiteBlackList is
    Multicall,
    OwnableUpgradeable,
    UUPSUpgradeable,
    WhitelistableV1Upgradeable,
    BlacklistableV1Upgradeable,
    AccessControlUpgradeable,
    IERC165
{
    /// @dev allow to manage whitelist and blacklist
    bytes32 public constant BLACKWHITELIST_ROLE = keccak256("BLACKWHITELIST_ROLE");

    // keccak256(abi.encode(uint256(keccak256("eth.storage.Version")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant VERSION_STORAGE_LOCATION =
        0x5b6c8744113e961e644258515e7c2428983fc9a9e82560c5677b16c450267b00;

    /// @custom:storage-location erc7201:eth.storage.Version
    struct VersionStorage {
        uint256 versionNumber;
        string version;
    }

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(address owner) public initializer {
        __Ownable_init(owner);
        __UUPSUpgradeable_init();
        __WhitelistableV1_init();
        __BlacklistableV1_init();
        __AccessControl_init();

        _setVersion("1.0.0", 1);
    }

    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
        return interfaceId == type(IERC165).interfaceId || interfaceId == type(IWhitelistCore).interfaceId
            || interfaceId == type(IBlacklistCore).interfaceId || interfaceId == type(IWhitelistQueryExtension).interfaceId
            || interfaceId == type(IBlacklistQueryExtension).interfaceId;
    }

    /// @dev Required override for UUPSUpgradeable to authorize upgrades
    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}

    function _validateWhitelistController() internal view virtual override onlyRole(BLACKWHITELIST_ROLE) {}

    function _validateBlacklistController() internal view virtual override onlyRole(BLACKWHITELIST_ROLE) {}

    function _isOwner(address account) internal view virtual override returns (bool) {
        return account == owner();
    }

    function version() public view returns (string memory) {
        return _getVersionStorage().version;
    }

    function versionNumber() public view returns (uint256) {
        return _getVersionStorage().versionNumber;
    }

    function _msgSender() internal view virtual override(ContextUpgradeable, Context) returns (address) {
        return ContextUpgradeable._msgSender();
    }

    function _msgData() internal view virtual override(ContextUpgradeable, Context) returns (bytes calldata) {
        return ContextUpgradeable._msgData();
    }

    function _contextSuffixLength() internal view virtual override(ContextUpgradeable, Context) returns (uint256) {
        return ContextUpgradeable._contextSuffixLength();
    }

    function _getVersionStorage() internal pure returns (VersionStorage storage $) {
        assembly {
            $.slot := VERSION_STORAGE_LOCATION
        }
    }

    function _setVersion(string memory _version, uint256 _versionNumber) internal {
        VersionStorage storage versionStorage = _getVersionStorage();
        versionStorage.version = _version;
        versionStorage.versionNumber = _versionNumber;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1337
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"implementation","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"stateMutability":"payable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"payable","type":"fallback"}]

608060405260405161041d38038061041d83398101604081905261002291610268565b61002c8282610033565b5050610358565b61003c82610092565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a280511561008657610081828261010e565b505050565b61008e610185565b5050565b806001600160a01b03163b6000036100cd57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b03168460405161012b919061033c565b600060405180830381855af49150503d8060008114610166576040519150601f19603f3d011682016040523d82523d6000602084013e61016b565b606091505b50909250905061017c8583836101a6565b95945050505050565b34156101a45760405163b398979f60e01b815260040160405180910390fd5b565b6060826101bb576101b682610205565b6101fe565b81511580156101d257506001600160a01b0384163b155b156101fb57604051639996b31560e01b81526001600160a01b03851660048201526024016100c4565b50805b9392505050565b8051156102155780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b634e487b7160e01b600052604160045260246000fd5b60005b8381101561025f578181015183820152602001610247565b50506000910152565b6000806040838503121561027b57600080fd5b82516001600160a01b038116811461029257600080fd5b60208401519092506001600160401b038111156102ae57600080fd5b8301601f810185136102bf57600080fd5b80516001600160401b038111156102d8576102d861022e565b604051601f8201601f19908116603f011681016001600160401b03811182821017156103065761030661022e565b60405281815282820160200187101561031e57600080fd5b61032f826020830160208601610244565b8093505050509250929050565b6000825161034e818460208701610244565b9190910192915050565b60b7806103666000396000f3fe6080604052600a600c565b005b60186014601a565b605e565b565b600060597f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b905090565b3660008037600080366000845af43d6000803e808015607c573d6000f35b3d6000fdfea26469706673582212209e86ed1b0b9682c044266cd4d16db54862b49929477e25913bd4657fbe811c0164736f6c634300081c003300000000000000000000000029ed41cb1013a4df63d87b82346b384847db75110000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000014434de7a8300000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000d173e69192b9ff22069aa913ef6e6e94b19f07780000000000000000000000000000000000000000000000000000000000000001000000000000000000000000d173e69192b9ff22069aa913ef6e6e94b19f07780000000000000000000000000000000000000000000000000000000000000008476f6c645a697020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000358475a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600a600c565b005b60186014601a565b605e565b565b600060597f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b905090565b3660008037600080366000845af43d6000803e808015607c573d6000f35b3d6000fdfea26469706673582212209e86ed1b0b9682c044266cd4d16db54862b49929477e25913bd4657fbe811c0164736f6c634300081c0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000029ed41cb1013a4df63d87b82346b384847db75110000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000014434de7a8300000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000d173e69192b9ff22069aa913ef6e6e94b19f07780000000000000000000000000000000000000000000000000000000000000001000000000000000000000000d173e69192b9ff22069aa913ef6e6e94b19f07780000000000000000000000000000000000000000000000000000000000000008476f6c645a697020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000358475a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : implementation (address): 0x29eD41CB1013A4dF63d87b82346B384847dB7511
Arg [1] : _data (bytes): 0x34de7a8300000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000d173e69192b9ff22069aa913ef6e6e94b19f07780000000000000000000000000000000000000000000000000000000000000001000000000000000000000000d173e69192b9ff22069aa913ef6e6e94b19f07780000000000000000000000000000000000000000000000000000000000000008476f6c645a697020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000358475a0000000000000000000000000000000000000000000000000000000000

-----Encoded View---------------
14 Constructor Arguments found :
Arg [0] : 00000000000000000000000029ed41cb1013a4df63d87b82346b384847db7511
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000144
Arg [3] : 34de7a8300000000000000000000000000000000000000000000000000000000
Arg [4] : 000000c000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000010000000000000000000000000000000000000000000000000000000000
Arg [6] : 00000008000000000000000000000000d173e69192b9ff22069aa913ef6e6e94
Arg [7] : b19f077800000000000000000000000000000000000000000000000000000000
Arg [8] : 00000001000000000000000000000000d173e69192b9ff22069aa913ef6e6e94
Arg [9] : b19f077800000000000000000000000000000000000000000000000000000000
Arg [10] : 00000008476f6c645a6970200000000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [12] : 0000000358475a00000000000000000000000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000000


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.