creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n     * constructor.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = !_initializing;\n        require(\n            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n            \"Initializable: contract is already initialized\"\n        );\n        _initialized = 1;\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: setting the version to 255 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint8 version) {\n        require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n        _initialized = version;\n        _initializing = true;\n        _;\n        _initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        require(_initializing, \"Initializable: contract is not initializing\");\n        _;\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        require(!_initializing, \"Initializable: contract is initializing\");\n        if (_initialized != type(uint8).max) {\n            _initialized = type(uint8).max;\n            emit Initialized(type(uint8).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint8) {\n        return _initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _initializing;\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract PausableUpgradeable is Initializable, ContextUpgradeable {\n    /**\n     * @dev Emitted when the pause is triggered by `account`.\n     */\n    event Paused(address account);\n\n    /**\n     * @dev Emitted when the pause is lifted by `account`.\n     */\n    event Unpaused(address account);\n\n    bool private _paused;\n\n    /**\n     * @dev Initializes the contract in unpaused state.\n     */\n    function __Pausable_init() internal onlyInitializing {\n        __Pausable_init_unchained();\n    }\n\n    function __Pausable_init_unchained() internal onlyInitializing {\n        _paused = false;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is not paused.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    modifier whenNotPaused() {\n        _requireNotPaused();\n        _;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is paused.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    modifier whenPaused() {\n        _requirePaused();\n        _;\n    }\n\n    /**\n     * @dev Returns true if the contract is paused, and false otherwise.\n     */\n    function paused() public view virtual returns (bool) {\n        return _paused;\n    }\n\n    /**\n     * @dev Throws if the contract is paused.\n     */\n    function _requireNotPaused() internal view virtual {\n        require(!paused(), \"Pausable: paused\");\n    }\n\n    /**\n     * @dev Throws if the contract is not paused.\n     */\n    function _requirePaused() internal view virtual {\n        require(paused(), \"Pausable: not paused\");\n    }\n\n    /**\n     * @dev Triggers stopped state.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    function _pause() internal virtual whenNotPaused {\n        _paused = true;\n        emit Paused(_msgSender());\n    }\n\n    /**\n     * @dev Returns to normal state.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    function _unpause() internal virtual whenPaused {\n        _paused = false;\n        emit Unpaused(_msgSender());\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    function __ReentrancyGuard_init() internal onlyInitializing {\n        __ReentrancyGuard_init_unchained();\n    }\n\n    function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20Upgradeable.sol\";\nimport \"./extensions/IERC20MetadataUpgradeable.sol\";\nimport \"../../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\n        __ERC20_init_unchained(name_, symbol_);\n    }\n\n    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[45] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20MetadataUpgradeable is IERC20Upgradeable {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20PermitUpgradeable {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n    using AddressUpgradeable for address;\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20PermitUpgradeable token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[50] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary MathUpgradeable {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"
      },
      "contracts/interfaces/IMasterWhitelist.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity =0.8.19;\n\n/// @title Master Whitelist Interface\n/// @notice Interface for a contract that manages a whitelist of users.\ninterface IMasterWhitelist {\n    // The whitelisting status.\n    enum WhitelistingStatus {\n        None,\n        Whitelisted,\n        Blacklisted\n    }\n\n    // --- Events ---\n\n    /// @notice Emits an event when an agent is added.\n    /// @param _agent The address of the agent.\n    event AgentAdded(address indexed _agent);\n\n    /// @notice Emits an event when an agent is removed.\n    /// @param _agent The address of the agent.\n    event AgentRemoved(address indexed _agent);\n\n    /// @notice Emitted when a user's whitelist status has changed.\n    /// @param _user The address of the user.\n    /// @param _oldStatus The status before the change.\n    /// @param _newStatus The status after the change.\n    event WhitelistingStatusChanged(\n        address indexed _user,\n        WhitelistingStatus indexed _oldStatus,\n        WhitelistingStatus indexed _newStatus\n    );\n\n    // --- Errors ---\n\n    /// @notice Error thrown when trying to perform an action reserved for agents.\n    error CallerIsNotAnAgent();\n\n    /// @notice Error thrown when trying to whitelist a user that's already whitelisted.\n    error UserAlreadyWhitelisted();\n\n    /// @notice Error thrown when trying to blacklist a user that's already blacklisted.\n    error UserAlreadyBlacklisted();\n\n    /// @notice Error thrown when trying to clear a user status.\n    error WhitelistingStatusAlreadyCleared();\n\n    // --- Functions ---\n\n    /// @notice Checks if a user is in the whitelist.\n    /// @param _user The address to check.\n    /// @return A value indicating whether this user is whitelisted.\n    function isUserWhitelisted(address _user) external view returns (bool);\n\n    /// @notice Checks if a user is in the blacklist.\n    /// @param _user The address to check.\n    /// @return A value indicating whether this user is blacklisted.\n    function isUserBlacklisted(address _user) external view returns (bool);\n\n    /// @notice Checks if this address is an agent.\n    /// @param _agent The address to check.\n    /// @return A value indicating whether this address is that of an agent.\n    function isAgent(address _agent) external view returns (bool);\n}\n"
      },
      "contracts/interfaces/IStakeManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity =0.8.19;\n\ninterface IStakeManager {\n    // validator replacement\n    function startAuction(\n        uint256 validatorId,\n        uint256 amount,\n        bool acceptDelegation,\n        bytes calldata signerPubkey\n    ) external;\n\n    function confirmAuctionBid(uint256 validatorId, uint256 heimdallFee) external;\n\n    function transferFunds(uint256 validatorId, uint256 amount, address delegator) external returns (bool);\n\n    function delegationDeposit(uint256 validatorId, uint256 amount, address delegator) external returns (bool);\n\n    function unstake(uint256 validatorId) external;\n\n    function stakeFor(\n        address user,\n        uint256 amount,\n        uint256 heimdallFee,\n        bool acceptDelegation,\n        bytes memory signerPubkey\n    ) external;\n\n    function checkSignatures(\n        uint256 blockInterval,\n        bytes32 voteHash,\n        bytes32 stateRoot,\n        address proposer,\n        uint[3][] calldata sigs\n    ) external returns (uint256);\n\n    function updateValidatorState(uint256 validatorId, int256 amount) external;\n\n    function slash(bytes calldata slashingInfoList) external returns (uint256);\n\n    function decreaseValidatorDelegatedAmount(uint256 validatorId, uint256 amount) external;\n\n    function withdrawDelegatorsReward(uint256 validatorId) external returns (uint256);\n\n    function dethroneAndStake(\n        address auctionUser,\n        uint256 heimdallFee,\n        uint256 validatorId,\n        uint256 auctionAmount,\n        bool acceptDelegation,\n        bytes calldata signerPubkey\n    ) external;\n\n    function totalStakedFor(address addr) external view returns (uint256);\n\n    function ownerOf(uint256 tokenId) external view returns (address);\n\n    function validatorStake(uint256 validatorId) external view returns (uint256);\n\n    function epoch() external view returns (uint256);\n\n    function getRegistry() external view returns (address);\n\n    function withdrawalDelay() external view returns (uint256);\n\n    function delegatedAmount(uint256 validatorId) external view returns (uint256);\n\n    function delegatorsReward(uint256 validatorId) external view returns (uint256);\n}\n"
      },
      "contracts/interfaces/ITruStakeMATICv2.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity =0.8.19;\n\nimport {ValidatorState} from \"../main/Types.sol\";\n\ninterface ITruStakeMATICv2 {\n    // --- Events ---\n\n    /// @notice Emitted on initialize.\n    /// @dev Params same as initialize function.\n    event StakerInitialized(\n        address _stakingTokenAddress,\n        address _stakeManagerContractAddress,\n        address _validator,\n        address _whitelistAddress,\n        address _treasuryAddress,\n        uint256 _phi,\n        uint256 _distPhi\n    );\n\n    // User Tracking\n\n    /// @notice Emitted on user deposit.\n    /// @param _user User which made the deposit tx.\n    /// @param _treasuryShares Newly minted shares added to the treasury user's balance.\n    /// @param _userShares Newly minted shares added to the depositing user's balance.\n    /// @param _amount Amount of MATIC transferred by user into the staker.\n    /// @param _stakedAmount Deposit _amount + any auto-claimed MATIC rewards sitting in the\n    /// staker from previous deposits or withdrawal requests made by any user.\n    /// @param _totalAssets Auto-claimed MATIC rewards that will sit in the staker\n    /// until the next deposit made by any user.\n    /// @param _validator Address of the validator the user has deposited to.\n    event Deposited(\n        address indexed _user,\n        uint256 _treasuryShares,\n        uint256 _userShares,\n        uint256 _amount,\n        uint256 _stakedAmount,\n        uint256 _totalAssets,\n        address indexed _validator\n    );\n\n    /// @notice Emitted on user requesting a withdrawal.\n    /// @param _user User which made the withdraw request tx.\n    /// @param _treasuryShares Newly minted shares added to the treasury user's balance\n    /// (fees taken: shares are newly minted as a result of the auto-claimed MATIC rewards).\n    /// @param _userShares Burnt shares removed from the depositing user's balance.\n    /// @param _amount Amount of MATIC unbonding, which will be claimable by user in\n    /// 80 checkpoints.\n    /// @param _totalAssets Auto-claimed MATIC rewards that will sit in the staker\n    /// until the next deposit made by any user.\n    /// @param _validator Address of the validator the withdrawal was requested from.\n    /// @param _unbondNonce Nonce of this unbond, which will be passed into the function\n    /// withdrawClaim(uint256 _unbondNonce)` in 80 checkpoints in order to claim this\n    /// the amount from this request.\n    /// @param _epoch The current checkpoint the stake manager is at, used to track how\n    /// how far from claiming the request is.\n    event WithdrawalRequested(\n        address indexed _user,\n        uint256 _treasuryShares,\n        uint256 _userShares,\n        uint256 _amount,\n        uint256 _totalAssets,\n        address indexed _validator,\n        uint256 _unbondNonce,\n        uint256 indexed _epoch\n    );\n\n    /// @notice Emitted on user claiming a withdrawal.\n    /// @param _user User which made the withdraw claim tx.\n    /// @param _validator Address of the validator the withdrawal was claimed from.\n    /// @param _unbondNonce Nonce of the original withdrawal request, which was passed\n    /// into the `withdrawClaim` function.\n    /// @param _claimedAmount Amount of MATIC claimed by the user.\n    /// @param _transferredAmount Amount of MATIC transferred to the user (originally from stake manager).\n    event WithdrawalClaimed(\n        address indexed _user,\n        address indexed _validator,\n        uint256 indexed _unbondNonce,\n        uint256 _claimedAmount,\n        uint256 _transferredAmount\n    );\n\n    // global tracking\n\n    /// @notice Emitted on rewards compound call.\n    /// @param _amount Amount of MATIC moved from rewards on the validator to staked funds.\n    /// @param _shares Newly minted shares added to the treasury user's balance (fees taken).\n    event RewardsCompounded(uint256 indexed _amount, uint256 indexed _shares);\n\n    // allocations\n\n    /// @notice Emitted on allocation.\n    /// @param _distributor Address of user who has allocated to someone else.\n    /// @param _recipient Address of user to whom something was allocated.\n    /// @param _individualAmount Total amount allocated to recipient by this distributor.\n    /// @param _individualNum Average share price numerator at which allocations occurred.\n    /// @param _individualDenom Average share price denominator at which allocations occurred.\n    event Allocated(\n        address indexed _distributor,\n        address indexed _recipient,\n        uint256 _individualAmount,\n        uint256 _individualNum,\n        uint256 _individualDenom\n    );\n\n    /// @notice Emitted on deallocations.\n    /// @param _distributor Address of user who has allocated to someone else.\n    /// @param _recipient Address of user to whom something was allocated.\n    /// @param _individualAmount Remaining amount allocated to recipient.\n    event Deallocated(address indexed _distributor, address indexed _recipient, uint256 _individualAmount);\n\n    /// @notice Emitted when rewards are distributed.\n    /// @param _distributor Address of user who has allocated to someone else.\n    /// @param _recipient Address of user to whom something was allocated.\n    /// @param _amount Amount of MATIC being distributed.\n    /// @param _shares Amount of shares being distributed.\n    /// @param _individualNum Average share price numerator at which distributor allocated.\n    /// @param _individualDenom Average share price numerator at which distributor allocated.\n    event DistributedRewards(\n        address indexed _distributor,\n        address indexed _recipient,\n        uint256 _amount,\n        uint256 _shares,\n        uint256 _individualNum,\n        uint256 _individualDenom\n    );\n\n    /// @notice Emitted when rewards are distributed.\n    /// @param _distributor Address of user who has allocated to someone else.\n    event DistributedAll(address indexed _distributor);\n\n    // Setter Tracking\n\n    event SetWhitelist(address indexed _oldWhitelistAddress, address indexed _newWhitelistAddress);\n\n    event SetTreasury(address indexed _oldTreasuryAddress, address indexed _newTreasuryAddress);\n\n    event SetDefaultValidator(address indexed _oldDefaultValidator, address indexed _newDefaultValidator);\n\n    event SetPhi(uint256 indexed _oldPhi, uint256 indexed _newPhi);\n\n    event SetDistPhi(uint256 indexed _oldDistPhi, uint256 indexed _newDistPhi);\n\n    event SetEpsilon(uint256 indexed _oldEpsilon, uint256 indexed _newEpsilon);\n\n    event SetMinDeposit(uint256 indexed _oldMinDeposit, uint256 indexed _newMinDeposit);\n\n    event ValidatorAdded(address indexed _validator, uint256 _stakedAmount, bool _isPrivate);\n\n    event ValidatorStateChanged(\n        address indexed _validator,\n        ValidatorState indexed _oldState,\n        ValidatorState indexed _newState\n    );\n\n    event RestakeError(address indexed _validator, string _reason);\n\n    event PrivateAccessGiven(address indexed _user, address indexed _validator);\n\n    event PrivateAccessRemoved(address indexed _user, address indexed _validator);\n\n    event ValidatorPrivacyChanged(address indexed _validator, bool _oldIsPrivate, bool _newIsPrivate);\n\n    // --- Errors ---\n\n    /// @notice Error thrown when user tries to transfer or approve to zero address.\n    error ZeroAddressNotSupported();\n\n    /// @notice Error thrown when a user tries to interact with a whitelisted-only function.\n    error UserNotWhitelisted();\n\n    /// @notice Error thrown when a user tries to deposit less than the minimum deposit amount.\n    error DepositBelowMinDeposit();\n\n    /// @notice Error thrown when a user tries to request a withdrawal with an amount larger\n    /// than their shares entitle them to.\n    error WithdrawalAmountTooLarge();\n\n    /// @notice Error thrown when a user tries to request a withdrawal of amount zero.\n    error WithdrawalRequestAmountCannotEqualZero();\n\n    /// @notice Error thrown when a user tries to claim a withdrawal they did not request.\n    error SenderMustHaveInitiatedWithdrawalRequest();\n\n    /// @notice Error thrown when a user tries to claim a withdrawal that does not exist.\n    error WithdrawClaimNonExistent();\n\n    /// @notice Error thrown when user allocates more MATIC than available.\n    error InsufficientDistributorBalance();\n\n    /// @notice Error thrown when a user attempts to allocate less than one MATIC.\n    error AllocationUnderOneMATIC();\n\n    /// @notice Error thrown when deallocation is greater than allocated amount.\n    error ExcessDeallocation();\n\n    /// @notice Error thrown when a user tries to deallocate from a user they do\n    /// not currently have anything allocated to.\n    error AllocationNonExistent();\n\n    /// @notice Error thrown when user calls distributeRewards when the allocation\n    /// share price is the same as the current share price.\n    error NothingToDistribute();\n\n    /// @notice Error thrown when no recipients are found to distribute to.\n    error NoRecipientsFound();\n\n    /// @notice Error thrown when the distribution fee is higher than the fee precision.\n    error DistPhiTooLarge();\n\n    /// @notice Error thrown when epsilon is set too high.\n    error EpsilonTooLarge();\n\n    /// @notice Error thrown when the new minimum deposit amount is too small.\n    error MinDepositTooSmall();\n\n    /// @notice Error thrown when the phi value is larger than the phi precision constant.\n    error PhiTooLarge();\n\n    /// @notice Error thrown when trying to add an existing validator.\n    error ValidatorAlreadyExists();\n\n    /// @notice Error thrown when trying to disable a validator that is not enabled.\n    error ValidatorNotEnabled();\n\n    /// @notice Error thrown when trying to enable a validator that is not disabled.\n    error ValidatorNotDisabled();\n\n    /// @notice Error thrown when trying to perform actions on a non-existent validator.\n    error ValidatorDoesNotExist();\n\n    /// @notice Error thrown when trying to privatise a validator that has assets remaining.\n    error ValidatorHasAssets();\n\n    /// @notice Error thrown when trying to give private validator access to a user who already got it.\n    error PrivateAccessAlreadyGiven();\n\n    /// @notice Error thrown when trying to remove private validator access to a user who hasn't got it.\n    error PrivateAccessNotGiven();\n\n    /// @notice Error thrown when trying to give a user private access to a validator that is non-private.\n    error ValidatorNotPrivate();\n\n    /// @notice Error thrown when a user is trying to access a validator they should not access.\n    error ValidatorAccessDenied();\n\n    /// @notice Error thrown when trying to set private status on an private validator.\n    error ValidatorAlreadyPrivate();\n\n    /// @notice Error thrown when trying to remove private status on a non-private validator.\n    error ValidatorAlreadyNonPrivate();\n}\n"
      },
      "contracts/interfaces/IValidatorShare.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity =0.8.19;\n\ninterface IValidatorShare {\n    function buyVoucher(uint256 _amount, uint256 _minSharesToMint) external returns (uint256 amountToDeposit);\n\n    // solhint-disable-next-line func-name-mixedcase\n    function sellVoucher_new(uint256 claimAmount, uint256 maximumSharesToBurn) external;\n\n    // solhint-disable-next-line func-name-mixedcase\n    function unstakeClaimTokens_new(uint256 unbondNonce) external;\n\n    function restake() external returns (uint256 amountRestaked, uint256 liquidReward);\n\n    function approve(address spender, uint256 amount) external;\n\n    function transfer(address to, uint256 value) external;\n\n    function transferFrom(address sender, address recipient, uint256 amount) external;\n\n    function getLiquidRewards(address user) external view returns (uint256);\n\n    function balanceOf(address account) external view returns (uint256);\n\n    function exchangeRate() external view returns (uint256);\n\n    function getTotalStake(address user) external view returns (uint256, uint256);\n\n    // automatically generated getter of a public mapping\n    // solhint-disable-next-line func-name-mixedcase\n    function unbonds_new(address user, uint256 unbondNonce) external view returns (uint256, uint256);\n\n    // automatically generated getter of a public mapping\n    function unbondNonces(address user) external view returns (uint256);\n}\n"
      },
      "contracts/main/ERC4626Storage.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity =0.8.19;\n\nimport {ERC20Upgradeable} from \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\n\n/// @title ERC4626Storage\n/// @notice This contract includes storage variables from OpenZeppelin's ERC4626Upgradeable.\n/// @dev Needed for compatibility with prior versions of the staker contract that inherited from ERC4626Upgradeable.\nabstract contract ERC4626Storage is ERC20Upgradeable {\n    address private _asset;\n    uint8 private _underlyingDecimals;\n    uint256[49] private __gap;\n}\n"
      },
      "contracts/main/TruStakeMATICv2.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity =0.8.19;\n\n// OpenZeppelin\nimport {IERC20Upgradeable} from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport {MathUpgradeable} from \"@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol\";\nimport {OwnableUpgradeable} from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport {ReentrancyGuardUpgradeable} from \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport {SafeERC20Upgradeable} from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport {PausableUpgradeable} from \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\n\n// Polygon\nimport {IValidatorShare} from \"../interfaces/IValidatorShare.sol\";\nimport {IStakeManager} from \"../interfaces/IStakeManager.sol\";\n\n// TruFin\nimport {ERC4626Storage} from \"./ERC4626Storage.sol\";\nimport {ITruStakeMATICv2} from \"../interfaces/ITruStakeMATICv2.sol\";\nimport {TruStakeMATICv2Storage} from \"./TruStakeMATICv2Storage.sol\";\nimport {Withdrawal, Allocation, ValidatorState, Validator} from \"./Types.sol\";\nimport {IMasterWhitelist} from \"../interfaces/IMasterWhitelist.sol\";\n\nuint256 constant PHI_PRECISION = 1e4;\nuint256 constant MAX_EPSILON = 1e12;\nuint256 constant ONE_MATIC = 1e18;\nuint256 constant SHARE_PRICE_PRECISION = 1e22;\n\n/// @title TruStakeMATICv2\n/// @notice An auto-compounding liquid staking MATIC vault with reward-allocating functionality.\ncontract TruStakeMATICv2 is\n    TruStakeMATICv2Storage,\n    ITruStakeMATICv2,\n    OwnableUpgradeable,\n    ReentrancyGuardUpgradeable,\n    ERC4626Storage,\n    PausableUpgradeable\n{\n    // *** LIBRARIES ***\n\n    using SafeERC20Upgradeable for IERC20Upgradeable;\n\n    // *** MODIFIERS ***\n    // Reverts call if caller is not whitelisted\n    modifier onlyWhitelist() {\n        if (!IMasterWhitelist(whitelistAddress).isUserWhitelisted(msg.sender)) {\n            revert UserNotWhitelisted();\n        }\n        _;\n    }\n\n    // *** CONSTRUCTOR & INITIALIZER ***\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    constructor() {\n        _disableInitializers();\n    }\n\n    /// @notice Vault state initializer.\n    /// @param _stakingTokenAddress MATIC token address.\n    /// @param _stakeManagerContractAddress Polygon's StakeManager contract address.\n    /// @param _validator Share contract address of the validator the vault delegates to.\n    /// @param _whitelistAddress The vault's whitelist contract address.\n    /// @param _treasuryAddress Treasury address that receives vault fees.\n    /// @param _phi Fee taken on restake in basis points.\n    /// @param _distPhi Fee taken during the distribution of rewards earned from allocations.\n    function initialize(\n        address _stakingTokenAddress,\n        address _stakeManagerContractAddress,\n        address _validator,\n        address _whitelistAddress,\n        address _treasuryAddress,\n        uint256 _phi,\n        uint256 _distPhi\n    ) external initializer {\n        // Initialize derived state\n        __ReentrancyGuard_init();\n        __Ownable_init();\n        __ERC20_init(\"TruStake MATIC Vault Shares\", \"TruMATIC\");\n        __Pausable_init();\n\n        // Ensure addresses are non-zero\n        _checkNotZeroAddress(_stakingTokenAddress);\n        _checkNotZeroAddress(_stakeManagerContractAddress);\n        _checkNotZeroAddress(_validator);\n        _checkNotZeroAddress(_whitelistAddress);\n        _checkNotZeroAddress(_treasuryAddress);\n\n        if (_phi > PHI_PRECISION) revert PhiTooLarge();\n\n        if (_distPhi > PHI_PRECISION) revert DistPhiTooLarge();\n\n        // Initialize contract state\n        stakingTokenAddress = _stakingTokenAddress;\n        stakeManagerContractAddress = _stakeManagerContractAddress;\n        defaultValidatorAddress = _validator;\n        validatorAddresses.push(_validator);\n        validators[_validator].state = ValidatorState.ENABLED;\n        whitelistAddress = _whitelistAddress;\n        treasuryAddress = _treasuryAddress;\n        phi = _phi;\n        distPhi = _distPhi;\n        epsilon = 1e4;\n        minDeposit = ONE_MATIC; // default minimum is 1 MATIC\n\n        emit StakerInitialized(\n            _stakingTokenAddress,\n            _stakeManagerContractAddress,\n            _validator,\n            _whitelistAddress,\n            _treasuryAddress,\n            _phi,\n            _distPhi\n        );\n    }\n\n    /// *** EXTERNAL METHODS ***\n    // *** VAULT OWNER ADMIN ACTIONS ***\n    /// @notice Allows owner to pause the contract. Requires the contract to be unpaused.\n    function pause() external onlyOwner {\n        _pause();\n    }\n\n    /// @notice Allows owner to unpause the contract. Requires the contract to be paused.\n    function unpause() external onlyOwner {\n        _unpause();\n    }\n\n    // *** VAULT OWNER ADMIN SETTERS ***\n    /// @notice Sets the whitelist used to check user status.\n    /// @param _whitelistAddress to point to.\n    function setWhitelist(address _whitelistAddress) external onlyOwner {\n        _checkNotZeroAddress(_whitelistAddress);\n        emit SetWhitelist(whitelistAddress, _whitelistAddress);\n        whitelistAddress = _whitelistAddress;\n    }\n\n    /// @notice Sets the treasury used to accumulate rewards.\n    /// @param _treasuryAddress to receive rewards and fees.\n    function setTreasury(address _treasuryAddress) external onlyOwner {\n        _checkNotZeroAddress(_treasuryAddress);\n        emit SetTreasury(treasuryAddress, _treasuryAddress);\n        treasuryAddress = _treasuryAddress;\n    }\n\n    /// @notice Sets the default validator used for staking.\n    /// @param _validator New default validator to stake to and withdraw from.\n    function setDefaultValidator(address _validator) external onlyOwner {\n        _checkNotZeroAddress(_validator);\n        if (validators[_validator].state != ValidatorState.ENABLED) revert ValidatorNotEnabled();\n\n        emit SetDefaultValidator(defaultValidatorAddress, _validator);\n        defaultValidatorAddress = _validator;\n    }\n\n    /// @notice Sets the fee on certain actions within the protocol.\n    /// @param _phi New fee cannot be larger than phi precision.\n    function setPhi(uint256 _phi) external onlyOwner {\n        if (_phi > PHI_PRECISION) revert PhiTooLarge();\n\n        emit SetPhi(phi, _phi);\n        phi = _phi;\n    }\n\n    /// @notice Sets the distribution fee.\n    /// @param _distPhi New distribution fee.\n    function setDistPhi(uint256 _distPhi) external onlyOwner {\n        if (_distPhi > PHI_PRECISION) revert DistPhiTooLarge();\n\n        emit SetDistPhi(distPhi, _distPhi);\n        distPhi = _distPhi;\n    }\n\n    /// @notice Sets the epsilon for rounding.\n    /// @param _epsilon Buffer amount for rounding.\n    function setEpsilon(uint256 _epsilon) external onlyOwner {\n        if (_epsilon > MAX_EPSILON) revert EpsilonTooLarge();\n\n        emit SetEpsilon(epsilon, _epsilon);\n        epsilon = _epsilon;\n    }\n\n    /// @notice Sets the lower deposit limit.\n    /// @param _newMinDeposit New minimum amount of MATIC one has to deposit (default 1e18 = 1 MATIC).\n    function setMinDeposit(uint256 _newMinDeposit) external onlyOwner {\n        if (_newMinDeposit < ONE_MATIC) revert MinDepositTooSmall();\n\n        emit SetMinDeposit(minDeposit, _newMinDeposit);\n        minDeposit = _newMinDeposit;\n    }\n\n    /// @notice Adds a new validator to the list of validators supported by the Staker.\n    /// @param _validator The share contract address of the validator to add.\n    /// @param _isPrivate A boolean indicating whether access to the validator is limited to some users.\n    /// @dev Newly added validators are considered enabled by default.\n    /// @dev This function reverts when a validator with the same share contract address already exists.\n    function addValidator(address _validator, bool _isPrivate) external onlyOwner {\n        _checkNotZeroAddress(_validator);\n\n        if (validators[_validator].state != ValidatorState.NONE) revert ValidatorAlreadyExists();\n\n        validatorAddresses.push(_validator);\n\n        (uint256 stakedAmount, ) = IValidatorShare(_validator).getTotalStake(address(this));\n        validators[_validator].state = ValidatorState.ENABLED;\n        validators[_validator].stakedAmount = stakedAmount;\n        validators[_validator].isPrivate = _isPrivate;\n\n        emit ValidatorAdded(_validator, stakedAmount, _isPrivate);\n    }\n\n    /// @notice Disable an enabled validator to prevent depositing and staking to it.\n    /// @param _validator The share contract address of the validator to disable.\n    function disableValidator(address _validator) external onlyOwner {\n        _checkNotZeroAddress(_validator);\n\n        if (validators[_validator].state != ValidatorState.ENABLED) revert ValidatorNotEnabled();\n\n        validators[_validator].state = ValidatorState.DISABLED;\n\n        emit ValidatorStateChanged(_validator, ValidatorState.ENABLED, ValidatorState.DISABLED);\n    }\n\n    /// @notice Enable a disabled validator to allow depositing and staking to it.\n    /// @param _validator The share contract address of the validator to enable.\n    function enableValidator(address _validator) external onlyOwner {\n        _checkNotZeroAddress(_validator);\n\n        if (validators[_validator].state != ValidatorState.DISABLED) revert ValidatorNotDisabled();\n\n        validators[_validator].state = ValidatorState.ENABLED;\n\n        emit ValidatorStateChanged(_validator, ValidatorState.DISABLED, ValidatorState.ENABLED);\n    }\n\n    /// @notice Gives a user private access to a validator.\n    /// @param _user The user address.\n    /// @param _validator The private validator address.\n    function givePrivateAccess(address _user, address _validator) external onlyOwner {\n        _checkNotZeroAddress(_user);\n        Validator memory validator = validators[_validator];\n        if (validator.state == ValidatorState.NONE) revert ValidatorDoesNotExist();\n        if (!validator.isPrivate) revert ValidatorNotPrivate();\n        if (usersPrivateAccess[_user] != address(0)) revert PrivateAccessAlreadyGiven();\n\n        usersPrivateAccess[_user] = _validator;\n\n        emit PrivateAccessGiven(_user, _validator);\n    }\n\n    /// @notice Removes private access to a private validator from a user.\n    /// @param _user The user address.\n    function removePrivateAccess(address _user) external onlyOwner {\n        address oldValidator = usersPrivateAccess[_user];\n        if (oldValidator == address(0)) revert PrivateAccessNotGiven();\n\n        delete usersPrivateAccess[_user];\n\n        emit PrivateAccessRemoved(_user, oldValidator);\n    }\n\n    /// @notice Changes the privacy status of a validator.\n    /// @param _validator The validator address.\n    /// @param _isPrivate Whether the validator should be private or not.\n    function changeValidatorPrivacy(address _validator, bool _isPrivate) external onlyOwner {\n        Validator storage validator = validators[_validator];\n        if (validator.state == ValidatorState.NONE) revert ValidatorDoesNotExist();\n\n        bool oldIsPrivate = validator.isPrivate;\n        if (oldIsPrivate && _isPrivate) revert ValidatorAlreadyPrivate();\n        if (!oldIsPrivate && !_isPrivate) revert ValidatorAlreadyNonPrivate();\n\n        // check assets are zero before privatising. Otherwise, assets on validator would be limited to private users.\n        if (!oldIsPrivate && validator.stakedAmount >= ONE_MATIC) revert ValidatorHasAssets();\n\n        validator.isPrivate = _isPrivate;\n\n        emit ValidatorPrivacyChanged(_validator, oldIsPrivate, _isPrivate);\n    }\n\n    /// @notice Claims a previously requested and now unbonded withdrawal.\n    /// @param _unbondNonce Nonce of the corresponding delegator unbond.\n    /// @param _validator Address of the validator to claim the withdrawal from.\n    function withdrawClaim(uint256 _unbondNonce, address _validator) external onlyWhitelist nonReentrant whenNotPaused {\n        _withdrawClaim(_unbondNonce, _validator);\n    }\n\n    /// @notice Claims multiple previously requested and now unbonded withdrawals from a specified validator.\n    /// @param _unbondNonces List of delegator unbond nonces corresponding to said withdrawals.\n    /// @param _validator Address of the validator to claim the withdrawals from.\n    function claimList(\n        uint256[] calldata _unbondNonces,\n        address _validator\n    ) external onlyWhitelist nonReentrant whenNotPaused {\n        uint256 len = _unbondNonces.length;\n\n        for (uint256 i; i < len; ) {\n            _withdrawClaim(_unbondNonces[i], _validator);\n\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /// @notice Restakes the vault's current unclaimed delegation-earned rewards on the respective validators and\n    /// stakes MATIC lingering in the vault to the validator provided.\n    /// @dev Can be called manually to prevent the rewards surpassing reserves. This could lead to insufficient funds for\n    /// withdrawals, as they are taken from delegated MATIC and not its rewards.\n    /// @dev This method should prevent staking the vault's assets on a private validator where they can't be withdrawn by non-private users.\n    /// @param _validator Address of the validator where MATIC in the vault should be staked to.\n    function compoundRewards(address _validator) external nonReentrant whenNotPaused {\n        (uint256 globalPriceNum, uint256 globalPriceDenom) = sharePrice();\n        uint256 amountRestaked = _restake();\n\n        // To keep share price constant when rewards are staked, new shares need to be minted\n        uint256 shareIncrease = (amountRestaked * phi * 1e18 * globalPriceDenom) / (globalPriceNum * PHI_PRECISION);\n\n        // Minted shares are given to the treasury to effectively take a fee\n        _mint(treasuryAddress, shareIncrease);\n\n        // if there is MATIC in the vault, stake it with the provided validator\n        if (totalAssets() > 0) {\n            _deposit(address(0), 0, _validator);\n        }\n\n        emit RewardsCompounded(amountRestaked, shareIncrease);\n    }\n\n    // *** ALLOCATIONS ***\n\n    /// @notice Allocates the validation rewards earned by an amount of the caller's staked MATIC to a user.\n    /// @param _amount The amount of staked MATIC to allocate.\n    /// @param _recipient The address of the target recipient.\n    function allocate(uint256 _amount, address _recipient) external onlyWhitelist nonReentrant whenNotPaused {\n        _checkNotZeroAddress(_recipient);\n\n        // can only allocate up to allocator's balance\n        if (_amount > maxWithdraw(msg.sender)) revert InsufficientDistributorBalance();\n\n        if (_amount < ONE_MATIC) revert AllocationUnderOneMATIC();\n\n        // variables up here for stack too deep issues\n        uint256 individualAmount;\n        uint256 individualPriceNum;\n        uint256 individualPriceDenom;\n\n        (uint256 globalPriceNum, uint256 globalPriceDenom) = sharePrice();\n        {\n            Allocation storage oldIndividualAllocation = allocations[msg.sender][_recipient][false];\n            uint256 oldIndividualAllocationMaticAmount = oldIndividualAllocation.maticAmount;\n\n            if (oldIndividualAllocationMaticAmount == 0) {\n                // if this is a new allocation\n                individualAmount = _amount;\n                individualPriceNum = globalPriceNum;\n                individualPriceDenom = globalPriceDenom;\n\n                // update mappings to keep track of recipients for each dist and vice versa\n                distributors[_recipient][false].push(msg.sender);\n                recipients[msg.sender][false].push(_recipient);\n            } else {\n                // if this adds to an existing allocation, update the individual allocation\n\n                individualAmount = oldIndividualAllocationMaticAmount + _amount;\n                individualPriceNum =\n                    oldIndividualAllocationMaticAmount *\n                    SHARE_PRICE_PRECISION +\n                    _amount *\n                    SHARE_PRICE_PRECISION;\n\n                individualPriceDenom =\n                    MathUpgradeable.mulDiv(\n                        oldIndividualAllocationMaticAmount * SHARE_PRICE_PRECISION,\n                        oldIndividualAllocation.sharePriceDenom,\n                        oldIndividualAllocation.sharePriceNum,\n                        MathUpgradeable.Rounding.Down\n                    ) +\n                    MathUpgradeable.mulDiv(\n                        _amount * SHARE_PRICE_PRECISION,\n                        globalPriceDenom,\n                        globalPriceNum,\n                        MathUpgradeable.Rounding.Down\n                    );\n                // rounding individual allocation share price denominator DOWN, in order to maximise the individual allocation share price\n                // which minimises the amount that is distributed in `distributeRewards()`\n            }\n\n            allocations[msg.sender][_recipient][false] = Allocation(\n                individualAmount,\n                individualPriceNum,\n                individualPriceDenom\n            );\n        }\n\n        emit Allocated(msg.sender, _recipient, individualAmount, individualPriceNum, individualPriceDenom);\n    }\n\n    /// @notice Deallocates an amount of MATIC previously allocated to a user.\n    /// @param _amount The amount the caller wishes to reduce the target's allocation by.\n    /// @param _recipient The address of the user whose allocation is being reduced.\n    function deallocate(uint256 _amount, address _recipient) external onlyWhitelist nonReentrant whenNotPaused {\n        Allocation storage individualAllocation = allocations[msg.sender][_recipient][false];\n\n        uint256 individualMaticAmount = individualAllocation.maticAmount;\n\n        if (individualMaticAmount == 0) revert AllocationNonExistent();\n\n        if (individualMaticAmount < _amount) revert ExcessDeallocation();\n\n        unchecked {\n            individualMaticAmount -= _amount;\n        }\n\n        if (individualMaticAmount < ONE_MATIC && individualMaticAmount != 0) revert AllocationUnderOneMATIC();\n\n        // check if this is a complete deallocation\n        if (individualMaticAmount == 0) {\n            // remove recipient from distributor's recipient array\n            delete allocations[msg.sender][_recipient][false];\n\n            address[] storage rec = recipients[msg.sender][false];\n            removeAddress(rec, _recipient);\n\n            // remove distributor from recipient's distributor array\n            address[] storage dist = distributors[_recipient][false];\n            removeAddress(dist, msg.sender);\n        } else {\n            individualAllocation.maticAmount = individualMaticAmount;\n        }\n\n        emit Deallocated(msg.sender, _recipient, individualMaticAmount);\n    }\n\n    /// @notice Distributes the rewards from the caller's allocations to all their recipients.\n    /// @param _inMatic A value indicating whether the reward is in MATIC or not.\n    /// @dev If _inMatic is set to true, the MATIC will be transferred straight from the distributor's wallet.\n    /// Their TruMATIC balance will not be altered.\n    function distributeAll(bool _inMatic) external onlyWhitelist nonReentrant whenNotPaused {\n        address[] storage rec = recipients[msg.sender][false];\n        uint256 recipientsCount = rec.length;\n\n        if (recipientsCount == 0) revert NoRecipientsFound();\n\n        (uint256 globalPriceNum, uint256 globalPriceDenom) = sharePrice();\n\n        for (uint256 i; i < recipientsCount; ) {\n            _distributeRewards(rec[i], msg.sender, _inMatic, globalPriceNum, globalPriceDenom);\n            unchecked {\n                ++i;\n            }\n        }\n\n        emit DistributedAll(msg.sender);\n    }\n\n    /// *** EXTERNAL VIEW METHODS ***\n    // *** VAULT INFO ***\n    /// @notice Calculates the amount of fees from MATIC rewards that haven't yet been turned into shares.\n    /// @return The amount of fees from rewards that haven't yet been turned into shares.\n    function getDust() external view returns (uint256) {\n        return (totalRewards() * phi) / PHI_PRECISION;\n    }\n\n    /// @notice Gets the latest unbond nonce from a specified validator.\n    /// @param _validator The address of the validator.\n    /// @return Current unbond nonce for vault-delegator unbonds.\n    function getUnbondNonce(address _validator) external view returns (uint256) {\n        return IValidatorShare(_validator).unbondNonces(address(this));\n    }\n\n    /// @notice Returns the addresses of the validators that are supported by the contract.\n    function getValidators() external view returns (address[] memory) {\n        return validatorAddresses;\n    }\n\n    /// @notice Checks if the unbond specified via the _unbondNonce can be claimed from the validator.\n    /// @dev Cannot check the claimability of pre-upgrade unbonds.\n    /// @param _unbondNonce Nonce of the unbond under consideration.\n    /// @param _validator The address of the validator.\n    /// @return  A value indicating whether the unbond can be claimed.\n    function isClaimable(uint256 _unbondNonce, address _validator) external view returns (bool) {\n        // Get epoch at which unbonding of delegated MATIC was initiated\n        (, uint256 withdrawEpoch) = IValidatorShare(_validator).unbonds_new(address(this), _unbondNonce);\n\n        // Check required epochs have passed\n        bool epochsPassed = getCurrentEpoch() >=\n            withdrawEpoch + IStakeManager(stakeManagerContractAddress).withdrawalDelay();\n\n        bool withdrawalPresent = withdrawals[_validator][_unbondNonce].user != address(0);\n\n        return withdrawalPresent && epochsPassed;\n    }\n\n    /// @notice Returns whether a user can access a validator.\n    /// @dev A private validator can only be accessed by its users.\n    /// Users who are not mapped to a private validator can only access validators that are not private.\n    /// @param _user The user address.\n    /// @param _validator The validator address.\n    /// @return True if the user can access the validator, false otherwise.\n    function canAccessValidator(address _user, address _validator) external view returns (bool) {\n        _checkNotZeroAddress(_user);\n        _checkNotZeroAddress(_validator);\n        Validator memory validator = validators[_validator];\n        if (validator.state == ValidatorState.NONE) revert ValidatorDoesNotExist();\n\n        return _canAccessValidator(_user, _validator);\n    }\n\n    // *** PUBLIC METHODS ***\n    /// @notice Deposits an amount of caller->-vault approved MATIC into the vault.\n    /// @param _assets The amount of MATIC to deposit.\n    /// @dev The MATIC is staked with the default validator.\n    /// @return The resulting amount of TruMATIC shares minted to the caller.\n    function deposit(uint256 _assets) public onlyWhitelist nonReentrant whenNotPaused returns (uint256) {\n        if (_assets < minDeposit) revert DepositBelowMinDeposit();\n        return _deposit(msg.sender, _assets, defaultValidatorAddress);\n    }\n\n    /// @notice Deposits an amount of caller->-vault approved MATIC into the vault.\n    /// @param _assets The amount of MATIC to deposit.\n    /// @param _validator Address of the validator you want to stake with.\n    /// @return The resulting amount of TruMATIC shares minted to the caller.\n    function depositToSpecificValidator(\n        uint256 _assets,\n        address _validator\n    ) public onlyWhitelist nonReentrant whenNotPaused returns (uint256) {\n        if (_assets < minDeposit) revert DepositBelowMinDeposit();\n        return _deposit(msg.sender, _assets, _validator);\n    }\n\n    /// @notice Initiates a withdrawal request for an amount of MATIC from the vault and burns corresponding TruMATIC shares.\n    /// @param _assets The amount of MATIC to withdraw.\n    /// @dev The MATIC is unstaked from the default validator.\n    /// @return The resulting amount of TruMATIC shares burned from the caller and the unbond nonce.\n    function withdraw(uint256 _assets) public onlyWhitelist nonReentrant whenNotPaused returns (uint256, uint256) {\n        return _withdrawRequest(msg.sender, _assets, defaultValidatorAddress);\n    }\n\n    /// @notice Initiates a withdrawal request for an amount of MATIC from the vault\n    /// and burns corresponding TruMATIC shares.\n    /// @param _assets The amount of MATIC to withdraw.\n    /// @param _validator The address of the validator from which to unstake.\n    /// @return The resulting amount of TruMATIC shares burned from the caller and the unbond nonce.\n    function withdrawFromSpecificValidator(\n        uint256 _assets,\n        address _validator\n    ) public onlyWhitelist nonReentrant whenNotPaused returns (uint256, uint256) {\n        if (validators[_validator].state == ValidatorState.NONE) revert ValidatorDoesNotExist();\n        return _withdrawRequest(msg.sender, _assets, _validator);\n    }\n\n    /// @notice Distributes allocation rewards from the caller to a recipient.\n    /// @param _recipient Address of allocation's recipient.\n    /// @param _inMatic A value indicating whether the reward is in MATIC or not.\n    /// @dev If _inMatic is set to true, the MATIC will be transferred straight from the distributor's wallet.\n    /// Their TruMATIC balance will not be altered.\n    function distributeRewards(address _recipient, bool _inMatic) public onlyWhitelist nonReentrant whenNotPaused {\n        (uint256 globalPriceNum, uint256 globalPriceDenom) = sharePrice();\n        _distributeRewards(_recipient, msg.sender, _inMatic, globalPriceNum, globalPriceDenom);\n    }\n\n    /// *** PUBLIC VIEW METHODS ***\n    /// @notice Gets the total amount of MATIC currently held by the vault.\n    /// @return Total amount of MATIC held by the vault.\n    function totalAssets() public view returns (uint256) {\n        return IERC20Upgradeable(stakingTokenAddress).balanceOf(address(this));\n    }\n\n    /// @notice Gets the total amount of MATIC currently staked by the vault.\n    /// @return Total amount of MATIC staked by the vault across all validator delegations.\n    function totalStaked() public view returns (uint256) {\n        uint256 validatorCount = validatorAddresses.length;\n        uint256 stake;\n        for (uint256 i; i < validatorCount; ) {\n            stake += validators[validatorAddresses[i]].stakedAmount;\n            unchecked {\n                ++i;\n            }\n        }\n        return stake;\n    }\n\n    /// @notice Gets the total unclaimed MATIC rewards on all validators.\n    /// @return Total amount of MATIC rewards earned through all validators.\n    function totalRewards() public view returns (uint256) {\n        uint256 validatorCount = validatorAddresses.length;\n        uint256 validatorRewards;\n        for (uint256 i; i < validatorCount; ) {\n            validatorRewards += IValidatorShare(validatorAddresses[i]).getLiquidRewards(address(this));\n            unchecked {\n                ++i;\n            }\n        }\n        return validatorRewards;\n    }\n\n    /// @notice Gets the price of one TruMATIC share in MATIC.\n    /// @dev Represented via a fraction. Factor of 1e18 included in numerator to avoid rounding errors (currently redundant).\n    /// @return Numerator of the vault's share price fraction.\n    /// @return Denominator of the vault's share price fraction.\n    function sharePrice() public view returns (uint256, uint256) {\n        if (totalSupply() == 0) return (1e18, 1);\n\n        uint256 totalCapitalTimesPhiPrecision = (totalStaked() + totalAssets()) *\n            PHI_PRECISION +\n            (PHI_PRECISION - phi) *\n            totalRewards();\n\n        return (totalCapitalTimesPhiPrecision * 1e18, totalSupply() * PHI_PRECISION);\n    }\n\n    /// @notice Convenience getter for retrieving user-relevant info.\n    /// @param _user Address of the user.\n    /// @return Maximum TruMATIC that can be redeemed by the user.\n    /// @return Maximum MATIC that can be withdrawn by the user.\n    /// @return Numerator of the vault's share price fraction.\n    /// @return Denominator of the vault's share price fraction.\n    /// @return Current Polygon epoch.\n    function getUserInfo(address _user) public view returns (uint256, uint256, uint256, uint256, uint256) {\n        (uint256 globalPriceNum, uint256 globalPriceDenom) = sharePrice();\n        uint256 maxRedeemable = balanceOf(_user);\n        uint256 maxWithdrawAmount = maxWithdraw(_user);\n        uint256 epoch = getCurrentEpoch();\n\n        return (maxRedeemable, maxWithdrawAmount, globalPriceNum, globalPriceDenom, epoch);\n    }\n\n    /// @notice Retrieves information for all supported validators.\n    /// @return An array of structs containing details for each validator.\n    function getAllValidators() public view returns (Validator[] memory) {\n        uint256 validatorCount = validatorAddresses.length;\n        Validator[] memory validatorArray = new Validator[](validatorCount);\n        for (uint256 i; i < validatorCount; ) {\n            address validatorAddress = validatorAddresses[i];\n            Validator memory validator = validators[validatorAddress];\n            validator.validatorAddress = validatorAddress;\n            validatorArray[i] = validator;\n            unchecked {\n                ++i;\n            }\n        }\n        return validatorArray;\n    }\n\n    /// @notice Retrieves information for the validators a user can access.\n    /// @param _user Address of the user.\n    /// @return An array of structs containing details for each validator a user can access.\n    function getUserValidators(address _user) public view returns (Validator[] memory) {\n        // find the validators the user has access to\n        Validator[] memory validators = getAllValidators();\n        Validator[] memory userValidatorsAll = new Validator[](validators.length);\n        uint256 userValidatorCount;\n        for (uint256 i; i < validators.length; i++) {\n            address validatorAddress = validators[i].validatorAddress;\n            if (_canAccessValidator(_user, validatorAddress)) {\n                userValidatorsAll[userValidatorCount] = validators[i];\n                userValidatorCount++;\n            }\n        }\n\n        // filter out zero items in userValidatorsAll\n        Validator[] memory userValidators = new Validator[](userValidatorCount);\n        for (uint256 i; i < userValidatorCount; i++) {\n            userValidators[i] = userValidatorsAll[i];\n        }\n\n        return userValidators;\n    }\n\n    /// @notice Gets the total unclaimed MATIC rewards on a specific validator.\n    /// @param _validator The address of the validator.\n    /// @return Amount of MATIC rewards earned through this validator.\n    function getRewardsFromValidator(address _validator) public view returns (uint256) {\n        return IValidatorShare(_validator).getLiquidRewards(address(this));\n    }\n\n    /// @notice Gets a recipient's distributors.\n    /// @param _user The recipient.\n    /// @return The recipient's distributors.\n    function getDistributors(address _user) public view returns (address[] memory) {\n        return distributors[_user][false];\n    }\n\n    /// @notice Gets a distributor's recipients.\n    /// @param _user The distributor.\n    /// @return The distributor's recipients.\n    function getRecipients(address _user) public view returns (address[] memory) {\n        return recipients[_user][false];\n    }\n\n    /// @notice Gets the current epoch from Polygons's StakeManager contract.\n    /// @return Current Polygon epoch.\n    function getCurrentEpoch() public view returns (uint256) {\n        return IStakeManager(stakeManagerContractAddress).epoch();\n    }\n\n    /// @notice Calculates the total amount of MATIC allocated by a distributor and the\n    /// average share price fraction at which it was allocated.\n    /// @param distributor The distributor.\n    /// @return An allocation struct representing the distributor's total allocations.\n    function getTotalAllocated(address distributor) public view returns (Allocation memory) {\n        uint256 recipientsCount = recipients[distributor][false].length; // fetch all recipients\n        uint256 totalAllocatedAmount;\n        uint256 sharePriceNum;\n        uint256 sharePriceDenom;\n\n        for (uint256 i; i < recipientsCount; i++) {\n            // loop through all recipient allocations\n            address recipient = recipients[distributor][false][i];\n            Allocation memory allocation = allocations[distributor][recipient][false];\n\n            // if this is the first iteration of the for loop\n            if (totalAllocatedAmount == 0) {\n                totalAllocatedAmount = allocation.maticAmount;\n                sharePriceNum = allocation.sharePriceNum;\n                sharePriceDenom = allocation.sharePriceDenom;\n                continue;\n            }\n\n            sharePriceDenom =\n                MathUpgradeable.mulDiv(\n                    totalAllocatedAmount * SHARE_PRICE_PRECISION,\n                    sharePriceDenom,\n                    sharePriceNum,\n                    MathUpgradeable.Rounding.Up\n                ) +\n                MathUpgradeable.mulDiv(\n                    allocation.maticAmount * SHARE_PRICE_PRECISION,\n                    allocation.sharePriceDenom,\n                    allocation.sharePriceNum,\n                    MathUpgradeable.Rounding.Up\n                );\n\n            sharePriceNum =\n                totalAllocatedAmount *\n                SHARE_PRICE_PRECISION +\n                allocation.maticAmount *\n                SHARE_PRICE_PRECISION;\n            totalAllocatedAmount += allocation.maticAmount;\n        }\n        return Allocation(totalAllocatedAmount, sharePriceNum, sharePriceDenom);\n    }\n\n    /// @notice Gets the maximum amount of MATIC a user can withdraw from the vault.\n    /// @param _user The user under consideration.\n    /// @return The amount of MATIC.\n    function maxWithdraw(address _user) public view returns (uint256) {\n        uint256 preview = previewRedeem(balanceOf(_user));\n\n        if (preview == 0) return 0;\n\n        return preview + epsilon;\n    }\n\n    /// @notice Returns the amount of TruMATIC needed to withdraw an amount of MATIC.\n    /// @dev Returns no fewer than the exact amount of TruMATIC that would be burned\n    /// in a withdraw request for the exact amount of MATIC.\n    /// @param _assets The exact amount of MATIC to withdraw.\n    /// @return The amount of TruMATIC burned.\n    function previewWithdraw(uint256 _assets) public view returns (uint256) {\n        return _convertToShares(_assets, MathUpgradeable.Rounding.Up);\n    }\n\n    /// @notice Returns the amount of MATIC that can be withdrawn for an amount of TruMATIC.\n    /// @dev Returns no fewer than the exact amount of MATIC that would be withdrawn\n    /// in a withdraw request that burns the exact amount of TruMATIC.\n    /// @param _shares The exact amount of TruMATIC to redeem.\n    /// @return The amount of MATIC withdrawn.\n    function previewRedeem(uint256 _shares) public view returns (uint256) {\n        return _convertToAssets(_shares, MathUpgradeable.Rounding.Up);\n    }\n\n    /// @notice Returns the amount of TruMATIC equivalent to an amount of MATIC.\n    /// @param _assets The amount of MATIC to convert.\n    /// @return The amount of TruMATIC that the Vault would exchange for the MATIC of assets provided.\n    function convertToShares(uint256 _assets) public view returns (uint256) {\n        return _convertToShares(_assets, MathUpgradeable.Rounding.Down);\n    }\n\n    /// @notice Returns the amount of MATIC equivalent to an amount of TruMATIC.\n    /// @param _shares The amount of TruMATIC to convert.\n    /// @return The amount of MATIC that the Vault would exchange for the amount of TruMATIC provided.\n    function convertToAssets(uint256 _shares) public view returns (uint256) {\n        return _convertToAssets(_shares, MathUpgradeable.Rounding.Down);\n    }\n\n    /// ***** PRIVATE METHODS *****\n    /// @notice Private deposit function which stakes and mints shares for the user + treasury.\n    /// @param _user User depositing the amount.\n    /// @param _amount Amount to be deposited.\n    /// @param _validator Address of the validator to stake to.\n    function _deposit(address _user, uint256 _amount, address _validator) private returns (uint256) {\n        if (!_canAccessValidator(_user, _validator)) revert ValidatorAccessDenied();\n        if (validators[_validator].state != ValidatorState.ENABLED) revert ValidatorNotEnabled();\n\n        (uint256 globalPriceNum, uint256 globalPriceDenom) = sharePrice();\n\n        // calculate share increase\n        uint256 shareIncreaseUser = convertToShares(_amount);\n        uint256 shareIncreaseTsy = (getRewardsFromValidator(_validator) * phi * 1e18 * globalPriceDenom) /\n            (globalPriceNum * PHI_PRECISION);\n\n        // piggyback previous withdrawn rewards in this staking call\n        uint256 totalAssetBalance = totalAssets();\n        uint256 stakeAmount = _amount + totalAssetBalance;\n\n        _mint(treasuryAddress, shareIncreaseTsy);\n\n        // mint shares to user and transfer staking token from user to Staker\n        if (_user != address(0)) {\n            _mint(_user, shareIncreaseUser);\n            IERC20Upgradeable(stakingTokenAddress).safeTransferFrom(_user, address(this), _amount);\n        }\n\n        // approve funds to Stake Manager\n        IERC20Upgradeable(stakingTokenAddress).safeIncreaseAllowance(stakeManagerContractAddress, stakeAmount);\n\n        // interact with Validator Share contract to stake\n        _stake(stakeAmount, _validator);\n        // claimed rewards increase here as liquid rewards on validator share contract\n        // are set to zero rewards and transferred to this vault\n\n        emit Deposited(_user, shareIncreaseTsy, shareIncreaseUser, _amount, stakeAmount, totalAssetBalance, _validator);\n\n        return shareIncreaseUser;\n    }\n\n    /// @notice Private function to handle withdrawals and burning shares.\n    /// @param _user The user that is making the request.\n    /// @param _amount The amount to be withdrawn.\n    /// @param _validator Address of the validator to withdraw from.\n    function _withdrawRequest(address _user, uint256 _amount, address _validator) private returns (uint256, uint256) {\n        if (!_canAccessValidator(_user, _validator)) revert ValidatorAccessDenied();\n        if (_amount == 0) revert WithdrawalRequestAmountCannotEqualZero();\n\n        uint256 maxWithdrawal = maxWithdraw(_user);\n        if (_amount > maxWithdrawal) revert WithdrawalAmountTooLarge();\n\n        (uint256 globalPriceNum, uint256 globalPriceDenom) = sharePrice();\n\n        // calculate share decrease\n        uint256 shareDecreaseUser = (_amount * globalPriceDenom * 1e18) / globalPriceNum;\n\n        uint256 shareIncreaseTsy = (getRewardsFromValidator(_validator) * phi * globalPriceDenom * 1e18) /\n            (globalPriceNum * PHI_PRECISION);\n\n        // If remaining user balance is below 1 MATIC, entire balance is withdrawn and all shares\n        // are burnt. We allow the user to withdraw their deposited amount + epsilon\n        if (maxWithdrawal - _amount < ONE_MATIC) {\n            _amount = maxWithdrawal;\n            shareDecreaseUser = balanceOf(_user);\n        }\n\n        _burn(_user, shareDecreaseUser);\n\n        _mint(treasuryAddress, shareIncreaseTsy);\n\n        // interact with staking contract to initiate unbonding\n        uint256 unbondNonce = _unbond(_amount, _validator);\n\n        // store user under unbond nonce, used for fair claiming\n        withdrawals[_validator][unbondNonce] = Withdrawal(_user, _amount);\n\n        emit WithdrawalRequested(\n            _user,\n            shareIncreaseTsy,\n            shareDecreaseUser,\n            _amount,\n            totalAssets(),\n            _validator,\n            unbondNonce,\n            getCurrentEpoch() // only once 80 epochs have passed can this be claimed\n        );\n\n        return (shareDecreaseUser, unbondNonce);\n    }\n\n    /// @notice Handles withdraw claims internally according to unbond nonces (once unbonding period has passed).\n    /// @param _unbondNonce The claim number the user got when initiating the withdrawal.\n    /// @param _validator Address of the validator to claim from.\n    function _withdrawClaim(uint256 _unbondNonce, address _validator) private {\n        Withdrawal memory withdrawal = withdrawals[_validator][_unbondNonce];\n\n        // if the nonce is linked to a withdrawal in the current mapping, use that\n        if (withdrawal.user != address(0)) {\n            delete withdrawals[_validator][_unbondNonce];\n        } else if (\n            _validator == 0xeA077b10A0eD33e4F68Edb2655C18FDA38F84712 &&\n            unbondingWithdrawals[_unbondNonce].user != address(0)\n        ) {\n            // else if the claim is for the twinstake staker, check the legacy mapping for the withdrawal\n            withdrawal = unbondingWithdrawals[_unbondNonce];\n            delete unbondingWithdrawals[_unbondNonce];\n        } else {\n            // else withdraw claim does not exist\n            revert WithdrawClaimNonExistent();\n        }\n\n        if (withdrawal.user != msg.sender) revert SenderMustHaveInitiatedWithdrawalRequest();\n\n        // claim will revert if unbonding not finished for this unbond nonce\n        uint256 receivedAmount = _claimStake(_unbondNonce, _validator);\n\n        // transfer claimed MATIC to claimer\n        IERC20Upgradeable(stakingTokenAddress).safeTransfer(msg.sender, receivedAmount);\n\n        emit WithdrawalClaimed(msg.sender, _validator, _unbondNonce, withdrawal.amount, receivedAmount);\n    }\n\n    /// @notice Validator function that transfers the _amount to the stake manager and stakes the assets onto the validator.\n    /// @param _amount Amount of MATIC to stake.\n    /// @param _validator Address of the validator to stake with.\n    function _stake(uint256 _amount, address _validator) private {\n        uint256 amountToDeposit = IValidatorShare(_validator).buyVoucher(_amount, _amount);\n        validators[_validator].stakedAmount += amountToDeposit;\n    }\n\n    /// @notice Requests to unstake a certain amount of MATIC from the specified validator.\n    /// @param _amount Amount of MATIC to initiate the unstaking of.\n    /// @param _validator Address of the validator to unstake from.\n    function _unbond(uint256 _amount, address _validator) private returns (uint256) {\n        validators[_validator].stakedAmount -= _amount;\n        IValidatorShare(_validator).sellVoucher_new(_amount, _amount);\n        return IValidatorShare(_validator).unbondNonces(address(this));\n    }\n\n    /// @notice Internal function for claiming the MATIC from a withdrawal request made previously.\n    /// @param _unbondNonce Unbond nonce of the withdrawal request being claimed.\n    /// @param _validator Address of the validator to claim from.\n    /// @return The amount of MATIC received by the vault from the validator.\n    function _claimStake(uint256 _unbondNonce, address _validator) private returns (uint256) {\n        uint256 assetsBefore = totalAssets();\n        IValidatorShare(_validator).unstakeClaimTokens_new(_unbondNonce);\n        return totalAssets() - assetsBefore;\n    }\n\n    /// @notice Calls the validator share contract's restake functionality on all enabled validators\n    /// to turn earned rewards into staked MATIC.\n    /// @dev Logs a RestakeError event when an exception occurs while calling restake on a validator.\n    function _restake() private returns (uint256) {\n        uint256 validatorCount = validatorAddresses.length;\n        uint256 totalAmountRestaked;\n        for (uint256 i; i < validatorCount; ) {\n            address validator = validatorAddresses[i];\n            if (validators[validator].state == ValidatorState.ENABLED) {\n                // log an event on \"Too small rewards to restake\" and other exceptions\n                try IValidatorShare(validator).restake() returns (uint256 amountRestaked, uint256 liquidRewards) {\n                    validators[validator].stakedAmount += amountRestaked;\n                    totalAmountRestaked += liquidRewards;\n                } catch Error(string memory reason) {\n                    emit RestakeError(validator, reason);\n                }\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n        return totalAmountRestaked;\n    }\n\n    /// @notice Distributes the rewards related to the allocation made to that receiver.\n    /// @param _recipient Receives the rewards.\n    /// @param _distributor Distributes their rewards.\n    /// @param _inMatic A value indicating whether rewards are in MATIC.\n    function _distributeRewards(\n        address _recipient,\n        address _distributor,\n        bool _inMatic,\n        uint256 globalPriceNum,\n        uint256 globalPriceDenom\n    ) private {\n        Allocation storage individualAllocation = allocations[_distributor][_recipient][false];\n        uint256 amt = individualAllocation.maticAmount;\n\n        // if there is no allocation, revert. This should never happen during a distributeAll call.\n        if (amt == 0) revert NothingToDistribute();\n\n        // check if there are any rewards to distribute. If not, return.\n        if (\n            individualAllocation.sharePriceNum / individualAllocation.sharePriceDenom ==\n            globalPriceNum / globalPriceDenom\n        ) {\n            return;\n        }\n\n        // calculate amount of TruMatic to move from distributor to recipient\n        uint256 sharesToMove;\n        {\n            sharesToMove =\n                MathUpgradeable.mulDiv(\n                    amt,\n                    individualAllocation.sharePriceDenom * 1e18,\n                    individualAllocation.sharePriceNum,\n                    MathUpgradeable.Rounding.Down\n                ) -\n                MathUpgradeable.mulDiv(amt, globalPriceDenom * 1e18, globalPriceNum, MathUpgradeable.Rounding.Up);\n\n            // calculate fees and transfer\n            uint256 fee = (sharesToMove * distPhi) / PHI_PRECISION;\n\n            sharesToMove -= fee;\n\n            _transfer(_distributor, treasuryAddress, fee);\n        }\n\n        if (_inMatic) {\n            uint256 maticAmount = convertToAssets(sharesToMove);\n            // transfer staking token from distributor to recipient\n            IERC20Upgradeable(stakingTokenAddress).safeTransferFrom(_distributor, _recipient, maticAmount);\n        } else {\n            _transfer(_distributor, _recipient, sharesToMove);\n        }\n\n        individualAllocation.sharePriceNum = globalPriceNum;\n        individualAllocation.sharePriceDenom = globalPriceDenom;\n\n        emit DistributedRewards(\n            _distributor,\n            _recipient,\n            convertToAssets(sharesToMove),\n            sharesToMove,\n            globalPriceNum,\n            globalPriceDenom\n        );\n    }\n\n    /// @notice Removes an address from an array of addresses.\n    /// @param addresses A storage array of addresses.\n    /// @param item The address to be removed.\n    function removeAddress(address[] storage addresses, address item) private {\n        uint256 addressCount = addresses.length;\n\n        for (uint256 i; i < addressCount; ) {\n            if (addresses[i] == item) {\n                addresses[i] = addresses[addressCount - 1];\n                addresses.pop();\n                break;\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /// ***** PRIVATE VIEW METHODS *****\n    /// @notice Private function to convert MATIC to TruMATIC.\n    /// @param assets Assets in MATIC to be converted into TruMATIC.\n    function _convertToShares(uint256 assets, MathUpgradeable.Rounding rounding) private view returns (uint256) {\n        (uint256 globalPriceNum, uint256 globalPriceDenom) = sharePrice();\n        return MathUpgradeable.mulDiv(assets * 1e18, globalPriceDenom, globalPriceNum, rounding);\n    }\n\n    /// @notice Private function to convert TruMATIC to MATIC.\n    /// @param shares TruMATIC shares to be converted into MATIC.\n    function _convertToAssets(uint256 shares, MathUpgradeable.Rounding rounding) private view returns (uint256) {\n        (uint256 globalPriceNum, uint256 globalPriceDenom) = sharePrice();\n        return MathUpgradeable.mulDiv(shares, globalPriceNum, globalPriceDenom * 1e18, rounding);\n    }\n\n    /// @notice Returns whether a user can access a validator.\n    /// @param _user The user address.\n    /// @param _validator The validator address.\n    /// @return True if the user can access the validator, false otherwise.\n    function _canAccessValidator(address _user, address _validator) private view returns (bool) {\n        address privateValidator = usersPrivateAccess[_user];\n\n        if (validators[privateValidator].isPrivate == true) {\n            // if the user is limited to a private validator, only that validator is accessible\n            return privateValidator == _validator;\n        }\n\n        // otherwise, non-private validators are accessible, private validators are not\n        return !validators[_validator].isPrivate;\n    }\n\n    /// @notice Checks whether an address is the zero address.\n    /// @dev Gas-efficient way to check using assembly.\n    /// @param toCheck Address to be checked.\n    function _checkNotZeroAddress(address toCheck) private pure {\n        assembly {\n            //more gas efficient to use assembly for zero address check\n            if iszero(toCheck) {\n                let ptr := mload(0x40)\n                mstore(ptr, 0x1cb411bc00000000000000000000000000000000000000000000000000000000) // selector for `ZeroAddressNotSupported()`\n                revert(ptr, 0x4)\n            }\n        }\n    }\n}\n"
      },
      "contracts/main/TruStakeMATICv2Storage.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity =0.8.19;\n\nimport {Withdrawal, Allocation, Validator} from \"./Types.sol\";\n\n/// @title TruStakeMATICStorage\nabstract contract TruStakeMATICv2Storage {\n    /// @notice Address of MATIC on this chain (Ethereum and Goerli supported).\n    address public stakingTokenAddress;\n\n    /// @notice The stake manager contract deployed by Polygon.\n    address public stakeManagerContractAddress;\n\n    /// @notice The address of the default validator.\n    address public defaultValidatorAddress;\n\n    /// @notice The whitelist contract keeps track of what users can interact with\n    ///   certain function in the TruStakeMATIC contract.\n    address public whitelistAddress;\n\n    /// @notice The treasury gathers fees during the restaking of rewards as shares.\n    address public treasuryAddress;\n\n    /// @notice Size of fee taken on rewards.\n    /// @dev Fee in basis points.\n    uint256 public phi;\n\n    /// @notice Size of fee taken on allocations.\n    /// @dev Distribution fee in basis points.\n    uint256 public distPhi;\n\n    /// @notice Deprecated but here for storage considerations.\n    uint256 public deprecated1;\n\n    /// @notice Mapping to keep track of (user, amount) values for each unbond nonce.\n    /// @dev Legacy mapping to keep track of pre-upgrade withdrawal claims.\n    /// @dev Maps nonce of validator unbonding to a Withdrawal (user & amount).\n    mapping(uint256 => Withdrawal) public unbondingWithdrawals;\n\n    /// @notice Deprecated but here for storage considerations.\n    mapping(address => mapping(bool => Allocation)) public deprecated2;\n\n    /// @notice Mapping of distributor to recipient to amount and share price.\n    mapping(address => mapping(address => mapping(bool => Allocation))) public allocations;\n\n    /// @notice Array of distributors to their recipients.\n    mapping(address => mapping(bool => address[])) public recipients;\n\n    /// @notice Array of recipients to their distributors.\n    mapping(address => mapping(bool => address[])) public distributors;\n\n    /// @notice Value to offset rounding errors.\n    uint256 public epsilon;\n\n    /// @notice Deprecated but here for storage considerations.\n    bool public deprecated3;\n\n    /// @notice Cap on the smallest amount one can deposit to the staker.\n    uint256 public minDeposit;\n\n    /// @notice Mapping of a validator address to the validator struct.\n    mapping(address => Validator) public validators;\n\n    /// @notice The array of validators share contract addresses configured in the contract.\n    address[] public validatorAddresses;\n\n    /// @notice Mapping to keep track of the withdrawals (user, amount) for each unbond nonce for each validator.\n    mapping(address => mapping(uint256 => Withdrawal)) public withdrawals;\n\n    /// @notice Mapping of users to the private validator they have access to.\n    mapping(address => address) public usersPrivateAccess;\n\n    /// @notice Gap for upgradeability.\n    uint256[43] private __gap;\n}\n"
      },
      "contracts/main/Types.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity =0.8.19;\n\n/// @notice Struct to hold information on a user's withdrawal request for fair claiming.\n/// @dev The epoch of withdrawal is not stored as that is the key in the `unbondingWithdrawals`\n/// mapping.\n/// @param user The user that made the withdrawal request.\n/// @param amount The amount of MATIC that the user requested to withdraw.\nstruct Withdrawal {\n    address user;\n    uint256 amount;\n}\n\n/// @notice Struct to hold information on user allocations.\n/// @dev The numerator and denominator update when the allocation amount increases,\n/// or when a distribution occurs.\n/// @param maticAmount the amount of MATIC allocated.\n/// @param sharePriceNum numerator of the share price for this allocation.\n/// @param sharePriceDenom denominator of the share price for this allocation.\nstruct Allocation {\n    uint256 maticAmount;\n    uint256 sharePriceNum;\n    uint256 sharePriceDenom;\n}\n\n/// @notice Struct to track information on a validator.\n/// @param state The state of the validator.\n/// @param stakedAmount The amount of Matic staked on the validator. This is the maximum that can be withdrawn from this validator.\n/// @param validatorAddress The address of the validator.\n/// @param isPrivate Indicates whether access to the validator is limited to specific users.\nstruct Validator {\n    ValidatorState state;\n    uint256 stakedAmount;\n    address validatorAddress;\n    bool isPrivate;\n}\n\n/// @notice Enum for the possible validator states.\nenum ValidatorState {\n    NONE,\n    ENABLED,\n    DISABLED\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 125
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}