creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/staking/AccToke.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\n// solhint-disable not-rely-on-time,no-complex-fallback\n\nimport { SafeERC20 } from \"openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20Metadata } from \"openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { ERC20 } from \"openzeppelin-contracts/token/ERC20/ERC20.sol\";\nimport { ERC20Votes } from \"openzeppelin-contracts/token/ERC20/extensions/ERC20Votes.sol\";\nimport { ERC20Permit } from \"openzeppelin-contracts/token/ERC20/extensions/draft-ERC20Permit.sol\";\nimport { Pausable } from \"openzeppelin-contracts/security/Pausable.sol\";\nimport { SafeCast } from \"openzeppelin-contracts/utils/math/SafeCast.sol\";\n\nimport { PRBMathUD60x18 } from \"prb-math/contracts/PRBMathUD60x18.sol\";\n\nimport { IWETH9 } from \"src/interfaces/utils/IWETH9.sol\";\nimport { IAccToke } from \"src/interfaces/staking/IAccToke.sol\";\nimport { ISystemRegistry } from \"src/interfaces/ISystemRegistry.sol\";\nimport { SecurityBase } from \"src/security/SecurityBase.sol\";\nimport { Errors } from \"src/utils/Errors.sol\";\nimport { SystemComponent } from \"src/SystemComponent.sol\";\nimport { Roles } from \"src/libs/Roles.sol\";\n\ncontract AccToke is IAccToke, ERC20Votes, Pausable, SystemComponent, SecurityBase {\n    using SafeERC20 for IERC20Metadata;\n    using SafeERC20 for IWETH9;\n\n    // variables\n    uint256 public immutable startEpoch;\n    uint256 public immutable minStakeDuration;\n    // solhint-disable-next-line const-name-snakecase\n    uint256 public maxStakeDuration = 1461 days; // default 4 years\n    uint256 public constant MIN_STAKE_AMOUNT = 10_000;\n    uint256 public constant MAX_STAKE_AMOUNT = 100e6 * 1e18; // default 100m toke\n\n    mapping(address => Lockup[]) public lockups;\n\n    uint256 private constant YEAR_BASE_BOOST = 18e17;\n    IERC20Metadata public immutable toke;\n\n    //\n    // Reward Vars\n    //\n    IWETH9 private immutable weth;\n\n    uint256 public constant REWARD_FACTOR = 1e12;\n\n    // tracks user's checkpointed reward debt per share\n    mapping(address => uint256) public rewardDebtPerShare;\n    // keeps track of rewards checkpointed / offloaded but not yet transferred\n    mapping(address => uint256) private unclaimedRewards;\n    // total current accumulated reward per share\n    uint256 public accRewardPerShare;\n\n    // See {IAccToke-totalRewardsEarned}\n    uint256 public totalRewardsEarned;\n    // See {IAccToke-totalRewardsClaimed}\n    uint256 public totalRewardsClaimed;\n    // See {IAccToke-rewardsClaimed}\n    mapping(address => uint256) public rewardsClaimed;\n\n    constructor(\n        ISystemRegistry _systemRegistry,\n        uint256 _startEpoch,\n        uint256 _minStakeDuration\n    )\n        SystemComponent(_systemRegistry)\n        ERC20(\"Staked Toke\", \"accToke\")\n        ERC20Permit(\"accToke\")\n        SecurityBase(address(_systemRegistry.accessController()))\n    {\n        startEpoch = _startEpoch;\n        minStakeDuration = _minStakeDuration;\n\n        toke = systemRegistry.toke();\n        weth = systemRegistry.weth();\n    }\n\n    // @dev short-circuit transfers\n    function transfer(address, uint256) public pure override returns (bool) {\n        revert TransfersDisabled();\n    }\n\n    // @dev short-circuit transfers\n    function transferFrom(address, address, uint256) public pure override returns (bool) {\n        revert TransfersDisabled();\n    }\n\n    /// @inheritdoc IAccToke\n    function stake(uint256 amount, uint256 duration, address to) external {\n        _stake(amount, duration, to);\n    }\n\n    /// @inheritdoc IAccToke\n    function stake(uint256 amount, uint256 duration) external {\n        _stake(amount, duration, msg.sender);\n    }\n\n    /// @inheritdoc IAccToke\n    function isStakeableAmount(uint256 amount) public pure returns (bool) {\n        return amount >= MIN_STAKE_AMOUNT && amount <= MAX_STAKE_AMOUNT;\n    }\n\n    function _stake(uint256 amount, uint256 duration, address to) internal whenNotPaused {\n        //\n        // validation checks\n        //\n        if (to == address(0)) revert ZeroAddress();\n        if (!isStakeableAmount(amount)) revert IncorrectStakingAmount();\n\n        // duration checked inside previewPoints\n        (uint256 points, uint256 end) = previewPoints(amount, duration);\n\n        if (points + totalSupply() > type(uint192).max) {\n            revert StakingPointsExceeded();\n        }\n\n        // checkpoint rewards for caller\n        _collectRewards(to, false);\n\n        // save information for current lockup\n        lockups[to].push(Lockup({ amount: SafeCast.toUint128(amount), end: SafeCast.toUint128(end), points: points }));\n\n        // create points for user\n        _mint(to, points);\n\n        emit Stake(to, lockups[to].length - 1, amount, end, points);\n\n        // transfer staked toke in\n        toke.safeTransferFrom(msg.sender, address(this), amount);\n    }\n\n    /// @inheritdoc IAccToke\n    function unstake(uint256[] memory lockupIds) external whenNotPaused {\n        _collectRewards(msg.sender, false);\n\n        uint256 length = lockupIds.length;\n        if (length == 0) revert InvalidLockupIds();\n\n        uint256 totalPoints = 0;\n        uint256 totalAmount = 0;\n\n        uint256 totalLockups = lockups[msg.sender].length;\n        for (uint256 iter = 0; iter < length;) {\n            uint256 lockupId = lockupIds[iter];\n            if (lockupId >= totalLockups) revert LockupDoesNotExist();\n\n            // get staking information\n            Lockup memory lockup = lockups[msg.sender][lockupId];\n\n            // slither-disable-next-line timestamp\n            if (block.timestamp < lockup.end) revert NotUnlockableYet();\n            if (lockup.end == 0) revert AlreadyUnlocked();\n\n            // remove stake\n            delete lockups[msg.sender][lockupId];\n\n            // tally total points to be burned\n            totalPoints += lockup.points;\n\n            emit Unstake(msg.sender, lockupId, lockup.amount, lockup.end, lockup.points);\n\n            // tally total toke amount to be returned\n            totalAmount += lockup.amount;\n\n            unchecked {\n                ++iter;\n            }\n        }\n\n        // wipe points\n        _burn(msg.sender, totalPoints);\n        // send staked toke back to user\n        toke.safeTransfer(msg.sender, totalAmount);\n    }\n\n    /// @inheritdoc IAccToke\n    function extend(uint256[] memory lockupIds, uint256[] memory durations) external whenNotPaused {\n        uint256 length = lockupIds.length;\n        if (length == 0) revert InvalidLockupIds();\n        if (length != durations.length) revert InvalidDurationLength();\n\n        // before doing anything, make sure the rewards checkpoints are updated!\n        _collectRewards(msg.sender, false);\n\n        uint256 totalExtendedPoints = 0;\n\n        uint256 totalLockups = lockups[msg.sender].length;\n        for (uint256 iter = 0; iter < length;) {\n            uint256 lockupId = lockupIds[iter];\n            uint256 duration = durations[iter];\n            if (lockupId >= totalLockups) revert LockupDoesNotExist();\n\n            // duration checked inside previewPoints\n            Lockup storage lockup = lockups[msg.sender][lockupId];\n            uint256 oldAmount = lockup.amount;\n            uint256 oldEnd = lockup.end;\n            uint256 oldPoints = lockup.points;\n\n            (uint256 newPoints, uint256 newEnd) = previewPoints(oldAmount, duration);\n\n            if (newEnd <= oldEnd) revert ExtendDurationTooShort();\n            lockup.end = SafeCast.toUint128(newEnd);\n            lockup.points = newPoints;\n            totalExtendedPoints = totalExtendedPoints + newPoints - oldPoints;\n\n            emit Extend(msg.sender, lockupId, oldAmount, oldEnd, newEnd, oldPoints, newPoints);\n\n            unchecked {\n                ++iter;\n            }\n        }\n\n        // issue extra points for extension\n        _mint(msg.sender, totalExtendedPoints);\n    }\n\n    /// @inheritdoc IAccToke\n    function previewPoints(uint256 amount, uint256 duration) public view returns (uint256 points, uint256 end) {\n        if (duration < minStakeDuration) revert StakingDurationTooShort();\n        if (duration > maxStakeDuration) revert StakingDurationTooLong();\n\n        // slither-disable-next-line timestamp\n        uint256 start = block.timestamp > startEpoch ? block.timestamp : startEpoch;\n        end = start + duration;\n\n        // calculate points based on duration from staking end date\n        uint256 endYearpoc = ((end - startEpoch) * 1e18) / 365 days;\n        uint256 multiplier = PRBMathUD60x18.pow(YEAR_BASE_BOOST, endYearpoc);\n\n        points = (amount * multiplier) / 1e18;\n    }\n\n    /// @inheritdoc IAccToke\n    function getLockups(address user) external view returns (Lockup[] memory) {\n        return lockups[user];\n    }\n\n    /// @notice Update max stake duration allowed\n    function setMaxStakeDuration(uint256 _maxStakeDuration) external hasRole(Roles.ACC_TOKE_MANAGER) {\n        uint256 old = maxStakeDuration;\n\n        maxStakeDuration = _maxStakeDuration;\n\n        emit SetMaxStakeDuration(old, _maxStakeDuration);\n    }\n\n    function pause() external hasRole(Roles.ACC_TOKE_MANAGER) {\n        _pause();\n    }\n\n    function unpause() external hasRole(Roles.ACC_TOKE_MANAGER) {\n        _unpause();\n    }\n\n    /* **************************************************************************** */\n    /*\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*/\n    /* \t\t\t\t\t\t\t\t\tRewards\t\t\t\t\t\t\t\t\t\t*/\n    /*\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*/\n    /* **************************************************************************** */\n\n    /// @notice Allows an actor to deposit ETH as staking reward to be distributed to all staked participants\n    /// @param amount Amount of `WETH` to take from caller and deposit as reward for the stakers\n    function addWETHRewards(uint256 amount) external {\n        // update accounting to factor in new rewards\n        _addWETHRewards(amount);\n        // actually transfer WETH\n        weth.safeTransferFrom(msg.sender, address(this), amount);\n    }\n\n    /// @dev Internal function used by both `addWETHRewards` external and the `receive()` function\n    /// @param amount See {IAccToke-addWETHRewards}.\n    function _addWETHRewards(uint256 amount) internal whenNotPaused {\n        Errors.verifyNotZero(amount, \"amount\");\n\n        uint256 supply = totalSupply();\n        Errors.verifyNotZero(supply, \"supply\");\n\n        if (amount * REWARD_FACTOR < supply) {\n            revert InsufficientAmount();\n        }\n\n        totalRewardsEarned += amount;\n        accRewardPerShare += amount * REWARD_FACTOR / supply;\n\n        emit RewardsAdded(amount, accRewardPerShare);\n    }\n\n    /// @inheritdoc IAccToke\n    function previewRewards() external view returns (uint256 amount) {\n        return previewRewards(msg.sender);\n    }\n\n    /// @inheritdoc IAccToke\n    function previewRewards(address user) public view returns (uint256 amount) {\n        uint256 supply = totalSupply();\n        if (supply == 0) {\n            return unclaimedRewards[user];\n        }\n\n        // calculate reward per share by taking the current reward per share and subtracting what user already claimed\n        uint256 _netRewardsPerShare = accRewardPerShare - rewardDebtPerShare[user];\n\n        // calculate full reward user is entitled to by taking their recently earned and adding unclaimed checkpointed\n        return ((balanceOf(user) * _netRewardsPerShare) / REWARD_FACTOR) + unclaimedRewards[user];\n    }\n\n    /// @inheritdoc IAccToke\n    function collectRewards() external returns (uint256) {\n        return _collectRewards(msg.sender, true);\n    }\n\n    /// @dev See {IAccToke-collectRewards}.\n    function _collectRewards(address user, bool distribute) internal returns (uint256) {\n        // calculate user's new rewards per share (current minus claimed)\n        uint256 netRewardsPerShare = accRewardPerShare - rewardDebtPerShare[user];\n        // calculate amount of actual rewards\n        uint256 netRewards = (balanceOf(user) * netRewardsPerShare) / REWARD_FACTOR;\n        // get reference to user's pending (sandboxed) rewards\n        uint256 pendingRewards = unclaimedRewards[user];\n\n        // update checkpoint to current\n        rewardDebtPerShare[user] = accRewardPerShare;\n\n        // if nothing to claim, bail\n        if (netRewards == 0 && pendingRewards == 0) {\n            return 0;\n        }\n\n        if (distribute) {\n            //\n            // if asked for actual distribution, transfer all earnings\n            //\n\n            // reset sandboxed rewards\n            unclaimedRewards[user] = 0;\n\n            // get total amount by adding new rewards and previously sandboxed\n            uint256 totalClaiming = netRewards + pendingRewards;\n\n            // update running totals\n            //slither-disable-next-line costly-loop\n            totalRewardsClaimed += totalClaiming;\n            rewardsClaimed[user] += totalClaiming;\n\n            emit RewardsClaimed(user, totalClaiming);\n\n            // send rewards to user\n            weth.safeTransfer(user, totalClaiming);\n\n            // return total amount claimed\n            return totalClaiming;\n        }\n\n        if (netRewards > 0) {\n            // Save (sandbox) to their account for later transfer\n            unclaimedRewards[user] += netRewards;\n\n            emit RewardsCollected(user, netRewards);\n        }\n\n        // nothing collected\n        return 0;\n    }\n\n    /// @notice Catch-all. If any eth is sent, wrap and add to rewards\n    receive() external payable {\n        // update accounting to factor in new rewards\n        // NOTE: doing it in this order keeps slither happy\n        _addWETHRewards(msg.value);\n        // appreciate the ETH! wrap and add as rewards\n        weth.deposit{ value: msg.value }();\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.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 SafeERC20 {\n    using Address for address;\n\n    function safeTransfer(\n        IERC20 token,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value\n    ) 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(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) 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    function safeIncreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\n\n    function safePermit(\n        IERC20Permit 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(IERC20 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        if (returndata.length > 0) {\n            // Return data is optional\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.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 \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\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"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.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 * 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 ERC20 is Context, IERC20, IERC20Metadata {\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     * The default value of {decimals} is 18. To select a different value for\n     * {decimals} you should overload it.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\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 value {ERC20} uses, unless this function is\n     * 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(\n        address from,\n        address to,\n        uint256 amount\n    ) 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(\n        address from,\n        address to,\n        uint256 amount\n    ) 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(\n        address owner,\n        address spender,\n        uint256 amount\n    ) 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(\n        address owner,\n        address spender,\n        uint256 amount\n    ) 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(\n        address from,\n        address to,\n        uint256 amount\n    ) 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(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.1) (token/ERC20/extensions/ERC20Votes.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-ERC20Permit.sol\";\nimport \"../../../utils/math/Math.sol\";\nimport \"../../../governance/utils/IVotes.sol\";\nimport \"../../../utils/math/SafeCast.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\n\n/**\n * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,\n * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.\n *\n * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.\n *\n * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either\n * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting\n * power can be queried through the public accessors {getVotes} and {getPastVotes}.\n *\n * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it\n * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.\n *\n * _Available since v4.2._\n */\nabstract contract ERC20Votes is IVotes, ERC20Permit {\n    struct Checkpoint {\n        uint32 fromBlock;\n        uint224 votes;\n    }\n\n    bytes32 private constant _DELEGATION_TYPEHASH =\n        keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n    mapping(address => address) private _delegates;\n    mapping(address => Checkpoint[]) private _checkpoints;\n    Checkpoint[] private _totalSupplyCheckpoints;\n\n    /**\n     * @dev Get the `pos`-th checkpoint for `account`.\n     */\n    function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {\n        return _checkpoints[account][pos];\n    }\n\n    /**\n     * @dev Get number of checkpoints for `account`.\n     */\n    function numCheckpoints(address account) public view virtual returns (uint32) {\n        return SafeCast.toUint32(_checkpoints[account].length);\n    }\n\n    /**\n     * @dev Get the address `account` is currently delegating to.\n     */\n    function delegates(address account) public view virtual override returns (address) {\n        return _delegates[account];\n    }\n\n    /**\n     * @dev Gets the current votes balance for `account`\n     */\n    function getVotes(address account) public view virtual override returns (uint256) {\n        uint256 pos = _checkpoints[account].length;\n        return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;\n    }\n\n    /**\n     * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.\n     *\n     * Requirements:\n     *\n     * - `blockNumber` must have been already mined\n     */\n    function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {\n        require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n        return _checkpointsLookup(_checkpoints[account], blockNumber);\n    }\n\n    /**\n     * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.\n     * It is but NOT the sum of all the delegated votes!\n     *\n     * Requirements:\n     *\n     * - `blockNumber` must have been already mined\n     */\n    function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {\n        require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n        return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);\n    }\n\n    /**\n     * @dev Lookup a value in a list of (sorted) checkpoints.\n     */\n    function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {\n        // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.\n        //\n        // Initially we check if the block is recent to narrow the search range.\n        // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).\n        // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.\n        // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)\n        // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)\n        // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not\n        // out of bounds (in which case we're looking too far in the past and the result is 0).\n        // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is\n        // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out\n        // the same.\n        uint256 length = ckpts.length;\n\n        uint256 low = 0;\n        uint256 high = length;\n\n        if (length > 5) {\n            uint256 mid = length - Math.sqrt(length);\n            if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {\n                high = mid;\n            } else {\n                low = mid + 1;\n            }\n        }\n\n        while (low < high) {\n            uint256 mid = Math.average(low, high);\n            if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {\n                high = mid;\n            } else {\n                low = mid + 1;\n            }\n        }\n\n        return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;\n    }\n\n    /**\n     * @dev Delegate votes from the sender to `delegatee`.\n     */\n    function delegate(address delegatee) public virtual override {\n        _delegate(_msgSender(), delegatee);\n    }\n\n    /**\n     * @dev Delegates votes from signer to `delegatee`\n     */\n    function delegateBySig(\n        address delegatee,\n        uint256 nonce,\n        uint256 expiry,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public virtual override {\n        require(block.timestamp <= expiry, \"ERC20Votes: signature expired\");\n        address signer = ECDSA.recover(\n            _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),\n            v,\n            r,\n            s\n        );\n        require(nonce == _useNonce(signer), \"ERC20Votes: invalid nonce\");\n        _delegate(signer, delegatee);\n    }\n\n    /**\n     * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).\n     */\n    function _maxSupply() internal view virtual returns (uint224) {\n        return type(uint224).max;\n    }\n\n    /**\n     * @dev Snapshots the totalSupply after it has been increased.\n     */\n    function _mint(address account, uint256 amount) internal virtual override {\n        super._mint(account, amount);\n        require(totalSupply() <= _maxSupply(), \"ERC20Votes: total supply risks overflowing votes\");\n\n        _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);\n    }\n\n    /**\n     * @dev Snapshots the totalSupply after it has been decreased.\n     */\n    function _burn(address account, uint256 amount) internal virtual override {\n        super._burn(account, amount);\n\n        _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);\n    }\n\n    /**\n     * @dev Move voting power when tokens are transferred.\n     *\n     * Emits a {IVotes-DelegateVotesChanged} event.\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override {\n        super._afterTokenTransfer(from, to, amount);\n\n        _moveVotingPower(delegates(from), delegates(to), amount);\n    }\n\n    /**\n     * @dev Change delegation for `delegator` to `delegatee`.\n     *\n     * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.\n     */\n    function _delegate(address delegator, address delegatee) internal virtual {\n        address currentDelegate = delegates(delegator);\n        uint256 delegatorBalance = balanceOf(delegator);\n        _delegates[delegator] = delegatee;\n\n        emit DelegateChanged(delegator, currentDelegate, delegatee);\n\n        _moveVotingPower(currentDelegate, delegatee, delegatorBalance);\n    }\n\n    function _moveVotingPower(\n        address src,\n        address dst,\n        uint256 amount\n    ) private {\n        if (src != dst && amount > 0) {\n            if (src != address(0)) {\n                (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);\n                emit DelegateVotesChanged(src, oldWeight, newWeight);\n            }\n\n            if (dst != address(0)) {\n                (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);\n                emit DelegateVotesChanged(dst, oldWeight, newWeight);\n            }\n        }\n    }\n\n    function _writeCheckpoint(\n        Checkpoint[] storage ckpts,\n        function(uint256, uint256) view returns (uint256) op,\n        uint256 delta\n    ) private returns (uint256 oldWeight, uint256 newWeight) {\n        uint256 pos = ckpts.length;\n\n        Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0) : _unsafeAccess(ckpts, pos - 1);\n\n        oldWeight = oldCkpt.votes;\n        newWeight = op(oldWeight, delta);\n\n        if (pos > 0 && oldCkpt.fromBlock == block.number) {\n            _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight);\n        } else {\n            ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));\n        }\n    }\n\n    function _add(uint256 a, uint256 b) private pure returns (uint256) {\n        return a + b;\n    }\n\n    function _subtract(uint256 a, uint256 b) private pure returns (uint256) {\n        return a - b;\n    }\n\n    /**\n     * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.\n     */\n    function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) {\n        assembly {\n            mstore(0, ckpts.slot)\n            result.slot := add(keccak256(0, 0x20), pos)\n        }\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20Permit.sol\";\nimport \"../ERC20.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\nimport \"../../../utils/cryptography/EIP712.sol\";\nimport \"../../../utils/Counters.sol\";\n\n/**\n * @dev Implementation 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 * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n    using Counters for Counters.Counter;\n\n    mapping(address => Counters.Counter) private _nonces;\n\n    // solhint-disable-next-line var-name-mixedcase\n    bytes32 private constant _PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n    /**\n     * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.\n     * However, to ensure consistency with the upgradeable transpiler, we will continue\n     * to reserve a slot.\n     * @custom:oz-renamed-from _PERMIT_TYPEHASH\n     */\n    // solhint-disable-next-line var-name-mixedcase\n    bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;\n\n    /**\n     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n     *\n     * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n     */\n    constructor(string memory name) EIP712(name, \"1\") {}\n\n    /**\n     * @dev See {IERC20Permit-permit}.\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    ) public virtual override {\n        require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n        bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        require(signer == owner, \"ERC20Permit: invalid signature\");\n\n        _approve(owner, spender, value);\n    }\n\n    /**\n     * @dev See {IERC20Permit-nonces}.\n     */\n    function nonces(address owner) public view virtual override returns (uint256) {\n        return _nonces[owner].current();\n    }\n\n    /**\n     * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n        return _domainSeparatorV4();\n    }\n\n    /**\n     * @dev \"Consume a nonce\": return the current value and increment.\n     *\n     * _Available since v4.1._\n     */\n    function _useNonce(address owner) internal virtual returns (uint256 current) {\n        Counters.Counter storage nonce = _nonces[owner];\n        current = nonce.current();\n        nonce.increment();\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/security/Pausable.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/Context.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 Pausable is Context {\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    constructor() {\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"
      },
      "lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n    /**\n     * @dev Returns the downcasted uint248 from uint256, reverting on\n     * overflow (when the input is greater than largest uint248).\n     *\n     * Counterpart to Solidity's `uint248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint248(uint256 value) internal pure returns (uint248) {\n        require(value <= type(uint248).max, \"SafeCast: value doesn't fit in 248 bits\");\n        return uint248(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint240 from uint256, reverting on\n     * overflow (when the input is greater than largest uint240).\n     *\n     * Counterpart to Solidity's `uint240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint240(uint256 value) internal pure returns (uint240) {\n        require(value <= type(uint240).max, \"SafeCast: value doesn't fit in 240 bits\");\n        return uint240(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint232 from uint256, reverting on\n     * overflow (when the input is greater than largest uint232).\n     *\n     * Counterpart to Solidity's `uint232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint232(uint256 value) internal pure returns (uint232) {\n        require(value <= type(uint232).max, \"SafeCast: value doesn't fit in 232 bits\");\n        return uint232(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     *\n     * _Available since v4.2._\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint216 from uint256, reverting on\n     * overflow (when the input is greater than largest uint216).\n     *\n     * Counterpart to Solidity's `uint216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint216(uint256 value) internal pure returns (uint216) {\n        require(value <= type(uint216).max, \"SafeCast: value doesn't fit in 216 bits\");\n        return uint216(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint208 from uint256, reverting on\n     * overflow (when the input is greater than largest uint208).\n     *\n     * Counterpart to Solidity's `uint208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint208(uint256 value) internal pure returns (uint208) {\n        require(value <= type(uint208).max, \"SafeCast: value doesn't fit in 208 bits\");\n        return uint208(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint200 from uint256, reverting on\n     * overflow (when the input is greater than largest uint200).\n     *\n     * Counterpart to Solidity's `uint200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint200(uint256 value) internal pure returns (uint200) {\n        require(value <= type(uint200).max, \"SafeCast: value doesn't fit in 200 bits\");\n        return uint200(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint192 from uint256, reverting on\n     * overflow (when the input is greater than largest uint192).\n     *\n     * Counterpart to Solidity's `uint192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint192(uint256 value) internal pure returns (uint192) {\n        require(value <= type(uint192).max, \"SafeCast: value doesn't fit in 192 bits\");\n        return uint192(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint184 from uint256, reverting on\n     * overflow (when the input is greater than largest uint184).\n     *\n     * Counterpart to Solidity's `uint184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint184(uint256 value) internal pure returns (uint184) {\n        require(value <= type(uint184).max, \"SafeCast: value doesn't fit in 184 bits\");\n        return uint184(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint176 from uint256, reverting on\n     * overflow (when the input is greater than largest uint176).\n     *\n     * Counterpart to Solidity's `uint176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint176(uint256 value) internal pure returns (uint176) {\n        require(value <= type(uint176).max, \"SafeCast: value doesn't fit in 176 bits\");\n        return uint176(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint168 from uint256, reverting on\n     * overflow (when the input is greater than largest uint168).\n     *\n     * Counterpart to Solidity's `uint168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint168(uint256 value) internal pure returns (uint168) {\n        require(value <= type(uint168).max, \"SafeCast: value doesn't fit in 168 bits\");\n        return uint168(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint160 from uint256, reverting on\n     * overflow (when the input is greater than largest uint160).\n     *\n     * Counterpart to Solidity's `uint160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint160(uint256 value) internal pure returns (uint160) {\n        require(value <= type(uint160).max, \"SafeCast: value doesn't fit in 160 bits\");\n        return uint160(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint152 from uint256, reverting on\n     * overflow (when the input is greater than largest uint152).\n     *\n     * Counterpart to Solidity's `uint152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint152(uint256 value) internal pure returns (uint152) {\n        require(value <= type(uint152).max, \"SafeCast: value doesn't fit in 152 bits\");\n        return uint152(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint144 from uint256, reverting on\n     * overflow (when the input is greater than largest uint144).\n     *\n     * Counterpart to Solidity's `uint144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint144(uint256 value) internal pure returns (uint144) {\n        require(value <= type(uint144).max, \"SafeCast: value doesn't fit in 144 bits\");\n        return uint144(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint136 from uint256, reverting on\n     * overflow (when the input is greater than largest uint136).\n     *\n     * Counterpart to Solidity's `uint136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint136(uint256 value) internal pure returns (uint136) {\n        require(value <= type(uint136).max, \"SafeCast: value doesn't fit in 136 bits\");\n        return uint136(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint120 from uint256, reverting on\n     * overflow (when the input is greater than largest uint120).\n     *\n     * Counterpart to Solidity's `uint120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint120(uint256 value) internal pure returns (uint120) {\n        require(value <= type(uint120).max, \"SafeCast: value doesn't fit in 120 bits\");\n        return uint120(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint112 from uint256, reverting on\n     * overflow (when the input is greater than largest uint112).\n     *\n     * Counterpart to Solidity's `uint112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint112(uint256 value) internal pure returns (uint112) {\n        require(value <= type(uint112).max, \"SafeCast: value doesn't fit in 112 bits\");\n        return uint112(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint104 from uint256, reverting on\n     * overflow (when the input is greater than largest uint104).\n     *\n     * Counterpart to Solidity's `uint104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint104(uint256 value) internal pure returns (uint104) {\n        require(value <= type(uint104).max, \"SafeCast: value doesn't fit in 104 bits\");\n        return uint104(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     *\n     * _Available since v4.2._\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint88 from uint256, reverting on\n     * overflow (when the input is greater than largest uint88).\n     *\n     * Counterpart to Solidity's `uint88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint88(uint256 value) internal pure returns (uint88) {\n        require(value <= type(uint88).max, \"SafeCast: value doesn't fit in 88 bits\");\n        return uint88(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint80 from uint256, reverting on\n     * overflow (when the input is greater than largest uint80).\n     *\n     * Counterpart to Solidity's `uint80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint80(uint256 value) internal pure returns (uint80) {\n        require(value <= type(uint80).max, \"SafeCast: value doesn't fit in 80 bits\");\n        return uint80(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint72 from uint256, reverting on\n     * overflow (when the input is greater than largest uint72).\n     *\n     * Counterpart to Solidity's `uint72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint72(uint256 value) internal pure returns (uint72) {\n        require(value <= type(uint72).max, \"SafeCast: value doesn't fit in 72 bits\");\n        return uint72(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint56 from uint256, reverting on\n     * overflow (when the input is greater than largest uint56).\n     *\n     * Counterpart to Solidity's `uint56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint56(uint256 value) internal pure returns (uint56) {\n        require(value <= type(uint56).max, \"SafeCast: value doesn't fit in 56 bits\");\n        return uint56(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint48 from uint256, reverting on\n     * overflow (when the input is greater than largest uint48).\n     *\n     * Counterpart to Solidity's `uint48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint48(uint256 value) internal pure returns (uint48) {\n        require(value <= type(uint48).max, \"SafeCast: value doesn't fit in 48 bits\");\n        return uint48(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint40 from uint256, reverting on\n     * overflow (when the input is greater than largest uint40).\n     *\n     * Counterpart to Solidity's `uint40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint40(uint256 value) internal pure returns (uint40) {\n        require(value <= type(uint40).max, \"SafeCast: value doesn't fit in 40 bits\");\n        return uint40(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint24 from uint256, reverting on\n     * overflow (when the input is greater than largest uint24).\n     *\n     * Counterpart to Solidity's `uint24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint24(uint256 value) internal pure returns (uint24) {\n        require(value <= type(uint24).max, \"SafeCast: value doesn't fit in 24 bits\");\n        return uint24(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     *\n     * _Available since v3.0._\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        require(value >= 0, \"SafeCast: value must be positive\");\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int248 from int256, reverting on\n     * overflow (when the input is less than smallest int248 or\n     * greater than largest int248).\n     *\n     * Counterpart to Solidity's `int248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt248(int256 value) internal pure returns (int248 downcasted) {\n        downcasted = int248(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 248 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int240 from int256, reverting on\n     * overflow (when the input is less than smallest int240 or\n     * greater than largest int240).\n     *\n     * Counterpart to Solidity's `int240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt240(int256 value) internal pure returns (int240 downcasted) {\n        downcasted = int240(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 240 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int232 from int256, reverting on\n     * overflow (when the input is less than smallest int232 or\n     * greater than largest int232).\n     *\n     * Counterpart to Solidity's `int232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt232(int256 value) internal pure returns (int232 downcasted) {\n        downcasted = int232(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 232 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int224 from int256, reverting on\n     * overflow (when the input is less than smallest int224 or\n     * greater than largest int224).\n     *\n     * Counterpart to Solidity's `int224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt224(int256 value) internal pure returns (int224 downcasted) {\n        downcasted = int224(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 224 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int216 from int256, reverting on\n     * overflow (when the input is less than smallest int216 or\n     * greater than largest int216).\n     *\n     * Counterpart to Solidity's `int216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt216(int256 value) internal pure returns (int216 downcasted) {\n        downcasted = int216(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 216 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int208 from int256, reverting on\n     * overflow (when the input is less than smallest int208 or\n     * greater than largest int208).\n     *\n     * Counterpart to Solidity's `int208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt208(int256 value) internal pure returns (int208 downcasted) {\n        downcasted = int208(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 208 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int200 from int256, reverting on\n     * overflow (when the input is less than smallest int200 or\n     * greater than largest int200).\n     *\n     * Counterpart to Solidity's `int200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt200(int256 value) internal pure returns (int200 downcasted) {\n        downcasted = int200(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 200 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int192 from int256, reverting on\n     * overflow (when the input is less than smallest int192 or\n     * greater than largest int192).\n     *\n     * Counterpart to Solidity's `int192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt192(int256 value) internal pure returns (int192 downcasted) {\n        downcasted = int192(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 192 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int184 from int256, reverting on\n     * overflow (when the input is less than smallest int184 or\n     * greater than largest int184).\n     *\n     * Counterpart to Solidity's `int184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt184(int256 value) internal pure returns (int184 downcasted) {\n        downcasted = int184(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 184 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int176 from int256, reverting on\n     * overflow (when the input is less than smallest int176 or\n     * greater than largest int176).\n     *\n     * Counterpart to Solidity's `int176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt176(int256 value) internal pure returns (int176 downcasted) {\n        downcasted = int176(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 176 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int168 from int256, reverting on\n     * overflow (when the input is less than smallest int168 or\n     * greater than largest int168).\n     *\n     * Counterpart to Solidity's `int168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt168(int256 value) internal pure returns (int168 downcasted) {\n        downcasted = int168(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 168 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int160 from int256, reverting on\n     * overflow (when the input is less than smallest int160 or\n     * greater than largest int160).\n     *\n     * Counterpart to Solidity's `int160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt160(int256 value) internal pure returns (int160 downcasted) {\n        downcasted = int160(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 160 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int152 from int256, reverting on\n     * overflow (when the input is less than smallest int152 or\n     * greater than largest int152).\n     *\n     * Counterpart to Solidity's `int152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt152(int256 value) internal pure returns (int152 downcasted) {\n        downcasted = int152(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 152 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int144 from int256, reverting on\n     * overflow (when the input is less than smallest int144 or\n     * greater than largest int144).\n     *\n     * Counterpart to Solidity's `int144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt144(int256 value) internal pure returns (int144 downcasted) {\n        downcasted = int144(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 144 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int136 from int256, reverting on\n     * overflow (when the input is less than smallest int136 or\n     * greater than largest int136).\n     *\n     * Counterpart to Solidity's `int136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt136(int256 value) internal pure returns (int136 downcasted) {\n        downcasted = int136(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 136 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt128(int256 value) internal pure returns (int128 downcasted) {\n        downcasted = int128(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 128 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int120 from int256, reverting on\n     * overflow (when the input is less than smallest int120 or\n     * greater than largest int120).\n     *\n     * Counterpart to Solidity's `int120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt120(int256 value) internal pure returns (int120 downcasted) {\n        downcasted = int120(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 120 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int112 from int256, reverting on\n     * overflow (when the input is less than smallest int112 or\n     * greater than largest int112).\n     *\n     * Counterpart to Solidity's `int112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt112(int256 value) internal pure returns (int112 downcasted) {\n        downcasted = int112(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 112 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int104 from int256, reverting on\n     * overflow (when the input is less than smallest int104 or\n     * greater than largest int104).\n     *\n     * Counterpart to Solidity's `int104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt104(int256 value) internal pure returns (int104 downcasted) {\n        downcasted = int104(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 104 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int96 from int256, reverting on\n     * overflow (when the input is less than smallest int96 or\n     * greater than largest int96).\n     *\n     * Counterpart to Solidity's `int96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt96(int256 value) internal pure returns (int96 downcasted) {\n        downcasted = int96(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 96 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int88 from int256, reverting on\n     * overflow (when the input is less than smallest int88 or\n     * greater than largest int88).\n     *\n     * Counterpart to Solidity's `int88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt88(int256 value) internal pure returns (int88 downcasted) {\n        downcasted = int88(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 88 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int80 from int256, reverting on\n     * overflow (when the input is less than smallest int80 or\n     * greater than largest int80).\n     *\n     * Counterpart to Solidity's `int80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt80(int256 value) internal pure returns (int80 downcasted) {\n        downcasted = int80(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 80 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int72 from int256, reverting on\n     * overflow (when the input is less than smallest int72 or\n     * greater than largest int72).\n     *\n     * Counterpart to Solidity's `int72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt72(int256 value) internal pure returns (int72 downcasted) {\n        downcasted = int72(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 72 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt64(int256 value) internal pure returns (int64 downcasted) {\n        downcasted = int64(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 64 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int56 from int256, reverting on\n     * overflow (when the input is less than smallest int56 or\n     * greater than largest int56).\n     *\n     * Counterpart to Solidity's `int56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt56(int256 value) internal pure returns (int56 downcasted) {\n        downcasted = int56(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 56 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int48 from int256, reverting on\n     * overflow (when the input is less than smallest int48 or\n     * greater than largest int48).\n     *\n     * Counterpart to Solidity's `int48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt48(int256 value) internal pure returns (int48 downcasted) {\n        downcasted = int48(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 48 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int40 from int256, reverting on\n     * overflow (when the input is less than smallest int40 or\n     * greater than largest int40).\n     *\n     * Counterpart to Solidity's `int40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt40(int256 value) internal pure returns (int40 downcasted) {\n        downcasted = int40(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 40 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt32(int256 value) internal pure returns (int32 downcasted) {\n        downcasted = int32(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 32 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int24 from int256, reverting on\n     * overflow (when the input is less than smallest int24 or\n     * greater than largest int24).\n     *\n     * Counterpart to Solidity's `int24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt24(int256 value) internal pure returns (int24 downcasted) {\n        downcasted = int24(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 24 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt16(int256 value) internal pure returns (int16 downcasted) {\n        downcasted = int16(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 16 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt8(int256 value) internal pure returns (int8 downcasted) {\n        downcasted = int8(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 8 bits\");\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     *\n     * _Available since v3.0._\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n        return int256(value);\n    }\n}\n"
      },
      "lib/prb-math/contracts/PRBMathUD60x18.sol": {
        "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\nimport \"./PRBMath.sol\";\n\n/// @title PRBMathUD60x18\n/// @author Paul Razvan Berg\n/// @notice Smart contract library for advanced fixed-point math that works with uint256 numbers considered to have 18\n/// trailing decimals. We call this number representation unsigned 60.18-decimal fixed-point, since there can be up to 60\n/// digits in the integer part and up to 18 decimals in the fractional part. The numbers are bound by the minimum and the\n/// maximum values permitted by the Solidity type uint256.\nlibrary PRBMathUD60x18 {\n    /// @dev Half the SCALE number.\n    uint256 internal constant HALF_SCALE = 5e17;\n\n    /// @dev log2(e) as an unsigned 60.18-decimal fixed-point number.\n    uint256 internal constant LOG2_E = 1_442695040888963407;\n\n    /// @dev The maximum value an unsigned 60.18-decimal fixed-point number can have.\n    uint256 internal constant MAX_UD60x18 =\n        115792089237316195423570985008687907853269984665640564039457_584007913129639935;\n\n    /// @dev The maximum whole value an unsigned 60.18-decimal fixed-point number can have.\n    uint256 internal constant MAX_WHOLE_UD60x18 =\n        115792089237316195423570985008687907853269984665640564039457_000000000000000000;\n\n    /// @dev How many trailing decimals can be represented.\n    uint256 internal constant SCALE = 1e18;\n\n    /// @notice Calculates the arithmetic average of x and y, rounding down.\n    /// @param x The first operand as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The second operand as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The arithmetic average as an unsigned 60.18-decimal fixed-point number.\n    function avg(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        // The operations can never overflow.\n        unchecked {\n            // The last operand checks if both x and y are odd and if that is the case, we add 1 to the result. We need\n            // to do this because if both numbers are odd, the 0.5 remainder gets truncated twice.\n            result = (x >> 1) + (y >> 1) + (x & y & 1);\n        }\n    }\n\n    /// @notice Yields the least unsigned 60.18 decimal fixed-point number greater than or equal to x.\n    ///\n    /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.\n    /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\n    ///\n    /// Requirements:\n    /// - x must be less than or equal to MAX_WHOLE_UD60x18.\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number to ceil.\n    /// @param result The least integer greater than or equal to x, as an unsigned 60.18-decimal fixed-point number.\n    function ceil(uint256 x) internal pure returns (uint256 result) {\n        if (x > MAX_WHOLE_UD60x18) {\n            revert PRBMathUD60x18__CeilOverflow(x);\n        }\n        assembly {\n            // Equivalent to \"x % SCALE\" but faster.\n            let remainder := mod(x, SCALE)\n\n            // Equivalent to \"SCALE - remainder\" but faster.\n            let delta := sub(SCALE, remainder)\n\n            // Equivalent to \"x + delta * (remainder > 0 ? 1 : 0)\" but faster.\n            result := add(x, mul(delta, gt(remainder, 0)))\n        }\n    }\n\n    /// @notice Divides two unsigned 60.18-decimal fixed-point numbers, returning a new unsigned 60.18-decimal fixed-point number.\n    ///\n    /// @dev Uses mulDiv to enable overflow-safe multiplication and division.\n    ///\n    /// Requirements:\n    /// - The denominator cannot be zero.\n    ///\n    /// @param x The numerator as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The denominator as an unsigned 60.18-decimal fixed-point number.\n    /// @param result The quotient as an unsigned 60.18-decimal fixed-point number.\n    function div(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        result = PRBMath.mulDiv(x, SCALE, y);\n    }\n\n    /// @notice Returns Euler's number as an unsigned 60.18-decimal fixed-point number.\n    /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant).\n    function e() internal pure returns (uint256 result) {\n        result = 2_718281828459045235;\n    }\n\n    /// @notice Calculates the natural exponent of x.\n    ///\n    /// @dev Based on the insight that e^x = 2^(x * log2(e)).\n    ///\n    /// Requirements:\n    /// - All from \"log2\".\n    /// - x must be less than 133.084258667509499441.\n    ///\n    /// @param x The exponent as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function exp(uint256 x) internal pure returns (uint256 result) {\n        // Without this check, the value passed to \"exp2\" would be greater than 192.\n        if (x >= 133_084258667509499441) {\n            revert PRBMathUD60x18__ExpInputTooBig(x);\n        }\n\n        // Do the fixed-point multiplication inline to save gas.\n        unchecked {\n            uint256 doubleScaleProduct = x * LOG2_E;\n            result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE);\n        }\n    }\n\n    /// @notice Calculates the binary exponent of x using the binary fraction method.\n    ///\n    /// @dev See https://ethereum.stackexchange.com/q/79903/24693.\n    ///\n    /// Requirements:\n    /// - x must be 192 or less.\n    /// - The result must fit within MAX_UD60x18.\n    ///\n    /// @param x The exponent as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function exp2(uint256 x) internal pure returns (uint256 result) {\n        // 2^192 doesn't fit within the 192.64-bit format used internally in this function.\n        if (x >= 192e18) {\n            revert PRBMathUD60x18__Exp2InputTooBig(x);\n        }\n\n        unchecked {\n            // Convert x to the 192.64-bit fixed-point format.\n            uint256 x192x64 = (x << 64) / SCALE;\n\n            // Pass x to the PRBMath.exp2 function, which uses the 192.64-bit fixed-point number representation.\n            result = PRBMath.exp2(x192x64);\n        }\n    }\n\n    /// @notice Yields the greatest unsigned 60.18 decimal fixed-point number less than or equal to x.\n    /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.\n    /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\n    /// @param x The unsigned 60.18-decimal fixed-point number to floor.\n    /// @param result The greatest integer less than or equal to x, as an unsigned 60.18-decimal fixed-point number.\n    function floor(uint256 x) internal pure returns (uint256 result) {\n        assembly {\n            // Equivalent to \"x % SCALE\" but faster.\n            let remainder := mod(x, SCALE)\n\n            // Equivalent to \"x - remainder * (remainder > 0 ? 1 : 0)\" but faster.\n            result := sub(x, mul(remainder, gt(remainder, 0)))\n        }\n    }\n\n    /// @notice Yields the excess beyond the floor of x.\n    /// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part.\n    /// @param x The unsigned 60.18-decimal fixed-point number to get the fractional part of.\n    /// @param result The fractional part of x as an unsigned 60.18-decimal fixed-point number.\n    function frac(uint256 x) internal pure returns (uint256 result) {\n        assembly {\n            result := mod(x, SCALE)\n        }\n    }\n\n    /// @notice Converts a number from basic integer form to unsigned 60.18-decimal fixed-point representation.\n    ///\n    /// @dev Requirements:\n    /// - x must be less than or equal to MAX_UD60x18 divided by SCALE.\n    ///\n    /// @param x The basic integer to convert.\n    /// @param result The same number in unsigned 60.18-decimal fixed-point representation.\n    function fromUint(uint256 x) internal pure returns (uint256 result) {\n        unchecked {\n            if (x > MAX_UD60x18 / SCALE) {\n                revert PRBMathUD60x18__FromUintOverflow(x);\n            }\n            result = x * SCALE;\n        }\n    }\n\n    /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down.\n    ///\n    /// @dev Requirements:\n    /// - x * y must fit within MAX_UD60x18, lest it overflows.\n    ///\n    /// @param x The first operand as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The second operand as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function gm(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        if (x == 0) {\n            return 0;\n        }\n\n        unchecked {\n            // Checking for overflow this way is faster than letting Solidity do it.\n            uint256 xy = x * y;\n            if (xy / x != y) {\n                revert PRBMathUD60x18__GmOverflow(x, y);\n            }\n\n            // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE\n            // during multiplication. See the comments within the \"sqrt\" function.\n            result = PRBMath.sqrt(xy);\n        }\n    }\n\n    /// @notice Calculates 1 / x, rounding toward zero.\n    ///\n    /// @dev Requirements:\n    /// - x cannot be zero.\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the inverse.\n    /// @return result The inverse as an unsigned 60.18-decimal fixed-point number.\n    function inv(uint256 x) internal pure returns (uint256 result) {\n        unchecked {\n            // 1e36 is SCALE * SCALE.\n            result = 1e36 / x;\n        }\n    }\n\n    /// @notice Calculates the natural logarithm of x.\n    ///\n    /// @dev Based on the insight that ln(x) = log2(x) / log2(e).\n    ///\n    /// Requirements:\n    /// - All from \"log2\".\n    ///\n    /// Caveats:\n    /// - All from \"log2\".\n    /// - This doesn't return exactly 1 for 2.718281828459045235, for that we would need more fine-grained precision.\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the natural logarithm.\n    /// @return result The natural logarithm as an unsigned 60.18-decimal fixed-point number.\n    function ln(uint256 x) internal pure returns (uint256 result) {\n        // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x)\n        // can return is 196205294292027477728.\n        unchecked {\n            result = (log2(x) * SCALE) / LOG2_E;\n        }\n    }\n\n    /// @notice Calculates the common logarithm of x.\n    ///\n    /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common\n    /// logarithm based on the insight that log10(x) = log2(x) / log2(10).\n    ///\n    /// Requirements:\n    /// - All from \"log2\".\n    ///\n    /// Caveats:\n    /// - All from \"log2\".\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the common logarithm.\n    /// @return result The common logarithm as an unsigned 60.18-decimal fixed-point number.\n    function log10(uint256 x) internal pure returns (uint256 result) {\n        if (x < SCALE) {\n            revert PRBMathUD60x18__LogInputTooSmall(x);\n        }\n\n        // Note that the \"mul\" in this block is the assembly multiplication operation, not the \"mul\" function defined\n        // in this contract.\n        // prettier-ignore\n        assembly {\n            switch x\n            case 1 { result := mul(SCALE, sub(0, 18)) }\n            case 10 { result := mul(SCALE, sub(1, 18)) }\n            case 100 { result := mul(SCALE, sub(2, 18)) }\n            case 1000 { result := mul(SCALE, sub(3, 18)) }\n            case 10000 { result := mul(SCALE, sub(4, 18)) }\n            case 100000 { result := mul(SCALE, sub(5, 18)) }\n            case 1000000 { result := mul(SCALE, sub(6, 18)) }\n            case 10000000 { result := mul(SCALE, sub(7, 18)) }\n            case 100000000 { result := mul(SCALE, sub(8, 18)) }\n            case 1000000000 { result := mul(SCALE, sub(9, 18)) }\n            case 10000000000 { result := mul(SCALE, sub(10, 18)) }\n            case 100000000000 { result := mul(SCALE, sub(11, 18)) }\n            case 1000000000000 { result := mul(SCALE, sub(12, 18)) }\n            case 10000000000000 { result := mul(SCALE, sub(13, 18)) }\n            case 100000000000000 { result := mul(SCALE, sub(14, 18)) }\n            case 1000000000000000 { result := mul(SCALE, sub(15, 18)) }\n            case 10000000000000000 { result := mul(SCALE, sub(16, 18)) }\n            case 100000000000000000 { result := mul(SCALE, sub(17, 18)) }\n            case 1000000000000000000 { result := 0 }\n            case 10000000000000000000 { result := SCALE }\n            case 100000000000000000000 { result := mul(SCALE, 2) }\n            case 1000000000000000000000 { result := mul(SCALE, 3) }\n            case 10000000000000000000000 { result := mul(SCALE, 4) }\n            case 100000000000000000000000 { result := mul(SCALE, 5) }\n            case 1000000000000000000000000 { result := mul(SCALE, 6) }\n            case 10000000000000000000000000 { result := mul(SCALE, 7) }\n            case 100000000000000000000000000 { result := mul(SCALE, 8) }\n            case 1000000000000000000000000000 { result := mul(SCALE, 9) }\n            case 10000000000000000000000000000 { result := mul(SCALE, 10) }\n            case 100000000000000000000000000000 { result := mul(SCALE, 11) }\n            case 1000000000000000000000000000000 { result := mul(SCALE, 12) }\n            case 10000000000000000000000000000000 { result := mul(SCALE, 13) }\n            case 100000000000000000000000000000000 { result := mul(SCALE, 14) }\n            case 1000000000000000000000000000000000 { result := mul(SCALE, 15) }\n            case 10000000000000000000000000000000000 { result := mul(SCALE, 16) }\n            case 100000000000000000000000000000000000 { result := mul(SCALE, 17) }\n            case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) }\n            case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) }\n            case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) }\n            case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) }\n            case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) }\n            case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) }\n            case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) }\n            case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) }\n            case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) }\n            case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) }\n            case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) }\n            case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) }\n            case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) }\n            case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) }\n            case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) }\n            case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) }\n            case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) }\n            case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) }\n            case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) }\n            case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) }\n            case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) }\n            case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) }\n            case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) }\n            case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) }\n            case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) }\n            case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) }\n            case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) }\n            case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) }\n            case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) }\n            case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) }\n            case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) }\n            case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) }\n            case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) }\n            case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) }\n            case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) }\n            case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) }\n            case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) }\n            case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) }\n            case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) }\n            case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) }\n            case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) }\n            case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 59) }\n            default {\n                result := MAX_UD60x18\n            }\n        }\n\n        if (result == MAX_UD60x18) {\n            // Do the fixed-point division inline to save gas. The denominator is log2(10).\n            unchecked {\n                result = (log2(x) * SCALE) / 3_321928094887362347;\n            }\n        }\n    }\n\n    /// @notice Calculates the binary logarithm of x.\n    ///\n    /// @dev Based on the iterative approximation algorithm.\n    /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation\n    ///\n    /// Requirements:\n    /// - x must be greater than or equal to SCALE, otherwise the result would be negative.\n    ///\n    /// Caveats:\n    /// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation.\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the binary logarithm.\n    /// @return result The binary logarithm as an unsigned 60.18-decimal fixed-point number.\n    function log2(uint256 x) internal pure returns (uint256 result) {\n        if (x < SCALE) {\n            revert PRBMathUD60x18__LogInputTooSmall(x);\n        }\n        unchecked {\n            // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).\n            uint256 n = PRBMath.mostSignificantBit(x / SCALE);\n\n            // The integer part of the logarithm as an unsigned 60.18-decimal fixed-point number. The operation can't overflow\n            // because n is maximum 255 and SCALE is 1e18.\n            result = n * SCALE;\n\n            // This is y = x * 2^(-n).\n            uint256 y = x >> n;\n\n            // If y = 1, the fractional part is zero.\n            if (y == SCALE) {\n                return result;\n            }\n\n            // Calculate the fractional part via the iterative approximation.\n            // The \"delta >>= 1\" part is equivalent to \"delta /= 2\", but shifting bits is faster.\n            for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) {\n                y = (y * y) / SCALE;\n\n                // Is y^2 > 2 and so in the range [2,4)?\n                if (y >= 2 * SCALE) {\n                    // Add the 2^(-m) factor to the logarithm.\n                    result += delta;\n\n                    // Corresponds to z/2 on Wikipedia.\n                    y >>= 1;\n                }\n            }\n        }\n    }\n\n    /// @notice Multiplies two unsigned 60.18-decimal fixed-point numbers together, returning a new unsigned 60.18-decimal\n    /// fixed-point number.\n    /// @dev See the documentation for the \"PRBMath.mulDivFixedPoint\" function.\n    /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The product as an unsigned 60.18-decimal fixed-point number.\n    function mul(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        result = PRBMath.mulDivFixedPoint(x, y);\n    }\n\n    /// @notice Returns PI as an unsigned 60.18-decimal fixed-point number.\n    function pi() internal pure returns (uint256 result) {\n        result = 3_141592653589793238;\n    }\n\n    /// @notice Raises x to the power of y.\n    ///\n    /// @dev Based on the insight that x^y = 2^(log2(x) * y).\n    ///\n    /// Requirements:\n    /// - All from \"exp2\", \"log2\" and \"mul\".\n    ///\n    /// Caveats:\n    /// - All from \"exp2\", \"log2\" and \"mul\".\n    /// - Assumes 0^0 is 1.\n    ///\n    /// @param x Number to raise to given power y, as an unsigned 60.18-decimal fixed-point number.\n    /// @param y Exponent to raise x to, as an unsigned 60.18-decimal fixed-point number.\n    /// @return result x raised to power y, as an unsigned 60.18-decimal fixed-point number.\n    function pow(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        if (x == 0) {\n            result = y == 0 ? SCALE : uint256(0);\n        } else {\n            result = exp2(mul(log2(x), y));\n        }\n    }\n\n    /// @notice Raises x (unsigned 60.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the\n    /// famous algorithm \"exponentiation by squaring\".\n    ///\n    /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring\n    ///\n    /// Requirements:\n    /// - The result must fit within MAX_UD60x18.\n    ///\n    /// Caveats:\n    /// - All from \"mul\".\n    /// - Assumes 0^0 is 1.\n    ///\n    /// @param x The base as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The exponent as an uint256.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function powu(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        // Calculate the first iteration of the loop in advance.\n        result = y & 1 > 0 ? x : SCALE;\n\n        // Equivalent to \"for(y /= 2; y > 0; y /= 2)\" but faster.\n        for (y >>= 1; y > 0; y >>= 1) {\n            x = PRBMath.mulDivFixedPoint(x, x);\n\n            // Equivalent to \"y % 2 == 1\" but faster.\n            if (y & 1 > 0) {\n                result = PRBMath.mulDivFixedPoint(result, x);\n            }\n        }\n    }\n\n    /// @notice Returns 1 as an unsigned 60.18-decimal fixed-point number.\n    function scale() internal pure returns (uint256 result) {\n        result = SCALE;\n    }\n\n    /// @notice Calculates the square root of x, rounding down.\n    /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n    ///\n    /// Requirements:\n    /// - x must be less than MAX_UD60x18 / SCALE.\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the square root.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point .\n    function sqrt(uint256 x) internal pure returns (uint256 result) {\n        unchecked {\n            if (x > MAX_UD60x18 / SCALE) {\n                revert PRBMathUD60x18__SqrtOverflow(x);\n            }\n            // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two unsigned\n            // 60.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root).\n            result = PRBMath.sqrt(x * SCALE);\n        }\n    }\n\n    /// @notice Converts a unsigned 60.18-decimal fixed-point number to basic integer form, rounding down in the process.\n    /// @param x The unsigned 60.18-decimal fixed-point number to convert.\n    /// @return result The same number in basic integer form.\n    function toUint(uint256 x) internal pure returns (uint256 result) {\n        unchecked {\n            result = x / SCALE;\n        }\n    }\n}\n"
      },
      "src/interfaces/utils/IWETH9.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nimport { IERC20 } from \"openzeppelin-contracts/token/ERC20/IERC20.sol\";\n\ninterface IWETH9 is IERC20 {\n    function symbol() external view returns (string memory);\n\n    function deposit() external payable;\n    function withdraw(uint256 amount) external;\n}\n"
      },
      "src/interfaces/staking/IAccToke.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IERC20Metadata } from \"openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface IAccToke {\n    ///////////////////////////////////////////////////////////////////\n    //                        Variables\n    ///////////////////////////////////////////////////////////////////\n\n    function startEpoch() external view returns (uint256);\n    function minStakeDuration() external view returns (uint256);\n\n    struct Lockup {\n        uint128 amount;\n        uint128 end;\n        uint256 points;\n    }\n\n    function getLockups(address user) external view returns (Lockup[] memory);\n    function toke() external view returns (IERC20Metadata);\n\n    ///////////////////////////////////////////////////////////////////\n    //                        Errors\n    ///////////////////////////////////////////////////////////////////\n\n    error ZeroAddress();\n    error StakingDurationTooShort();\n    error StakingDurationTooLong();\n    error StakingPointsExceeded();\n    error IncorrectStakingAmount();\n    error InsufficientFunds();\n    error LockupDoesNotExist();\n    error NotUnlockableYet();\n    error AlreadyUnlocked();\n    error ExtendDurationTooShort();\n    error TransfersDisabled();\n    error TransferFailed();\n    error NoRewardsToClaim();\n    error InsufficientAmount();\n    error InvalidLockupIds();\n    error InvalidDurationLength();\n\n    ///////////////////////////////////////////////////////////////////\n    //                        Events\n    ///////////////////////////////////////////////////////////////////\n    event SetMaxStakeDuration(uint256 oldDuration, uint256 newDuration);\n    event Stake(address indexed user, uint256 lockupId, uint256 amount, uint256 end, uint256 points);\n    event Unstake(address indexed user, uint256 lockupId, uint256 amount, uint256 end, uint256 points);\n    event Extend(\n        address indexed user,\n        uint256 lockupId,\n        uint256 amount,\n        uint256 oldEnd,\n        uint256 newEnd,\n        uint256 oldPoints,\n        uint256 newPoints\n    );\n    event RewardsAdded(uint256 amount, uint256 accRewardPerShare);\n    event RewardsCollected(address indexed user, uint256 amount);\n    event RewardsClaimed(address indexed user, uint256 amount);\n\n    ///////////////////////////////////////////////////////////////////\n    //\n    //                        Staking Methods\n    //\n    ///////////////////////////////////////////////////////////////////\n\n    /**\n     * @notice Stake TOKE to an address that may not be the same as the sender of the funds. This can be used to give\n     * staked funds to someone else.\n     *\n     * If staking before the start of staking (epoch), then the lockup start and end dates are shifted forward so that\n     * the lockup starts at the epoch.\n     *\n     * @param amount TOKE to lockup in the stake\n     * @param duration in seconds for the stake\n     * @param to address to receive ownership of the stake\n     */\n    function stake(uint256 amount, uint256 duration, address to) external;\n\n    /**\n     * @notice Stake TOKE\n     *\n     * If staking before the start of staking (epoch), then the lockup start and end dates are shifted forward so that\n     * the lockup starts at the epoch.\n     *\n     * @notice Stake TOKE for myself.\n     * @param amount TOKE to lockup in the stake\n     * @param duration in seconds for the stake\n     */\n    function stake(uint256 amount, uint256 duration) external;\n\n    /**\n     * @notice Collect staked TOKE for a lockup and any earned rewards.\n     * @param lockupIds the id of the lockup to unstake\n     */\n    function unstake(uint256[] memory lockupIds) external;\n\n    /**\n     * @notice Extend a stake lockup for additional points.\n     *\n     * The stake end time is computed from the current time + duration, just like it is for new stakes. So a new stake\n     * for seven days duration and an old stake extended with a seven days duration would have the same end.\n     *\n     * If an extend is made before the start of staking, the start time for the new stake is shifted forwards to the\n     * start of staking, which also shifts forward the end date.\n     *\n     * @param lockupIds the id of the old lockup to extend\n     * @param durations number of seconds from now to stake for\n     */\n    function extend(uint256[] memory lockupIds, uint256[] memory durations) external;\n\n    ///////////////////////////////////////////////////////////////////\n    //\n    //                        Rewards\n    //\n    ///////////////////////////////////////////////////////////////////\n\n    /// @notice The total amount of rewards earned for all stakes\n    function totalRewardsEarned() external returns (uint256);\n\n    /// @notice Total rewards claimed by all stakers\n    function totalRewardsClaimed() external returns (uint256);\n\n    /// @notice Rewards claimed by a specific wallet\n    /// @param user Address of the wallet to check\n    function rewardsClaimed(address user) external returns (uint256);\n\n    /**\n     * @notice Preview the number of points that would be returned for the\n     * given amount and duration.\n     *\n     * @param amount TOKE to be staked\n     * @param duration number of seconds to stake for\n     * @return points staking points that would be returned\n     * @return end staking period end date\n     */\n    function previewPoints(uint256 amount, uint256 duration) external view returns (uint256, uint256);\n\n    /// @notice Preview the reward amount a caller can claim\n    function previewRewards() external view returns (uint256);\n\n    /// @notice Preview the reward amount a specified wallet can claim\n    function previewRewards(address user) external view returns (uint256);\n\n    /// @notice Claim rewards for the caller\n    function collectRewards() external returns (uint256);\n\n    /// @notice Check if amount can be staked\n    function isStakeableAmount(uint256 amount) external pure returns (bool);\n}\n"
      },
      "src/interfaces/ISystemRegistry.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\n\npragma solidity 0.8.17;\n\nimport { IWETH9 } from \"src/interfaces/utils/IWETH9.sol\";\nimport { IAccToke } from \"src/interfaces/staking/IAccToke.sol\";\nimport { IAutopoolRegistry } from \"src/interfaces/vault/IAutopoolRegistry.sol\";\nimport { IAccessController } from \"src/interfaces/security/IAccessController.sol\";\nimport { ISwapRouter } from \"src/interfaces/swapper/ISwapRouter.sol\";\nimport { ICurveResolver } from \"src/interfaces/utils/ICurveResolver.sol\";\nimport { IAutopilotRouter } from \"src/interfaces/vault/IAutopilotRouter.sol\";\nimport { IAutopoolFactory } from \"src/interfaces/vault/IAutopoolFactory.sol\";\nimport { ISystemSecurity } from \"src/interfaces/security/ISystemSecurity.sol\";\nimport { IDestinationRegistry } from \"src/interfaces/destinations/IDestinationRegistry.sol\";\nimport { IRootPriceOracle } from \"src/interfaces/oracles/IRootPriceOracle.sol\";\nimport { IDestinationVaultRegistry } from \"src/interfaces/vault/IDestinationVaultRegistry.sol\";\nimport { IAccessController } from \"src/interfaces/security/IAccessController.sol\";\nimport { IStatsCalculatorRegistry } from \"src/interfaces/stats/IStatsCalculatorRegistry.sol\";\nimport { IAsyncSwapperRegistry } from \"src/interfaces/liquidation/IAsyncSwapperRegistry.sol\";\nimport { IERC20Metadata } from \"openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IIncentivesPricingStats } from \"src/interfaces/stats/IIncentivesPricingStats.sol\";\nimport { IMessageProxy } from \"src/interfaces/messageProxy/IMessageProxy.sol\";\n\n/// @notice Root most registry contract for the system\ninterface ISystemRegistry {\n    /// @notice Get the TOKE contract for the system\n    /// @return toke instance of TOKE used in the system\n    function toke() external view returns (IERC20Metadata);\n\n    /// @notice Get the referenced WETH contract for the system\n    /// @return weth contract pointer\n    function weth() external view returns (IWETH9);\n\n    /// @notice Get the AccToke staking contract\n    /// @return accToke instance of the accToke contract for the system\n    function accToke() external view returns (IAccToke);\n\n    /// @notice Get the AutopoolRegistry for this system\n    /// @return registry instance of the registry for this system\n    function autoPoolRegistry() external view returns (IAutopoolRegistry registry);\n\n    /// @notice Get the destination Vault registry for this system\n    /// @return registry instance of the registry for this system\n    function destinationVaultRegistry() external view returns (IDestinationVaultRegistry registry);\n\n    /// @notice Get the access Controller for this system\n    /// @return controller instance of the access controller for this system\n    function accessController() external view returns (IAccessController controller);\n\n    /// @notice Get the destination template registry for this system\n    /// @return registry instance of the registry for this system\n    function destinationTemplateRegistry() external view returns (IDestinationRegistry registry);\n\n    /// @notice Auto Pilot Router\n    /// @return router instance of the system\n    function autoPoolRouter() external view returns (IAutopilotRouter router);\n\n    /// @notice Vault factory lookup by type\n    /// @return vaultFactory instance of the vault factory for this vault type\n    function getAutopoolFactoryByType(bytes32 vaultType) external view returns (IAutopoolFactory vaultFactory);\n\n    /// @notice Get the stats calculator registry for this system\n    /// @return registry instance of the registry for this system\n    function statsCalculatorRegistry() external view returns (IStatsCalculatorRegistry registry);\n\n    /// @notice Get the root price oracle for this system\n    /// @return oracle instance of the root price oracle for this system\n    function rootPriceOracle() external view returns (IRootPriceOracle oracle);\n\n    /// @notice Get the async swapper registry for this system\n    /// @return registry instance of the registry for this system\n    function asyncSwapperRegistry() external view returns (IAsyncSwapperRegistry registry);\n\n    /// @notice Get the swap router for this system\n    /// @return router instance of the swap router for this system\n    function swapRouter() external view returns (ISwapRouter router);\n\n    /// @notice Get the curve resolver for this system\n    /// @return resolver instance of the curve resolver for this system\n    function curveResolver() external view returns (ICurveResolver resolver);\n\n    /// @notice Verify if given address is registered as Reward Token\n    /// @param rewardToken token address to verify\n    /// @return bool that indicates true if token is registered and false if not\n    function isRewardToken(address rewardToken) external view returns (bool);\n\n    /// @notice Get the system security instance for this system\n    /// @return security instance of system security for this system\n    function systemSecurity() external view returns (ISystemSecurity security);\n\n    /// @notice Get the Incentive Pricing Stats\n    /// @return incentivePricing the incentive pricing contract\n    function incentivePricing() external view returns (IIncentivesPricingStats);\n\n    /// @notice Get the Messagy Proxy\n    /// @return Message proxy contract\n    function messageProxy() external view returns (IMessageProxy);\n}\n"
      },
      "src/security/SecurityBase.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IAccessController } from \"src/interfaces/security/IAccessController.sol\";\nimport { Errors } from \"src/utils/Errors.sol\";\n\ncontract SecurityBase {\n    IAccessController public immutable accessController;\n\n    error UndefinedAddress();\n\n    constructor(address _accessController) {\n        if (_accessController == address(0)) revert UndefinedAddress();\n\n        accessController = IAccessController(_accessController);\n    }\n\n    modifier onlyOwner() {\n        accessController.verifyOwner(msg.sender);\n        _;\n    }\n\n    modifier hasRole(bytes32 role) {\n        if (!accessController.hasRole(role, msg.sender)) revert Errors.AccessDenied();\n        _;\n    }\n\n    ///////////////////////////////////////////////////////////////////\n    //\n    //  Forward all the regular methods to central security module\n    //\n    ///////////////////////////////////////////////////////////////////\n\n    function _hasRole(bytes32 role, address account) internal view returns (bool) {\n        return accessController.hasRole(role, account);\n    }\n}\n"
      },
      "src/utils/Errors.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { Address } from \"openzeppelin-contracts/utils/Address.sol\";\n\nlibrary Errors {\n    using Address for address;\n    ///////////////////////////////////////////////////////////////////\n    //                       Set errors\n    ///////////////////////////////////////////////////////////////////\n\n    error AccessDenied();\n    error ZeroAddress(string paramName);\n    error ZeroAmount();\n    error InsufficientBalance(address token);\n    error AssetNotAllowed(address token);\n    error NotImplemented();\n    error InvalidAddress(address addr);\n    error InvalidParam(string paramName);\n    error InvalidParams();\n    error UnsafePrice(address token, uint256 spotPrice, uint256 safePrice);\n    error AlreadySet(string param);\n    error AlreadyRegistered(address param);\n    error SlippageExceeded(uint256 expected, uint256 actual);\n    error ArrayLengthMismatch(uint256 length1, uint256 length2, string details);\n\n    error ItemNotFound();\n    error ItemExists();\n    error MissingRole(bytes32 role, address user);\n    error RegistryItemMissing(string item);\n    error NotRegistered();\n    // Used to check storage slot is empty before setting.\n    error MustBeZero();\n    // Used to check storage slot set before deleting.\n    error MustBeSet();\n\n    error ApprovalFailed(address token);\n    error FlashLoanFailed(address token, uint256 amount);\n\n    error SystemMismatch(address source1, address source2);\n\n    error InvalidToken(address token);\n    error UnreachableError();\n\n    error InvalidSigner(address signer);\n\n    error InvalidChainId(uint256 chainId);\n\n    error SenderMismatch(address recipient, address sender);\n\n    function verifyNotZero(address addr, string memory paramName) internal pure {\n        if (addr == address(0)) {\n            revert ZeroAddress(paramName);\n        }\n    }\n\n    function verifyNotZero(bytes32 key, string memory paramName) internal pure {\n        if (key == bytes32(0)) {\n            revert InvalidParam(paramName);\n        }\n    }\n\n    function verifyNotEmpty(string memory val, string memory paramName) internal pure {\n        if (bytes(val).length == 0) {\n            revert InvalidParam(paramName);\n        }\n    }\n\n    function verifyNotZero(uint256 num, string memory paramName) internal pure {\n        if (num == 0) {\n            revert InvalidParam(paramName);\n        }\n    }\n\n    function verifySystemsMatch(address component1, address component2) internal view {\n        bytes memory call = abi.encodeWithSignature(\"getSystemRegistry()\");\n\n        address registry1 = abi.decode(component1.functionStaticCall(call), (address));\n        address registry2 = abi.decode(component2.functionStaticCall(call), (address));\n\n        if (registry1 != registry2) {\n            revert SystemMismatch(component1, component2);\n        }\n    }\n\n    function verifyArrayLengths(uint256 length1, uint256 length2, string memory details) internal pure {\n        if (length1 != length2) {\n            revert ArrayLengthMismatch(length1, length2, details);\n        }\n    }\n}\n"
      },
      "src/SystemComponent.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { ISystemComponent } from \"src/interfaces/ISystemComponent.sol\";\nimport { ISystemRegistry } from \"src/interfaces/ISystemRegistry.sol\";\nimport { Errors } from \"src/utils/Errors.sol\";\n\ncontract SystemComponent is ISystemComponent {\n    ISystemRegistry internal immutable systemRegistry;\n\n    constructor(ISystemRegistry _systemRegistry) {\n        Errors.verifyNotZero(address(_systemRegistry), \"_systemRegistry\");\n        systemRegistry = _systemRegistry;\n    }\n\n    /// @inheritdoc ISystemComponent\n    function getSystemRegistry() external view returns (address) {\n        return address(systemRegistry);\n    }\n}\n"
      },
      "src/libs/Roles.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\n\npragma solidity 0.8.17;\n\nlibrary Roles {\n    // --------------------------------------------------------------------\n    // Central roles list used by all contracts that call AccessController\n    // --------------------------------------------------------------------\n    // TODO: Update the hash values to match the variable names for new deployments.\n\n    // Naming Conventions:\n    // - Use MANAGER, CREATOR, UPDATER, ..., for roles primarily managing on-chain activities.\n    // - Use EXECUTOR for roles that trigger off-chain initiated actions.\n    // - Group roles by functional area for clarity.\n    // --------------------------------------------------------------------\n\n    // Destination Vault Management\n    bytes32 public constant DESTINATION_VAULT_FACTORY_MANAGER = keccak256(\"CREATE_DESTINATION_VAULT_ROLE\");\n    bytes32 public constant DESTINATION_VAULT_REGISTRY_MANAGER = keccak256(\"DESTINATION_VAULT_REGISTRY_MANAGER\");\n    bytes32 public constant DESTINATION_VAULT_MANAGER = keccak256(\"DESTINATION_VAULT_MANAGER\");\n\n    // Auto Pool Factory and Registry Management\n    bytes32 public constant AUTO_POOL_REGISTRY_UPDATER = keccak256(\"REGISTRY_UPDATER\");\n    bytes32 public constant AUTO_POOL_FACTORY_MANAGER = 0x00; // keccak256(\"LMP_VAULT_FACTORY_MANAGER\");\n    bytes32 public constant AUTO_POOL_FACTORY_VAULT_CREATOR = keccak256(\"CREATE_POOL_ROLE\");\n\n    // Auto Pool Management\n    bytes32 public constant AUTO_POOL_DESTINATION_UPDATER = keccak256(\"DESTINATION_VAULTS_UPDATER\");\n    bytes32 public constant AUTO_POOL_FEE_UPDATER = keccak256(\"AUTO_POOL_FEE_SETTER_ROLE\");\n    bytes32 public constant AUTO_POOL_PERIODIC_FEE_UPDATER = keccak256(\"AUTO_POOL_PERIODIC_FEE_SETTER_ROLE\");\n    bytes32 public constant AUTO_POOL_REWARD_MANAGER = keccak256(\"AUTO_POOL_REWARD_MANAGER_ROLE\");\n    bytes32 public constant AUTO_POOL_MANAGER = keccak256(\"AUTO_POOL_ADMIN\");\n    bytes32 public constant REBALANCER = keccak256(\"REBALANCER_ROLE\");\n\n    // Reward Management\n    bytes32 public constant LIQUIDATOR_MANAGER = keccak256(\"LIQUIDATOR_ROLE\");\n    bytes32 public constant DV_REWARD_MANAGER = keccak256(\"DV_REWARD_MANAGER_ROLE\");\n    bytes32 public constant REWARD_LIQUIDATION_MANAGER = keccak256(\"REWARD_LIQUIDATION_MANAGER\");\n    bytes32 public constant EXTRA_REWARD_MANAGER = keccak256(\"EXTRA_REWARD_MANAGER_ROLE\");\n    bytes32 public constant REWARD_LIQUIDATION_EXECUTOR = keccak256(\"REWARD_LIQUIDATION_EXECUTOR\");\n\n    // Statistics and Reporting\n    bytes32 public constant STATS_CALC_REGISTRY_MANAGER = 0x00; // keccak256(\"STATS_CALC_REGISTRY_MANAGER\");\n    bytes32 public constant STATS_CALC_FACTORY_MANAGER = keccak256(\"CREATE_STATS_CALC_ROLE\");\n    bytes32 public constant STATS_CALC_FACTORY_TEMPLATE_MANAGER = keccak256(\"STATS_CALC_TEMPLATE_MGMT_ROLE\");\n\n    bytes32 public constant STATS_SNAPSHOT_EXECUTOR = keccak256(\"STATS_SNAPSHOT_ROLE\");\n    bytes32 public constant STATS_INCENTIVE_TOKEN_UPDATER = keccak256(\"STATS_INCENTIVE_TOKEN_UPDATER\");\n    bytes32 public constant STATS_GENERAL_MANAGER = keccak256(\"STATS_GENERAL_MANAGER\");\n\n    // Emergency Management\n    bytes32 public constant EMERGENCY_PAUSER = keccak256(\"EMERGENCY_PAUSER\");\n\n    // Miscellaneous Roles\n    bytes32 public constant SOLVER = keccak256(\"SOLVER_ROLE\");\n    bytes32 public constant AUTO_POOL_REPORTING_EXECUTOR = keccak256(\"AUTO_POOL_UPDATE_DEBT_REPORTING_ROLE\");\n\n    // Swapper Roles\n    bytes32 public constant SWAP_ROUTER_MANAGER = 0x00; // keccak256(\"SWAP_ROUTER_MANAGER\");\n\n    // Price Oracles Roles\n    bytes32 public constant ORACLE_MANAGER = keccak256(\"ORACLE_MANAGER_ROLE\");\n    bytes32 public constant CUSTOM_ORACLE_EXECUTOR = keccak256(\"CUSTOM_ORACLE_EXECUTOR\");\n    bytes32 public constant MAVERICK_FEE_ORACLE_EXECUTOR = keccak256(\"MAVERICK_FEE_ORACLE_MANAGER\");\n\n    // AccToke Roles\n    bytes32 public constant ACC_TOKE_MANAGER = keccak256(\"ACC_TOKE_MANAGER\");\n\n    // Admin Roles\n    bytes32 public constant TOKEN_RECOVERY_MANAGER = keccak256(\"TOKEN_RECOVERY_ROLE\");\n\n    // Message Proxy Roles\n    bytes32 public constant MESSAGE_PROXY_MANAGER = keccak256(\"MESSAGE_PROXY_MANAGER\");\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.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 IERC20 {\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(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-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 */\ninterface IERC20Permit {\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    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"
      },
      "lib/openzeppelin-contracts/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\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     *\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://diligence.consensys.net/posts/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.5.11/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(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) 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"
      },
      "lib/openzeppelin-contracts/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\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 Context {\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"
      },
      "lib/openzeppelin-contracts/contracts/utils/math/Math.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.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 Math {\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(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) 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                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1);\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(\n        uint256 x,\n        uint256 y,\n        uint256 denominator,\n        Rounding rounding\n    ) 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 10, 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 * 8) < value ? 1 : 0);\n        }\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol)\npragma solidity ^0.8.0;\n\n/**\n * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.\n *\n * _Available since v4.5._\n */\ninterface IVotes {\n    /**\n     * @dev Emitted when an account changes their delegate.\n     */\n    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\n\n    /**\n     * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.\n     */\n    event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);\n\n    /**\n     * @dev Returns the current amount of votes that `account` has.\n     */\n    function getVotes(address account) external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).\n     */\n    function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);\n\n    /**\n     * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).\n     *\n     * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n     * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n     * vote.\n     */\n    function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);\n\n    /**\n     * @dev Returns the delegate that `account` has chosen.\n     */\n    function delegates(address account) external view returns (address);\n\n    /**\n     * @dev Delegates votes from the sender to `delegatee`.\n     */\n    function delegate(address delegatee) external;\n\n    /**\n     * @dev Delegates votes from signer to `delegatee`.\n     */\n    function delegateBySig(\n        address delegatee,\n        uint256 nonce,\n        uint256 expiry,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV // Deprecated in v4.8\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) >> 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n    /* solhint-disable var-name-mixedcase */\n    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n    // invalidate the cached domain separator if the chain id changes.\n    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n    uint256 private immutable _CACHED_CHAIN_ID;\n    address private immutable _CACHED_THIS;\n\n    bytes32 private immutable _HASHED_NAME;\n    bytes32 private immutable _HASHED_VERSION;\n    bytes32 private immutable _TYPE_HASH;\n\n    /* solhint-enable var-name-mixedcase */\n\n    /**\n     * @dev Initializes the domain separator and parameter caches.\n     *\n     * The meaning of `name` and `version` is specified in\n     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n     *\n     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n     * - `version`: the current major version of the signing domain.\n     *\n     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n     * contract upgrade].\n     */\n    constructor(string memory name, string memory version) {\n        bytes32 hashedName = keccak256(bytes(name));\n        bytes32 hashedVersion = keccak256(bytes(version));\n        bytes32 typeHash = keccak256(\n            \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n        );\n        _HASHED_NAME = hashedName;\n        _HASHED_VERSION = hashedVersion;\n        _CACHED_CHAIN_ID = block.chainid;\n        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n        _CACHED_THIS = address(this);\n        _TYPE_HASH = typeHash;\n    }\n\n    /**\n     * @dev Returns the domain separator for the current chain.\n     */\n    function _domainSeparatorV4() internal view returns (bytes32) {\n        if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n            return _CACHED_DOMAIN_SEPARATOR;\n        } else {\n            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n        }\n    }\n\n    function _buildDomainSeparator(\n        bytes32 typeHash,\n        bytes32 nameHash,\n        bytes32 versionHash\n    ) private view returns (bytes32) {\n        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n    }\n\n    /**\n     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n     * function returns the hash of the fully encoded EIP712 message for this domain.\n     *\n     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n     *\n     * ```solidity\n     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n     *     keccak256(\"Mail(address to,string contents)\"),\n     *     mailTo,\n     *     keccak256(bytes(mailContents))\n     * )));\n     * address signer = ECDSA.recover(digest, signature);\n     * ```\n     */\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/Counters.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n    struct Counter {\n        // This variable should never be directly accessed by users of the library: interactions must be restricted to\n        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n        // this feature: see https://github.com/ethereum/solidity/issues/4637\n        uint256 _value; // default: 0\n    }\n\n    function current(Counter storage counter) internal view returns (uint256) {\n        return counter._value;\n    }\n\n    function increment(Counter storage counter) internal {\n        unchecked {\n            counter._value += 1;\n        }\n    }\n\n    function decrement(Counter storage counter) internal {\n        uint256 value = counter._value;\n        require(value > 0, \"Counter: decrement overflow\");\n        unchecked {\n            counter._value = value - 1;\n        }\n    }\n\n    function reset(Counter storage counter) internal {\n        counter._value = 0;\n    }\n}\n"
      },
      "lib/prb-math/contracts/PRBMath.sol": {
        "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\n\n/// @notice Emitted when one of the inputs is type(int256).min.\nerror PRBMath__MulDivSignedInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows int256.\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is MIN_SD59x18.\nerror PRBMathSD59x18__AbsInputTooSmall();\n\n/// @notice Emitted when ceiling a number overflows SD59x18.\nerror PRBMathSD59x18__CeilOverflow(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__DivInputTooSmall();\n\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\n\n/// @notice Emitted when flooring a number underflows SD59x18.\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\n\n/// @notice Emitted when the product of the inputs is negative.\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\n\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\n\n/// @notice Emitted when the input is less than or equal to zero.\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__MulInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is negative.\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\n\n/// @notice Emitted when the calculating the square root overflows SD59x18.\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\n\n/// @notice Emitted when addition overflows UD60x18.\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when ceiling a number overflows UD60x18.\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\n\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when the input is less than 1.\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\n\n/// @notice Emitted when the calculating the square root overflows UD60x18.\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\n\n/// @notice Emitted when subtraction underflows UD60x18.\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\n\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\nlibrary PRBMath {\n    /// STRUCTS ///\n\n    struct SD59x18 {\n        int256 value;\n    }\n\n    struct UD60x18 {\n        uint256 value;\n    }\n\n    /// STORAGE ///\n\n    /// @dev How many trailing decimals can be represented.\n    uint256 internal constant SCALE = 1e18;\n\n    /// @dev Largest power of two divisor of SCALE.\n    uint256 internal constant SCALE_LPOTD = 262144;\n\n    /// @dev SCALE inverted mod 2^256.\n    uint256 internal constant SCALE_INVERSE =\n        78156646155174841979727994598816262306175212592076161876661_508869554232690281;\n\n    /// FUNCTIONS ///\n\n    /// @notice Calculates the binary exponent of x using the binary fraction method.\n    /// @dev Has to use 192.64-bit fixed-point numbers.\n    /// See https://ethereum.stackexchange.com/a/96594/24693.\n    /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function exp2(uint256 x) internal pure returns (uint256 result) {\n        unchecked {\n            // Start from 0.5 in the 192.64-bit fixed-point format.\n            result = 0x800000000000000000000000000000000000000000000000;\n\n            // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\n            // because the initial result is 2^191 and all magic factors are less than 2^65.\n            if (x & 0x8000000000000000 > 0) {\n                result = (result * 0x16A09E667F3BCC909) >> 64;\n            }\n            if (x & 0x4000000000000000 > 0) {\n                result = (result * 0x1306FE0A31B7152DF) >> 64;\n            }\n            if (x & 0x2000000000000000 > 0) {\n                result = (result * 0x1172B83C7D517ADCE) >> 64;\n            }\n            if (x & 0x1000000000000000 > 0) {\n                result = (result * 0x10B5586CF9890F62A) >> 64;\n            }\n            if (x & 0x800000000000000 > 0) {\n                result = (result * 0x1059B0D31585743AE) >> 64;\n            }\n            if (x & 0x400000000000000 > 0) {\n                result = (result * 0x102C9A3E778060EE7) >> 64;\n            }\n            if (x & 0x200000000000000 > 0) {\n                result = (result * 0x10163DA9FB33356D8) >> 64;\n            }\n            if (x & 0x100000000000000 > 0) {\n                result = (result * 0x100B1AFA5ABCBED61) >> 64;\n            }\n            if (x & 0x80000000000000 > 0) {\n                result = (result * 0x10058C86DA1C09EA2) >> 64;\n            }\n            if (x & 0x40000000000000 > 0) {\n                result = (result * 0x1002C605E2E8CEC50) >> 64;\n            }\n            if (x & 0x20000000000000 > 0) {\n                result = (result * 0x100162F3904051FA1) >> 64;\n            }\n            if (x & 0x10000000000000 > 0) {\n                result = (result * 0x1000B175EFFDC76BA) >> 64;\n            }\n            if (x & 0x8000000000000 > 0) {\n                result = (result * 0x100058BA01FB9F96D) >> 64;\n            }\n            if (x & 0x4000000000000 > 0) {\n                result = (result * 0x10002C5CC37DA9492) >> 64;\n            }\n            if (x & 0x2000000000000 > 0) {\n                result = (result * 0x1000162E525EE0547) >> 64;\n            }\n            if (x & 0x1000000000000 > 0) {\n                result = (result * 0x10000B17255775C04) >> 64;\n            }\n            if (x & 0x800000000000 > 0) {\n                result = (result * 0x1000058B91B5BC9AE) >> 64;\n            }\n            if (x & 0x400000000000 > 0) {\n                result = (result * 0x100002C5C89D5EC6D) >> 64;\n            }\n            if (x & 0x200000000000 > 0) {\n                result = (result * 0x10000162E43F4F831) >> 64;\n            }\n            if (x & 0x100000000000 > 0) {\n                result = (result * 0x100000B1721BCFC9A) >> 64;\n            }\n            if (x & 0x80000000000 > 0) {\n                result = (result * 0x10000058B90CF1E6E) >> 64;\n            }\n            if (x & 0x40000000000 > 0) {\n                result = (result * 0x1000002C5C863B73F) >> 64;\n            }\n            if (x & 0x20000000000 > 0) {\n                result = (result * 0x100000162E430E5A2) >> 64;\n            }\n            if (x & 0x10000000000 > 0) {\n                result = (result * 0x1000000B172183551) >> 64;\n            }\n            if (x & 0x8000000000 > 0) {\n                result = (result * 0x100000058B90C0B49) >> 64;\n            }\n            if (x & 0x4000000000 > 0) {\n                result = (result * 0x10000002C5C8601CC) >> 64;\n            }\n            if (x & 0x2000000000 > 0) {\n                result = (result * 0x1000000162E42FFF0) >> 64;\n            }\n            if (x & 0x1000000000 > 0) {\n                result = (result * 0x10000000B17217FBB) >> 64;\n            }\n            if (x & 0x800000000 > 0) {\n                result = (result * 0x1000000058B90BFCE) >> 64;\n            }\n            if (x & 0x400000000 > 0) {\n                result = (result * 0x100000002C5C85FE3) >> 64;\n            }\n            if (x & 0x200000000 > 0) {\n                result = (result * 0x10000000162E42FF1) >> 64;\n            }\n            if (x & 0x100000000 > 0) {\n                result = (result * 0x100000000B17217F8) >> 64;\n            }\n            if (x & 0x80000000 > 0) {\n                result = (result * 0x10000000058B90BFC) >> 64;\n            }\n            if (x & 0x40000000 > 0) {\n                result = (result * 0x1000000002C5C85FE) >> 64;\n            }\n            if (x & 0x20000000 > 0) {\n                result = (result * 0x100000000162E42FF) >> 64;\n            }\n            if (x & 0x10000000 > 0) {\n                result = (result * 0x1000000000B17217F) >> 64;\n            }\n            if (x & 0x8000000 > 0) {\n                result = (result * 0x100000000058B90C0) >> 64;\n            }\n            if (x & 0x4000000 > 0) {\n                result = (result * 0x10000000002C5C860) >> 64;\n            }\n            if (x & 0x2000000 > 0) {\n                result = (result * 0x1000000000162E430) >> 64;\n            }\n            if (x & 0x1000000 > 0) {\n                result = (result * 0x10000000000B17218) >> 64;\n            }\n            if (x & 0x800000 > 0) {\n                result = (result * 0x1000000000058B90C) >> 64;\n            }\n            if (x & 0x400000 > 0) {\n                result = (result * 0x100000000002C5C86) >> 64;\n            }\n            if (x & 0x200000 > 0) {\n                result = (result * 0x10000000000162E43) >> 64;\n            }\n            if (x & 0x100000 > 0) {\n                result = (result * 0x100000000000B1721) >> 64;\n            }\n            if (x & 0x80000 > 0) {\n                result = (result * 0x10000000000058B91) >> 64;\n            }\n            if (x & 0x40000 > 0) {\n                result = (result * 0x1000000000002C5C8) >> 64;\n            }\n            if (x & 0x20000 > 0) {\n                result = (result * 0x100000000000162E4) >> 64;\n            }\n            if (x & 0x10000 > 0) {\n                result = (result * 0x1000000000000B172) >> 64;\n            }\n            if (x & 0x8000 > 0) {\n                result = (result * 0x100000000000058B9) >> 64;\n            }\n            if (x & 0x4000 > 0) {\n                result = (result * 0x10000000000002C5D) >> 64;\n            }\n            if (x & 0x2000 > 0) {\n                result = (result * 0x1000000000000162E) >> 64;\n            }\n            if (x & 0x1000 > 0) {\n                result = (result * 0x10000000000000B17) >> 64;\n            }\n            if (x & 0x800 > 0) {\n                result = (result * 0x1000000000000058C) >> 64;\n            }\n            if (x & 0x400 > 0) {\n                result = (result * 0x100000000000002C6) >> 64;\n            }\n            if (x & 0x200 > 0) {\n                result = (result * 0x10000000000000163) >> 64;\n            }\n            if (x & 0x100 > 0) {\n                result = (result * 0x100000000000000B1) >> 64;\n            }\n            if (x & 0x80 > 0) {\n                result = (result * 0x10000000000000059) >> 64;\n            }\n            if (x & 0x40 > 0) {\n                result = (result * 0x1000000000000002C) >> 64;\n            }\n            if (x & 0x20 > 0) {\n                result = (result * 0x10000000000000016) >> 64;\n            }\n            if (x & 0x10 > 0) {\n                result = (result * 0x1000000000000000B) >> 64;\n            }\n            if (x & 0x8 > 0) {\n                result = (result * 0x10000000000000006) >> 64;\n            }\n            if (x & 0x4 > 0) {\n                result = (result * 0x10000000000000003) >> 64;\n            }\n            if (x & 0x2 > 0) {\n                result = (result * 0x10000000000000001) >> 64;\n            }\n            if (x & 0x1 > 0) {\n                result = (result * 0x10000000000000001) >> 64;\n            }\n\n            // We're doing two things at the same time:\n            //\n            //   1. Multiply the result by 2^n + 1, where \"2^n\" is the integer part and the one is added to account for\n            //      the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\n            //      rather than 192.\n            //   2. Convert the result to the unsigned 60.18-decimal fixed-point format.\n            //\n            // This works because 2^(191-ip) = 2^ip / 2^191, where \"ip\" is the integer part \"2^n\".\n            result *= SCALE;\n            result >>= (191 - (x >> 64));\n        }\n    }\n\n    /// @notice Finds the zero-based index of the first one in the binary representation of x.\n    /// @dev See the note on msb in the \"Find First Set\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\n    /// @param x The uint256 number for which to find the index of the most significant bit.\n    /// @return msb The index of the most significant bit as an uint256.\n    function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\n        if (x >= 2**128) {\n            x >>= 128;\n            msb += 128;\n        }\n        if (x >= 2**64) {\n            x >>= 64;\n            msb += 64;\n        }\n        if (x >= 2**32) {\n            x >>= 32;\n            msb += 32;\n        }\n        if (x >= 2**16) {\n            x >>= 16;\n            msb += 16;\n        }\n        if (x >= 2**8) {\n            x >>= 8;\n            msb += 8;\n        }\n        if (x >= 2**4) {\n            x >>= 4;\n            msb += 4;\n        }\n        if (x >= 2**2) {\n            x >>= 2;\n            msb += 2;\n        }\n        if (x >= 2**1) {\n            // No need to shift x any more.\n            msb += 1;\n        }\n    }\n\n    /// @notice Calculates floor(x*y÷denominator) with full precision.\n    ///\n    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\n    ///\n    /// Requirements:\n    /// - The denominator cannot be zero.\n    /// - The result must fit within uint256.\n    ///\n    /// Caveats:\n    /// - This function does not work with fixed-point numbers.\n    ///\n    /// @param x The multiplicand as an uint256.\n    /// @param y The multiplier as an uint256.\n    /// @param denominator The divisor as an uint256.\n    /// @return result The result as an uint256.\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 result) {\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            unchecked {\n                result = prod0 / denominator;\n            }\n            return result;\n        }\n\n        // Make sure the result is less than 2^256. Also prevents denominator == 0.\n        if (prod1 >= denominator) {\n            revert PRBMath__MulDivOverflow(prod1, denominator);\n        }\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        unchecked {\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 lpotdod = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by lpotdod.\n                denominator := div(denominator, lpotdod)\n\n                // Divide [prod1 prod0] by lpotdod.\n                prod0 := div(prod0, lpotdod)\n\n                // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\n                lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * lpotdod;\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    /// @notice Calculates floor(x*y÷1e18) with full precision.\n    ///\n    /// @dev Variant of \"mulDiv\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\n    /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\n    /// being rounded to 1e-18.  See \"Listing 6\" and text above it at https://accu.org/index.php/journals/1717.\n    ///\n    /// Requirements:\n    /// - The result must fit within uint256.\n    ///\n    /// Caveats:\n    /// - The body is purposely left uncommented; see the NatSpec comments in \"PRBMath.mulDiv\" to understand how this works.\n    /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\n    ///     1. x * y = type(uint256).max * SCALE\n    ///     2. (x * y) % SCALE >= SCALE / 2\n    ///\n    /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        uint256 prod0;\n        uint256 prod1;\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        if (prod1 >= SCALE) {\n            revert PRBMath__MulDivFixedPointOverflow(prod1);\n        }\n\n        uint256 remainder;\n        uint256 roundUpUnit;\n        assembly {\n            remainder := mulmod(x, y, SCALE)\n            roundUpUnit := gt(remainder, 499999999999999999)\n        }\n\n        if (prod1 == 0) {\n            unchecked {\n                result = (prod0 / SCALE) + roundUpUnit;\n                return result;\n            }\n        }\n\n        assembly {\n            result := add(\n                mul(\n                    or(\n                        div(sub(prod0, remainder), SCALE_LPOTD),\n                        mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\n                    ),\n                    SCALE_INVERSE\n                ),\n                roundUpUnit\n            )\n        }\n    }\n\n    /// @notice Calculates floor(x*y÷denominator) with full precision.\n    ///\n    /// @dev An extension of \"mulDiv\" for signed numbers. Works by computing the signs and the absolute values separately.\n    ///\n    /// Requirements:\n    /// - None of the inputs can be type(int256).min.\n    /// - The result must fit within int256.\n    ///\n    /// @param x The multiplicand as an int256.\n    /// @param y The multiplier as an int256.\n    /// @param denominator The divisor as an int256.\n    /// @return result The result as an int256.\n    function mulDivSigned(\n        int256 x,\n        int256 y,\n        int256 denominator\n    ) internal pure returns (int256 result) {\n        if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\n            revert PRBMath__MulDivSignedInputTooSmall();\n        }\n\n        // Get hold of the absolute values of x, y and the denominator.\n        uint256 ax;\n        uint256 ay;\n        uint256 ad;\n        unchecked {\n            ax = x < 0 ? uint256(-x) : uint256(x);\n            ay = y < 0 ? uint256(-y) : uint256(y);\n            ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\n        }\n\n        // Compute the absolute value of (x*y)÷denominator. The result must fit within int256.\n        uint256 rAbs = mulDiv(ax, ay, ad);\n        if (rAbs > uint256(type(int256).max)) {\n            revert PRBMath__MulDivSignedOverflow(rAbs);\n        }\n\n        // Get the signs of x, y and the denominator.\n        uint256 sx;\n        uint256 sy;\n        uint256 sd;\n        assembly {\n            sx := sgt(x, sub(0, 1))\n            sy := sgt(y, sub(0, 1))\n            sd := sgt(denominator, sub(0, 1))\n        }\n\n        // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\n        // If yes, the result should be negative.\n        result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\n    }\n\n    /// @notice Calculates the square root of x, rounding down.\n    /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n    ///\n    /// Caveats:\n    /// - This function does not work with fixed-point numbers.\n    ///\n    /// @param x The uint256 number for which to calculate the square root.\n    /// @return result The result as an uint256.\n    function sqrt(uint256 x) internal pure returns (uint256 result) {\n        if (x == 0) {\n            return 0;\n        }\n\n        // Set the initial guess to the least power of two that is greater than or equal to sqrt(x).\n        uint256 xAux = uint256(x);\n        result = 1;\n        if (xAux >= 0x100000000000000000000000000000000) {\n            xAux >>= 128;\n            result <<= 64;\n        }\n        if (xAux >= 0x10000000000000000) {\n            xAux >>= 64;\n            result <<= 32;\n        }\n        if (xAux >= 0x100000000) {\n            xAux >>= 32;\n            result <<= 16;\n        }\n        if (xAux >= 0x10000) {\n            xAux >>= 16;\n            result <<= 8;\n        }\n        if (xAux >= 0x100) {\n            xAux >>= 8;\n            result <<= 4;\n        }\n        if (xAux >= 0x10) {\n            xAux >>= 4;\n            result <<= 2;\n        }\n        if (xAux >= 0x8) {\n            result <<= 1;\n        }\n\n        // The operations can never overflow because the result is max 2^127 when it enters this block.\n        unchecked {\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1; // Seven iterations should be enough\n            uint256 roundedDownResult = x / result;\n            return result >= roundedDownResult ? roundedDownResult : result;\n        }\n    }\n}\n"
      },
      "src/interfaces/vault/IAutopoolRegistry.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\n/// @title Keep track of Vaults created through the Vault Factory\ninterface IAutopoolRegistry {\n    ///////////////////////////////////////////////////////////////////\n    //                        Errors\n    ///////////////////////////////////////////////////////////////////\n\n    error VaultNotFound(address vaultAddress);\n    error VaultAlreadyExists(address vaultAddress);\n\n    ///////////////////////////////////////////////////////////////////\n    //                        Events\n    ///////////////////////////////////////////////////////////////////\n    event VaultAdded(address indexed asset, address indexed vault);\n    event VaultRemoved(address indexed asset, address indexed vault);\n\n    ///////////////////////////////////////////////////////////////////\n    //                        Functions\n    ///////////////////////////////////////////////////////////////////\n\n    /// @notice Checks if an address is a valid vault\n    /// @param vaultAddress Vault address to be added\n    function isVault(address vaultAddress) external view returns (bool);\n\n    /// @notice Registers a vault\n    /// @param vaultAddress Vault address to be added\n    function addVault(address vaultAddress) external;\n\n    /// @notice Removes vault registration\n    /// @param vaultAddress Vault address to be removed\n    function removeVault(address vaultAddress) external;\n\n    /// @notice Returns a list of all registered vaults\n    function listVaults() external view returns (address[] memory);\n\n    /// @notice Returns a list of all registered vaults for a given asset\n    /// @param asset Asset address\n    function listVaultsForAsset(address asset) external view returns (address[] memory);\n\n    /// @notice Returns a list of all registered vaults for a given type\n    /// @param _vaultType Vault type\n    function listVaultsForType(bytes32 _vaultType) external view returns (address[] memory);\n}\n"
      },
      "src/interfaces/security/IAccessController.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IAccessControlEnumerable } from \"openzeppelin-contracts/access/IAccessControlEnumerable.sol\";\n\ninterface IAccessController is IAccessControlEnumerable {\n    error AccessDenied();\n\n    /**\n     * @notice Setup a role for an account\n     * @param role The role to setup\n     * @param account The account to setup the role for\n     */\n    function setupRole(bytes32 role, address account) external;\n\n    /**\n     * @notice Verify if an account is an owner. Reverts if not\n     * @param account The account to verify\n     */\n    function verifyOwner(address account) external view;\n}\n"
      },
      "src/interfaces/swapper/ISwapRouter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { ISyncSwapper } from \"src/interfaces/swapper/ISyncSwapper.sol\";\n\ninterface ISwapRouter {\n    struct SwapData {\n        address token;\n        address pool;\n        ISyncSwapper swapper;\n        bytes data;\n    }\n\n    error MaxSlippageExceeded();\n    error SwapRouteLookupFailed(address from, address to);\n    error SwapFailed();\n\n    event SwapRouteSet(address indexed token, SwapData[] routes);\n    event SwapForQuoteSuccessful(\n        address indexed assetToken,\n        uint256 sellAmount,\n        address indexed quoteToken,\n        uint256 minBuyAmount,\n        uint256 buyAmount\n    );\n\n    /**\n     * @notice Sets a new swap route for a given asset token.\n     * @param assetToken The asset token for which the swap route is being set.\n     * @param _swapRoute The new swap route as an array of SwapData. The last element represents the quoteToken.\n     * @dev Each 'hop' in the swap route is validated using the respective swapper's validate function. The validate\n     * function ensures that the encoded data contains the correct 'fromAddress' and 'toAddress' (swapData.token), and\n     * verifies that these tokens are in the pool.\n     */\n    function setSwapRoute(address assetToken, SwapData[] calldata _swapRoute) external;\n\n    /**\n     * @notice Swaps the asset token for the quote token.\n     * @dev We're adopting an \"exact in, variable out\" model for all our swaps. This ensures that the entire sellAmount\n     * is used, eliminating the need for additional balance checks and refunds. This model is expected to be followed by\n     * all swapper implementations to maintain consistency and to optimize for gas efficiency.\n     * @param assetToken The address of the asset token to swap.\n     * @param sellAmount The exact amount of the asset token to swap.\n     * @param quoteToken The address of the quote token.\n     * @param minBuyAmount The minimum amount of the quote token expected to be received from the swap.\n     * @return The amount received from the swap.\n     */\n    function swapForQuote(\n        address assetToken,\n        uint256 sellAmount,\n        address quoteToken,\n        uint256 minBuyAmount\n    ) external returns (uint256);\n}\n"
      },
      "src/interfaces/utils/ICurveResolver.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\n\npragma solidity 0.8.17;\n\ninterface ICurveResolver {\n    /// @notice Resolve details of a Curve pool regardless of type or version\n    /// @dev This resolves tokens without unwrapping to underlying in the case of meta pools.\n    /// @param poolAddress pool address to lookup\n    /// @return tokens tokens that make up the pool\n    /// @return numTokens the number of tokens. tokens are not unwrapped.\n    /// @return isStableSwap is this a StableSwap pool. false = CryptoSwap\n    function resolve(address poolAddress)\n        external\n        view\n        returns (address[8] memory tokens, uint256 numTokens, bool isStableSwap);\n\n    /// @notice Resolve details of a Curve pool regardless of type or version\n    /// @dev This resolves tokens without unwrapping to underlying in the case of meta pools.\n    /// @dev Use the isStableSwap value to differentiate between StableSwap (V1) and CryptoSwap (V2) pools.\n    /// @param poolAddress pool address to lookup\n    /// @return tokens tokens that make up the pool\n    /// @return numTokens the number of tokens. tokens are not unwrapped\n    /// @return lpToken lp token of the pool\n    /// @return isStableSwap is this a StableSwap pool. false = CryptoSwap\n    function resolveWithLpToken(address poolAddress)\n        external\n        view\n        returns (address[8] memory tokens, uint256 numTokens, address lpToken, bool isStableSwap);\n\n    /// @notice Get the lp token of a Curve pool\n    /// @param poolAddress pool address to lookup\n    function getLpToken(address poolAddress) external view returns (address);\n\n    /// @notice Get the reserves of a Curve pools' tokens\n    /// @dev Actual balances length might differ from 8 and should be verified by the caller\n    /// @param poolAddress pool address to lookup\n    /// @return balances reserves of the pool tokens\n    function getReservesInfo(address poolAddress) external view returns (uint256[8] memory balances);\n}\n"
      },
      "src/interfaces/vault/IAutopilotRouter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IAutopool } from \"src/interfaces/vault/IAutopool.sol\";\nimport { IAutopilotRouterBase } from \"src/interfaces/vault/IAutopilotRouterBase.sol\";\nimport { IRewards } from \"src/interfaces/rewarders/IRewards.sol\";\nimport { SwapParams } from \"src/interfaces/liquidation/IAsyncSwapper.sol\";\n\n/**\n * @title IAutopilotRouter Interface\n * @notice Extends the IAutopilotRouterBase with specific flows to save gas\n */\ninterface IAutopilotRouter is IAutopilotRouterBase {\n    /**\n     * ***************************   Deposit ********************************\n     */\n\n    /**\n     * @notice deposit available asset balance to a AutopoolETH.\n     * @param vault The AutopoolETH to deposit assets to.\n     * @param to The destination of ownership shares.\n     * @param minSharesOut The min amount of `vault` shares received by `to`.\n     * @return sharesOut the amount of shares received by `to`.\n     * @dev throws MinSharesError\n     */\n    function depositBalance(IAutopool vault, address to, uint256 minSharesOut) external returns (uint256 sharesOut);\n\n    /**\n     * @notice deposit max assets to a AutopoolETH.\n     * @param vault The AutopoolETH to deposit assets to.\n     * @param to The destination of ownership shares.\n     * @param minSharesOut The min amount of `vault` shares received by `to`.\n     * @return sharesOut the amount of shares received by `to`.\n     * @dev throws MinSharesError\n     */\n    function depositMax(IAutopool vault, address to, uint256 minSharesOut) external returns (uint256 sharesOut);\n\n    /**\n     * *************************   Withdraw   **********************************\n     */\n\n    /**\n     * @notice withdraw `amount` to a AutopoolETH.\n     * @param fromVault The AutopoolETH to withdraw assets from.\n     * @param toVault The AutopoolETH to deposit assets to.\n     * @param to The destination of ownership shares.\n     * @param amount The amount of assets to withdraw from fromVault.\n     * @param maxSharesIn The max amount of fromVault shares withdrawn by caller.\n     * @param minSharesOut The min amount of toVault shares received by `to`.\n     * @return sharesOut the amount of shares received by `to`.\n     * @dev throws MaxSharesError, MinSharesError\n     */\n    function withdrawToDeposit(\n        IAutopool fromVault,\n        IAutopool toVault,\n        address to,\n        uint256 amount,\n        uint256 maxSharesIn,\n        uint256 minSharesOut\n    ) external returns (uint256 sharesOut);\n\n    /**\n     * *************************   Redeem    ********************************\n     */\n\n    /**\n     * @notice redeem `shares` to a AutopoolETH.\n     * @param fromVault The AutopoolETH to redeem shares from.\n     * @param toVault The AutopoolETH to deposit assets to.\n     * @param to The destination of ownership shares.\n     * @param shares The amount of shares to redeem from fromVault.\n     * @param minSharesOut The min amount of toVault shares received by `to`.\n     * @return sharesOut the amount of shares received by `to`.\n     * @dev throws MinAmountError, MinSharesError\n     */\n    function redeemToDeposit(\n        IAutopool fromVault,\n        IAutopool toVault,\n        address to,\n        uint256 shares,\n        uint256 minSharesOut\n    ) external returns (uint256 sharesOut);\n\n    /**\n     * @notice redeem max shares to a AutopoolETH.\n     * @param vault The AutopoolETH to redeem shares from.\n     * @param to The destination of assets.\n     * @param minAmountOut The min amount of assets received by `to`.\n     * @return amountOut the amount of assets received by `to`.\n     * @dev throws MinAmountError\n     */\n    function redeemMax(IAutopool vault, address to, uint256 minAmountOut) external returns (uint256 amountOut);\n\n    /**\n     * @notice swaps token\n     * @param swapper Address of the swapper to use\n     * @param swapParams  Parameters for the swap\n     * @return amountReceived Swap output amount\n     */\n    function swapToken(address swapper, SwapParams memory swapParams) external returns (uint256 amountReceived);\n\n    /**\n     * @notice claims vault token rewards\n     * @param rewarder Address of the rewarder to claim from\n     * @param recipient Struct containing recipient details\n     * @return amountReceived Swap output amount\n     */\n    function claimRewards(\n        IRewards rewarder,\n        IRewards.Recipient calldata recipient,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (uint256);\n}\n"
      },
      "src/interfaces/vault/IAutopoolFactory.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\ninterface IAutopoolFactory {\n    ///////////////////////////////////////////////////////////////////\n    //                        Vault Creation\n    ///////////////////////////////////////////////////////////////////\n\n    /**\n     * @notice Spin up a new AutopoolETH\n     * @param strategy Strategy template address\n     * @param symbolSuffix Symbol suffix of the new token\n     * @param descPrefix Description prefix of the new token\n     * @param salt Vault creation salt\n     * @param extraParams Any extra data needed for the vault\n     */\n    function createVault(\n        address strategy,\n        string memory symbolSuffix,\n        string memory descPrefix,\n        bytes32 salt,\n        bytes calldata extraParams\n    ) external payable returns (address newVaultAddress);\n\n    function addStrategyTemplate(address strategyTemplate) external;\n\n    function removeStrategyTemplate(address strategyTemplate) external;\n}\n"
      },
      "src/interfaces/security/ISystemSecurity.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\ninterface ISystemSecurity {\n    /// @notice Get the number of NAV/share operations currently in progress\n    /// @return Number of operations\n    function navOpsInProgress() external view returns (uint256);\n\n    /// @notice Called at the start of any NAV/share changing operation\n    function enterNavOperation() external;\n\n    /// @notice Called at the end of any NAV/share changing operation\n    function exitNavOperation() external;\n\n    /// @notice Whether or not the system as a whole is paused\n    function isSystemPaused() external view returns (bool);\n}\n"
      },
      "src/interfaces/destinations/IDestinationRegistry.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IDestinationAdapter } from \"src/interfaces/destinations/IDestinationAdapter.sol\";\n\ninterface IDestinationRegistry {\n    event Register(bytes32[] indexed destinationTypes, address[] indexed targets);\n    event Replace(bytes32[] indexed destinationTypes, address[] indexed targets);\n    event Unregister(bytes32[] indexed destinationTypes);\n\n    event Whitelist(bytes32[] indexed destinationTypes);\n    event RemoveFromWhitelist(bytes32[] indexed destinationTypes);\n\n    error InvalidAddress(address addr);\n    error NotAllowedDestination();\n    error DestinationAlreadySet();\n\n    /**\n     * @notice Adds a new addresses of the given destination types\n     * @dev Fails if trying to overwrite previous value of the same destination type\n     * @param destinationTypes Ones from the destination type whitelist\n     * @param targets addresses of the deployed DestinationAdapters, cannot be 0\n     */\n    function register(bytes32[] calldata destinationTypes, address[] calldata targets) external;\n\n    /**\n     * @notice Replaces an addresses of the given destination types\n     * @dev Fails if given destination type was not set previously\n     * @param destinationTypes Ones from the destination type whitelist\n     * @param targets addresses of the deployed DestinationAdapters, cannot be 0\n     */\n    function replace(bytes32[] calldata destinationTypes, address[] calldata targets) external;\n\n    /**\n     * @notice Removes an addresses of the given pre-registered destination types\n     * @param destinationTypes Ones from the destination types whitelist\n     */\n    function unregister(bytes32[] calldata destinationTypes) external;\n\n    /**\n     * @notice Gives an address of the given destination type\n     * @dev Should revert on missing destination\n     * @param destination One from the destination type whitelist\n     */\n    function getAdapter(bytes32 destination) external returns (IDestinationAdapter);\n\n    /**\n     * @notice Adds given destination types to the whitelist\n     * @param destinationTypes Types to whitelist\n     */\n    function addToWhitelist(bytes32[] calldata destinationTypes) external;\n\n    /**\n     * @notice Removes given pre-whitelisted destination types\n     * @param destinationTypes Ones from the destination type whitelist\n     */\n    function removeFromWhitelist(bytes32[] calldata destinationTypes) external;\n\n    /**\n     * @notice Checks if the given destination type is whitelisted\n     * @param destinationType Type to verify\n     */\n    function isWhitelistedDestination(bytes32 destinationType) external view returns (bool);\n}\n"
      },
      "src/interfaces/oracles/IRootPriceOracle.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\n\npragma solidity 0.8.17;\n\n/// @notice Retrieve a price for any token used in the system\ninterface IRootPriceOracle {\n    /// @notice Returns a fair price for the provided token in ETH\n    /// @param token token to get the price of\n    /// @return price the price of the token in ETH\n    function getPriceInEth(address token) external returns (uint256 price);\n\n    /// @notice Returns a spot price for the provided token in ETH, utilizing specified liquidity pool\n    /// @param token token to get the spot price of\n    /// @param pool liquidity pool to be used for price determination\n    /// @return price the spot price of the token in ETH based on the provided pool\n    function getSpotPriceInEth(address token, address pool) external returns (uint256);\n\n    /// @notice Returns a price for base token in quote token.\n    /// @dev Requires both tokens to be registered.\n    /// @param base Address of base token.\n    /// @param quote Address of quote token.\n    /// @return price Price of the base token in quote token.\n    function getPriceInQuote(address base, address quote) external returns (uint256 price);\n\n    /// @notice Retrieve the price of LP token based on the reserves\n    /// @param lpToken LP token to get the price of\n    /// @param pool liquidity pool to be used for price determination\n    /// @param quoteToken token to quote the price in\n    function getRangePricesLP(\n        address lpToken,\n        address pool,\n        address quoteToken\n    ) external returns (uint256 spotPriceInQuote, uint256 safePriceInQuote, bool isSpotSafe);\n\n    /// @notice Returns floor or ceiling price of the supplied lp token in terms of requested quote.\n    /// @dev  Floor price: the minimum price among all the spot prices and safe prices of the tokens in the pool.\n    ///       Ceiling price: the maximum price among all the spot prices and safe prices of the tokens in the pool.\n    /// @param pool Address of pool to get spot pricing from.\n    /// @param lpToken Address of the lp token to price.\n    /// @param inQuote Address of desired quote token.\n    /// @param ceiling Bool indicating whether to get floor or ceiling price.\n    /// @return floorOrCeilingPerLpToken Floor or ceiling price of the lp token.\n    function getFloorCeilingPrice(\n        address pool,\n        address lpToken,\n        address inQuote,\n        bool ceiling\n    ) external returns (uint256 floorOrCeilingPerLpToken);\n\n    function getFloorPrice(address, address, address) external returns (uint256 price);\n\n    function getCeilingPrice(address, address, address) external returns (uint256 price);\n}\n"
      },
      "src/interfaces/vault/IDestinationVaultRegistry.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IDestinationVaultFactory } from \"src/interfaces/vault/IDestinationVaultFactory.sol\";\n\n/// @notice Tracks valid Destination Vaults for the system\ninterface IDestinationVaultRegistry {\n    /// @notice Determines if a given address is a valid Destination Vault in the system\n    /// @param destinationVault address to check\n    /// @return True if vault is registered\n    function isRegistered(address destinationVault) external view returns (bool);\n\n    /// @notice Registers a new Destination Vault\n    /// @dev Should be locked down to only a factory\n    /// @param newDestinationVault Address of the new vault\n    function register(address newDestinationVault) external;\n\n    /// @notice Checks if an address is a valid Destination Vault and reverts if not\n    /// @param destinationVault Destination Vault address to checked\n    function verifyIsRegistered(address destinationVault) external view;\n\n    /// @notice Returns a list of all registered vaults\n    function listVaults() external view returns (address[] memory);\n\n    /// @notice Factory that is allowed to create and registry Destination Vaults\n    function factory() external view returns (IDestinationVaultFactory);\n}\n"
      },
      "src/interfaces/stats/IStatsCalculatorRegistry.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IStatsCalculator } from \"src/interfaces/stats/IStatsCalculator.sol\";\n\n/// @notice Track stat calculators for this instance of the system\ninterface IStatsCalculatorRegistry {\n    /// @notice Get a registered calculator\n    /// @dev Should revert if missing\n    /// @param aprId key of the calculator to get\n    /// @return calculator instance of the calculator\n    function getCalculator(bytes32 aprId) external view returns (IStatsCalculator calculator);\n\n    /// @notice Register a new stats calculator\n    /// @param calculator address of the calculator\n    function register(address calculator) external;\n\n    /// @notice Set the factory that can register calculators\n    /// @param factory address of the factory\n    function setCalculatorFactory(address factory) external;\n}\n"
      },
      "src/interfaces/liquidation/IAsyncSwapperRegistry.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\ninterface IAsyncSwapperRegistry {\n    event SwapperAdded(address indexed item);\n    event SwapperRemoved(address indexed item);\n\n    /// @notice Registers an item\n    /// @param item Item address to be added\n    function register(address item) external;\n\n    /// @notice Removes item registration\n    /// @param item Item address to be removed\n    function unregister(address item) external;\n\n    /// @notice Returns a list of all registered items\n    function list() external view returns (address[] memory);\n\n    /// @notice Checks if an address is a valid item\n    /// @param item Item address to be checked\n    function isRegistered(address item) external view returns (bool);\n\n    /// @notice Checks if an address is a valid swapper and reverts if not\n    /// @param item Swapper address to be checked\n    function verifyIsRegistered(address item) external view;\n}\n"
      },
      "src/interfaces/stats/IIncentivesPricingStats.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\n/// @title EWMA pricing for incentive tokens\ninterface IIncentivesPricingStats {\n    event TokenAdded(address indexed token);\n    event TokenRemoved(address indexed token);\n    event TokenSnapshot(\n        address indexed token,\n        uint40 lastSnapshot,\n        uint256 fastFilterPrice,\n        uint256 slowFilterPrice,\n        uint256 initCount,\n        bool initComplete\n    );\n\n    error TokenAlreadyRegistered(address token);\n    error TokenNotFound(address token);\n    error IncentiveTokenPriceStale(address token);\n    error TokenSnapshotNotReady(address token);\n\n    struct TokenSnapshotInfo {\n        uint40 lastSnapshot;\n        bool _initComplete;\n        uint8 _initCount;\n        uint256 _initAcc;\n        uint256 fastFilterPrice;\n        uint256 slowFilterPrice;\n    }\n\n    /// @notice add a token to snapshot\n    /// @dev the token must be configured in the RootPriceOracle before adding here\n    /// @param token the address of the token to add\n    function setRegisteredToken(address token) external;\n\n    /// @notice remove a token from being snapshot\n    /// @param token the address of the token to remove\n    function removeRegisteredToken(address token) external;\n\n    /// @notice get the addresses for all currently registered tokens\n    /// @return tokens all of the registered token addresses\n    function getRegisteredTokens() external view returns (address[] memory tokens);\n\n    /// @notice get all of the registered tokens with the latest snapshot info\n    /// @return tokenAddresses token addresses in the same order as info\n    /// @return info a list of snapshot info for the tokens\n    function getTokenPricingInfo()\n        external\n        view\n        returns (address[] memory tokenAddresses, TokenSnapshotInfo[] memory info);\n\n    /// @notice update the snapshot for the specified tokens\n    /// @dev if a token is not ready to be snapshot the entire call will fail\n    function snapshot(address[] calldata tokensToSnapshot) external;\n\n    /// @notice get the latest prices for an incentive token. Reverts if token is not registered\n    /// @return fastPrice the price based on the faster filter (weighted toward current prices)\n    /// @return slowPrice the price based on the slower filter (weighted toward older prices, relative to fast)\n    function getPrice(address token, uint40 staleCheck) external view returns (uint256 fastPrice, uint256 slowPrice);\n\n    /// @notice get the latest prices for an incentive token or zero if the token is not registered\n    /// @return fastPrice the price based on the faster filter (weighted toward current prices)\n    /// @return slowPrice the price based on the slower filter (weighted toward older prices, relative to fast)\n    function getPriceOrZero(\n        address token,\n        uint40 staleCheck\n    ) external view returns (uint256 fastPrice, uint256 slowPrice);\n}\n"
      },
      "src/interfaces/messageProxy/IMessageProxy.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\n/// @title Send messages to our systems on other chains\ninterface IMessageProxy {\n    function sendMessage(bytes32 messageType, bytes memory message) external;\n}\n"
      },
      "src/interfaces/ISystemComponent.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\n/// @notice Stores a reference to the registry for this system\ninterface ISystemComponent {\n    /// @notice The system instance this contract is tied to\n    function getSystemRegistry() external view returns (address registry);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/Strings.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/access/IAccessControlEnumerable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n    /**\n     * @dev Returns one of the accounts that have `role`. `index` must be a\n     * value between 0 and {getRoleMemberCount}, non-inclusive.\n     *\n     * Role bearers are not sorted in any particular way, and their ordering may\n     * change at any point.\n     *\n     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n     * you perform all queries on the same block. See the following\n     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n     * for more information.\n     */\n    function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n    /**\n     * @dev Returns the number of accounts that have `role`. Can be used\n     * together with {getRoleMember} to enumerate all bearers of a role.\n     */\n    function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n"
      },
      "src/interfaces/swapper/ISyncSwapper.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { ISwapRouter } from \"src/interfaces/swapper/ISwapRouter.sol\";\n\ninterface ISyncSwapper {\n    error DataMismatch(string element);\n    error InvalidIndex();\n\n    /**\n     * @notice Swaps sellToken for buyToken\n     * @param pool The address of the pool for the swapper\n     * @param sellTokenAddress The address of the token to sell\n     * @param sellAmount The amount of sellToken to sell\n     * @param buyTokenAddress The address of the token to buy\n     * @param minBuyAmount The minimum amount of buyToken expected\n     * @param data Additional data used differently by the different swappers\n     * @return actualBuyAmount The actual amount received from the swap\n     */\n    function swap(\n        address pool,\n        address sellTokenAddress,\n        uint256 sellAmount,\n        address buyTokenAddress,\n        uint256 minBuyAmount,\n        bytes memory data\n    ) external returns (uint256 actualBuyAmount);\n\n    /**\n     * @notice Validates that the swapData contains the correct information, ensuring that the encoded data contains the\n     * correct 'fromAddress' and 'toAddress' (swapData.token), and verifies that these tokens are in the pool\n     * @dev This function should revert with a DataMismatch error if the swapData is invalid\n     * @param fromAddress The address from which the swap originates\n     * @param swapData The data associated with the swap that needs to be validated\n     */\n    function validate(address fromAddress, ISwapRouter.SwapData memory swapData) external view;\n}\n"
      },
      "src/interfaces/vault/IAutopool.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { AutopoolDebt } from \"src/vault/libs/AutopoolDebt.sol\";\nimport { IERC4626 } from \"src/interfaces/vault/IERC4626.sol\";\nimport { Math } from \"openzeppelin-contracts/utils/math/Math.sol\";\nimport { IAutopoolStrategy } from \"src/interfaces/strategy/IAutopoolStrategy.sol\";\nimport { IMainRewarder } from \"src/interfaces/rewarders/IMainRewarder.sol\";\nimport { IERC20Permit } from \"openzeppelin-contracts/token/ERC20/extensions/draft-IERC20Permit.sol\";\n\ninterface IAutopool is IERC4626, IERC20Permit {\n    enum VaultShutdownStatus {\n        Active,\n        Deprecated,\n        Exploit\n    }\n\n    /// @param unlockPeriodInSeconds Time it takes for profit to unlock in seconds\n    /// @param fullProfitUnlockTime Time at which all profit will have been unlocked\n    /// @param lastProfitUnlockTime Last time profits were unlocked\n    /// @param profitUnlockRate Per second rate at which profit shares unlocks. Rate when calculated is denominated in\n    /// MAX_BPS_PROFIT. TODO: Get into uint112\n    struct ProfitUnlockSettings {\n        uint48 unlockPeriodInSeconds;\n        uint48 fullProfitUnlockTime;\n        uint48 lastProfitUnlockTime;\n        uint256 profitUnlockRate;\n    }\n\n    /// @param feeSink Where claimed fees are sent\n    /// @param totalAssetsHighMark The last totalAssets amount we took fees at\n    /// @param totalAssetsHighMarkTimestamp The last timestamp we updated the high water mark\n    /// @param lastPeriodicFeeTake Timestamp of when the last periodic fee was taken.\n    /// @param periodicFeeSink Address that receives periodic fee.\n    /// @param periodicFeeBps Current periodic fee.  100% == 10000.\n    /// @param streamingFeeBps Current streaming fee taken on profit. 100% == 10000\n    /// @param navPerShareLastFeeMark The last nav/share height we took fees at\n    /// @param navPerShareLastFeeMarkTimestamp The last timestamp we took fees at\n    /// @param rebalanceFeeHighWaterMarkEnabled Returns whether the nav/share high water mark is enabled for the\n    /// rebalance fee\n    struct AutopoolFeeSettings {\n        address feeSink;\n        uint256 totalAssetsHighMark;\n        uint256 totalAssetsHighMarkTimestamp;\n        uint256 lastPeriodicFeeTake;\n        address periodicFeeSink;\n        uint256 periodicFeeBps;\n        uint256 streamingFeeBps;\n        uint256 navPerShareLastFeeMark;\n        uint256 navPerShareLastFeeMarkTimestamp;\n        bool rebalanceFeeHighWaterMarkEnabled;\n    }\n\n    /// @param totalIdle The amount of baseAsset deposited into the contract pending deployment\n    /// @param totalDebt The current (though cached) value of assets we've deployed\n    /// @param totalDebtMin The current (though cached) value of assets we use for valuing during deposits\n    /// @param totalDebtMax The current (though cached) value of assets we use for valuing during withdrawals\n    struct AssetBreakdown {\n        uint256 totalIdle;\n        uint256 totalDebt;\n        uint256 totalDebtMin;\n        uint256 totalDebtMax;\n    }\n\n    enum TotalAssetPurpose {\n        Global,\n        Deposit,\n        Withdraw\n    }\n\n    /* ******************************** */\n    /*      Events                      */\n    /* ******************************** */\n    event TokensPulled(address[] tokens, uint256[] amounts, address[] destinations);\n    event TokensRecovered(address[] tokens, uint256[] amounts, address[] destinations);\n    event Nav(uint256 idle, uint256 debt, uint256 totalSupply);\n    event RewarderSet(address newRewarder, address oldRewarder);\n    event DestinationDebtReporting(address destination, uint256 debtValue, uint256 claimed, uint256 claimGasUsed);\n    event FeeCollected(uint256 fees, address feeSink, uint256 mintedShares, uint256 profit, uint256 idle, uint256 debt);\n    event PeriodicFeeCollected(uint256 fees, address feeSink, uint256 mintedShares);\n    event Shutdown(VaultShutdownStatus reason);\n\n    /* ******************************** */\n    /*      Errors                      */\n    /* ******************************** */\n\n    error ERC4626MintExceedsMax(uint256 shares, uint256 maxMint);\n    error ERC4626DepositExceedsMax(uint256 assets, uint256 maxDeposit);\n    error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max);\n    error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max);\n    error InvalidShutdownStatus(VaultShutdownStatus status);\n\n    error WithdrawalFailed();\n    error DepositFailed();\n    error InsufficientFundsInDestinations(uint256 deficit);\n    error WithdrawalIncomplete();\n    error ValueSharesMismatch(uint256 value, uint256 shares);\n\n    /// @notice A full unit of this pool\n    // solhint-disable-next-line func-name-mixedcase\n    function ONE() external view returns (uint256);\n\n    /// @notice Query the type of vault\n    function vaultType() external view returns (bytes32);\n\n    /// @notice Strategy governing the pools rebalances\n    function autoPoolStrategy() external view returns (IAutopoolStrategy);\n\n    /// @notice Allow token recoverer to collect dust / unintended transfers (non-tracked assets only)\n    function recover(address[] calldata tokens, uint256[] calldata amounts, address[] calldata destinations) external;\n\n    /// @notice Set the order of destination vaults used for withdrawals\n    // NOTE: will be done going directly to strategy (IStrategy) vault points to.\n    //       How it'll delegate is still being decided\n    // function setWithdrawalQueue(address[] calldata destinations) external;\n\n    /// @notice Get a list of destination vaults with pending assets to clear out\n    function getRemovalQueue() external view returns (address[] memory);\n\n    function getFeeSettings() external view returns (AutopoolFeeSettings memory);\n\n    /// @notice Initiate the shutdown procedures for this vault\n    function shutdown(VaultShutdownStatus reason) external;\n\n    /// @notice True if the vault has been shutdown\n    function isShutdown() external view returns (bool);\n\n    /// @notice Returns the reason for shutdown (or `Active` if not shutdown)\n    function shutdownStatus() external view returns (VaultShutdownStatus);\n\n    /// @notice gets the list of supported destination vaults for the Autopool/Strategy\n    /// @return _destinations List of supported destination vaults\n    function getDestinations() external view returns (address[] memory _destinations);\n\n    function convertToShares(\n        uint256 assets,\n        uint256 totalAssetsForPurpose,\n        uint256 supply,\n        Math.Rounding rounding\n    ) external view returns (uint256 shares);\n\n    function convertToAssets(\n        uint256 shares,\n        uint256 totalAssetsForPurpose,\n        uint256 supply,\n        Math.Rounding rounding\n    ) external view returns (uint256 assets);\n\n    function totalAssets(TotalAssetPurpose purpose) external view returns (uint256);\n\n    function getAssetBreakdown() external view returns (AssetBreakdown memory);\n\n    /// @notice get a destinations last reported debt value\n    /// @param destVault the address of the target destination\n    /// @return destinations last reported debt value\n    function getDestinationInfo(address destVault) external view returns (AutopoolDebt.DestinationInfo memory);\n\n    /// @notice check if a destination is registered with the vault\n    function isDestinationRegistered(address destination) external view returns (bool);\n\n    /// @notice get if a destinationVault is queued for removal by the AutopoolETH\n    function isDestinationQueuedForRemoval(address destination) external view returns (bool);\n\n    /// @notice Returns instance of vault rewarder.\n    function rewarder() external view returns (IMainRewarder);\n\n    /// @notice Returns all past rewarders.\n    function getPastRewarders() external view returns (address[] memory _pastRewarders);\n\n    /// @notice Returns boolean telling whether address passed in is past rewarder.\n    function isPastRewarder(address _pastRewarder) external view returns (bool);\n}\n"
      },
      "src/interfaces/vault/IAutopilotRouterBase.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity >=0.8.7;\n\nimport { IAutopool } from \"src/interfaces/vault/IAutopool.sol\";\nimport { IMainRewarder } from \"src/interfaces/rewarders/IMainRewarder.sol\";\nimport { IERC20 } from \"openzeppelin-contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title AutopoolETH Router Base Interface\n * @notice A canonical router between AutopoolETHs\n *\n * The base router is a multicall style router inspired by Uniswap v3 with built-in features for permit,\n * WETH9 wrap/unwrap, and ERC20 token pulling/sweeping/approving. It includes methods for the four mutable\n * ERC4626 functions deposit/mint/withdraw/redeem as well.\n *\n * These can all be arbitrarily composed using the multicall functionality of the router.\n *\n * NOTE the router is capable of pulling any approved token from your wallet. This is only possible when\n * your address is msg.sender, but regardless be careful when interacting with the router or ERC4626 Vaults.\n * The router makes no special considerations for unique ERC20 implementations such as fee on transfer.\n * There are no built in protections for unexpected behavior beyond enforcing the minSharesOut is received.\n */\ninterface IAutopilotRouterBase {\n    /// @notice thrown when amount of assets received is below the min set by caller\n    error MinAmountError();\n\n    /// @notice thrown when amount of shares received is below the min set by caller\n    error MinSharesError();\n\n    /// @notice thrown when amount of assets received is above the max set by caller\n    error MaxAmountError();\n\n    /// @notice thrown when amount of shares received is above the max set by caller\n    error MaxSharesError();\n\n    /**\n     * @notice mint `shares` from an ERC4626 vault.\n     * @param vault The AutopoolETH to mint shares from.\n     * @param to The destination of ownership shares.\n     * @param shares The amount of shares to mint from `vault`.\n     * @param maxAmountIn The max amount of assets used to mint.\n     * @return amountIn the amount of assets used to mint by `to`.\n     * @dev throws MaxAmountError\n     */\n    function mint(\n        IAutopool vault,\n        address to,\n        uint256 shares,\n        uint256 maxAmountIn\n    ) external payable returns (uint256 amountIn);\n\n    /**\n     * @notice deposit `amount` to an ERC4626 vault.\n     * @param vault The AutopoolETH to deposit assets to.\n     * @param to The destination of ownership shares.\n     * @param amount The amount of assets to deposit to `vault`.\n     * @param minSharesOut The min amount of `vault` shares received by `to`.\n     * @return sharesOut the amount of shares received by `to`.\n     * @dev throws MinSharesError\n     */\n    function deposit(\n        IAutopool vault,\n        address to,\n        uint256 amount,\n        uint256 minSharesOut\n    ) external payable returns (uint256 sharesOut);\n\n    /**\n     * @notice withdraw `amount` from an ERC4626 vault.\n     * @param vault The AutopoolETH to withdraw assets from.\n     * @param to The destination of assets.\n     * @param amount The amount of assets to withdraw from vault.\n     * @param maxSharesOut The max amount of shares burned for assets requested.\n     * @return sharesOut the amount of shares received by `to`.\n     * @dev throws MaxSharesError\n     */\n    function withdraw(\n        IAutopool vault,\n        address to,\n        uint256 amount,\n        uint256 maxSharesOut\n    ) external payable returns (uint256 sharesOut);\n\n    /**\n     * @notice redeem `shares` shares from a AutopoolETH\n     * @param vault The AutopoolETH to redeem shares from.\n     * @param to The destination of assets.\n     * @param shares The amount of shares to redeem from vault.\n     * @param minAmountOut The min amount of assets received by `to`.\n     * @return amountOut the amount of assets received by `to`.\n     * @dev throws MinAmountError\n     */\n    function redeem(\n        IAutopool vault,\n        address to,\n        uint256 shares,\n        uint256 minAmountOut\n    ) external payable returns (uint256 amountOut);\n\n    /// @notice Stakes vault token to corresponding rewarder.\n    /// @param vault IERC20 instance of an Autopool to stake to.\n    /// @param maxAmount Maximum amount for user to stake.  Amount > balanceOf(user) will stake all present tokens.\n    /// @return staked Returns total amount staked.\n    function stakeVaultToken(IERC20 vault, uint256 maxAmount) external returns (uint256 staked);\n\n    /// @notice Unstakes vault token from corresponding rewarder.\n    /// @param vault IAutopool instance of the vault token to withdraw.\n    /// @param rewarder Rewarder to withdraw from.\n    /// @param maxAmount Amount of vault token to withdraw Amount > balanceOf(user) will withdraw all owned tokens.\n    /// @param claim Claiming rewards or not on unstaking.\n    /// @return withdrawn Amount of vault token withdrawn.\n    function withdrawVaultToken(\n        IAutopool vault,\n        IMainRewarder rewarder,\n        uint256 maxAmount,\n        bool claim\n    ) external returns (uint256 withdrawn);\n\n    /// @notice Claims rewards on user stake of vault token.\n    /// @param vault IAutopool instance of vault token to claim rewards for.\n    /// @param rewarder Rewarder to claim rewards from.\n    function claimAutopoolRewards(IAutopool vault, IMainRewarder rewarder) external;\n}\n"
      },
      "src/interfaces/rewarders/IRewards.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2024 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IERC20 } from \"openzeppelin-contracts/token/ERC20/IERC20.sol\";\n\n/**\n *  @title Validates and distributes Vault token rewards based on the\n *  the signed and submitted payloads\n */\ninterface IRewards {\n    struct Recipient {\n        uint256 chainId;\n        uint256 cycle;\n        address wallet;\n        uint256 amount;\n    }\n\n    event SignerSet(address newSigner);\n    event Claimed(uint256 cycle, address recipient, uint256 amount);\n\n    /// @notice Get the underlying token rewards are paid in\n    /// @return Token address\n    function vaultToken() external view returns (IERC20);\n\n    /// @notice Get the current payload signer;\n    /// @return Signer address\n    function rewardsSigner() external view returns (address);\n\n    /// @notice Check the amount an account has already claimed\n    /// @param account Account to check\n    /// @return Amount already claimed\n    function claimedAmounts(address account) external view returns (uint256);\n\n    /// @notice Get the amount that is claimable based on the provided payload\n    /// @param recipient Published rewards payload\n    /// @return Amount claimable if the payload is signed\n    function getClaimableAmount(Recipient calldata recipient) external view returns (uint256);\n\n    /// @notice Change the signer used to validate payloads\n    /// @param newSigner The new address that will be signing rewards payloads\n    function setSigner(address newSigner) external;\n\n    /// @notice Claim your rewards\n    /// @param recipient Published rewards payload\n    /// @param v v component of the payload signature\n    /// @param r r component of the payload signature\n    /// @param s s component of the payload signature\n    function claim(Recipient calldata recipient, uint8 v, bytes32 r, bytes32 s) external returns (uint256);\n\n    /// @notice Claim rewards on behalf of another account , invoked primarily by the router\n    /// @param recipient Published rewards payload\n    /// @param v v component of the payload signature\n    /// @param r r component of the payload signature\n    /// @param s s component of the payload signature\n    function claimFor(Recipient calldata recipient, uint8 v, bytes32 r, bytes32 s) external returns (uint256);\n\n    /// @notice Generate the hash of the payload\n    /// @param recipient Published rewards payload\n    /// @return Hash of the payload\n    function genHash(Recipient memory recipient) external view returns (bytes32);\n}\n"
      },
      "src/interfaces/liquidation/IAsyncSwapper.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nstruct SwapParams {\n    /// @dev The address of the token to be sold.\n    address sellTokenAddress;\n    /// @dev The amount of tokens to be sold.\n    uint256 sellAmount;\n    /// @dev The address of the token to be bought.\n    address buyTokenAddress;\n    /// @dev The expected minimum amount of tokens to be bought.\n    uint256 buyAmount;\n    /// @dev Data payload to be used for complex swap operations.\n    bytes data;\n    /// @dev Extra data payload reserved for future development. This field allows for additional information\n    /// or functionality to be added without changing the struct and interface.\n    bytes extraData;\n}\n\ninterface IAsyncSwapper {\n    error TokenAddressZero();\n    error SwapFailed();\n    error InsufficientBuyAmountReceived(uint256 buyTokenAmountReceived, uint256 buyAmount);\n    error InsufficientSellAmount();\n    error InsufficientBuyAmount();\n    error InsufficientBalance(uint256 balanceNeeded, uint256 balanceAvailable);\n\n    event Swapped(\n        address indexed sellTokenAddress,\n        address indexed buyTokenAddress,\n        uint256 sellAmount,\n        uint256 buyAmount,\n        uint256 buyTokenAmountReceived\n    );\n\n    /**\n     * @notice Swaps sellToken for buyToken\n     * @param swapParams Encoded swap data\n     * @return buyTokenAmountReceived The amount of buyToken received from the swap\n     */\n    function swap(SwapParams memory swapParams) external returns (uint256 buyTokenAmountReceived);\n}\n"
      },
      "src/interfaces/destinations/IDestinationAdapter.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\n/**\n * @title IDestinationAdapter\n * @dev This is a super-interface to unify different types of adapters to be registered in Destination Registry.\n *      Specific interface type is defined by extending from this interface.\n */\ninterface IDestinationAdapter {\n    error MustBeMoreThanZero();\n    error ArraysLengthMismatch();\n    error BalanceMustIncrease();\n    error MinLpAmountNotReached();\n    error LpTokenAmountMismatch();\n    error NoNonZeroAmountProvided();\n    error InvalidBalanceChange();\n    error InvalidAddress(address);\n}\n"
      },
      "src/interfaces/vault/IDestinationVaultFactory.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { ISystemComponent } from \"src/interfaces/ISystemComponent.sol\";\n\n/// @notice Creates and registers Destination Vaults for the system\ninterface IDestinationVaultFactory is ISystemComponent {\n    /// @notice Creates a vault of the specified type\n    /// @dev vaultType will be bytes32 encoded and checked that a template is registered\n    /// @param vaultType human readable key of the vault template\n    /// @param baseAsset Base asset of the system. WETH/USDC/etc\n    /// @param underlyer Underlying asset the vault will wrap\n    /// @param incentiveCalculator Incentive calculator of the vault\n    /// @param additionalTrackedTokens Any tokens in addition to base and underlyer that should be tracked\n    /// @param salt Contracts are created via CREATE2 with this value\n    /// @param params params to be passed to vaults initialize function\n    /// @return vault address of the newly created destination vault\n    function create(\n        string memory vaultType,\n        address baseAsset,\n        address underlyer,\n        address incentiveCalculator,\n        address[] memory additionalTrackedTokens,\n        bytes32 salt,\n        bytes memory params\n    ) external returns (address vault);\n\n    /// @notice Sets the default reward ratio\n    /// @param rewardRatio new default reward ratio\n    function setDefaultRewardRatio(uint256 rewardRatio) external;\n\n    /// @notice Sets the default reward block duration\n    /// @param blockDuration new default reward block duration\n    function setDefaultRewardBlockDuration(uint256 blockDuration) external;\n}\n"
      },
      "src/interfaces/stats/IStatsCalculator.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\n/// @title Capture information about a pool or destination\ninterface IStatsCalculator {\n    /// @notice thrown when no snapshot is taken\n    error NoSnapshotTaken();\n\n    /// @notice The id for this instance of a calculator\n    function getAprId() external view returns (bytes32);\n\n    /// @notice The id of the underlying asset/pool/destination this calculator represents\n    /// @dev This may be a generated address\n    function getAddressId() external view returns (address);\n\n    /// @notice Setup the calculator after it has been copied\n    /// @dev Should only be executed one time\n    /// @param dependentAprIds apr ids that cover the dependencies of this calculator\n    /// @param initData setup data specific to this type of calculator\n    function initialize(bytes32[] calldata dependentAprIds, bytes calldata initData) external;\n\n    /// @notice Capture stat data about this setup\n    function snapshot() external;\n\n    /// @notice Indicates if a snapshot should be taken\n    /// @return takeSnapshot if true then a snapshot should be taken. If false, calling snapshot will do nothing\n    function shouldSnapshot() external view returns (bool takeSnapshot);\n\n    /// @dev Enum representing the snapshot status for a given rewarder (Convex and Aura) or reward token (Maverick)\n    enum SnapshotStatus {\n        noSnapshot, // Indicates that no snapshot has been taken yet for the rewarder.\n        tooSoon, // Indicates that it's too soon to take another snapshot since the last one.\n        shouldFinalize, // Indicates that the conditions are met for finalizing a snapshot.\n        shouldRestart // Indicates that the conditions are met for restarting a snapshot.\n\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/access/IAccessControl.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     *\n     * _Available since v3.1._\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call, an admin role\n     * bearer except when using {AccessControl-_setupRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     */\n    function renounceRole(bytes32 role, address account) external;\n}\n"
      },
      "src/vault/libs/AutopoolDebt.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\n\npragma solidity 0.8.17;\n\nimport { Errors } from \"src/utils/Errors.sol\";\nimport { LibAdapter } from \"src/libs/LibAdapter.sol\";\nimport { IDestinationVault } from \"src/interfaces/vault/IDestinationVault.sol\";\nimport { Math } from \"openzeppelin-contracts/utils/math/Math.sol\";\nimport { EnumerableSet } from \"openzeppelin-contracts/utils/structs/EnumerableSet.sol\";\nimport { IStrategy } from \"src/interfaces/strategy/IStrategy.sol\";\nimport { SafeERC20 } from \"openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20Metadata as IERC20 } from \"openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC3156FlashBorrower } from \"openzeppelin-contracts/interfaces/IERC3156FlashBorrower.sol\";\nimport { IAutopoolStrategy } from \"src/interfaces/strategy/IAutopoolStrategy.sol\";\nimport { StructuredLinkedList } from \"src/strategy/StructuredLinkedList.sol\";\nimport { WithdrawalQueue } from \"src/strategy/WithdrawalQueue.sol\";\nimport { IAutopool } from \"src/interfaces/vault/IAutopool.sol\";\nimport { IMainRewarder } from \"src/interfaces/rewarders/IMainRewarder.sol\";\nimport { AutopoolToken } from \"src/vault/libs/AutopoolToken.sol\";\n\nlibrary AutopoolDebt {\n    using Math for uint256;\n    using SafeERC20 for IERC20;\n    using WithdrawalQueue for StructuredLinkedList.List;\n    using EnumerableSet for EnumerableSet.AddressSet;\n    using AutopoolToken for AutopoolToken.TokenData;\n\n    /// @notice Max time a cached debt report can be used\n    uint256 public constant MAX_DEBT_REPORT_AGE_SECONDS = 1 days;\n\n    error VaultShutdown();\n    error WithdrawShareCalcInvalid(uint256 currentShares, uint256 cachedShares);\n    error RebalanceDestinationsMatch(address destinationVault);\n    error RebalanceFailed(string message);\n    error InvalidPrices();\n    error InvalidTotalAssetPurpose();\n    error InvalidDestination(address destination);\n    error TooFewAssets(uint256 requested, uint256 actual);\n    error SharesAndAssetsReceived(uint256 assets, uint256 shares);\n    error AmountExceedsAllowance(uint256 shares, uint256 allowed);\n\n    event DestinationDebtReporting(\n        address destination, AutopoolDebt.IdleDebtUpdates debtInfo, uint256 claimed, uint256 claimGasUsed\n    );\n    event NewNavShareFeeMark(uint256 navPerShare, uint256 timestamp);\n    event Nav(uint256 idle, uint256 debt, uint256 totalSupply);\n    event Withdraw(\n        address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares\n    );\n\n    struct DestinationInfo {\n        /// @notice Current underlying value at the destination vault\n        /// @dev Used for calculating totalDebt, mid point of min and max\n        uint256 cachedDebtValue;\n        /// @notice Current minimum underlying value at the destination vault\n        /// @dev Used for calculating totalDebt during withdrawal\n        uint256 cachedMinDebtValue;\n        /// @notice Current maximum underlying value at the destination vault\n        /// @dev Used for calculating totalDebt of the deposit\n        uint256 cachedMaxDebtValue;\n        /// @notice Last block timestamp this info was updated\n        uint256 lastReport;\n        /// @notice How many shares of the destination vault we owned at last report\n        uint256 ownedShares;\n    }\n\n    struct IdleDebtUpdates {\n        bool pricesWereSafe;\n        uint256 totalIdleDecrease;\n        uint256 totalIdleIncrease;\n        uint256 totalDebtIncrease;\n        uint256 totalDebtDecrease;\n        uint256 totalMinDebtIncrease;\n        uint256 totalMinDebtDecrease;\n        uint256 totalMaxDebtIncrease;\n        uint256 totalMaxDebtDecrease;\n    }\n\n    struct RebalanceOutParams {\n        /// Address that will received the withdrawn underlyer\n        address receiver;\n        /// The \"out\" destination vault\n        address destinationOut;\n        /// The amount of tokenOut that will be withdrawn\n        uint256 amountOut;\n        /// The underlyer for destinationOut\n        address tokenOut;\n        IERC20 _baseAsset;\n        bool _shutdown;\n    }\n\n    /// @dev In memory struct only for managing vars in _withdraw\n    struct WithdrawInfo {\n        uint256 currentIdle;\n        uint256 assetsFromIdle;\n        uint256 totalAssetsToPull;\n        uint256 assetsToPull;\n        uint256 assetsPulled;\n        uint256 idleIncrease;\n        uint256 debtDecrease;\n        uint256 debtMinDecrease;\n        uint256 debtMaxDecrease;\n        uint256 totalMinDebt;\n        uint256 destinationRound;\n        uint256 lastRoundSlippage;\n        uint256 expectedAssets;\n    }\n\n    struct FlashRebalanceParams {\n        uint256 totalIdle;\n        uint256 totalDebt;\n        IERC20 baseAsset;\n        bool shutdown;\n    }\n\n    struct FlashResultInfo {\n        uint256 tokenInBalanceBefore;\n        uint256 tokenInBalanceAfter;\n        bytes32 flashResult;\n    }\n\n    function flashRebalance(\n        DestinationInfo storage destInfoOut,\n        DestinationInfo storage destInfoIn,\n        IERC3156FlashBorrower receiver,\n        IStrategy.RebalanceParams memory params,\n        IStrategy.SummaryStats memory destSummaryOut,\n        IAutopoolStrategy autoPoolStrategy,\n        FlashRebalanceParams memory flashParams,\n        bytes calldata data\n    ) external returns (IdleDebtUpdates memory result) {\n        // Handle decrease (shares going \"Out\", cashing in shares and sending underlying back to swapper)\n        // If the tokenOut is _asset we assume they are taking idle\n        // which is already in the contract\n        result = _handleRebalanceOut(\n            AutopoolDebt.RebalanceOutParams({\n                receiver: address(receiver),\n                destinationOut: params.destinationOut,\n                amountOut: params.amountOut,\n                tokenOut: params.tokenOut,\n                _baseAsset: flashParams.baseAsset,\n                _shutdown: flashParams.shutdown\n            }),\n            destInfoOut\n        );\n\n        if (!result.pricesWereSafe) {\n            revert InvalidPrices();\n        }\n\n        // Handle increase (shares coming \"In\", getting underlying from the swapper and trading for new shares)\n        if (params.amountIn > 0) {\n            FlashResultInfo memory flashResultInfo;\n            // get \"before\" counts\n            flashResultInfo.tokenInBalanceBefore = IERC20(params.tokenIn).balanceOf(address(this));\n\n            // Give control back to the solver so they can make use of the \"out\" assets\n            // and get our \"in\" asset\n            flashResultInfo.flashResult = receiver.onFlashLoan(msg.sender, params.tokenIn, params.amountIn, 0, data);\n\n            // We assume the solver will send us the assets\n            flashResultInfo.tokenInBalanceAfter = IERC20(params.tokenIn).balanceOf(address(this));\n\n            // Make sure the call was successful and verify we have at least the assets we think\n            // we were getting\n            if (\n                flashResultInfo.flashResult != keccak256(\"ERC3156FlashBorrower.onFlashLoan\")\n                    || flashResultInfo.tokenInBalanceAfter < flashResultInfo.tokenInBalanceBefore + params.amountIn\n            ) {\n                revert Errors.FlashLoanFailed(params.tokenIn, params.amountIn);\n            }\n\n            {\n                // make sure we have a valid path\n                (bool success, string memory message) = autoPoolStrategy.verifyRebalance(params, destSummaryOut);\n                if (!success) {\n                    revert RebalanceFailed(message);\n                }\n            }\n\n            if (params.tokenIn != address(flashParams.baseAsset)) {\n                IdleDebtUpdates memory inDebtResult = _handleRebalanceIn(\n                    destInfoIn,\n                    IDestinationVault(params.destinationIn),\n                    params.tokenIn,\n                    flashResultInfo.tokenInBalanceAfter\n                );\n                if (!inDebtResult.pricesWereSafe) {\n                    revert InvalidPrices();\n                }\n                result.totalDebtDecrease += inDebtResult.totalDebtDecrease;\n                result.totalDebtIncrease += inDebtResult.totalDebtIncrease;\n                result.totalMinDebtDecrease += inDebtResult.totalMinDebtDecrease;\n                result.totalMinDebtIncrease += inDebtResult.totalMinDebtIncrease;\n                result.totalMaxDebtDecrease += inDebtResult.totalMaxDebtDecrease;\n                result.totalMaxDebtIncrease += inDebtResult.totalMaxDebtIncrease;\n            } else {\n                result.totalIdleIncrease += flashResultInfo.tokenInBalanceAfter - flashResultInfo.tokenInBalanceBefore;\n            }\n        }\n    }\n\n    /// @notice Perform deposit and debt info update for the \"in\" destination during a rebalance\n    /// @dev This \"in\" function performs less validations than its \"out\" version\n    /// @param dvIn The \"in\" destination vault\n    /// @param tokenIn The underlyer for dvIn\n    /// @param depositAmount The amount of tokenIn that will be deposited\n    /// @return result Changes in debt values\n    function _handleRebalanceIn(\n        DestinationInfo storage destInfo,\n        IDestinationVault dvIn,\n        address tokenIn,\n        uint256 depositAmount\n    ) private returns (IdleDebtUpdates memory result) {\n        LibAdapter._approve(IERC20(tokenIn), address(dvIn), depositAmount);\n\n        // Snapshot our current shares so we know how much to back out\n        uint256 originalShareBal = dvIn.balanceOf(address(this));\n\n        // deposit to dv\n        uint256 newShares = dvIn.depositUnderlying(depositAmount);\n\n        // Update the debt info snapshot\n        result = _recalculateDestInfo(destInfo, dvIn, originalShareBal, originalShareBal + newShares);\n    }\n\n    /**\n     * @notice Perform withdraw and debt info update for the \"out\" destination during a rebalance\n     * @dev This \"out\" function performs more validations and handles idle as opposed to \"in\" which does not\n     *  debtDecrease The previous amount of debt destinationOut accounted for in totalDebt\n     *  debtIncrease The current amount of debt destinationOut should account for in totalDebt\n     *  idleDecrease Amount of baseAsset that was sent from the vault. > 0 only when tokenOut == baseAsset\n     *  idleIncrease Amount of baseAsset that was claimed from Destination Vault\n     * @param params Rebalance out params\n     * @param destOutInfo The \"out\" destination vault info\n     * @return assetChange debt and idle change data\n     */\n    function _handleRebalanceOut(\n        RebalanceOutParams memory params,\n        DestinationInfo storage destOutInfo\n    ) private returns (IdleDebtUpdates memory assetChange) {\n        // Handle decrease (shares going \"Out\", cashing in shares and sending underlying back to swapper)\n        // If the tokenOut is _asset we assume they are taking idle\n        // which is already in the contract\n        if (params.amountOut > 0) {\n            if (params.tokenOut != address(params._baseAsset)) {\n                IDestinationVault dvOut = IDestinationVault(params.destinationOut);\n\n                // Snapshot our current shares so we know how much to back out\n                uint256 originalShareBal = dvOut.balanceOf(address(this));\n\n                // Burning our shares will claim any pending baseAsset\n                // rewards and send them to us.\n                // Get our starting balance\n                uint256 beforeBaseAssetBal = params._baseAsset.balanceOf(address(this));\n\n                // Withdraw underlying from the destination vault\n                // Shares are sent directly to the flashRebalance receiver\n                // slither-disable-next-line unused-return\n                dvOut.withdrawUnderlying(params.amountOut, params.receiver);\n\n                // Update the debt info snapshot\n                assetChange =\n                    _recalculateDestInfo(destOutInfo, dvOut, originalShareBal, originalShareBal - params.amountOut);\n\n                // Capture any rewards we may have claimed as part of withdrawing\n                assetChange.totalIdleIncrease = params._baseAsset.balanceOf(address(this)) - beforeBaseAssetBal;\n            } else {\n                // If we are shutdown then the only operations we should be performing are those that get\n                // the base asset back to the vault. We shouldn't be sending out more\n\n                if (params._shutdown) {\n                    revert VaultShutdown();\n                }\n                // Working with idle baseAsset which should be in the vault already\n                // Just send it out\n                IERC20(params.tokenOut).safeTransfer(params.receiver, params.amountOut);\n                assetChange.totalIdleDecrease = params.amountOut;\n\n                // We weren't dealing with any debt or pricing, just idle, so we can just mark\n                // it as safe\n                assetChange.pricesWereSafe = true;\n            }\n        }\n    }\n\n    function recalculateDestInfo(\n        DestinationInfo storage destInfo,\n        IDestinationVault destVault,\n        uint256 originalShares,\n        uint256 currentShares\n    ) external returns (IdleDebtUpdates memory result) {\n        result = _recalculateDestInfo(destInfo, destVault, originalShares, currentShares);\n    }\n\n    /// @dev Will not revert on unsafe prices. Up to the caller.\n    function _recalculateDestInfo(\n        DestinationInfo storage destInfo,\n        IDestinationVault destVault,\n        uint256 originalShares,\n        uint256 currentShares\n    ) private returns (IdleDebtUpdates memory result) {\n        // TODO: Trace the use of this fn and ensure that every is handling is pricesWereSafe\n\n        // Figure out what to back out of our totalDebt number.\n        // We could have had withdraws since the last snapshot which means our\n        // cached currentDebt number should be decreased based on the remaining shares\n        // totalDebt is decreased using the same proportion of shares method during withdrawals\n        // so this should represent whatever is remaining.\n\n        // Prices are per LP token and whether or not the prices are safe to use\n        // If they aren't safe then just continue and we'll get it on the next go around\n        (uint256 spotPrice, uint256 safePrice, bool isSpotSafe) = destVault.getRangePricesLP();\n\n        // Calculate what we're backing out based on the original shares\n        uint256 minPrice = spotPrice > safePrice ? safePrice : spotPrice;\n        uint256 maxPrice = spotPrice > safePrice ? spotPrice : safePrice;\n\n        // If we previously had shares, calculate how much of our cached numbers\n        // still remain as this will be deducted from the overall debt numbers\n        // TODO: Evaluate whether to round these up so we don't accumulate small amounts\n        // over time\n        uint256 prevOwnedShares = destInfo.ownedShares;\n        if (prevOwnedShares > 0) {\n            result.totalDebtDecrease = (destInfo.cachedDebtValue * originalShares) / prevOwnedShares;\n            result.totalMinDebtDecrease = (destInfo.cachedMinDebtValue * originalShares) / prevOwnedShares;\n            result.totalMaxDebtDecrease = (destInfo.cachedMaxDebtValue * originalShares) / prevOwnedShares;\n        }\n\n        // The overall debt value is the mid point of min and max\n        uint256 div = 10 ** destVault.decimals();\n        uint256 newDebtValue = (minPrice * currentShares + maxPrice * currentShares) / (div * 2);\n\n        result.pricesWereSafe = isSpotSafe;\n        result.totalDebtIncrease = newDebtValue;\n        result.totalMinDebtIncrease = minPrice * currentShares / div;\n        result.totalMaxDebtIncrease = maxPrice * currentShares / div;\n\n        // Save our current new values\n        destInfo.cachedDebtValue = newDebtValue;\n        destInfo.cachedMinDebtValue = result.totalMinDebtIncrease;\n        destInfo.cachedMaxDebtValue = result.totalMaxDebtIncrease;\n        destInfo.lastReport = block.timestamp;\n        destInfo.ownedShares = currentShares;\n    }\n\n    function totalAssetsTimeChecked(\n        StructuredLinkedList.List storage debtReportQueue,\n        mapping(address => AutopoolDebt.DestinationInfo) storage destinationInfo,\n        IAutopool.TotalAssetPurpose purpose\n    ) external returns (uint256) {\n        IDestinationVault destVault = IDestinationVault(debtReportQueue.peekHead());\n        uint256 recalculatedTotalAssets = IAutopool(address(this)).totalAssets(purpose);\n\n        while (address(destVault) != address(0)) {\n            uint256 lastReport = destinationInfo[address(destVault)].lastReport;\n\n            if (lastReport + MAX_DEBT_REPORT_AGE_SECONDS > block.timestamp) {\n                // Its not stale\n\n                // This report is OK, we don't need to recalculate anything\n                break;\n            } else {\n                // It is stale, recalculate\n\n                //slither-disable-next-line unused-return\n                uint256 currentShares = destVault.balanceOf(address(this));\n                uint256 staleDebt;\n                uint256 extremePrice;\n\n                // Figure out exactly which price to use based on its purpose\n                if (purpose == IAutopool.TotalAssetPurpose.Deposit) {\n                    // We use max value so that anything deposited is worth less\n                    extremePrice = destVault.getUnderlyerCeilingPrice();\n\n                    // Round down. We are subtracting this value out of the total so some left\n                    // behind just increases the value which is what we want\n                    staleDebt = destinationInfo[address(destVault)].cachedMaxDebtValue.mulDiv(\n                        currentShares, destinationInfo[address(destVault)].ownedShares, Math.Rounding.Down\n                    );\n                } else if (purpose == IAutopool.TotalAssetPurpose.Withdraw) {\n                    // We use min value so that we value the shares as worth less\n                    extremePrice = destVault.getUnderlyerFloorPrice();\n                    // Round up. We are subtracting this value out of the total so if we take a little\n                    // extra it just decreases the value which is what we want\n                    staleDebt = destinationInfo[address(destVault)].cachedMinDebtValue.mulDiv(\n                        currentShares, destinationInfo[address(destVault)].ownedShares, Math.Rounding.Up\n                    );\n                } else {\n                    revert InvalidTotalAssetPurpose();\n                }\n\n                // Back out our stale debt, add in its new value\n                // Our goal is to find the most conservative value in each situation. If the current\n                // value we have represents that, then use it. Otherwise, use the new one.\n                uint256 newValue = (currentShares * extremePrice) / destVault.ONE();\n\n                if (purpose == IAutopool.TotalAssetPurpose.Deposit && staleDebt > newValue) {\n                    newValue = staleDebt;\n                } else if (purpose == IAutopool.TotalAssetPurpose.Withdraw && staleDebt < newValue) {\n                    newValue = staleDebt;\n                }\n\n                recalculatedTotalAssets = recalculatedTotalAssets + newValue - staleDebt;\n            }\n\n            destVault = IDestinationVault(debtReportQueue.getAdjacent(address(destVault), true));\n        }\n\n        return recalculatedTotalAssets;\n    }\n\n    function _updateDebtReporting(\n        StructuredLinkedList.List storage debtReportQueue,\n        mapping(address => AutopoolDebt.DestinationInfo) storage destinationInfo,\n        uint256 numToProcess\n    ) external returns (IdleDebtUpdates memory result) {\n        numToProcess = Math.min(numToProcess, debtReportQueue.sizeOf());\n\n        for (uint256 i = 0; i < numToProcess; ++i) {\n            IDestinationVault destVault = IDestinationVault(debtReportQueue.popHead());\n\n            // Get the reward value we've earned. DV rewards are always in terms of base asset\n            // We track the gas used purely for off-chain stats purposes\n            // Main rewarder on DV's store the earned and liquidated rewards\n            // Extra rewarders are disabled at the DV level\n            uint256 claimGasUsed = gasleft();\n            uint256 beforeBaseAsset = IERC20(IAutopool(address(this)).asset()).balanceOf(address(this));\n            IMainRewarder(destVault.rewarder()).getReward(address(this), false);\n            uint256 claimedRewardValue =\n                IERC20(IAutopool(address(this)).asset()).balanceOf(address(this)) - beforeBaseAsset;\n            result.totalIdleIncrease += claimedRewardValue;\n\n            // Recalculate the debt info figuring out the change in\n            // total debt value we can roll up later\n            uint256 currentShareBalance = destVault.balanceOf(address(this));\n\n            AutopoolDebt.IdleDebtUpdates memory debtResult = _recalculateDestInfo(\n                destinationInfo[address(destVault)], destVault, currentShareBalance, currentShareBalance\n            );\n\n            result.totalDebtDecrease += debtResult.totalDebtDecrease;\n            result.totalDebtIncrease += debtResult.totalDebtIncrease;\n            result.totalMinDebtDecrease += debtResult.totalMinDebtDecrease;\n            result.totalMinDebtIncrease += debtResult.totalMinDebtIncrease;\n            result.totalMaxDebtDecrease += debtResult.totalMaxDebtDecrease;\n            result.totalMaxDebtIncrease += debtResult.totalMaxDebtIncrease;\n\n            // If we no longer have shares, then there's no reason to continue reporting on the destination.\n            // The strategy will only call for the info if its moving \"out\" of the destination\n            // and that will only happen if we have shares.\n            // A rebalance where we move \"in\" to the position will refresh the data at that time\n            if (currentShareBalance > 0) {\n                debtReportQueue.addToTail(address(destVault));\n            }\n\n            claimGasUsed -= gasleft();\n\n            emit DestinationDebtReporting(address(destVault), debtResult, claimedRewardValue, claimGasUsed);\n        }\n    }\n\n    function _initiateWithdrawInfo(\n        uint256 assets,\n        IAutopool.AssetBreakdown storage assetBreakdown\n    ) private view returns (WithdrawInfo memory) {\n        uint256 idle = assetBreakdown.totalIdle;\n        WithdrawInfo memory info = WithdrawInfo({\n            currentIdle: idle,\n            // If idle can cover the full amount, then we want to pull all assets from there\n            // Otherwise, we want to pull from the market and only get idle if we exhaust the market\n            assetsFromIdle: assets > idle ? 0 : assets,\n            totalAssetsToPull: 0,\n            assetsToPull: 0,\n            assetsPulled: 0,\n            idleIncrease: 0,\n            debtDecrease: 0,\n            debtMinDecrease: 0,\n            debtMaxDecrease: 0,\n            totalMinDebt: assetBreakdown.totalDebtMin,\n            destinationRound: 0,\n            lastRoundSlippage: 0,\n            expectedAssets: 0\n        });\n\n        info.totalAssetsToPull = assets - info.assetsFromIdle;\n\n        // This var we use to track our progress later\n        info.assetsToPull = assets - info.assetsFromIdle;\n\n        // Idle + minDebt is the maximum amount of assets/debt we could burn during a withdraw.\n        // If the user is request more than that (like during a withdraw) we can just revert\n        // early without trying\n        if (info.totalAssetsToPull > info.currentIdle + info.totalMinDebt) {\n            revert TooFewAssets(assets, info.currentIdle + info.totalMinDebt);\n        }\n\n        return info;\n    }\n\n    function withdraw(\n        uint256 assets,\n        uint256 applicableTotalAssets,\n        IAutopool.AssetBreakdown storage assetBreakdown,\n        StructuredLinkedList.List storage withdrawalQueue,\n        mapping(address => AutopoolDebt.DestinationInfo) storage destinationInfo\n    ) public returns (uint256 actualAssets, uint256 actualShares, uint256 debtBurned) {\n        WithdrawInfo memory info = _initiateWithdrawInfo(assets, assetBreakdown);\n\n        // Pull the market if there aren't enough funds in idle to cover the entire amount\n\n        // This flow is not bounded by a set number of shares. The user has requested X assets\n        // and a variable number of shares to burn so we don't have easy break out points like we do\n        // during redeem (like using debt burned). When we get slippage here and don't meet the requested assets\n        // we need to keep going if we can. This is tricky if we consider that (most of) our destinations are\n        // LP positions and we'll be swapping assets, so we can expect some slippage. Even\n        // if our minDebtValue numbers are up to date and perfectly accurate slippage could ensure we\n        // are always receiving less than we expect/calculate and we never hit the requested assets\n        // even though the owner would have shares to cover it. Under normal/expected conditions, our\n        // minDebtValue is lower than actual and we expect overall value to be going up, so we burn a tad\n        // more than we should and receive a tad more than we expect. This should cover us. However,\n        // in other conditions we have to be sure we aren't endlessly trying to approach 0 so we are tracking\n        // the slippage we received on the last pull, repricing, and applying an increasing multiplier until we either\n        // pull enough to cover or pull them all and/or move to the next destination.\n\n        uint256 dvSharesToBurn;\n        while (info.assetsToPull > 0) {\n            IDestinationVault destVault = IDestinationVault(withdrawalQueue.peekHead());\n            if (address(destVault) == address(0)) {\n                // TODO: This may be some NULL value too, check the underlying library\n                break;\n            }\n\n            uint256 dvShares = destVault.balanceOf(address(this));\n            {\n                uint256 dvSharesValue;\n                if (info.destinationRound == 0) {\n                    // First time pulling\n\n                    // We use the min debt value here because its a withdrawal and we're trying to cover an amount\n                    // of assets. Undervaluing the shares may mean we pull more but given that we expect slippage\n                    // that is desirable.\n                    dvSharesValue = destinationInfo[address(destVault)].cachedMinDebtValue * dvShares\n                        / destinationInfo[address(destVault)].ownedShares;\n                } else {\n                    // When we've pulled from this destination before, i.e. destinationRound > 0, then we\n                    // know a more accurate exchange rate and its worse than we were expecting.\n                    // We even will pad it a bit as we want to account for any additional slippage we\n                    // may receive by say being farther down an AMM curve.\n\n                    // dvSharesToBurn is the last value we used when pulling from this destination\n                    // info.expectedAssets is how much we expected to get on that last pull\n                    // info.expectedAssets - info.lastRoundSlippage is how much we actually received\n\n                    uint256 paddedSlippage = info.lastRoundSlippage * (info.destinationRound + 10_000) / 10_000;\n\n                    if (paddedSlippage < info.expectedAssets) {\n                        dvSharesValue = (info.expectedAssets - paddedSlippage) * dvShares / dvSharesToBurn;\n                    } else {\n                        // This will just mean we pull all shares\n                        dvSharesValue = 0;\n                    }\n                }\n\n                if (dvSharesValue > info.assetsToPull) {\n                    dvSharesToBurn = (dvShares * info.assetsToPull) / dvSharesValue;\n                    // Only need to set it here because the only time we'll use it is if\n                    // we don't exhaust all shares and have to try the destination again\n                    info.expectedAssets = info.assetsToPull;\n                } else {\n                    dvSharesToBurn = dvShares;\n                }\n            }\n\n            // Destination Vaults always burn the exact amount we instruct them to\n            uint256 pulledAssets = destVault.withdrawBaseAsset(dvSharesToBurn, address(this));\n\n            info.assetsPulled += pulledAssets;\n\n            // Calculate the totalDebt we'll need to remove based on the shares we're burning\n            // We're rounding up here so take care when actually applying to totalDebt\n            // The assets we calculated to pull are from the minDebt number we track so\n            // we'll use that one to ensure we properly account for slippage (the `pulled` var below)\n            // The other two debt numbers we just need to keep up to date.\n            uint256 debtMinDecrease = destinationInfo[address(destVault)].cachedMinDebtValue.mulDiv(\n                dvSharesToBurn, destinationInfo[address(destVault)].ownedShares, Math.Rounding.Up\n            );\n            info.debtMinDecrease += debtMinDecrease;\n\n            info.debtDecrease += destinationInfo[address(destVault)].cachedDebtValue.mulDiv(\n                dvSharesToBurn, destinationInfo[address(destVault)].ownedShares, Math.Rounding.Up\n            );\n            info.debtMaxDecrease += destinationInfo[address(destVault)].cachedMaxDebtValue.mulDiv(\n                dvSharesToBurn, destinationInfo[address(destVault)].ownedShares, Math.Rounding.Up\n            );\n\n            // If we've exhausted all shares we can remove the withdrawal from the queue\n            // We need to leave it in the debt report queue though so that our destination specific\n            // debt tracking values can be updated\n            if (dvShares == dvSharesToBurn) {\n                withdrawalQueue.popAddress(address(destVault));\n                info.destinationRound = 0;\n                info.lastRoundSlippage = 0;\n            } else {\n                // If we didn't burn all the shares and we received enough to cover our\n                // expected that means we'll break out below as we've hit our target\n                unchecked {\n                    if (pulledAssets < info.expectedAssets) {\n                        info.lastRoundSlippage = info.expectedAssets - pulledAssets;\n                        if (info.destinationRound == 0) {\n                            info.destinationRound = 100;\n                        } else {\n                            info.destinationRound *= 2;\n                        }\n                    }\n                }\n            }\n\n            // It's possible we'll get back more assets than we anticipate from a swap\n            // so if we do, throw it in idle and stop processing. You don't get more than we've calculated\n            if (info.assetsPulled >= info.totalAssetsToPull) {\n                info.idleIncrease += info.assetsPulled - info.totalAssetsToPull;\n                info.assetsPulled = info.totalAssetsToPull;\n                break;\n            }\n\n            info.assetsToPull -= pulledAssets;\n        }\n\n        // info.assetsToPull isn't safe to use past this point.\n        // It may or may not be accurate from the previous loop\n\n        // We didn't get enough assets from the debt pull\n        // See if we can get the rest from idle\n        if (info.assetsPulled < assets && info.currentIdle > 0) {\n            uint256 remaining = assets - info.assetsPulled;\n            if (remaining <= info.currentIdle) {\n                info.assetsFromIdle = remaining;\n            }\n            // We don't worry about the else case because if currentIdle can't\n            // cover remaining then we'll fail the `actualAssets < assets`\n            // check below and revert\n        }\n\n        debtBurned = info.assetsFromIdle + info.debtMinDecrease;\n        actualAssets = info.assetsFromIdle + info.assetsPulled;\n\n        if (actualAssets < assets) {\n            revert TooFewAssets(assets, actualAssets);\n        }\n\n        actualShares = IAutopool(address(this)).convertToShares(\n            Math.max(actualAssets, debtBurned),\n            applicableTotalAssets,\n            IAutopool(address(this)).totalSupply(),\n            Math.Rounding.Up\n        );\n\n        // Subtract what's taken out of idle from totalIdle\n        // We may also have some increase to account for it we over pulled\n        // or received better execution than we were anticipating\n        // slither-disable-next-line events-maths\n        assetBreakdown.totalIdle = info.currentIdle + info.idleIncrease - info.assetsFromIdle;\n\n        // Save off our various debt numbers\n        if (info.debtDecrease > assetBreakdown.totalDebt) {\n            assetBreakdown.totalDebt = 0;\n        } else {\n            assetBreakdown.totalDebt -= info.debtDecrease;\n        }\n\n        if (info.debtMinDecrease > info.totalMinDebt) {\n            assetBreakdown.totalDebtMin = 0;\n        } else {\n            assetBreakdown.totalDebtMin -= info.debtMinDecrease;\n        }\n\n        if (info.debtMaxDecrease > assetBreakdown.totalDebtMax) {\n            assetBreakdown.totalDebtMax = 0;\n        } else {\n            assetBreakdown.totalDebtMax -= info.debtMaxDecrease;\n        }\n    }\n\n    /// @notice Perform a removal of assets via the redeem path where the shares are the limiting factor.\n    /// This means we break out whenever we reach either `assets` retrieved or debt value equivalent to `assets` burned\n    function redeem(\n        uint256 assets,\n        uint256 applicableTotalAssets,\n        IAutopool.AssetBreakdown storage assetBreakdown,\n        StructuredLinkedList.List storage withdrawalQueue,\n        mapping(address => AutopoolDebt.DestinationInfo) storage destinationInfo\n    ) public returns (uint256 actualAssets, uint256 actualShares, uint256 debtBurned) {\n        WithdrawInfo memory info = _initiateWithdrawInfo(assets, assetBreakdown);\n\n        // If not enough funds in idle, then pull what we need from destinations\n        bool exhaustedDestinations = false;\n        while (info.assetsToPull > 0) {\n            IDestinationVault destVault = IDestinationVault(withdrawalQueue.peekHead());\n            if (address(destVault) == address(0)) {\n                exhaustedDestinations = true;\n                break;\n            }\n\n            uint256 dvShares = destVault.balanceOf(address(this));\n            uint256 dvSharesToBurn = dvShares;\n            {\n                // Valuing these shares higher, rounding up, will result in us burning less of them\n                // in the event we don't burn all of them. Good thing.\n                uint256 dvSharesValue = destinationInfo[address(destVault)].cachedMinDebtValue.mulDiv(\n                    dvSharesToBurn, destinationInfo[address(destVault)].ownedShares, Math.Rounding.Up\n                );\n\n                // If the dv shares we own are worth more than we need, limit the shares to burn\n                // Any extra we get will be dropped into idle\n                if (dvSharesValue > info.assetsToPull) {\n                    uint256 limitedShares = (dvSharesToBurn * info.assetsToPull) / dvSharesValue;\n\n                    // Final set for the actual shares we'll burn later\n                    dvSharesToBurn = limitedShares;\n                }\n            }\n\n            // Destination Vaults always burn the exact amount we instruct them to\n            uint256 pulledAssets = destVault.withdrawBaseAsset(dvSharesToBurn, address(this));\n\n            info.assetsPulled += pulledAssets;\n\n            // Calculate the totalDebt we'll need to remove based on the shares we're burning\n            // We're rounding up here so take care when actually applying to totalDebt\n            // The assets we calculated to pull are from the minDebt number we track so\n            // we'll use that one to ensure we properly account for slippage (the `pulled` var below)\n            // The other two debt numbers we just need to keep up to date.\n            uint256 debtMinDecrease = destinationInfo[address(destVault)].cachedMinDebtValue.mulDiv(\n                dvSharesToBurn, destinationInfo[address(destVault)].ownedShares, Math.Rounding.Up\n            );\n            info.debtMinDecrease += debtMinDecrease;\n\n            info.debtDecrease += destinationInfo[address(destVault)].cachedDebtValue.mulDiv(\n                dvSharesToBurn, destinationInfo[address(destVault)].ownedShares, Math.Rounding.Up\n            );\n            info.debtMaxDecrease += destinationInfo[address(destVault)].cachedMaxDebtValue.mulDiv(\n                dvSharesToBurn, destinationInfo[address(destVault)].ownedShares, Math.Rounding.Up\n            );\n\n            // If we've exhausted all shares we can remove the withdrawal from the queue\n            // We need to leave it in the debt report queue though so that our destination specific\n            // debt tracking values can be updated\n\n            if (dvShares == dvSharesToBurn) {\n                withdrawalQueue.popAddress(address(destVault));\n            }\n\n            // It's possible we'll get back more assets than we anticipate from a swap\n            // so if we do, throw it in idle and stop processing. You don't get more than we've calculated\n            if (info.assetsPulled >= info.totalAssetsToPull) {\n                info.idleIncrease += info.assetsPulled - info.totalAssetsToPull;\n                info.assetsPulled = info.totalAssetsToPull;\n                break;\n            }\n\n            // Any deficiency in the amount we received is slippage. debtDecrease is what we expected\n            // to receive. If we received any extra, that's great we'll roll it forward so we burn\n            // less on the next loop.\n            uint256 pulled = Math.max(debtMinDecrease, pulledAssets);\n            if (pulled >= info.assetsToPull) {\n                // We either have enough assets, or we've burned the max debt we're allowed\n                break;\n            } else {\n                info.assetsToPull -= pulled;\n            }\n\n            // If we didn't exhaust all of the shares from the destination it means we\n            // assume we will get everything we need from there and everything else is slippage\n            if (dvShares != dvSharesToBurn) {\n                break;\n            }\n        }\n\n        // info.assetsToPull isn't safe to use past this point.\n        // It may or may not be accurate from the previous loop\n\n        // We didn't get enough assets from the debt pull\n        // See if we can get the rest from idle\n        // Check the debt burned though to ensure that we don't try to make up\n        // slippage incurred out of idle\n        if (\n            info.assetsPulled < assets && info.debtMinDecrease < assets && info.currentIdle > 0 && exhaustedDestinations\n        ) {\n            uint256 remaining = assets - Math.max(info.assetsPulled, info.debtMinDecrease);\n            if (remaining < info.currentIdle) {\n                info.assetsFromIdle = remaining;\n            } else {\n                info.assetsFromIdle = info.currentIdle;\n            }\n        }\n\n        debtBurned = info.assetsFromIdle + info.debtMinDecrease;\n        actualAssets = info.assetsFromIdle + info.assetsPulled;\n\n        actualShares = IAutopool(address(this)).convertToShares(\n            debtBurned, applicableTotalAssets, IAutopool(address(this)).totalSupply(), Math.Rounding.Up\n        );\n\n        // Subtract what's taken out of idle from totalIdle\n        // We may also have some increase to account for it we over pulled\n        // or received better execution than we were anticipating\n        // slither-disable-next-line events-maths\n        assetBreakdown.totalIdle = info.currentIdle + info.idleIncrease - info.assetsFromIdle;\n\n        // Save off our various debt numbers\n        if (info.debtDecrease > assetBreakdown.totalDebt) {\n            assetBreakdown.totalDebt = 0;\n        } else {\n            assetBreakdown.totalDebt -= info.debtDecrease;\n        }\n\n        if (info.debtMinDecrease > info.totalMinDebt) {\n            assetBreakdown.totalDebtMin = 0;\n        } else {\n            assetBreakdown.totalDebtMin -= info.debtMinDecrease;\n        }\n\n        if (info.debtMaxDecrease > assetBreakdown.totalDebtMax) {\n            assetBreakdown.totalDebtMax = 0;\n        } else {\n            assetBreakdown.totalDebtMax -= info.debtMaxDecrease;\n        }\n    }\n\n    /**\n     * @notice Function to complete a withdrawal or redeem.  This runs after shares to be burned and assets to be\n     *    transferred are calculated.\n     * @param assets Amount of assets to be transferred to receiver.\n     * @param shares Amount of shares to be burned from owner.\n     * @param owner Owner of shares, user to burn shares from.\n     * @param receiver The receiver of the baseAsset.\n     * @param baseAsset Base asset of the Autopool.\n     * @param assetBreakdown Asset breakdown for the Autopool.\n     * @param tokenData Token data for the Autopool.\n     */\n    function completeWithdrawal(\n        uint256 assets,\n        uint256 shares,\n        address owner,\n        address receiver,\n        IERC20 baseAsset,\n        IAutopool.AssetBreakdown storage assetBreakdown,\n        AutopoolToken.TokenData storage tokenData\n    ) external {\n        if (msg.sender != owner) {\n            uint256 allowed = IAutopool(address(this)).allowance(owner, msg.sender);\n            if (allowed != type(uint256).max) {\n                if (shares > allowed) revert AmountExceedsAllowance(shares, allowed);\n\n                unchecked {\n                    tokenData.approve(owner, msg.sender, allowed - shares);\n                }\n            }\n        }\n\n        tokenData.burn(owner, shares);\n\n        uint256 ts = IAutopool(address(this)).totalSupply();\n\n        emit Withdraw(msg.sender, receiver, owner, assets, shares);\n\n        emit Nav(assetBreakdown.totalIdle, assetBreakdown.totalDebt, ts);\n\n        baseAsset.safeTransfer(receiver, assets);\n    }\n\n    /**\n     * @notice A helper function to get estimates of what would happen on a withdraw or redeem.\n     * @dev Reverts all changing state.\n     * @param previewWithdraw Bool denoting whether to preview a redeem or withdrawal.\n     * @param assets Assets to be withdrawn or redeemed.\n     * @param applicableTotalAssets Operation dependent assets in the Autopool.\n     * @param functionCallEncoded Abi encoded function signature for recursive call.\n     * @param assetBreakdown Breakdown of vault assets from Autopool storage.\n     * @param withdrawalQueue Destination vault withdrawal queue from Autopool storage.\n     * @param destinationInfo Mapping of information for destinations.\n     * @return assetsAmount Preview of amount of assets to send to receiver.\n     * @return sharesAmount Preview of amount of assets to burn from owner.\n     */\n    function preview(\n        bool previewWithdraw,\n        uint256 assets,\n        uint256 applicableTotalAssets,\n        bytes memory functionCallEncoded,\n        IAutopool.AssetBreakdown storage assetBreakdown,\n        StructuredLinkedList.List storage withdrawalQueue,\n        mapping(address => AutopoolDebt.DestinationInfo) storage destinationInfo\n    ) external returns (uint256 assetsAmount, uint256 sharesAmount) {\n        if (msg.sender != address(this)) {\n            // Perform a recursive call the function in `funcCallEncoded`.  This will result in a call back to\n            // the Autopool, and then this function. The intention is to reach the \"else\" block in this function.\n            // solhint-disable avoid-low-level-calls\n            // slither-disable-next-line missing-zero-check,low-level-calls\n            (bool success, bytes memory returnData) = address(this).call(functionCallEncoded);\n            // solhint-enable avoid-low-level-calls\n\n            // If the recursive call is successful, it means an unintended code path was taken.\n            if (success) {\n                revert Errors.UnreachableError();\n            }\n\n            bytes4 sharesAmountSig = bytes4(keccak256(\"SharesAndAssetsReceived(uint256,uint256)\"));\n\n            // Extract the error signature (first 4 bytes) from the revert reason.\n            bytes4 errorSignature;\n            // solhint-disable no-inline-assembly\n            assembly {\n                errorSignature := mload(add(returnData, 0x20))\n            }\n\n            // If the error matches the expected signature, extract the amount from the revert reason and return.\n            if (errorSignature == sharesAmountSig) {\n                // Extract subsequent bytes for uint256.\n                assembly {\n                    assetsAmount := mload(add(returnData, 0x24))\n                    sharesAmount := mload(add(returnData, 0x44))\n                }\n            } else {\n                // If the error is not the expected one, forward the original revert reason.\n                assembly {\n                    revert(add(32, returnData), mload(returnData))\n                }\n            }\n            // solhint-enable no-inline-assembly\n        }\n        // This branch is taken during the recursive call.\n        else {\n            // Perform the actual withdrawal or redeem logic to compute the amount. This will be reverted to\n            // simulate the action.\n            uint256 previewAssets;\n            uint256 previewShares;\n            if (previewWithdraw) {\n                (previewAssets, previewShares,) =\n                    withdraw(assets, applicableTotalAssets, assetBreakdown, withdrawalQueue, destinationInfo);\n            } else {\n                (previewAssets, previewShares,) =\n                    redeem(assets, applicableTotalAssets, assetBreakdown, withdrawalQueue, destinationInfo);\n            }\n\n            // Revert with the computed amount as an error.\n            revert SharesAndAssetsReceived(previewAssets, previewShares);\n        }\n    }\n}\n"
      },
      "src/interfaces/vault/IERC4626.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\nimport { IERC20Metadata } from \"openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n/// @dev Interface of the ERC4626 \"Tokenized Vault Standard\", as defined in https://eips.ethereum.org/EIPS/eip-4626\n/// @dev Due to the nature of obtaining estimates for previewing withdraws and redeems, a few functions are not\n///     view and therefore do not conform to eip 4626.  These functions use state changing operations\n///     to get accurate estimates, reverting after the preview amounts have been obtained.\ninterface IERC4626 is IERC20Metadata {\n    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n    event Withdraw(\n        address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares\n    );\n\n    /// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and\n    /// withdrawing.\n    /// @dev\n    /// - MUST be an ERC-20 token contract.\n    /// - MUST NOT revert.\n    function asset() external view returns (address assetTokenAddress);\n\n    /// @notice Returns the total amount of the underlying asset that is “managed” by Vault.\n    /// @dev\n    /// - SHOULD include any compounding that occurs from yield.\n    /// - MUST be inclusive of any fees that are charged against assets in the Vault.\n    /// - MUST NOT revert.\n    function totalAssets() external view returns (uint256 totalManagedAssets);\n\n    /// @notice Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an\n    /// ideal\n    /// scenario where all the conditions are met.\n    /// @dev\n    /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n    /// - MUST NOT show any variations depending on the caller.\n    /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n    /// - MUST NOT revert.\n    ///\n    /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n    /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n    /// from.\n    function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n    /// @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an\n    /// ideal\n    /// scenario where all the conditions are met.\n    /// @dev\n    /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n    /// - MUST NOT show any variations depending on the caller.\n    /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n    /// - MUST NOT revert.\n    ///\n    /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n    /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n    /// from.\n    function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n    /// @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the\n    /// receiver,\n    /// through a deposit call.\n    /// @dev\n    /// - MUST return a limited value if receiver is subject to some deposit limit.\n    /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n    /// - MUST NOT revert.\n    function maxDeposit(address receiver) external returns (uint256 maxAssets);\n\n    /// @notice Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block,\n    /// given\n    /// current on-chain conditions.\n    /// @dev\n    /// - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n    ///   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n    ///   in the same transaction.\n    /// - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n    ///   deposit would be accepted, regardless if the user has enough tokens approved, etc.\n    /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n    /// - MUST NOT revert.\n    ///\n    /// NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n    /// share price or some other type of condition, meaning the depositor will lose assets by depositing.\n    function previewDeposit(uint256 assets) external returns (uint256 shares);\n\n    /// @notice Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n    /// @dev\n    /// - MUST emit the Deposit event.\n    /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n    ///   deposit execution, and are accounted for during deposit.\n    /// - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n    ///   approving enough underlying tokens to the Vault contract, etc).\n    ///\n    /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n    /// @notice Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n    /// @dev\n    /// - MUST return a limited value if receiver is subject to some mint limit.\n    /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n    /// - MUST NOT revert.\n    function maxMint(address receiver) external returns (uint256 maxShares);\n\n    /// @notice Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n    /// current on-chain conditions.\n    /// @dev\n    /// - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n    ///   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n    ///   same transaction.\n    /// - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n    ///   would be accepted, regardless if the user has enough tokens approved, etc.\n    /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n    /// - MUST NOT revert.\n    ///\n    /// NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n    /// share price or some other type of condition, meaning the depositor will lose assets by minting.\n    function previewMint(uint256 shares) external returns (uint256 assets);\n\n    /// @notice Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n    /// @dev\n    /// - MUST emit the Deposit event.\n    /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n    ///   execution, and are accounted for during mint.\n    /// - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n    ///   approving enough underlying tokens to the Vault contract, etc).\n    ///\n    /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n    function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n    /// @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n    /// Vault, through a withdraw call.\n    /// @dev\n    /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n    /// - MUST NOT revert.\n    function maxWithdraw(address owner) external returns (uint256 maxAssets);\n\n    /// @notice Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n    /// given current on-chain conditions.\n    /// @dev\n    /// - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n    ///   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n    ///   called\n    ///   in the same transaction.\n    /// - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n    ///   the withdrawal would be accepted, regardless if the user has enough shares, etc.\n    /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n    /// - MUST NOT revert.\n    ///\n    /// NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n    /// share price or some other type of condition, meaning the depositor will lose assets by depositing.\n    function previewWithdraw(uint256 assets) external returns (uint256 shares);\n\n    /// @notice Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n    /// @dev\n    /// - MUST emit the Withdraw event.\n    /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n    ///   withdraw execution, and are accounted for during withdraw.\n    /// - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n    ///   not having enough shares, etc).\n    ///\n    /// Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n    /// Those methods should be performed separately.\n    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n    /// @notice Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n    /// through a redeem call.\n    /// @dev\n    /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n    /// - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n    /// - MUST NOT revert.\n    function maxRedeem(address owner) external returns (uint256 maxShares);\n\n    /// @notice Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n    /// given current on-chain conditions.\n    /// @dev\n    /// - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n    ///   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n    ///   same transaction.\n    /// - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n    ///   redemption would be accepted, regardless if the user has enough shares, etc.\n    /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n    /// - MUST NOT revert.\n    ///\n    /// NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n    /// share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n    function previewRedeem(uint256 shares) external returns (uint256 assets);\n\n    /// @notice Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n    /// @dev\n    /// - MUST emit the Withdraw event.\n    /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n    ///   redeem execution, and are accounted for during redeem.\n    /// - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n    ///   not having enough shares, etc).\n    ///\n    /// NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n    /// Those methods should be performed separately.\n    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"
      },
      "src/interfaces/strategy/IAutopoolStrategy.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IStrategy } from \"src/interfaces/strategy/IStrategy.sol\";\n\ninterface IAutopoolStrategy {\n    enum RebalanceDirection {\n        In,\n        Out\n    }\n\n    /// @notice verify that a rebalance (swap between destinations) meets all the strategy constraints\n    /// @dev Signature identical to IStrategy.verifyRebalance\n    function verifyRebalance(\n        IStrategy.RebalanceParams memory,\n        IStrategy.SummaryStats memory\n    ) external returns (bool, string memory message);\n\n    /// @notice called by the Autopool when NAV is updated\n    /// @dev can only be called by the strategy's registered Autopool\n    /// @param navPerShare The navPerShare to record\n    function navUpdate(uint256 navPerShare) external;\n\n    /// @notice called by the Autopool when a rebalance is completed\n    /// @dev can only be called by the strategy's registered Autopool\n    /// @param rebalanceParams The parameters for the rebalance that was executed\n    function rebalanceSuccessfullyExecuted(IStrategy.RebalanceParams memory rebalanceParams) external;\n\n    /// @notice called by the Autopool during rebalance process\n    /// @param rebalanceParams The parameters for the rebalance that was executed\n    function getRebalanceOutSummaryStats(IStrategy.RebalanceParams memory rebalanceParams)\n        external\n        returns (IStrategy.SummaryStats memory outSummary);\n\n    /// @notice the number of days to pause rebalancing due to NAV decay\n    function pauseRebalancePeriodInDays() external view returns (uint16);\n\n    /// @notice the number of seconds gap between consecutive rebalances\n    function rebalanceTimeGapInSeconds() external view returns (uint256);\n\n    /// @notice destinations trading a premium above maxPremium will be blocked from new capital deployments\n    function maxPremium() external view returns (int256); // 100% = 1e18\n\n    /// @notice destinations trading a discount above maxDiscount will be blocked from new capital deployments\n    function maxDiscount() external view returns (int256); // 100% = 1e18\n\n    /// @notice the allowed staleness of stats data before a revert occurs\n    function staleDataToleranceInSeconds() external view returns (uint40);\n\n    /// @notice the swap cost offset period to initialize the strategy with\n    function swapCostOffsetInitInDays() external view returns (uint16);\n\n    /// @notice the number of violations required to trigger a tightening of the swap cost offset period (1 to 10)\n    function swapCostOffsetTightenThresholdInViolations() external view returns (uint16);\n\n    /// @notice the number of days to decrease the swap offset period for each tightening step\n    function swapCostOffsetTightenStepInDays() external view returns (uint16);\n\n    /// @notice the number of days since a rebalance required to trigger a relaxing of the swap cost offset period\n    function swapCostOffsetRelaxThresholdInDays() external view returns (uint16);\n\n    /// @notice the number of days to increase the swap offset period for each relaxing step\n    function swapCostOffsetRelaxStepInDays() external view returns (uint16);\n\n    // slither-disable-start similar-names\n    /// @notice the maximum the swap cost offset period can reach. This is the loosest the strategy will be\n    function swapCostOffsetMaxInDays() external view returns (uint16);\n\n    /// @notice the minimum the swap cost offset period can reach. This is the most conservative the strategy will be\n    function swapCostOffsetMinInDays() external view returns (uint16);\n\n    /// @notice the number of days for the first NAV decay comparison (e.g., 30 days)\n    function navLookback1InDays() external view returns (uint8);\n\n    /// @notice the number of days for the second NAV decay comparison (e.g., 60 days)\n    function navLookback2InDays() external view returns (uint8);\n\n    /// @notice the number of days for the third NAV decay comparison (e.g., 90 days)\n    function navLookback3InDays() external view returns (uint8);\n    // slither-disable-end similar-names\n\n    /// @notice the maximum slippage that is allowed for a normal rebalance\n    function maxNormalOperationSlippage() external view returns (uint256); // 100% = 1e18\n\n    /// @notice the maximum amount of slippage to allow when a destination is trimmed due to constraint violations\n    /// recommend setting this higher than maxNormalOperationSlippage\n    function maxTrimOperationSlippage() external view returns (uint256); // 100% = 1e18\n\n    /// @notice the maximum amount of slippage to allow when a destinationVault has been shutdown\n    /// shutdown for a vault is abnormal and means there is an issue at that destination\n    /// recommend setting this higher than maxNormalOperationSlippage\n    function maxEmergencyOperationSlippage() external view returns (uint256); // 100% = 1e18\n\n    /// @notice the maximum amount of slippage to allow when the Autopool has been shutdown\n    function maxShutdownOperationSlippage() external view returns (uint256); // 100% = 1e18\n\n    /// @notice the maximum discount used for price return\n    function maxAllowedDiscount() external view returns (int256); // 18 precision\n\n    /// @notice model weight used for LSTs base yield, 1e6 is the highest\n    function weightBase() external view returns (uint256);\n\n    /// @notice model weight used for DEX fee yield, 1e6 is the highest\n    function weightFee() external view returns (uint256);\n\n    /// @notice model weight used for incentive yield\n    function weightIncentive() external view returns (uint256);\n\n    /// @notice model weight used slashing costs\n    function weightSlashing() external view returns (uint256);\n\n    /// @notice model weight applied to an LST discount when exiting the position\n    function weightPriceDiscountExit() external view returns (int256);\n\n    /// @notice model weight applied to an LST discount when entering the position\n    function weightPriceDiscountEnter() external view returns (int256);\n\n    /// @notice model weight applied to an LST premium when entering or exiting the position\n    function weightPricePremium() external view returns (int256);\n\n    /// @notice initial value of the swap cost offset to use\n    function swapCostOffsetInit() external view returns (uint16);\n\n    /// @notice initial lst price gap tolerance\n    function defaultLstPriceGapTolerance() external view returns (uint256);\n}\n"
      },
      "src/interfaces/rewarders/IMainRewarder.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IBaseRewarder } from \"src/interfaces/rewarders/IBaseRewarder.sol\";\nimport { IExtraRewarder } from \"src/interfaces/rewarders/IExtraRewarder.sol\";\n\ninterface IMainRewarder is IBaseRewarder {\n    error ExtraRewardsNotAllowed();\n\n    event ExtraRewardAdded(address reward);\n    event ExtraRewardsCleared();\n    event ExtraRewardRemoved(address reward);\n\n    /**\n     * @notice Adds an ExtraRewarder contract address to the extraRewards array.\n     * @param reward The address of the ExtraRewarder contract.\n     */\n    function addExtraReward(address reward) external;\n\n    /**\n     * @notice Removes a list of ExtraRewarder contract addresses from the extraRewards array.\n     */\n    function removeExtraRewards(address[] calldata _rewards) external;\n\n    /**\n     * @notice Withdraws the specified amount of tokens from the vault for the specified account, and transfers all\n     * rewards for the account from this contract and any linked extra reward contracts.\n     * @param account The address of the account to withdraw tokens and claim rewards for.\n     * @param amount The amount of tokens to withdraw.\n     * @param claim If true, claims all rewards for the account from this contract and any linked extra reward\n     * contracts.\n     */\n    function withdraw(address account, uint256 amount, bool claim) external;\n\n    /**\n     * @notice Clears the extraRewards array.\n     */\n    function clearExtraRewards() external;\n\n    /**\n     * @notice Claims and transfers all rewards for the specified account from this contract and any linked extra reward\n     * contracts.\n     * @dev If claimExtras is true, also claims all rewards from linked extra reward contracts.\n     * @param account The address of the account to claim rewards for.\n     * @param claimExtras If true, claims rewards from linked extra reward contracts.\n     */\n    function getReward(address account, bool claimExtras) external;\n\n    /**\n     * @notice Number of extra rewards currently registered\n     */\n    function extraRewardsLength() external view returns (uint256);\n\n    /**\n     * @notice Get the extra rewards array values\n     */\n    function extraRewards() external view returns (address[] memory);\n\n    /**\n     * @notice Get the rewarder at the specified index\n     */\n    function getExtraRewarder(uint256 index) external view returns (IExtraRewarder);\n}\n"
      },
      "src/libs/LibAdapter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IERC20 } from \"openzeppelin-contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol\";\n\nlibrary LibAdapter {\n    using SafeERC20 for IERC20;\n\n    address public constant CURVE_REGISTRY_ETH_ADDRESS_POINTER = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n    error MinLpAmountNotReached();\n    error LpTokenAmountMismatch();\n    error NoNonZeroAmountProvided();\n    error InvalidBalanceChange();\n\n    // Utils\n    function _approve(IERC20 token, address spender, uint256 amount) internal {\n        uint256 currentAllowance = token.allowance(address(this), spender);\n        if (currentAllowance > 0) {\n            token.safeDecreaseAllowance(spender, currentAllowance);\n        }\n        token.safeIncreaseAllowance(spender, amount);\n    }\n}\n"
      },
      "src/interfaces/vault/IDestinationVault.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IERC20Metadata as IERC20 } from \"openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport { IBaseAssetVault } from \"src/interfaces/vault/IBaseAssetVault.sol\";\nimport { IMainRewarder } from \"src/interfaces/rewarders/IMainRewarder.sol\";\nimport { IDexLSTStats } from \"src/interfaces/stats/IDexLSTStats.sol\";\n\ninterface IDestinationVault is IBaseAssetVault, IERC20 {\n    enum VaultShutdownStatus {\n        Active,\n        Deprecated,\n        Exploit\n    }\n\n    error LogicDefect();\n    error BaseAmountReceived(uint256 amount);\n\n    /* ******************************** */\n    /* View                             */\n    /* ******************************** */\n\n    /// @notice A full unit of this vault\n    // solhint-disable-next-line func-name-mixedcase\n    function ONE() external view returns (uint256);\n\n    /// @notice The asset that is deposited into the vault\n    function underlying() external view returns (address);\n\n    /// @notice The asset that rewards and withdrawals to the Autopool are denominated in\n    /// @inheritdoc IBaseAssetVault\n    function baseAsset() external view override returns (address);\n\n    /// @notice Debt balance of underlying asset that is in contract.  This\n    ///     value includes only assets that are known as debt by the rest of the\n    ///     system (i.e. transferred in on rebalance), and does not include\n    ///     extraneous amounts of underlyer that may have ended up in this contract.\n    function internalDebtBalance() external view returns (uint256);\n\n    /// @notice Debt balance of underlyering asset staked externally.  This value only\n    ///     includes assets known as debt to the rest of the system, and does not include\n    ///     any assets staked on behalf of the DV in external contracts.\n    function externalDebtBalance() external view returns (uint256);\n\n    /// @notice Returns true value of _underlyer in DV.  Debt + tokens that may have\n    ///     been transferred into the contract outside of rebalance.\n    function internalQueriedBalance() external view returns (uint256);\n\n    /// @notice Returns true value of staked _underlyer in external contract.  This\n    ///     will include any _underlyer that has been staked on behalf of the DV.\n    function externalQueriedBalance() external view returns (uint256);\n\n    /// @notice Balance of underlying debt, sum of `externalDebtBalance()` and `internalDebtBalance()`.\n    function balanceOfUnderlyingDebt() external view returns (uint256);\n\n    /// @notice Rewarder for this vault\n    function rewarder() external view returns (address);\n\n    /// @notice Exchange this destination vault points to\n    function exchangeName() external view returns (string memory);\n\n    /// @notice The type of pool associated with this vault\n    function poolType() external view returns (string memory);\n\n    /// @notice If the pool only deals in ETH when adding or removing liquidity\n    function poolDealInEth() external view returns (bool);\n\n    /// @notice Tokens that base asset can be swapped into\n    function underlyingTokens() external view returns (address[] memory);\n\n    /* ******************************** */\n    /* Events                           */\n    /* ******************************** */\n\n    event Donated(address sender, uint256 amount);\n    event Withdraw(\n        uint256 target, uint256 actual, uint256 debtLoss, uint256 claimLoss, uint256 fromIdle, uint256 fromDebt\n    );\n    event UpdateSignedMessage(bytes32 hash, bool flag);\n\n    /* ******************************** */\n    /* Errors                           */\n    /* ******************************** */\n\n    error ZeroAddress(string paramName);\n    error InvalidShutdownStatus(VaultShutdownStatus status);\n\n    /* ******************************** */\n    /* Functions                        */\n    /* ******************************** */\n\n    /// @notice Setup the contract. These will be cloned so no constructor\n    /// @param baseAsset_ Base asset of the system. WETH/USDC/etc\n    /// @param underlyer_ Underlying asset the vault will wrap\n    /// @param rewarder_ Reward tracker for this vault\n    /// @param incentiveCalculator_ Incentive calculator for this vault\n    /// @param additionalTrackedTokens_ Additional tokens that should be considered 'tracked'\n    /// @param params_ Any extra parameters needed to setup the contract\n    function initialize(\n        IERC20 baseAsset_,\n        IERC20 underlyer_,\n        IMainRewarder rewarder_,\n        address incentiveCalculator_,\n        address[] memory additionalTrackedTokens_,\n        bytes memory params_\n    ) external;\n\n    function getRangePricesLP() external returns (uint256 spotPrice, uint256 safePrice, bool isSpotSafe);\n\n    /// @notice Calculates the current value of a portion of the debt based on shares\n    /// @dev Queries the current value of all tokens we have deployed, whether its a single place, multiple, staked, etc\n    /// @param shares The number of shares to value\n    /// @return value The current value of our debt in terms of the baseAsset\n    function debtValue(uint256 shares) external returns (uint256 value);\n\n    /// @notice Collects any earned rewards from staking, incentives, etc. Transfers to sender\n    /// @dev Should be limited to LIQUIDATOR_MANAGER. Rewards must be collected before claimed\n    /// @return amounts amount of rewards claimed for each token\n    /// @return tokens tokens claimed\n    function collectRewards() external returns (uint256[] memory amounts, address[] memory tokens);\n\n    /// @notice Pull any non-tracked token to the specified destination\n    /// @dev Should be limited to TOKEN_RECOVERY_MANAGER\n    function recover(address[] calldata tokens, uint256[] calldata amounts, address[] calldata destinations) external;\n\n    /// @notice Recovers any extra underlying both in DV and staked externally not tracked as debt.\n    /// @dev Should be limited to TOKEN_SAVER_ROLE.\n    /// @param destination The address to send excess underlyer to.\n    function recoverUnderlying(address destination) external;\n\n    /// @notice Deposit underlying to receive destination vault shares\n    /// @param amount amount of base lp asset to deposit\n    function depositUnderlying(uint256 amount) external returns (uint256 shares);\n\n    /// @notice Withdraw underlying by burning destination vault shares\n    /// @param shares amount of destination vault shares to burn\n    /// @param to destination of the underlying asset\n    /// @return amount underlyer amount 'to' received\n    function withdrawUnderlying(uint256 shares, address to) external returns (uint256 amount);\n\n    /// @notice Burn specified shares for underlyer swapped to base asset\n    /// @param shares amount of vault shares to burn\n    /// @param to destination of the base asset\n    /// @return amount base asset amount 'to' received\n    function withdrawBaseAsset(uint256 shares, address to) external returns (uint256 amount);\n\n    /// @notice Mark this vault as shutdown so that autoPools can react\n    function shutdown(VaultShutdownStatus reason) external;\n\n    /// @notice True if the vault has been shutdown\n    function isShutdown() external view returns (bool);\n\n    /// @notice Returns the reason for shutdown (or `Active` if not shutdown)\n    function shutdownStatus() external view returns (VaultShutdownStatus);\n\n    /// @notice Stats contract for this vault\n    function getStats() external view returns (IDexLSTStats);\n\n    /// @notice get the marketplace rewards\n    /// @return rewardTokens list of reward token addresses\n    /// @return rewardRates list of reward rates\n    function getMarketplaceRewards() external returns (uint256[] memory rewardTokens, uint256[] memory rewardRates);\n\n    /// @notice Get the address of the underlying pool the vault points to\n    /// @return poolAddress address of the underlying pool\n    function getPool() external view returns (address poolAddress);\n\n    /// @notice Gets the spot price of the underlying LP token\n    /// @dev Price validated to be inside our tolerance against safe price. Will revert if outside.\n    /// @return price Value of 1 unit of the underlying LP token in terms of the base asset\n    function getValidatedSpotPrice() external returns (uint256 price);\n\n    /// @notice Gets the safe price of the underlying LP token\n    /// @dev Price validated to be inside our tolerance against spot price. Will revert if outside.\n    /// @return price Value of 1 unit of the underlying LP token in terms of the base asset\n    function getValidatedSafePrice() external returns (uint256 price);\n\n    /// @notice Get the lowest price we can get for the LP token\n    /// @dev This price can be attacked is not validate to be in any range\n    /// @return price Value of 1 unit of the underlying LP token in terms of the base asset\n    function getUnderlyerFloorPrice() external returns (uint256 price);\n\n    /// @notice Get the highest price we can get for the LP token\n    /// @dev This price can be attacked is not validate to be in any range\n    /// @return price Value of 1 unit of the underlying LP token in terms of the base asset\n    function getUnderlyerCeilingPrice() external returns (uint256 price);\n\n    /// @notice Set or unset  a hash as a signed message\n    /// @dev Should be limited to DESTINATION_VAULTS_UPDATER. The set hash is used to vaildate a signature.\n    /// This signature can be potentially used to claim offchain rewards earned by Destination Vaults.\n    /// @param hash bytes32 hash of a payload\n    /// @param flag boolean flag to indicate a validity of hash\n    function setMessage(bytes32 hash, bool flag) external;\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n *     // Add the library methods\n *     using EnumerableSet for EnumerableSet.AddressSet;\n *\n *     // Declare a set state variable\n *     EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 => uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        bytes32[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n"
      },
      "src/interfaces/strategy/IStrategy.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IERC3156FlashBorrower } from \"openzeppelin-contracts/interfaces/IERC3156FlashBorrower.sol\";\n\ninterface IStrategy {\n    /* ******************************** */\n    /*      Events                      */\n    /* ******************************** */\n    event DestinationVaultAdded(address destination);\n    event DestinationVaultRemoved(address destination);\n    event WithdrawalQueueSet(address[] destinations);\n    event AddedToRemovalQueue(address destination);\n    event RemovedFromRemovalQueue(address destination);\n\n    error InvalidDestinationVault();\n\n    error RebalanceFailed(string message);\n\n    /// @notice gets the list of supported destination vaults for the Autopool/Strategy\n    /// @return _destinations List of supported destination vaults\n    function getDestinations() external view returns (address[] memory _destinations);\n\n    /// @notice add supported destination vaults for the Autopool/Strategy\n    /// @param _destinations The list of destination vaults to add\n    function addDestinations(address[] calldata _destinations) external;\n\n    /// @notice remove supported destination vaults for the Autopool/Strategy\n    /// @param _destinations The list of destination vaults to remove\n    function removeDestinations(address[] calldata _destinations) external;\n\n    /// @param destinationIn The address / lp token of the destination vault that will increase\n    /// @param tokenIn The address of the underlyer token that will be provided by the swapper\n    /// @param amountIn The amount of the underlying LP tokens that will be received\n    /// @param destinationOut The address of the destination vault that will decrease\n    /// @param tokenOut The address of the underlyer token that will be received by the swapper\n    /// @param amountOut The amount of the tokenOut that will be received by the swapper\n    struct RebalanceParams {\n        address destinationIn;\n        address tokenIn;\n        uint256 amountIn;\n        address destinationOut;\n        address tokenOut;\n        uint256 amountOut;\n    }\n\n    /// @param destination The address / lp token of the destination vault\n    /// @param baseApr Base Apr is the yield generated by staking rewards\n    /// @param feeApr Yield for pool trading fees\n    /// @param incentiveApr Incentives for LP\n    /// @param safeTotalSupply Safe supply for LP tokens\n    /// @param priceReturn Return from price movement to & away from peg\n    /// @param maxDiscount Max discount to peg\n    /// @param maxPremium Max premium to peg\n    /// @param ownedShares Shares owned for this destination\n    /// @param compositeReturn Total return combined from the individual yield components\n    /// @param pricePerShare Price per share\n    /// @param slashingCost The loss due to slashing of the backing\n    struct SummaryStats {\n        address destination;\n        uint256 baseApr;\n        uint256 feeApr;\n        uint256 incentiveApr;\n        uint256 safeTotalSupply;\n        int256 priceReturn;\n        int256 maxDiscount;\n        int256 maxPremium;\n        uint256 ownedShares;\n        int256 compositeReturn;\n        uint256 pricePerShare;\n        uint256 slashingCost;\n    }\n\n    /// @notice rebalance the Autopool from the tokenOut (decrease) to the tokenIn (increase)\n    /// This uses a flash loan to receive the tokenOut to reduce the working capital requirements of the swapper\n    /// @param receiver The contract receiving the tokens, needs to implement the\n    /// `onFlashLoan(address user, address token, uint256 amount, uint256 fee, bytes calldata)` interface\n    /// @param params Parameters by which to perform the rebalance\n    /// @param data A data parameter to be passed on to the `receiver` for any custom use\n    function flashRebalance(\n        IERC3156FlashBorrower receiver,\n        RebalanceParams calldata params,\n        bytes calldata data\n    ) external;\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC3156FlashBorrower.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC3156 FlashBorrower, as defined in\n * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].\n *\n * _Available since v4.1._\n */\ninterface IERC3156FlashBorrower {\n    /**\n     * @dev Receive a flash loan.\n     * @param initiator The initiator of the loan.\n     * @param token The loan currency.\n     * @param amount The amount of tokens lent.\n     * @param fee The additional amount of tokens to repay.\n     * @param data Arbitrary data structure, intended to contain user-defined parameters.\n     * @return The keccak256 hash of \"IERC3156FlashBorrower.onFlashLoan\"\n     */\n    function onFlashLoan(\n        address initiator,\n        address token,\n        uint256 amount,\n        uint256 fee,\n        bytes calldata data\n    ) external returns (bytes32);\n}\n"
      },
      "src/strategy/StructuredLinkedList.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity =0.8.17;\n\n/**\n * @title StructuredLinkedList\n * @author Vittorio Minacori (https://github.com/vittominacori)\n * @dev An utility library for using sorted linked list data structures in your Solidity project.\n * @notice Adapted from\n * https://github.com/Layr-Labs/eigenlayer-contracts/blob/master/src/contracts/libraries/StructuredLinkedList.sol\n */\nlibrary StructuredLinkedList {\n    uint256 private constant _NULL = 0;\n    uint256 private constant _HEAD = 0;\n\n    bool private constant _PREV = false;\n    bool private constant _NEXT = true;\n\n    struct List {\n        uint256 size;\n        mapping(uint256 => mapping(bool => uint256)) list;\n    }\n\n    /**\n     * @dev Checks if the list exists\n     * @param self stored linked list from contract\n     * @return bool true if list exists, false otherwise\n     */\n    function listExists(List storage self) public view returns (bool) {\n        // if the head nodes previous or next pointers both point to itself, then there are no items in the list\n        if (self.list[_HEAD][_PREV] != _HEAD || self.list[_HEAD][_NEXT] != _HEAD) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Checks if the node exists\n     * @param self stored linked list from contract\n     * @param _node a node to search for\n     * @return bool true if node exists, false otherwise\n     */\n    function nodeExists(List storage self, uint256 _node) public view returns (bool) {\n        if (self.list[_node][_PREV] == _HEAD && self.list[_node][_NEXT] == _HEAD) {\n            if (self.list[_HEAD][_NEXT] == _node) {\n                return true;\n            } else {\n                return false;\n            }\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * @dev Returns the number of elements in the list\n     * @param self stored linked list from contract\n     * @return uint256\n     */\n    // slither-disable-next-line dead-code\n    function sizeOf(List storage self) public view returns (uint256) {\n        return self.size;\n    }\n\n    /**\n     * @dev Gets the head of the list\n     * @param self stored linked list from contract\n     * @return uint256 the head of the list\n     */\n    function getHead(List storage self) public view returns (uint256) {\n        return self.list[_HEAD][_NEXT];\n    }\n\n    /**\n     * @dev Gets the head of the list\n     * @param self stored linked list from contract\n     * @return uint256 the head of the list\n     */\n    function getTail(List storage self) public view returns (uint256) {\n        return self.list[_HEAD][_PREV];\n    }\n\n    /**\n     * @dev Returns the links of a node as a tuple\n     * @param self stored linked list from contract\n     * @param _node id of the node to get\n     * @return bool, uint256, uint256 true if node exists or false otherwise, previous node, next node\n     */\n    // slither-disable-next-line dead-code\n    function getNode(List storage self, uint256 _node) public view returns (bool, uint256, uint256) {\n        if (!nodeExists(self, _node)) {\n            return (false, 0, 0);\n        } else {\n            return (true, self.list[_node][_PREV], self.list[_node][_NEXT]);\n        }\n    }\n\n    /**\n     * @dev Returns the link of a node `_node` in direction `_direction`.\n     * @param self stored linked list from contract\n     * @param _node id of the node to step from\n     * @param _direction direction to step in\n     * @return bool, uint256 true if node exists or false otherwise, node in _direction\n     */\n    // slither-disable-next-line dead-code\n    function getAdjacent(List storage self, uint256 _node, bool _direction) public view returns (bool, uint256) {\n        if (!nodeExists(self, _node)) {\n            return (false, 0);\n        } else {\n            uint256 adjacent = self.list[_node][_direction];\n            return (adjacent != _HEAD, adjacent);\n        }\n    }\n\n    /**\n     * @dev Returns the link of a node `_node` in direction `_NEXT`.\n     * @param self stored linked list from contract\n     * @param _node id of the node to step from\n     * @return bool, uint256 true if node exists or false otherwise, next node\n     */\n    // slither-disable-next-line dead-code\n    function getNextNode(List storage self, uint256 _node) public view returns (bool, uint256) {\n        return getAdjacent(self, _node, _NEXT);\n    }\n\n    /**\n     * @dev Returns the link of a node `_node` in direction `_PREV`.\n     * @param self stored linked list from contract\n     * @param _node id of the node to step from\n     * @return bool, uint256 true if node exists or false otherwise, previous node\n     */\n    // slither-disable-next-line dead-code\n    function getPreviousNode(List storage self, uint256 _node) public view returns (bool, uint256) {\n        return getAdjacent(self, _node, _PREV);\n    }\n\n    /**\n     * @dev Insert node `_new` beside existing node `_node` in direction `_NEXT`.\n     * @param self stored linked list from contract\n     * @param _node existing node\n     * @param _new  new node to insert\n     * @return bool true if success, false otherwise\n     */\n    // slither-disable-next-line dead-code\n    function insertAfter(List storage self, uint256 _node, uint256 _new) public returns (bool) {\n        return _insert(self, _node, _new, _NEXT);\n    }\n\n    /**\n     * @dev Insert node `_new` beside existing node `_node` in direction `_PREV`.\n     * @param self stored linked list from contract\n     * @param _node existing node\n     * @param _new  new node to insert\n     * @return bool true if success, false otherwise\n     */\n    // slither-disable-next-line dead-code\n    function insertBefore(List storage self, uint256 _node, uint256 _new) public returns (bool) {\n        return _insert(self, _node, _new, _PREV);\n    }\n\n    /**\n     * @dev Removes an entry from the linked list\n     * @param self stored linked list from contract\n     * @param _node node to remove from the list\n     * @return uint256 the removed node\n     */\n    function remove(List storage self, uint256 _node) public returns (uint256) {\n        if ((_node == _NULL) || (!nodeExists(self, _node))) {\n            return 0;\n        }\n        _createLink(self, self.list[_node][_PREV], self.list[_node][_NEXT], _NEXT);\n        delete self.list[_node][_PREV];\n        delete self.list[_node][_NEXT];\n\n        self.size -= 1;\n\n        return _node;\n    }\n\n    /**\n     * @dev Pushes an entry to the head of the linked list\n     * @param self stored linked list from contract\n     * @param _node new entry to push to the head\n     * @return bool true if success, false otherwise\n     */\n    function pushFront(List storage self, uint256 _node) public returns (bool) {\n        return _push(self, _node, _NEXT);\n    }\n\n    /**\n     * @dev Pushes an entry to the tail of the linked list\n     * @param self stored linked list from contract\n     * @param _node new entry to push to the tail\n     * @return bool true if success, false otherwise\n     */\n    function pushBack(List storage self, uint256 _node) public returns (bool) {\n        return _push(self, _node, _PREV);\n    }\n\n    /**\n     * @dev Pops the first entry from the head of the linked list\n     * @param self stored linked list from contract\n     * @return uint256 the removed node\n     */\n    // slither-disable-next-line dead-code\n    function popFront(List storage self) public returns (uint256) {\n        return _pop(self, _NEXT);\n    }\n\n    /**\n     * @dev Pops the first entry from the tail of the linked list\n     * @param self stored linked list from contract\n     * @return uint256 the removed node\n     */\n    // slither-disable-next-line dead-code\n    function popBack(List storage self) public returns (uint256) {\n        return _pop(self, _PREV);\n    }\n\n    /**\n     * @dev Pushes an entry to the head of the linked list\n     * @param self stored linked list from contract\n     * @param _node new entry to push to the head\n     * @param _direction push to the head (_NEXT) or tail (_PREV)\n     * @return bool true if success, false otherwise\n     */\n    function _push(List storage self, uint256 _node, bool _direction) private returns (bool) {\n        return _insert(self, _HEAD, _node, _direction);\n    }\n\n    /**\n     * @dev Pops the first entry from the linked list\n     * @param self stored linked list from contract\n     * @param _direction pop from the head (_NEXT) or the tail (_PREV)\n     * @return uint256 the removed node\n     */\n    // slither-disable-next-line dead-code\n    function _pop(List storage self, bool _direction) private returns (uint256) {\n        uint256 adj;\n        (, adj) = getAdjacent(self, _HEAD, _direction);\n        return remove(self, adj);\n    }\n\n    /**\n     * @dev Insert node `_new` beside existing node `_node` in direction `_direction`.\n     * @param self stored linked list from contract\n     * @param _node existing node\n     * @param _new  new node to insert\n     * @param _direction direction to insert node in\n     * @return bool true if success, false otherwise\n     */\n    function _insert(List storage self, uint256 _node, uint256 _new, bool _direction) private returns (bool) {\n        if (!nodeExists(self, _new) && nodeExists(self, _node)) {\n            uint256 c = self.list[_node][_direction];\n            _createLink(self, _node, _new, _direction);\n            _createLink(self, _new, c, _direction);\n\n            self.size += 1;\n\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * @dev Creates a bidirectional link between two nodes on direction `_direction`\n     * @param self stored linked list from contract\n     * @param _node existing node\n     * @param _link node to link to in the _direction\n     * @param _direction direction to insert node in\n     */\n    function _createLink(List storage self, uint256 _node, uint256 _link, bool _direction) private {\n        self.list[_link][!_direction] = _node;\n        self.list[_node][_direction] = _link;\n    }\n}\n"
      },
      "src/strategy/WithdrawalQueue.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17; // their version was using 8.12?\n\nimport { StructuredLinkedList } from \"src/strategy/StructuredLinkedList.sol\";\n\n// https://github.com/Layr-Labs/eigenlayer-contracts/blob/master/src/contracts/libraries/StructuredLinkedList.sol\nlibrary WithdrawalQueue {\n    using StructuredLinkedList for StructuredLinkedList.List;\n\n    error CannotInsertZeroAddress();\n    error UnexpectedNodeRemoved();\n    error AddToHeadFailed();\n    error AddToTailFailed();\n    error NodeDoesNotExist();\n\n    /// @notice Returns true if the address is in the queue.\n    function addressExists(StructuredLinkedList.List storage queue, address addr) public view returns (bool) {\n        return StructuredLinkedList.nodeExists(queue, _addressToUint(addr));\n    }\n\n    /// @notice Returns the current head.\n    function peekHead(StructuredLinkedList.List storage queue) public view returns (address) {\n        return _uintToAddress(StructuredLinkedList.getHead(queue));\n    }\n\n    /// @notice Returns the current tail.\n    function peekTail(StructuredLinkedList.List storage queue) public view returns (address) {\n        return _uintToAddress(StructuredLinkedList.getTail(queue));\n    }\n\n    /// @notice Returns the number of items in the queue\n    function sizeOf(StructuredLinkedList.List storage queue) public view returns (uint256) {\n        return StructuredLinkedList.sizeOf(queue);\n    }\n\n    /// @notice Return all items in the queue\n    /// @dev Enumerates from head to tail\n    function getList(StructuredLinkedList.List storage self) public view returns (address[] memory list) {\n        uint256 size = self.sizeOf();\n        list = new address[](size);\n\n        if (size > 0) {\n            uint256 lastNode = self.getHead();\n            list[0] = _uintToAddress(lastNode);\n            for (uint256 i = 1; i < size; ++i) {\n                (bool exists, uint256 node) = self.getAdjacent(lastNode, true);\n\n                if (!exists) {\n                    revert NodeDoesNotExist();\n                }\n\n                list[i] = _uintToAddress(node);\n                lastNode = node;\n            }\n        }\n    }\n\n    /// @notice Returns the current tail.\n    function popHead(StructuredLinkedList.List storage queue) public returns (address) {\n        return _uintToAddress(StructuredLinkedList.popFront(queue));\n    }\n\n    /// @notice remove address toRemove from queue if it exists.\n    function popAddress(StructuredLinkedList.List storage queue, address toRemove) public {\n        uint256 addrAsUint = _addressToUint(toRemove);\n        uint256 _removedNode = StructuredLinkedList.remove(queue, addrAsUint);\n        if (!((_removedNode == addrAsUint) || (_removedNode == 0))) {\n            revert UnexpectedNodeRemoved();\n        }\n    }\n\n    /// @notice returns true if there are no addresses in queue.\n    function isEmpty(StructuredLinkedList.List storage queue) public view returns (bool) {\n        return !StructuredLinkedList.listExists(queue);\n    }\n\n    /// @notice if addr in queue, move it to the top\n    // if addr not in queue, add it to the top of the queue.\n    // if queue is empty, make a new queue with addr as the only node\n    function addToHead(StructuredLinkedList.List storage queue, address addr) public {\n        if (addr == address(0)) {\n            revert CannotInsertZeroAddress();\n        }\n        popAddress(queue, addr);\n        bool success = StructuredLinkedList.pushFront(queue, _addressToUint(addr));\n        if (!success) {\n            revert AddToHeadFailed();\n        }\n    }\n\n    function getAdjacent(\n        StructuredLinkedList.List storage queue,\n        address addr,\n        bool direction\n    ) public view returns (address) {\n        (bool exists, uint256 addrNum) = queue.getAdjacent(_addressToUint(addr), direction);\n        if (!exists) {\n            return address(0);\n        }\n        return _uintToAddress(addrNum);\n    }\n\n    /// @notice if addr in queue, move it to the end\n    // if addr not in queue, add it to the end of the queue.\n    // if queue is empty, make a new queue with addr as the only node\n    function addToTail(StructuredLinkedList.List storage queue, address addr) public {\n        if (addr == address(0)) {\n            revert CannotInsertZeroAddress();\n        }\n\n        popAddress(queue, addr);\n        bool success = StructuredLinkedList.pushBack(queue, _addressToUint(addr));\n        if (!success) {\n            revert AddToTailFailed();\n        }\n    }\n\n    function _addressToUint(address addr) private pure returns (uint256) {\n        return uint256(uint160(addr));\n    }\n\n    function _uintToAddress(uint256 x) private pure returns (address) {\n        return address(uint160(x));\n    }\n}\n"
      },
      "src/vault/libs/AutopoolToken.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\n\npragma solidity 0.8.17;\n\nimport { ECDSA } from \"openzeppelin-contracts/utils/cryptography/ECDSA.sol\";\nimport { IERC20Permit } from \"openzeppelin-contracts/token/ERC20/extensions/draft-IERC20Permit.sol\";\n\n/// @notice ERC20 token functionality converted into a library. Based on OZ's v5\n/// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.1/contracts/token/ERC20/ERC20.sol\nlibrary AutopoolToken {\n    struct TokenData {\n        /// @notice Token balances\n        /// @dev account => balance\n        mapping(address => uint256) balances;\n        /// @notice Account spender allowances\n        /// @dev account => spender => allowance\n        mapping(address => mapping(address => uint256)) allowances;\n        /// @notice Total supply of the pool. Be careful when using this directly from the struct. The pool itself\n        /// modifies this number based on unlocked profited shares\n        uint256 totalSupply;\n        /// @notice ERC20 Permit nonces\n        /// @dev account -> nonce. Exposed via `nonces(owner)`\n        mapping(address => uint256) nonces;\n    }\n\n    /// @notice EIP2612 permit type hash\n    bytes32 public constant PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n    /// @notice EIP712 domain type hash\n    bytes32 public constant TYPE_HASH =\n        keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n\n    /// @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n    /// @param sender Address whose tokens are being transferred.\n    /// @param balance Current balance for the interacting account.\n    /// @param needed Minimum amount required to perform a transfer.\n    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);\n\n    /// @dev Indicates a failure with the token `sender`. Used in transfers.\n    /// @param sender Address whose tokens are being transferred.\n    error ERC20InvalidSender(address sender);\n\n    /// @dev Indicates a failure with the token `receiver`. Used in transfers.\n    /// @param receiver Address to which tokens are being transferred.\n    error ERC20InvalidReceiver(address receiver);\n\n    /// @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.\n    ///@param spender Address that may be allowed to operate on tokens without being their owner.\n    /// @param allowance Amount of tokens a `spender` is allowed to operate with.\n    ///@param needed Minimum amount required to perform a transfer.\n    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n    /// @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n    /// @param approver Address initiating an approval operation.\n    error ERC20InvalidApprover(address approver);\n\n    /// @dev Indicates a failure with the `spender` to be approved. Used in approvals.\n    /// @param spender Address that may be allowed to operate on tokens without being their owner.\n    error ERC20InvalidSpender(address spender);\n\n    /// @dev Permit deadline has expired.\n    error ERC2612ExpiredSignature(uint256 deadline);\n    /// @dev Mismatched signature.\n    error ERC2612InvalidSigner(address signer, address owner);\n    /// @dev The nonce used for an `account` is not the expected current nonce.\n    error InvalidAccountNonce(address account, uint256 currentNonce);\n\n    /// @dev Emitted when `value` tokens are moved from one account `from` to another `to`.\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /// @dev Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}.\n    /// `value` is the new allowance.\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /// @dev Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens.\n    function approve(TokenData storage data, address spender, uint256 value) external returns (bool) {\n        address owner = msg.sender;\n        approve(data, owner, spender, value);\n        return true;\n    }\n\n    /// @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.\n    function approve(TokenData storage data, address owner, address spender, uint256 value) public {\n        _approve(data, owner, spender, value, true);\n    }\n\n    function transfer(TokenData storage data, address to, uint256 value) external returns (bool) {\n        address owner = msg.sender;\n        _transfer(data, owner, to, value);\n        return true;\n    }\n\n    /// @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism.\n    /// value` is then deducted from the caller's allowance.\n    function transferFrom(TokenData storage data, address from, address to, uint256 value) external returns (bool) {\n        address spender = msg.sender;\n        _spendAllowance(data, from, spender, value);\n        _transfer(data, from, to, value);\n        return true;\n    }\n\n    /// @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).\n    function mint(TokenData storage data, address account, uint256 value) external {\n        if (account == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(data, address(0), account, value);\n    }\n\n    /// @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.\n    function burn(TokenData storage data, address account, uint256 value) external {\n        if (account == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        _update(data, account, address(0), value);\n    }\n\n    function permit(\n        TokenData storage data,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external {\n        if (block.timestamp > deadline) {\n            revert ERC2612ExpiredSignature(deadline);\n        }\n\n        uint256 nonce;\n        // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be\n        // decremented or reset. This guarantees that the nonce never overflows.\n        unchecked {\n            // It is important to do x++ and not ++x here. Nonces starts at 0\n            nonce = data.nonces[owner]++;\n        }\n\n        bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonce, deadline));\n\n        bytes32 hash = ECDSA.toTypedDataHash(IERC20Permit(address(this)).DOMAIN_SEPARATOR(), structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        if (signer != owner) {\n            revert ERC2612InvalidSigner(signer, owner);\n        }\n\n        approve(data, owner, spender, value);\n    }\n\n    /// @dev Moves a `value` amount of tokens from `from` to `to`.\n    function _transfer(TokenData storage data, address from, address to, uint256 value) private {\n        if (from == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        if (to == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(data, from, to, value);\n    }\n\n    /// @dev Updates `owner` s allowance for `spender` based on spent `value`.\n    function _spendAllowance(TokenData storage data, address owner, address spender, uint256 value) private {\n        uint256 currentAllowance = data.allowances[owner][spender];\n        if (currentAllowance != type(uint256).max) {\n            if (currentAllowance < value) {\n                revert ERC20InsufficientAllowance(spender, currentAllowance, value);\n            }\n            unchecked {\n                _approve(data, owner, spender, currentAllowance - value, false);\n            }\n        }\n    }\n\n    /// @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`\n    /// (or `to`) is the zero address.\n    function _update(TokenData storage data, address from, address to, uint256 value) private {\n        if (from == address(0)) {\n            // Overflow check required: The rest of the code assumes that totalSupply never overflows\n            data.totalSupply += value;\n        } else {\n            uint256 fromBalance = data.balances[from];\n            if (fromBalance < value) {\n                revert ERC20InsufficientBalance(from, fromBalance, value);\n            }\n            unchecked {\n                // Overflow not possible: value <= fromBalance <= totalSupply.\n                data.balances[from] = fromBalance - value;\n            }\n        }\n\n        if (to == address(0)) {\n            unchecked {\n                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.\n                data.totalSupply -= value;\n            }\n        } else {\n            unchecked {\n                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.\n                data.balances[to] += value;\n            }\n        }\n\n        emit Transfer(from, to, value);\n    }\n\n    /// @dev Variant of `_approve` with an optional flag to enable or disable the Approval event.\n    function _approve(TokenData storage data, address owner, address spender, uint256 value, bool emitEvent) private {\n        if (owner == address(0)) {\n            revert ERC20InvalidApprover(address(0));\n        }\n        if (spender == address(0)) {\n            revert ERC20InvalidSpender(address(0));\n        }\n        data.allowances[owner][spender] = value;\n        if (emitEvent) {\n            emit Approval(owner, spender, value);\n        }\n    }\n}\n"
      },
      "src/interfaces/rewarders/IBaseRewarder.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\ninterface IBaseRewarder {\n    event RewardAdded(\n        uint256 reward,\n        uint256 rewardRate,\n        uint256 lastUpdateBlock,\n        uint256 periodInBlockFinish,\n        uint256 historicalRewards\n    );\n    event UserRewardUpdated(\n        address indexed user, uint256 amount, uint256 rewardPerTokenStored, uint256 lastUpdateBlock\n    );\n    event Staked(address indexed user, uint256 amount);\n    event Withdrawn(address indexed user, uint256 amount);\n    event RewardPaid(address indexed user, uint256 reward);\n    event QueuedRewardsUpdated(uint256 startingQueuedRewards, uint256 startingNewRewards, uint256 queuedRewards);\n    event AddedToWhitelist(address indexed wallet);\n    event RemovedFromWhitelist(address indexed wallet);\n\n    event TokeLockDurationUpdated(uint256 newDuration);\n\n    /**\n     * @notice Claims and transfers all rewards for the specified account\n     */\n    function getReward() external;\n\n    /**\n     * @notice Stakes the specified amount of tokens for the specified account.\n     * @param account The address of the account to stake tokens for.\n     * @param amount The amount of tokens to stake.\n     */\n    function stake(address account, uint256 amount) external;\n\n    /**\n     * @notice Calculate the earned rewards for an account.\n     * @param account Address of the account.\n     * @return The earned rewards for the given account.\n     */\n    function earned(address account) external view returns (uint256);\n\n    /**\n     * @notice Calculates the rewards per token for the current block.\n     * @dev The total amount of rewards available in the system is fixed, and it needs to be distributed among the users\n     * based on their token balances and staking duration.\n     * Rewards per token represent the amount of rewards that each token is entitled to receive at the current block.\n     * The calculation takes into account the reward rate, the time duration since the last update,\n     * and the total supply of tokens in the staking pool.\n     * @return The updated rewards per token value for the current block.\n     */\n    function rewardPerToken() external view returns (uint256);\n\n    /**\n     * @notice Get the current reward rate per block.\n     * @return The current reward rate per block.\n     */\n    function rewardRate() external view returns (uint256);\n\n    /**\n     * @notice Get the current TOKE lock duration.\n     * @return The current TOKE lock duration.\n     */\n    function tokeLockDuration() external view returns (uint256);\n\n    /**\n     * @notice Get the last block where rewards are applicable.\n     * @return The last block number where rewards are applicable.\n     */\n    function lastBlockRewardApplicable() external view returns (uint256);\n\n    /**\n     * @notice The total amount of tokens staked\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @notice The amount of tokens staked for the specified account\n     * @param account The address of the account to get the balance of\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @notice Queue new rewards to be distributed.\n     * @param newRewards The amount of new rewards to be queued.\n     */\n    function queueNewRewards(uint256 newRewards) external;\n\n    /**\n     * @notice Token distributed as rewards\n     * @return reward token address\n     */\n    function rewardToken() external view returns (address);\n\n    /**\n     * @notice Add an address to the whitelist.\n     * @param wallet The address to be added to the whitelist.\n     */\n    function addToWhitelist(address wallet) external;\n\n    /**\n     * @notice Remove an address from the whitelist.\n     * @param wallet The address to be removed from the whitelist.\n     */\n    function removeFromWhitelist(address wallet) external;\n\n    /**\n     * @notice Check if an address is whitelisted.\n     * @param wallet The address to be checked.\n     * @return bool indicating if the address is whitelisted.\n     */\n    function isWhitelisted(address wallet) external view returns (bool);\n}\n"
      },
      "src/interfaces/rewarders/IExtraRewarder.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IBaseRewarder } from \"src/interfaces/rewarders/IBaseRewarder.sol\";\n\ninterface IExtraRewarder is IBaseRewarder {\n    /**\n     * @notice Withdraws the specified amount of tokens from the vault for the specified account.\n     * @param account The address of the account to withdraw tokens for.\n     * @param amount The amount of tokens to withdraw.\n     */\n    function withdraw(address account, uint256 amount) external;\n\n    /**\n     * @notice Claims and transfers all rewards for the specified account from this contract.\n     * @param account The address of the account to claim rewards for.\n     */\n    function getReward(address account) external;\n}\n"
      },
      "src/interfaces/vault/IBaseAssetVault.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\ninterface IBaseAssetVault {\n    /// @notice Asset that this Vault primarily manages\n    /// @dev Vault decimals should be the same as the baseAsset\n    function baseAsset() external view returns (address);\n}\n"
      },
      "src/interfaces/stats/IDexLSTStats.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { ILSTStats } from \"src/interfaces/stats/ILSTStats.sol\";\n\n/// @title Return stats DEXs with LSTs\ninterface IDexLSTStats {\n    event DexSnapshotTaken(uint256 snapshotTimestamp, uint256 priorFeeApr, uint256 newFeeApr, uint256 unfilteredFeeApr);\n\n    struct StakingIncentiveStats {\n        // time-weighted average total supply to prevent spikes/attacks from impacting rebalancing\n        uint256 safeTotalSupply;\n        // rewardTokens, annualizedRewardAmounts, and periodFinishForRewards will match indexes\n        // they are split to workaround an issue with forge having nested structs\n        // address of the reward tokens\n        address[] rewardTokens;\n        // the annualized reward rate for the reward token\n        uint256[] annualizedRewardAmounts;\n        // the timestamp for when the rewards are set to terminate\n        uint40[] periodFinishForRewards;\n        // incentive rewards score. max 48, min 0\n        uint8 incentiveCredits;\n    }\n\n    struct DexLSTStatsData {\n        uint256 lastSnapshotTimestamp;\n        uint256 feeApr;\n        uint256[] reservesInEth;\n        StakingIncentiveStats stakingIncentiveStats;\n        ILSTStats.LSTStatsData[] lstStatsData;\n    }\n\n    /// @notice Get the current stats for the DEX with underlying LST tokens\n    /// @dev Returned data is a combination of current data and filtered snapshots\n    /// @return dexLSTStatsData current data on the DEX\n    function current() external returns (DexLSTStatsData memory dexLSTStatsData);\n}\n"
      },
      "src/interfaces/stats/ILSTStats.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\n/// @title Return stats on base LSTs\ninterface ILSTStats {\n    struct LSTStatsData {\n        uint256 lastSnapshotTimestamp;\n        uint256 baseApr;\n        int256 discount; // positive number is a discount, negative is a premium\n        uint24[10] discountHistory; // 7 decimal precision\n        uint40[5] discountTimestampByPercent; // each index is the timestamp that the token reached that discount\n        uint256[] slashingCosts;\n        uint256[] slashingTimestamps;\n    }\n\n    /// @notice Used to transfer LST snapshot data to other chain.\n    struct LSTDestinationInfo {\n        uint256 snapshotTimestamp;\n        uint256 newBaseApr;\n        uint256 currentEthPerToken;\n    }\n\n    /// @notice Get the current stats for the LST\n    /// @dev Returned data is a combination of current data and filtered snapshots\n    /// @return lstStatsData current data on the LST\n    function current() external returns (LSTStatsData memory lstStatsData);\n\n    /// @notice Get the EthPerToken (or Share) for the LST\n    /// @return ethPerShare the backing eth for the LST\n    function calculateEthPerToken() external view returns (uint256 ethPerShare);\n\n    /// @notice Get if the underlying LST token is rebasing\n    /// @return rebasing is true if the lst is a rebasing token\n    function isRebasing() external view returns (bool rebasing);\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "forge-std/=lib/forge-std/src/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "src/=src/",
        "test/=test/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
        "erc4626-tests/=lib/erc4626-tests/",
        "prb-math/=lib/prb-math/",
        "crytic/properties/=lib/properties/",
        "ERC4626/=lib/properties/lib/ERC4626/contracts/",
        "properties/=lib/properties/contracts/",
        "solmate/=lib/properties/lib/solmate/src/",
        "usingtellor/=lib/usingtellor/contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs"
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "london",
      "viaIR": false,
      "libraries": {}
    }
  }}