{"file_path":"contracts/IdleCDOEpochVariant.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.10;\n\nimport {IdleCDOCreditVault} from \"./IdleCDOCreditVault.sol\";\nimport {IKeyring} from \"./interfaces/keyring/IKeyring.sol\";\nimport {IProgrammableBorrower} from \"./interfaces/IProgrammableBorrower.sol\";\nimport {IdleCreditVault} from \"./strategies/idle/IdleCreditVault.sol\";\n\nerror NotAllowed();\n\n/// @title IdleCDO variant that supports epochs. \n/// @dev When epoch is running no deposits or withdrawals are allowed. When epoch ends \n/// lenders can request withdrawals, that will be fullfilled by the end of the next epoch.\n/// If the apr for the new epoch is lower than the last one, lenders can request 'instant' \n/// withdrawals that will be fullfilled when the epoch starts and after instantWithdrawDelay (3 days).\n/// Funds for instant and normal withdrawals are sent to the strategy contract (IdleCreditVault)\n/// @custom:oz-upgrades-unsafe-allow missing-initializer\ncontract IdleCDOEpochVariant is IdleCDOCreditVault {\n  /// @notice flag to check if epoch is running\n  bool public isEpochRunning;\n  /// @notice flag to allow AA withdraw requests\n  bool public allowAAWithdrawRequest;\n  /// @notice flag to allow BB withdraw requests\n  bool public allowBBWithdrawRequest;\n  /// @notice duration of the epoch\n  uint256 public epochDuration;\n  /// @notice delay to allow instant withdraw requests after next epoch starts\n  uint256 public instantWithdrawDelay;\n  /// @notice expected interest for the current epoch\n  uint256 public expectedEpochInterest;\n  /// @notice end date of the current epoch\n  uint256 public epochEndDate;\n  /// @notice deadline to allow instant withdraw requests\n  uint256 public instantWithdrawDeadline;\n  /// @notice apr of the last epoch, unscaled\n  uint256 public lastEpochApr;\n  /// @notice min apr change to trigger instant withdraw\n  uint256 public instantWithdrawAprDelta;\n  /// @notice fees from pending withdraw request for the curr epoch\n  uint256 public pendingWithdrawFees;\n  /// @notice net underlyings gained last epoch\n  uint256 public lastEpochInterest;\n  /// @notice flag to allow instant withdraws\n  bool public allowInstantWithdraw;\n  /// @notice flag to completely disable instant withdraw\n  bool public disableInstantWithdraw;\n  /// @notice flag to check if borrower defaulted\n  bool public defaulted;\n  /// @notice Keyring wallet checker address\n  address public keyring;\n  /// @notice keyring policyId\n  uint256 public keyringPolicyId;\n  /// @notice time between 2 epochs, can be set to 0 to start the next epoch without waiting a specified time\n  uint256 public bufferPeriod;\n  /// @dev Deprecated storage slot. Do not remove: kept to preserve the upgradeable storage layout.\n  bool internal keyringAllowWithdraw;\n  /// @notice amount of over/under performance that withdrawal requests will cause\n  int256 internal interestForOverUnderPerformance;\n  /// @notice flag to disable deposits during an epoch\n  bool public isDepositDuringEpochDisabled;\n  /// @notice flag to mint interest as strategy tokens without moving underlyings\n  bool public isInterestMinted;\n\n  event AccrueInterest(uint256 interest, uint256 fees);\n  event BorrowerDefault(uint256 funds);\n\n  function _additionalInit() internal virtual override {\n    // all yield to senior\n    isAYSActive = false;\n\n    // set epoch params\n    epochDuration = 30 days;\n    bufferPeriod = 5 days;\n    // we set epochEndDate to avoid issues with the first epoch, so we set\n    // it to current time minus bufferPeriod so that the first epoch can start right away\n    epochEndDate = block.timestamp - 5 days;\n\n    // allow requests for withdrawals\n    allowAAWithdrawRequest = true;\n    allowBBWithdrawRequest = true;\n\n    // default no instant withdraw allowed\n    disableInstantWithdraw = true;\n\n    // by default deposits during an epoch are disabled\n    isDepositDuringEpochDisabled = true;\n\n    // scale the apr to include the buffer period\n    _setScaledApr(_getStrategyApr());\n  }\n\n  /// @notice Check if msg sender is owner or manager\n  function _checkOnlyOwnerOrManager() internal view {\n    _checkNotAllowed(msg.sender != owner() && msg.sender != IdleCreditVault(strategy).manager());\n  }\n\n  /// @notice Revert if condition is true\n  /// @param _revertCondition condition to check\n  function _checkNotAllowed(bool _revertCondition) internal pure {\n    if (_revertCondition) revert NotAllowed();\n  }\n\n  /// @notice Ensure programmable borrowers are only used with minted-interest accounting.\n  /// @dev Programmable borrower flows assume minted interest and do not support instant funding.\n  function _checkProgrammableBorrowerMode() internal view {\n    _checkNotAllowed(isProgrammableBorrower && (!isInterestMinted || _pendingInstant() != 0));\n  }\n\n  ///\n  /// Only owner or manager methods \n  ///\n\n  /// @notice update epoch duration\n  /// @dev IMPORTANT: bufferPeriod should not be changed once set otherwise interest calculations will be wrong\n  /// @param _epochDuration duration in seconds\n  /// @param _bufferPeriod time between 2 epochs\n  function setEpochParams(uint256 _epochDuration, uint256 _bufferPeriod) public {\n    _checkOnlyOwnerOrManager();\n    // cannot set epoch params if epoch is running\n    // cannot set epochDuration to 0 as it's reserved for closing the pool\n    // and cannot set epochDuration if previously was set to 0 as borrower repaid all funds\n    _checkNotAllowed(defaulted || isEpochRunning || _epochDuration == 0 || epochDuration == 0);\n    epochDuration = _epochDuration;\n    bufferPeriod = _bufferPeriod;\n  }\n\n  /// @notice update instant withdraw params\n  /// @param _delay delay in seconds\n  /// @param _aprDelta min apr delta to trigger instant withdraw\n  /// @param _disable flag to disable instant withdraw\n  function setInstantWithdrawParams(uint256 _delay, uint256 _aprDelta, bool _disable) public virtual {\n    _checkOnlyOwnerOrManager();\n    _checkNotAllowed(paused());\n    instantWithdrawDelay = _delay;\n    instantWithdrawAprDelta = _aprDelta;\n    disableInstantWithdraw = _disable;\n  }\n\n  /// @notice update keyring address\n  /// @param _keyring address of the keyring contract\n  /// @param _keyringPolicyId policyId to check for wallet\n  function setKeyringParams(address _keyring, uint256 _keyringPolicyId) external {\n    _checkOnlyOwnerOrManager();\n    keyring = _keyring;\n    keyringPolicyId = _keyringPolicyId;\n  }\n\n  /// @notice set flag to disable deposits during an epoch\n  /// @param _isDisabled true to disable deposits during an epoch\n  function setIsDepositDuringEpochDisabled(bool _isDisabled) external {\n    _checkOnlyOwnerOrManager();\n    isDepositDuringEpochDisabled = _isDisabled;\n  }\n\n  /// @notice Skim raw donated underlyings before forcing accounting.\n  /// @dev Prevents unsolicited transfers from being crystallized as tranche gains by manual accounting.\n  function updateAccounting() external override {\n    _checkOnlyOwnerOrGuardian();\n    _skimDonatedAssets();\n    _forceUpdateAccounting();\n  }\n\n  /// @notice set flag to mint interest as strategy tokens without moving underlyings\n  /// @dev Programmable borrowers always require minted-interest accounting.\n  /// @param _isMinted true to mint interest instead of transferring underlyings\n  function setIsInterestMinted(bool _isMinted) external {\n    _checkOnlyOwner();\n    _checkNotAllowed(!_isMinted && isProgrammableBorrower);\n    isInterestMinted = _isMinted;\n  }\n\n  /// @notice Set whether the current strategy borrower should be treated as programmable.\n  /// @dev This is configured explicitly instead of inferring from code size so contract borrowers\n  /// such as Safe wallets are not misclassified. The flag cannot be changed while an epoch is live.\n  /// @param _isProgrammable true to enable programmable-borrower hooks and accounting\n  function setIsProgrammableBorrower(bool _isProgrammable) external {\n    _checkOnlyOwner();\n    _checkNotAllowed(isEpochRunning);\n    isProgrammableBorrower = _isProgrammable;\n  }\n\n  /// @notice Finalize a hard-default recovery and crystallize the realized loss on tranche prices.\n  /// @dev `_recoverySource` must approve the strategy for `_recoveredAmount`. Recovered funds are sent\n  /// directly to the strategy recovery reserve so they do not inflate CDO NAV before finalization.\n  /// Finalization is one-time and cannot be topped up through this recovery path. Any raw underlying\n  /// held by the CDO is treated as a donation and sent to `feeReceiver` before recovery is calculated.\n  /// Recovery uses one aggregate multiplier and does not preserve AA seniority. Before applying\n  /// that multiplier, active gross backing is split by saved NAV and active default interest uses\n  /// the configured AA/BB APR split, matching the tranche-specific interest in fixed-APR receipts.\n  /// A zero or subprecision aggregate recovery finalizes at price zero so tranche prices expose the\n  /// full loss and pending receipts can be cleared without a payout.\n  /// @param _recoveredAmount amount of underlying recovered for active LPs and defaulted receipts\n  /// @param _recoverySource address that supplies the recovered underlying\n  function finalizeDefault(uint256 _recoveredAmount, address _recoverySource) external {\n    _checkOnlyOwnerOrManager();\n    // Send raw CDO underlying to feeReceiver as donated assets; recovery must enter through the strategy.\n    _skimDonatedAssets();\n    // Recovery math and reserve accounting live in the strategy where receipt claims are paid.\n    uint256 defaultBBNav = IdleCreditVault(strategy).finalizeDefaultRecovery(_recoveredAmount, _recoverySource);\n\n    // Default recovery should not keep accruing fees or leave old fee claims senior to LP recovery.\n    fee = 0;\n    managementFee = 0;\n    unclaimedFees = 0;\n    latestHarvestBlock = block.timestamp;\n\n    // The strategy returns BB's final recovered active NAV. Writing both final NAVs directly\n    // makes hard default the sole exception to the ordinary BB-first loss waterfall.\n    lastNAVBB = defaultBBNav;\n    lastNAVAA = _contractTokenBalance(strategyToken) - defaultBBNav;\n\n    // Crystallize the strategy-token rebalance so virtualPrice/tranchePrice expose the realized loss.\n    _forceUpdateAccounting();\n\n    expectedEpochInterest = 0;\n    pendingWithdrawFees = 0;\n    allowAAWithdrawRequest = true;\n    allowBBWithdrawRequest = true;\n    // This flag gates claimInstantWithdrawRequest. New instant requests stay disabled below.\n    allowInstantWithdraw = true;\n    disableInstantWithdraw = true;\n    epochDuration = 0;\n    epochEndDate = 0;\n    _setScaledApr(0);\n  }\n\n  /// @notice Start the epoch. No deposits or withdrawals are allowed after this.\n  /// @dev We calculate the total funds that the borrower should return at the end of the epoch\n  /// ie interests + fees from normal withdraw requests. We send to the borrower underlyings amounts ie interests + \n  /// new deposits - instant withdraw requests if any. If funds are not enough to satisfy all requests\n  /// then borrower should return the difference before instantWithdrawDeadline. After epoch start there\n  /// should be no underlyings in this contract\n  function startEpoch() external {\n    _checkOnlyOwnerOrManager();\n\n    // Check that buffer period passed (and epoch is not running as epochEndDate is set)\n    // and that the pool is not closed (ie epochDuration == 0)\n    uint256 _epochDuration = epochDuration; \n    _checkNotAllowed(defaulted || block.timestamp < (epochEndDate + bufferPeriod) || _epochDuration == 0);\n    _checkProgrammableBorrowerMode();\n    // Remove raw donated underlyings before calculating epoch interest or borrower transfer amounts.\n    _skimDonatedAssets();\n\n    isEpochRunning = true;\n    // prevent deposits\n    _pause();\n\n    // prevent withdrawals requests\n    allowAAWithdrawRequest = false;\n    allowBBWithdrawRequest = false;\n\n    IdleCreditVault _strategy = IdleCreditVault(strategy);\n\n    // calculate expected interest \n    // NOTE: all withdrawal requests, burn tranche tokens and decrease getContractValue,\n    // this can be done only prior to the start of the epoch so getContractValue() is the total amount net\n    // of all withdrawal requests. We add the fee that we should get for normal pending withdraws\n    // we also add/remove the over/under performance caused by withdraw requests.\n    // Pending fees remain due even if fixed-APR requests exhaust active interest.\n    int256 adjustedActiveInterest = int256(_calcInterest(getContractValue())) + interestForOverUnderPerformance;\n    if (adjustedActiveInterest < 0) adjustedActiveInterest = 0;\n    expectedEpochInterest = pendingWithdrawFees + uint256(adjustedActiveInterest);\n    interestForOverUnderPerformance = 0;\n\n    // set expected epoch end date\n    epochEndDate = block.timestamp + _epochDuration;\n    // set instant withdraw deadline\n    instantWithdrawDeadline = block.timestamp + instantWithdrawDelay;\n\n    // transfer in this contract funds from interest payment (if any) and buffer deposits sent to the strategy\n    uint256 _totEpochDeposits = _strategy.totEpochDeposits();\n    // If interest is minted we do not transfer interest to the strategy\n    uint256 _toSend = isInterestMinted ? _totEpochDeposits : lastEpochInterest + _totEpochDeposits;\n    _strategy.sendInterestAndDeposits(_toSend);\n\n    // we should first check if there are *instant* redeem requests pending \n    // and if yes we should send as much underlyings as possible to the IdleCreditVault contract\n    // if there is any surplus then we send those to the borrower\n    uint256 pendingInstant = _pendingInstant();\n    uint256 totUnderlyings = _contractTokenBalance(token);\n    uint256 _pendingWithdraws = _strategy.pendingWithdraws();\n    _strategy.collectInstantWithdrawFunds(pendingInstant > totUnderlyings ? totUnderlyings : pendingInstant);\n\n    // if there are more requests than the current underlyings we simply send all underlyings\n    // to the IdleCreditVault contract\n    if (pendingInstant > totUnderlyings) {\n      // if borrower is programmable, notify epoch start even if no funds were sent\n      _startEpochProgrammableBorrower(_pendingWithdraws);\n      return;\n    }\n    // allow instant withdraws right away without waiting for the deadline\n    allowInstantWithdraw = true;\n    // and transfer the surplus to the borrower\n    uint256 _toBorrower = totUnderlyings - pendingInstant;\n    try this.sendFundsToBorrower(_toBorrower) {\n      // funds transferred correctly\n      _startEpochProgrammableBorrower(_pendingWithdraws);\n    } catch {\n      // The borrower did not receive the funds, so keep the strategy-token backing in the strategy.\n      _transferUnderlyings(address(_strategy), _toBorrower);\n      _strategy.reserveDefaultRecovery(_toBorrower);\n      _handleBorrowerDefault(_toBorrower);\n    }\n  }\n\n  /// @notice workaround to have safeTransfer to borrower as external and use it in a try/catch block\n  /// @param _amount Amount of underlyings to transfer\n  function sendFundsToBorrower(uint256 _amount) external {\n    _checkNotAllowed(msg.sender != address(this));\n    _transferUnderlyings(_borrower(), _amount);\n  }\n\n  /// @notice Stop epoch, accrue interest to the vault and get funds to fullfill normal\n  /// (ie non-instant) withdraw requests from the prev epoch.\n  /// @param _newApr New apr to set for the next epoch\n  /// @param _interest Interest gained in the epoch. This will overwrite the expected interest\n  /// must be 0 if there is no need to overwrite the expected interest and if > 0 then it should\n  /// be greater than the pending withdraw fees and newApr must be 0. If `_interest` is 1 then\n  /// it is interpreted as a special case where we request everything back from the borrower.\n  /// Programmable borrowers only support `_interest` values `0` and `1`.\n  /// @dev Only owner or manager can call this function. Borrower MUST approve this contract\n  function stopEpoch(uint256 _newApr, uint256 _interest) public {\n    _stopEpoch(_newApr, _interest, 0);\n  }\n\n  /// @notice Internal stop-epoch implementation with optional proportional pending-receipt loss.\n  /// @param _newApr New apr to set for the next epoch\n  /// @param _interest Interest gained in the epoch\n  /// @param _lossAmount Loss amount to split between active LPs and pending receipts\n  function _stopEpoch(uint256 _newApr, uint256 _interest, uint256 _lossAmount) private {\n    _checkOnlyOwnerOrManager();\n    bool _isRequestingAllFunds = _interest == 1;\n    _checkProgrammableBorrowerMode();\n\n    IdleCreditVault _strategy = IdleCreditVault(strategy);\n    uint256 _pendingWithdrawFees = pendingWithdrawFees;\n\n    _checkNotAllowed(\n      // Check that epoch is running\n      !isEpochRunning || \n      // Check that end date is passed\n      block.timestamp < epochEndDate || \n      // Check that there are no pending instant withdraws, ie `getInstantWithdrawFunds` was called\n      // before closing the epoch\n      _pendingInstant() != 0 ||\n      // Check that overridden interest, if passed (ie > 1), is greater than pending withdraw fees and the apr is 0 \n      // otherwise withdrawal requests may not be fullfilled as they consider also the interest gained in the next epoch \n      (_interest > 1 && (_interest < _pendingWithdrawFees || _newApr != 0)) ||\n      // Closing already recalls all principal, so applying a separate loss burn would strand returned cash.\n      (_isRequestingAllFunds && _lossAmount != 0)\n    );\n\n    uint256 _totBorrowed = _beforeStopEpoch(_isRequestingAllFunds);\n    // we check if there are donated assets to the pool and transfer them to the feeReceiver if any\n    _skimDonatedAssets();\n\n    _interest = _resolveStopEpochInterest(_interest);\n\n    // Base interest for stopEpoch: explicit override (>1) or precomputed expected epoch interest.\n    uint256 _expectedInterest;\n    // Strategy finalizes APR0 bucket state and returns adjusted stopEpoch values.\n    (_expectedInterest, _pendingWithdrawFees) = _strategy.prepareStopEpochWithApr0(_interest);\n    // Pending withdraws may be increased during APR0 settlement, so read after prepareStopEpochWithApr0.\n    uint256 _pendingWithdraws = _strategy.pendingWithdraws();\n\n    // special case where we get everything back from the borrower\n    if (_isRequestingAllFunds) {\n      // Recall gross strategy-token principal, including fee backing excluded from net CDO NAV.\n      // Prefunded variants also add queue deposits already sent directly to the borrower.\n      _totBorrowed += _contractTokenBalance(strategyToken);\n      _expectedInterest += _totBorrowed;\n    }\n    uint256 _grossInterest = _isRequestingAllFunds ? _expectedInterest - _totBorrowed : _expectedInterest;\n    bool _mintInterest = isInterestMinted && !_isRequestingAllFunds;\n    // In minted mode IdleCDO only needs cash for withdraw requests, not for epoch interest itself.\n    uint256 _amountToPullFromBorrower = _mintInterest ? 0 : _expectedInterest;\n    if (_mintInterest && _interest > 1) {\n      uint256 _maxApr = _strategy.maxApr();\n      _checkNotAllowed(_maxApr != 0 && _grossInterest > _calcInterestWithApr(getContractValue(), _maxApr) + _pendingWithdrawFees);\n    }\n\n    // Checkpoint management fees before borrower funds are pulled in so the elapsed-period\n    // accrual applies only to the pre-stop live NAV, not to newly received epoch interest.\n    _accrueManagementFee();\n\n    // Persist only resolved epoch interest for recovery accounting. In close-pool mode `_interest == 1`\n    // is a sentinel: `_grossInterest` excludes the principal added to `_expectedInterest` above.\n    expectedEpochInterest = _grossInterest;\n    pendingWithdrawFees = _pendingWithdrawFees;\n\n    // Pending receipts have no tranche identity, so their aggregate loss is pro rata across all\n    // receipts. The remaining active loss is applied BB-first after the stop succeeds.\n    (_pendingWithdraws, _lossAmount) = _strategy.previewLossAdjustedWithdrawFunds(_lossAmount);\n\n    if (isProgrammableBorrower) {\n      // Ask the programmable borrower to recall ERC4626 liquidity before IdleCDO pulls funds.\n      // Hook reverts bubble so transient ERC4626 liquidity failures can be retried.\n      if (!IProgrammableBorrower(_borrower()).onStopEpoch(_amountToPullFromBorrower + _pendingWithdraws, _isRequestingAllFunds)) {\n        // Emit the exact cash liability requested from the borrower, including recalled principal\n        // in close-pool mode and excluding interest fronted through minted accounting.\n        _handleBorrowerDefault(_amountToPullFromBorrower + _pendingWithdraws);\n        return;\n      }\n    }\n\n    // accrue interest to idleCDO, this will increase tranche prices.\n    // Send also tot withdraw requests amount to the IdleCreditVault contract\n    try this.getFundsFromBorrower(_amountToPullFromBorrower + _pendingWithdraws) {\n      // transfer in strategy and decrease pendingWithdraws\n        _strategy.collectWithdrawFunds(_pendingWithdraws);\n      // Only settle borrower interest when CDO is fronting it (minted mode, not closing pool).\n      // When requesting all funds (_interest == 1) the CDO pulls cash directly, no fronting.\n      if (_mintInterest && isProgrammableBorrower) {\n        IProgrammableBorrower(_borrower()).settleBorrowerInterest();\n      }\n      // Split pending withdraw fees before update accounting\n      // NOTE: Fees are sent with 2 different transfer calls, here and after updateAccounting, to avoid complicated calculations\n      if (!_mintInterest) {\n        _transferFeeUnderlyings(_pendingWithdrawFees);\n      }\n\n      if (_isRequestingAllFunds) {\n        // we already have strategyTokens equal to _totBorrowed in this contract\n        // so we transfer _totBorrowed to the strategy to avoid double counting for getContractValue\n        _transferUnderlyings(address(_strategy), _totBorrowed);\n      }\n\n      if (_mintInterest) {\n        // if interest is not transferred we mint strategy tokens equal to the full epoch interest\n        if (_grossInterest != 0) _strategy.mintStrategyTokens(_grossInterest);\n        // and increase unclaimedFees by pending withdraw fees before _updateAccounting\n        unclaimedFees += _pendingWithdrawFees;\n      }\n\n      // update tranche prices and unclaimed fees\n      _updateAccounting();\n\n      // transfer fees\n      uint256 _fees = unclaimedFees;\n      if (_mintInterest) {\n        // If interest is minted then we mint new shares for fee receivers instead of transferring underlyings\n        if (_fees != 0) {\n          uint256 feeReceiverAmount = _feeReceiverAmount(_fees);\n          if (feeReceiverAmount != 0) {\n            _mintSharesAtCurrPrice(feeReceiverAmount, feeReceiver, AATranche);\n          }\n          _mintSharesAtCurrPrice(_fees - feeReceiverAmount, owner(), AATranche);\n          _updateSplitRatio(_getAARatio(true));\n        }\n      } else {\n        // Cash-funded fees can only use gross interest not already owed to pending withdrawals.\n        uint256 _availableForFees = _grossInterest > _pendingWithdrawFees ? _grossInterest - _pendingWithdrawFees : 0;\n        if (_fees > _availableForFees) {\n          _fees = _availableForFees;\n        }\n        _transferFeeUnderlyings(_fees);\n      }\n      // Any fee that cannot be paid in cash remains accrued and continues reducing NAV.\n      unclaimedFees -= _fees;\n\n      uint256 _totalFees = _fees + (_mintInterest ? 0 : _pendingWithdrawFees);\n      // save net gain (this does not include interest gained for pending withdrawals)\n      uint256 netInterest = _grossInterest > _totalFees ? _grossInterest - _totalFees : 0;\n      lastEpochInterest = netInterest;\n      // mint strategyTokens equal to interest and send underlying to strategy to avoid double counting for NAV\n      _strategy.deposit(_mintInterest ? 0 : netInterest);\n\n      // save last apr, unscaled\n      lastEpochApr = _strategy.unscaledApr();\n      // set apr for next epoch\n      _setScaledApr(_newApr);\n\n      // stop epoch\n      isEpochRunning = false;\n      expectedEpochInterest = 0;\n      pendingWithdrawFees = 0;\n\n      if (!skipDefaultCheck) {\n        // Reopen ordinary deposits and requests only when operations were not explicitly shut down.\n        _unpause();\n        allowAAWithdrawRequest = true;\n        allowBBWithdrawRequest = true;\n      }\n      // block instant withdraws claims as these can be done only after the deadline\n      // or only if borrower is repaying all funds\n      allowInstantWithdraw = _isRequestingAllFunds;\n\n      if (_isRequestingAllFunds) {\n        // user will request only normal withdraw and can claim right after\n        disableInstantWithdraw = true;\n        epochDuration = 0;\n        epochEndDate = 0;\n      }\n\n      emit AccrueInterest(_expectedInterest - _totBorrowed, _totalFees);\n      if (_lossAmount != 0) {\n        _strategy.burnStrategyTokens(_lossAmount);\n        // Realize the active loss immediately through the ordinary BB-first waterfall.\n        _forceUpdateAccounting();\n      }\n    } catch {\n      // if borrower defaults, prev instant withdraw requests can still be withdrawn\n      // as were already fullfilled prior to the default (all funds already sent to the strategy)\n      _handleBorrowerDefault(_amountToPullFromBorrower + _pendingWithdraws);\n    }\n  }\n\n  /// @notice Stop epoch and set new duration\n  /// @dev see stopEpoch and setEpochParams for more details, bufferPeriod is not modified\n  /// Loss accounting policy for `_lossAmount`:\n  /// - pending receipts share the pending portion of the loss pro rata because tranche identity is not stored\n  /// - the remaining active-position loss uses the ordinary BB-first tranche waterfall\n  /// - hard borrower defaults instead apply one aggregate recovery multiplier to active and pending claims\n  /// - if `stopEpoch` defaults (`defaulted = true`), the post-stop loss burn and epoch updates are skipped,\n  ///   but variant hooks still run so prefunded queues can settle deposits already sent to the borrower\n  /// @param _newApr New apr to set for the next epoch\n  /// @param _interest Interest gained in the epoch\n  /// @param _duration New epoch duration\n  /// @param _lossAmount Amount of strategy tokens to burn as realized loss\n  function stopEpochWithDuration(uint256 _newApr, uint256 _interest, uint256 _duration, uint256 _lossAmount) public {\n    // stop epoch checks that msg.sender is allowed\n    _stopEpoch(_newApr, _interest, _lossAmount);\n    if (_interest != 1 && !defaulted) {\n      // buffer period is not changed\n      setEpochParams(_duration, bufferPeriod);\n      // scale the apr with the new duration and buffer\n      _setScaledApr(_newApr);\n    }\n    _afterStopEpochWithDuration();\n  }\n\n  /// @notice Hook called before stopping an epoch.\n  /// @dev The base variant has no external principal and returns zero. The prefunded variant\n  /// overrides this hook to guard direct stops and include principal already sent to the borrower.\n  /// @param _isClosing true when this stop recalls all pool principal\n  /// @return additionalPrincipal principal held outside the CDO strategy-token balance\n  function _beforeStopEpoch(bool _isClosing) internal view virtual returns (uint256) {}\n\n  /// @notice internal function called in stop epoch with duration after doing anything else\n  function _afterStopEpochWithDuration() internal virtual {}\n\n  /// @notice Set the scaled apr for the next epoch\n  /// @param _newApr New apr to set for the next epoch\n  function _setScaledApr(uint256 _newApr) internal {\n    IdleCreditVault(strategy).setAprsWithBuffer(_newApr, epochDuration, bufferPeriod);\n  }\n\n  /// @dev Get funds from borrower through an external self-call so callers can use try/catch.\n  /// @param _amount Total amount to transfer\n  function getFundsFromBorrower(uint256 _amount) external {\n    _checkNotAllowed(msg.sender != address(this));\n    _transferUnderlyingsFrom(_borrower(), address(this), _amount);\n  }\n\n  /// @notice Get funds from borrower to fullfill instant withdraw requests\n  /// Manager should call this method after instantWithdrawDeadline (when epoch is running)\n  /// @dev Instant withdrawals are not supported when a programmable borrower is configured.\n  function getInstantWithdrawFunds() external {\n    _checkOnlyOwnerOrManager();\n    // Check that programmable mode is disabled, the epoch is running and the deadline passed.\n    _checkNotAllowed(isProgrammableBorrower || !isEpochRunning || block.timestamp < instantWithdrawDeadline);\n\n    IdleCreditVault _strategy = IdleCreditVault(strategy);\n    uint256 _instantWithdraws = _pendingInstant();\n    // transfer funds for instant withdraw to this contract\n    try this.getFundsFromBorrower(_instantWithdraws) {\n      // transfer funds to IdleCreditVault and decrease pendingInstantWithdraws\n      _strategy.collectInstantWithdrawFunds(_instantWithdraws);\n      // allow instant withdraws\n      allowInstantWithdraw = true;\n    } catch {\n      _handleBorrowerDefault(_instantWithdraws);\n    }\n  }\n\n  /// @notice Handle borrower default\n  function _handleBorrowerDefault(uint256 funds) internal {\n    defaulted = true;\n    // Do not reopen instant claims here. They remain disabled when funding is pending;\n    // successful full funding is the only path that enables them before finalization.\n\n    if (isProgrammableBorrower) {\n      IProgrammableBorrower(_borrower()).onDefault();\n    }\n\n    // deposits should be already prevented\n    if (!paused()) {\n      _pause();\n    }\n\n    // stop the current epoch\n    isEpochRunning = false;\n\n    // prevent withdrawals requests\n    allowAAWithdrawRequest = false;\n    allowBBWithdrawRequest = false;\n\n    emit BorrowerDefault(funds);\n  }\n\n  /// @notice Prevent deposits and redeems for all classes of tranches\n  function _emergencyShutdown(bool isAAWithdrawAllowed) internal override {\n    // prevent deposits\n    if (!paused()) {\n      _pause();\n    }\n    // Preserve AA requests only if they were already open. This keeps a forced mid-epoch loss or\n    // prior emergency from reopening them, while a normal explicit-loss stop can leave them open.\n    if (!isAAWithdrawAllowed) {\n      allowAAWithdrawRequest = false;\n    }\n    allowBBWithdrawRequest = false;\n    // Persist the emergency state and let authorized forced accounting crystallize the loss.\n    skipDefaultCheck = true;\n  }\n\n  /// @notice allow deposits and redeems for all classes of tranches\n  /// @dev can be called by the owner only\n  function restoreOperations() external override {\n    _checkOnlyOwner();\n    // Check if the pool was defaulted\n    _checkNotAllowed(defaulted || priceAA == 0);\n    skipDefaultCheck = false;\n    // During an epoch ordinary deposits and withdrawal requests must remain disabled. Clearing\n    // the emergency flag intentionally restores only the dedicated depositDuringEpoch path.\n    if (isEpochRunning) return;\n    if (paused()) {\n      _unpause();\n    }\n    allowAAWithdrawRequest = true;\n    allowBBWithdrawRequest = true;\n  }\n\n  /// @notice Prevent external unpause while an epoch, emergency shutdown, or hard default is active.\n  function _beforeUnpause() internal view override {\n    _checkNotAllowed(defaulted || isEpochRunning || skipDefaultCheck);\n  }\n\n  /// \n  /// User methods\n  ///\n\n  /// @notice Deposit funds in the vault. Overrides the parent method and adds a check for wallet \n  function _deposit(uint256 _amount, address _tranche) internal override whenNotPaused returns (uint256) {\n    _checkNotAllowed(!isWalletAllowed(msg.sender));\n    // we check if there are donated assets to the pool and transfer them to the feeReceiver if any\n    _skimDonatedAssets();\n    // do the inherited deposit flow\n    return super._deposit(_amount, _tranche);\n  }\n\n  /// @notice Deposit during an active epoch with prorated interest\n  /// @param _amount Amount of underlyings\n  /// @param _tranche Tranche to deposit into\n  /// @return _minted Amount of tranche tokens minted\n  function depositDuringEpoch(uint256 _amount, address _tranche) external virtual returns (uint256 _minted) {\n    _checkTranche(_tranche);\n    _checkNotAllowed(\n      (_tranche == BBTranche && !isBBDepositEnabled) ||\n      isDepositDuringEpochDisabled ||\n      skipDefaultCheck ||\n      // programmable borrowers use APR=0 so mid-epoch deposits would dilute existing depositors\n      isProgrammableBorrower ||\n      // check if AYS is active as we don't support deposits during epoch in that case\n      isAYSActive ||\n      // check if epoch is still running even if not manually stopped yet\n      !isEpochRunning || block.timestamp >= epochEndDate ||\n      !isWalletAllowed(msg.sender)\n    );\n\n    if (_amount == 0) {\n      return _minted;\n    }\n\n    uint256 _trancheTotSupply = _trancheSupply(_tranche);\n    // Avoid pricing discontinuities for the first mid-epoch deposit in a tranche\n    _checkNotAllowed(_trancheTotSupply == 0);\n\n    _skimDonatedAssets();\n    // Check that limit is not exceeded after removing skimmable raw donations.\n    _guarded(_amount);\n    _updateAccounting();\n\n    // Get underlyings from user\n    _transferUnderlyingsFrom(msg.sender, address(this), _amount);\n\n    // interest for the remaining epoch plus the full buffer period\n    // NOTE: _calcInterest already gives full‑epoch + full‑buffer interest for the whole epoch\n    //   So when a user joins mid‑epoch, we take the fraction of that full‑period interest \n    //   that matches the time they actually remain plus the entire buffer\n    uint256 buffer = bufferPeriod;\n    uint256 remaining = epochEndDate - block.timestamp;\n    uint256 interest = _calcInterest(_amount) *\n      // the time the depositor actually participates (remaining epoch + full buffer)\n      (remaining + buffer) /\n      // the total time baked into the scaled APR (epoch + buffer).\n      (epochDuration + buffer);\n\n    uint256 expectedInt = expectedEpochInterest;\n    uint256 pendingFees = pendingWithdrawFees;\n    uint256 trancheExpected;\n    // existing holders' share of net expected interest for the epoch (pre-deposit)\n    // (exclude pendingWithdrawFees since they go to fee receivers, not tranche holders)\n    if (expectedInt > pendingFees) {\n      trancheExpected = _calcTrancheInterestShare(\n        _netGainAfterFees(expectedInt - pendingFees, _calculateManagementFee(lastNAVAA + lastNAVBB, remaining)),\n        _tranche\n      );\n    }\n    // interest this deposit will earn for the tranche over the remaining time (net of fees)\n    uint256 trancheInterest = _calcTrancheInterestShare(\n      _netGainAfterFees(interest, _calculateManagementFee(_amount, remaining)),\n      _tranche\n    );\n    // pre-deposit expected final NAV for existing holders.\n    // This won't ever be zero as we checked _trancheTotSupply and we seed initial NAV at tranche creation\n    uint256 expectedFinal = _lastSavedNAV(_tranche) + trancheExpected;\n\n    // mint at a discounted price so depositor gets principal + its prorated interest at epoch end\n    // A mid‑epoch depositor should get _amount + trancheInterest at epoch end.\n    // So they need minted = (amount + trancheInterest) / priceEnd.\n    // priceEnd = expectedFinal / _trancheTotSupply\n    // so minted = (amount + trancheInterest) * _trancheTotSupply / expectedFinal\n    _minted = (_amount + trancheInterest) * _trancheTotSupply / expectedFinal;\n    _mintShares(_tranche, msg.sender, _minted, _amount);\n\n    // update expected epoch interest\n    expectedEpochInterest += interest;\n    // mint strategy tokens to this contract\n    IdleCreditVault(strategy).mintStrategyTokens(_amount);\n    // transfer underlyings to the borrower\n    _transferUnderlyings(_borrower(), _amount);\n  }\n\n  /// @notice Request a withdraw from the vault\n  /// @param _amount Amount of tranche tokens \n  /// @param _tranche Tranche to withdraw from\n  /// @return _underlyings Amount of underlyings requested\n  function requestWithdraw(uint256 _amount, address _tranche) external returns (uint256 _underlyings) {\n    _checkTranche(_tranche);\n    _checkNotAllowed(\n      (_tranche == AATranche ? !allowAAWithdrawRequest : !allowBBWithdrawRequest) ||\n      !isWalletAllowed(msg.sender)\n    );\n  \n    // we check if there are donated assets to the pool and transfer them to the feeReceiver if any\n    _skimDonatedAssets();\n\n    // we trigger an update accounting to check for eventual losses\n    _updateAccounting();\n\n    IdleCreditVault creditVault = IdleCreditVault(strategy);\n    if (_amount == 0) {\n      _amount = _userTrancheBal(msg.sender, _tranche);\n    }\n    _underlyings = _trancheToUnderlyings(_amount, _tranche);\n\n    // Programmable borrower deployments do not support instant withdrawals.\n    // If apr decresed wrt last epoch, request instant withdraw and burn tranche tokens directly\n    // we compare unscaled aprs\n    if (_isInstantWithdrawEnabled()) {\n      uint256 currentApr = creditVault.unscaledApr();\n      if (lastEpochApr > (currentApr + instantWithdrawAprDelta)) {\n        // burn strategy tokens from cdo and mint an equal amount to msg.sender as receipt\n        creditVault.requestInstantWithdraw(_underlyings, msg.sender);\n        // burn tranche tokens and decrease NAV\n        _withdrawOps(_amount, _underlyings, _tranche);\n        return _underlyings;\n      }\n    }\n\n    uint256 principal = _underlyings;\n    (uint256 interest, int256 diff) = _calcInterestWithdrawRequest(_underlyings, _tranche);\n    uint256 totalFees = _totalWithdrawFees(principal, interest);\n    // user is requesting principal + interest minus upfront management fee and net performance fee\n    _underlyings = principal + interest - totalFees;\n    // add expected fees to pending withdraw fees counter\n    pendingWithdrawFees += totalFees;\n\n    /// if there is an AA withdrawal the overperformance that the amount withdrawed would have generated for BB tranches\n    /// is saved in interestForOverUnderPerformance. This is used to calculate the interest that should be added to the\n    /// expectedEpochInterest at the startEpoch.\n    /// If there is a BB withdrawal this amount is subtracted from the expectedEpochInterest\n    interestForOverUnderPerformance += diff;\n\n    // The receipt is fixed now and leaves live NAV. Charge management fees upfront\n    // for the time it waits outside live NAV: remaining buffer plus the next epoch.\n    creditVault.requestWithdraw(_underlyings, msg.sender, principal);\n    // burn tranche tokens and decrease NAV without interest for the next epoch as it was not yet counted in NAV\n    _withdrawOps(_amount, principal, _tranche);\n  }\n\n  /// @notice Transfer donated assets to the feeReceiver\n  function _skimDonatedAssets() internal {\n    _transferUnderlyings(feeReceiver, _contractTokenBalance(token));\n  }\n\n  /// @notice Calculate the interest of an epoch for the given amount\n  /// @param _amount Amount of underlyings\n  function _calcInterest(uint256 _amount) internal view returns (uint256) {\n    return _calcInterestWithApr(_amount, _getStrategyApr());\n  }\n\n  /// @notice Calculate the interest of an epoch for the given amount and apr\n  /// @param _amount Amount of underlyings\n  /// @param _apr Apr used for the calculation\n  function _calcInterestWithApr(uint256 _amount, uint256 _apr) internal view returns (uint256) {\n    return _amount * (_apr / 100) * epochDuration / (365 days * ONE_TRANCHE_TOKEN);\n  }\n\n  /// @notice Get current tranches value\n  /// @param _amount Amount of tranche tokens\n  /// @param _tranche Tranche to get the value for\n  /// @return Value of the tranche tokens in underlyings\n  function _trancheToUnderlyings(uint256 _amount, address _tranche) internal view returns (uint256) {\n    return _amount * _tranchePrice(_tranche) / ONE_TRANCHE_TOKEN;\n  }\n\n  /// @notice Revert unless an address is one of this vault's tranche tokens.\n  /// @param _tranche tranche address to validate\n  function _checkTranche(address _tranche) internal view {\n    _checkNotAllowed(_tranche != AATranche && _tranche != BBTranche);\n  }\n\n  /// @notice Get borrower address from strategy.\n  /// @return borrower address\n  function _borrower() internal view returns (address) {\n    return IdleCreditVault(strategy).borrower();\n  }\n\n  /// @notice Get pending instant withdraws from strategy.\n  /// @return pending instant withdraws\n  function _pendingInstant() internal view returns (uint256) {\n    return IdleCreditVault(strategy).pendingInstantWithdraws();\n  }\n\n  /// @notice Return whether new requests may use instant-withdraw mode.\n  /// @dev Child variants can permanently disable instant mode independently of legacy storage.\n  function _isInstantWithdrawEnabled() internal view virtual returns (bool) {\n    return !disableInstantWithdraw && !isProgrammableBorrower;\n  }\n\n  /// @notice Calculate the interest of an epoch for a withdraw request\n  /// @dev to avoid having funds not getting interest during buffer period, the apr \n  /// set in the stopEpoch is higher than then intended one so it will cover also the buffer period\n  /// eg epoch = 30 days, buffer = 5 days, then if we want to give 10% apr for all the 35 days then\n  /// in stop epoch we set the apr to 10% * 35/30 = 11.67%. For this reason people who instead request\n  /// a withdraw should not get the additional interest for the buffer period because they can withdraw\n  /// a block after the buffer period starts. So we calculate the interest for the 30 days only,\n  /// eg. if apr is set to 11.67% and we want to calculate the interest for 30 days at 10% we need to do the \n  /// the opposite -> 11.67% * 30/35 = 10%\n  /// @param _amount Amount of underlyings\n  /// @param _tranche Tranche to withdraw from\n  /// @return _interest Interest for the given amount and given tranche\n  /// @return _diff over/under performance that this withdraw will cause to the other tranche\n  function _calcInterestWithdrawRequest(uint256 _amount, address _tranche) internal view returns (uint256 _interest, int256 _diff) {\n    uint256 _duration = epochDuration;\n    if (_duration == 0) {\n      return (_interest, _diff);\n    }\n\n    uint256 _buffer = bufferPeriod;\n    // calculate total vault interest (they don't get the interest for the buffer period for withdraw requests so \n    // we scale it back since _calcInterest is scaling the interest with tht buffer period),\n    uint256 totInterest = _calcInterest(_managedContractValue()) * _duration / (_duration + _buffer);\n    // calculate total tranche interest for the whole tranche supply\n    uint256 totTrancheInterest = _calcTrancheInterestShare(totInterest, _tranche);\n    // calculate interest for the given tranche and given amount\n    uint256 _trancheBal = _lastSavedNAV(_tranche);\n    _interest = _trancheBal == 0 ? 0 : _amount * totTrancheInterest / _trancheBal;\n    // calculate the interest that the _amount would have received if there was no split ratio (ie interest split based only on tvl).\n    // This is used to calculate the interest that should be added to the expectedEpochInterest when \n    // withdrawing an AA tranche or the interest that should be removed from expectedEpochInterest when\n    // withdrawing a BB tranche\n    uint256 interestWithoutSplitRatio = _calcInterest(_amount) * _duration / (_duration + _buffer);\n    // difference between total interest and tranche interest (positive for AA, negative for BB)\n    _diff = int256(interestWithoutSplitRatio) - int256(_interest);\n  }\n\n  /// @notice Calculate the tranche share of the total interest for the epoch\n  /// @param _totalInterest Total interest for the epoch (net of fees not meant for tranches)\n  /// @param _tranche Tranche to get the interest for\n  function _calcTrancheInterestShare(uint256 _totalInterest, address _tranche) internal view returns (uint256) {\n    uint256 ratio = trancheAPRSplitRatio;\n    return _totalInterest * (_tranche == AATranche ? ratio : FULL_ALLOC - ratio) / FULL_ALLOC;\n  }\n\n  /// @notice Apply projected management and performance fees to a positive gain.\n  function _netGainAfterFees(uint256 _gain, uint256 _managementFee) private view returns (uint256 netGain) {\n    if (_managementFee >= _gain) return netGain;\n    // remove mgmt fee and performance fee\n    _gain -= _managementFee;\n    return _gain - _gain * fee / FULL_ALLOC;\n  }\n\n  /// @notice Calculate total fees charged on a withdrawal request.\n  /// @param _principal Principal leaving live NAV.\n  /// @param _interest Projected interest for the requested principal.\n  /// @return Total management and performance fees to subtract from principal plus projected interest.\n  function _totalWithdrawFees(uint256 _principal, uint256 _interest) private view returns (uint256) {\n    uint256 _mgmtFee = _calculateManagementFee(_principal, _withdrawRequestManagementFeeDuration());\n    // When interest covers management fees, interest - netGain equals management fee plus performance fee.\n    return _mgmtFee >= _interest ?\n      _mgmtFee :\n      _interest - _netGainAfterFees(_interest, _mgmtFee);\n  }\n\n  /// @notice Get the max amount of underlyings that can be withdrawn by user\n  /// @param _user User address\n  /// @param _tranche Tranche to withdraw from\n  function maxWithdrawable(address _user, address _tranche) external view returns (uint256 currentUnderlyings) {\n    currentUnderlyings = _trancheToUnderlyings(_userTrancheBal(_user, _tranche), _tranche);\n    currentUnderlyings -= _calculateManagementFee(currentUnderlyings, block.timestamp - latestHarvestBlock);\n    // add interest for one epoch\n    (uint256 interest, ) = _calcInterestWithdrawRequest(currentUnderlyings, _tranche);\n    // remove upfront management fee and performance fee on the remaining projected interest\n    currentUnderlyings = currentUnderlyings + interest - _totalWithdrawFees(currentUnderlyings, interest);\n  }\n\n  /// @notice Get the duration used for upfront management fees on withdrawal receipts.\n  /// @dev Receipts leave live NAV at request time but can be claimed only after the\n  /// next epoch settles. Requests made during the buffer also pay for the remaining\n  /// buffer time before that next epoch can start.\n  /// @return _duration One epoch plus any remaining buffer before the next epoch.\n  function _withdrawRequestManagementFeeDuration() private view returns (uint256 _duration) {\n    uint256 bufferEnd = epochEndDate + bufferPeriod;\n    _duration = epochDuration;\n    if (block.timestamp < bufferEnd) {\n      _duration += bufferEnd - block.timestamp;\n    }\n  }\n\n  /// @notice Write off the deposit, this will be used if the borrower and a lender comes to an off-chain agreement\n  /// so here we burn tranche tokens, the equivalent amount of strategy tokens. Only the borrower can call this\n  /// @param _amount Amount of tranche tokens to write off\n  function writeOffDeposit(uint256 _amount, address _tranche) external {\n    // only borrower can call this method and only during an epoch, otherwise one should follow the traditional flow\n    _checkNotAllowed(_borrower() != msg.sender || !isEpochRunning);\n    _checkTranche(_tranche);\n    // Remove raw donations so write-off interest math only sees accounted vault value.\n    _skimDonatedAssets();\n\n    // Calculate tranche tokens value with current tranche price\n    uint256 _underlyings = _trancheToUnderlyings(_amount, _tranche);\n    // We now calculate how much interest + fee the tranche would have generated in the current epoch\n    (uint256 interest, int256 diff) = _calcInterestWithdrawRequest(_underlyings, _tranche);\n    // given that _calcInterestWithdrawRequest returns an interest and diff value meant to be used in requestWithdraw\n    // it does not include the buffer period but given that the epoch is running expectedEpochInterest was\n    // calculated with the buffer period included, so we need to scale the interest\n    uint256 _epochDuration = epochDuration;\n\n    // (interest + diff) gives the interest based on tvl as write off debt won't follow senior/junior interest split ratio\n    // diff is positive for AA and negative for BB (in this case it won't be > of interest)\n    interest = uint256(int256(interest) + diff) * (_epochDuration + bufferPeriod) / _epochDuration;\n\n    // Burn tranche tokens and decrease lastNAV\n    _withdrawOps(_amount, _underlyings, _tranche);\n    // Burn strategy tokens and decrease NAV (1:1 with underlyings)\n    IdleCreditVault(strategy).burnStrategyTokens(_underlyings);\n\n    // remove the interest + fee from expectedEpochInterest\n    expectedEpochInterest -= interest;\n  }\n\n  /// @notice Claim a withdraw request from the vault. Can be done when at least 1 epoch passed\n  /// since last withdraw request\n  function claimWithdrawRequest() external {\n    // underlyings requested, here we check that user waited at least one epoch and that borrower\n    // did not default upon repayment (old requests can still be claimed)\n    IdleCreditVault(strategy).claimWithdrawRequest(msg.sender);\n  }\n\n  /// @notice Claim an instant withdraw request from the vault. Can be done when epoch is running\n  /// as funds will get transferred from borrower when epoch starts\n  function claimInstantWithdrawRequest() external {\n    // Check that instant withdraws are available\n    _checkNotAllowed(!allowInstantWithdraw);\n    IdleCreditVault(strategy).claimInstantWithdrawRequest(msg.sender);\n  }\n\n  /// @notice Check if wallet is allowed to interact with the contract\n  /// @param _user User address\n  /// @return true if wallet is allowed or keyring address is not set\n  function isWalletAllowed(address _user) public view returns (bool) {\n    address _keyring = keyring;\n    return _keyring == address(0) || IKeyring(_keyring).checkCredential(keyringPolicyId, _user);\n  }\n\n  /// @notice Notify a programmable borrower that a new epoch has started.\n  /// @param _pendingWithdraws Amount reserved for withdraw requests that mature at epoch stop.\n  function _startEpochProgrammableBorrower(uint256 _pendingWithdraws) internal {\n    if (isProgrammableBorrower) {\n      IProgrammableBorrower(_borrower()).onStartEpoch(_pendingWithdraws);\n    }\n  }\n\n  /// @notice Resolve the stop-epoch interest value, optionally sourcing it from a programmable borrower.\n  /// @dev Programmable borrowers are always the source of truth for epoch interest.\n  /// In that mode `_interest` values `0` and `1` both resolve to the realized epoch interest,\n  /// while `1` still separately signals the close-pool path to the caller.\n  function _resolveStopEpochInterest(uint256 _interest) internal view returns (uint256 _resolvedInterest) {\n    if (isProgrammableBorrower) {\n      _checkNotAllowed(_interest > 1);\n      return IProgrammableBorrower(_borrower()).totalInterestDueNow();\n    }\n\n    _resolvedInterest = _interest;\n  }\n}\n","deployed_bytecode":"0x60806040523480156200001157600080fd5b50600436106200042a5760003560e01c80630553c2e7146200042f578063085a2b78146200044d578063088f4b7814620004575780631072cbea146200047057806312361ac214620004875780632544e841146200049157806325cdd860146200049c57806329811ee514620004a65780632e02cd5e14620004bd5780632e2452ab14620004e557806333986ffa14620004f357806333f0f80014620004fd5780633403c2fc14620005085780633f4ba83a1462000512578063400f7d32146200051c578063408f3a30146200052657806340a2029e146200053d578063435d44d9146200055457806343848aed146200056b57806344966ba01462000576578063494347e714620005995780634954380b14620005a35780634da4f60314620005b15780634ff0876a14620005c5578063514b6dbd14620005d057806358cdd22b14620005e75780635b4a346214620005fb5780635c975abb14620006125780635f0b472a146200061e57806362adade5146200062d5780636373ea691462000637578063655c9a5314620006415780636736d616146200064c57806369e25ec114620006635780636bd7b30114620006785780636c4321eb1462000687578063715018a6146200069c578063734d828714620006a6578063747efea114620006b057806375d1497b14620006c457806381f5ae7e14620006cf5780638260dbba14620006d957806383975b6714620006e45780638456cb5914620006ee5780638a0dac4a14620006f85780638da5cb5b146200070f5780638ed8f575146200071957806391b900ef14620007305780639290d427146200074757806396164236146200075e5780639638529c1462000772578063991052b714620007895780639a4d360814620007935780639ed9de9414620007aa578063a219d21814620007c6578063a2454e5514620007dd578063a27eccc114620007f4578063a2c8b17714620007fe578063a4d66daf1462000808578063a6f7f5d61462000812578063a8c62e76146200081c578063b3f006741462000830578063b450dfce1462000844578063c5c75098146200085b578063c61e3faa146200086a578063c88e84471462000881578063c9aba3561462000898578063ccc143b814620008a8578063cfa5656714620008bf578063d19d3bdc14620008c9578063d48099ad14620008e0578063d636b05f14620008f7578063dc82697c1462000902578063ddca3f43146200090c578063dee7c2cb1462000916578063dfd5b1c9146200092d578063dfefc7f81462000938578063e2988e6e1462000943578063e3e39368146200094e578063e70875ad1462000962578063ef191b7f1462000979578063f2fde38b1462000990578063fa69d17714620009a7578063fc0c546a14620009be578063fde4ebe414620009d2578063fe81a02414620009e9575b600080fd5b6200043a61012a5481565b6040519081526020015b60405180910390f35b6200043a60da5481565b6200046e620004683660046200496f565b620009f3565b005b6200046e62000481366004620049a5565b62000a10565b6200043a60dc5481565b6200043a6101245481565b6200043a62000a3a565b6200043a620004b7366004620049d4565b62000a4d565b620004d4620004ce366004620049d4565b62000b12565b604051901515815260200162000444565b60f054620004d49060ff1681565b6200046e62000bb0565b6200043a6101255481565b6200046e62000c2b565b6200046e62000c43565b6200043a60dd5481565b6200046e62000537366004620049f4565b62000c61565b6200046e6200054e36600462004a0e565b62000c70565b6200046e62000565366004620049f4565b62000cb7565b6200043a6101275481565b60d6546200058a906001600160a01b031681565b60405162000444919062004a4a565b6200046e62000cd6565b60f254620004d49060ff1681565b61011e54620004d490610100900460ff1681565b6200043a61011f5481565b6200046e620005e13660046200496f565b62000cf4565b61012854620004d490610100900460ff1681565b6200046e6200060c3660046200496f565b62000d23565b60335460ff16620004d4565b61012d54620004d49060ff1681565b6200043a60de5481565b6200043a60e95481565b6200043a6101265481565b6200046e6200065d3660046200496f565b62000d41565b61012854620004d49062010000900460ff1681565b61012854620004d49060ff1681565b61011e54620004d49062010000900460ff1681565b6200046e62000d80565b6200043a60e15481565b60d5546200058a906001600160a01b031681565b6200043a6101225481565b6200043a60cc5481565b6200043a6101205481565b6200046e62000d96565b6200046e62000e09565b6200046e62000709366004620049d4565b62000e1d565b6200058a62000e51565b6200046e6200072a366004620049f4565b62000e60565b6200046e6200074136600462004a5e565b62000e84565b6200043a62000758366004620049d4565b62000f07565b61012d54620004d490610100900460ff1681565b6200046e6200078336600462004a9c565b62000f45565b6200046e62001397565b6200046e620007a4366004620049f4565b62001412565b610128546200058a90630100000090046001600160a01b031681565b6200043a620007d7366004620049d4565b62001435565b6200046e620007ee366004620049a5565b62001448565b6200043a60d15481565b6200046e62001484565b6200043a60c95481565b6200043a60f15481565b60d4546200058a906001600160a01b031681565b60e4546200058a906001600160a01b031681565b6200043a62000855366004620049f4565b620018a5565b61011e54620004d49060ff1681565b6200043a6200087b36600462004b2b565b620018c1565b6200046e6200089236600462004b5e565b62001b84565b6200043a670de0b6b3a764000081565b6200043a620008b936600462004b2b565b62001bd3565b6200046e62001e78565b6200046e620008da36600462004b2b565b62001f95565b6200046e620008f136600462004b91565b620020bd565b6200043a6101295481565b6200043a620020cb565b6200043a60e35481565b6200046e6200092736600462004b2b565b62002118565b6200043a620186a081565b6200043a6101235481565b6200043a6101215481565b60d7546200058a906001600160a01b031681565b6200043a62000973366004620049f4565b6200224e565b6200043a6200098a36600462004bb4565b6200227c565b6200046e620009a1366004620049d4565b620022f5565b6200046e620009b836600462004b91565b62002371565b60cf546200058a906001600160a01b031681565b6200046e620009e33660046200496f565b620023c5565b6200043a60df5481565b620009fd620023e2565b60ea805460ff1916911515919091179055565b62000a1a620023e2565b60ca5462000a36906001600160a01b0384811691168362002402565b5050565b600062000a4860006200245c565b905090565b60008062000a5c60006200245c565b9050600062000a6a620024e6565b905081158062000a7c5750620186a082145b1562000aad5760d6546001600160a01b0385811691161482151462000aa2578062000aa5565b60005b949350505050565b60da5460d6546001600160a01b0386811691161462000b055762000ad583620186a062004bfd565b62000ae482620186a062004bfd565b62000af0908462004c17565b62000afc919062004c4f565b95945050505050565b8262000af0828462004c17565b61012854600090630100000090046001600160a01b031680158062000ba957506101295460405163043bb58960e51b81526001600160a01b03831691638776b1209162000b659190879060040162004c66565b602060405180830381865afa15801562000b83573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000ba9919062004c7d565b9392505050565b60d45460405163370a95eb60e21b81526001600160a01b039091169063dc2a57ac9062000be290339060040162004a4a565b6020604051808303816000875af115801562000c02573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c28919062004c9d565b50565b62000c3562002557565b62000c41600062002599565b565b62000c4d62002557565b62000c57620025e4565b62000c416200261f565b62000c6b620023e2565b60c955565b62000c7a6200266f565b62000c9162000c8b60335460ff1690565b6200272a565b610120929092556101255561012880549115156101000261ff0019909216919091179055565b62000cc1620023e2565b62000c28620186a08260ec819055116200274a565b62000ce062002557565b62000cea6200276a565b62000c4162002793565b62000cfe620023e2565b61011e5462000d109060ff166200272a565b60f0805460ff1916911515919091179055565b62000d2d6200266f565b61012d805460ff1916911515919091179055565b62000d4b620023e2565b62000d658115801562000c8b575060f05460ff166200272a565b61012d80549115156101000261ff0019909216919091179055565b62000d8a620027d8565b62000c4160006200283b565b62000da0620023e2565b6101285462000dc39062010000900460ff168062000c8b575060dc54156200272a565b60d3805460ff60b81b1916905561011e5460ff161562000ddf57565b60335460ff161562000df55762000df56200261f565b61011e805462ffff00191662010100179055565b62000e1362002557565b62000c416200288d565b62000e27620023e2565b60d080546001600160a01b0319166001600160a01b03831690811790915562000c289015620028cd565b6065546001600160a01b031690565b62000e6e333014156200272a565b62000c2862000e7c620028ed565b30836200295e565b62000e8e620023e2565b62000ec4614e2084118062000ea55750620186a083115b8062000ebe575062000ebb600a614e2062004c4f565b82115b6200274a565b60e480546001600160a01b0319166001600160a01b03861690811790915562000eee9015620028cd565b62000ef862002983565b60e39290925560e95560f15550565b600062000f3e8262000f18620029be565b60df5460de5462000f2a919062004cb7565b62000f358662002a03565b60da5462002a2d565b5092915050565b600054610100900460ff161580801562000f665750600054600160ff909116105b8062000f8b575062000f783062002c04565b15801562000f8b575060005460ff166001145b62000ff45760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801562001018576000805461ff0019166101001790555b60cf546001600160a01b031615620010425760405162dc149f60e41b815260040160405180910390fd5b6200106a6001600160a01b03841615806200106457506001600160a01b038816155b620028cd565b6200107a620186a083116200274a565b6200108462002c13565b6200109188878762002c47565b6000836001600160a01b031663747efea16040518163ffffffff1660e01b8152600401602060405180830381865afa158015620010d2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620010f8919062004cd2565b90506000816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156200113b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001165919081019062004d37565b9050620011ac6040518060400160405280600781526020016602830b932ba37960cd1b815250604051806040016040528060018152602001600760fc1b8152508362002cad565b60d660006101000a8154816001600160a01b0302191690836001600160a01b031602179055506200121d6040518060400160405280600a81526020016902830b932ba37902121160b51b815250604051806040016040528060048152602001637042425f60e01b8152508362002cad565b60d780546001600160a01b03199081166001600160a01b039384161790915560cf805482168c841690811790915560d48054831689851617905560d5805490921692851692909217905560da8590556040805163313ce56760e01b815290516000929163313ce5679160048083019260209291908290030181865afa158015620012ab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620012d1919062004c9d565b620012de90600a62004ee1565b60d181905560dc81905560dd8190559050620012fb8a8762002d08565b62001307838762002d08565b60d080546001600160a01b0319166001600160a01b038a1617905560ea805460ff1916600117905561c35060ec554260cc556200134362002d20565b50505080156200138d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b61012854620013aa9060ff16156200272a565b60d4546040516347e9887560e11b81526001600160a01b0390911690638fd310ea90620013dc90339060040162004a4a565b600060405180830381600087803b158015620013f757600080fd5b505af11580156200140c573d6000803e3d6000fd5b50505050565b62001420333014156200272a565b62000c286200142e620028ed565b8262002d92565b6000620014428262002db5565b92915050565b620014526200266f565b61012880546001600160a01b039093166301000000026301000000600160b81b03199093169290921790915561012955565b6200148e6200266f565b61011f5461012854620014d19062010000900460ff1680620014c2575061012a5461012254620014bf919062004cb7565b42105b8062000c8b575081156200272a565b620014db62002df6565b620014e56200276a565b61011e805460ff19166001179055620014fd6200288d565b61011e805462ffff001916905560d45461012c546001600160a01b0390911690600090620015346200152e620020cb565b62002e2f565b62001540919062004eef565b9050600081121562001550575060005b806101265462001561919062004cb7565b61012155600061012c5562001577834262004cb7565b61012255610120546200158b904262004cb7565b610123819055506000826001600160a01b031663efda7e076040518163ffffffff1660e01b8152600401602060405180830381865afa158015620015d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620015f9919062004c9d565b61012d54909150600090610100900460ff166200162757816101275462001621919062004cb7565b62001629565b815b6040516001625a42ed60e11b03198152600481018290529091506001600160a01b0385169063ff4b7a2690602401600060405180830381600087803b1580156200167257600080fd5b505af115801562001687573d6000803e3d6000fd5b5050505060006200169762002e46565b60cf54909150600090620016b4906001600160a01b031662002e91565b90506000866001600160a01b031663a9a949686040518163ffffffff1660e01b8152600401602060405180830381865afa158015620016f7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200171d919062004c9d565b9050866001600160a01b031663f25b11408385116200173d57846200173f565b835b6040518263ffffffff1660e01b81526004016200175e91815260200190565b600060405180830381600087803b1580156200177957600080fd5b505af11580156200178e573d6000803e3d6000fd5b5050505081831115620017a6576200138d8162002f06565b610128805460ff191660011790556000620017c2848462004bfd565b604051631349a6c160e31b8152600481018290529091503090639a4d360890602401600060405180830381600087803b158015620017ff57600080fd5b505af192505050801562001811575060015b6200188f5762001822888262002d92565b60405163e41ee1b360e01b8152600481018290526001600160a01b0389169063e41ee1b390602401600060405180830381600087803b1580156200186557600080fd5b505af11580156200187a573d6000803e3d6000fd5b50505050620018898162002f81565b6200189a565b6200189a8262002f06565b505050505050505050565b60d654600090620014429083906001600160a01b031662003056565b6000620018ce8262003087565b60d7546200196c906001600160a01b038481169116148015620018f4575060f25460ff16155b8062001903575061012d5460ff165b8062001918575060d354600160b81b900460ff165b8062001926575060f05460ff165b8062001934575060ea5460ff165b8062001944575061011e5460ff16155b80620019535750610122544210155b8062000c8b5750620019653362000b12565b156200272a565b82620019785762001442565b60006200198583620030be565b90506200199381156200272a565b6200199d6200276a565b620019a884620030ff565b620019b262003141565b50620019c03330866200295e565b61012a5461012254600090620019d890429062004bfd565b905060008261011f54620019ed919062004cb7565b620019f9848462004cb7565b62001a048962002e2f565b62001a10919062004c17565b62001a1c919062004c4f565b61012154610126549192509060008183111562001a745762001a7162001a6a62001a47848662004bfd565b62001a6460df5460de5462001a5d919062004cb7565b89620032bc565b620032ee565b8a62003338565b90505b600062001a9262001a8b8662001a648e8a620032bc565b8b62003338565b905060008262001aa28c62002a03565b62001aae919062004cb7565b9050808962001abe848f62004cb7565b62001aca919062004c17565b62001ad6919062004c4f565b995062001ae68b338c8f62003389565b85610121600082825462001afb919062004cb7565b909155505060d454604051633ec701eb60e01b8152600481018e90526001600160a01b0390911690633ec701eb90602401600060405180830381600087803b15801562001b4757600080fd5b505af115801562001b5c573d6000803e3d6000fd5b5050505062001b7562001b6e620028ed565b8d62002d92565b50505050505050505092915050565b62001b9184848362003445565b8260011415801562001bad57506101285462010000900460ff16155b1562001bcd5762001bc28261012a5462002371565b62001bcd8462003dc5565b6200140c565b600062001be08262003087565b60d65462001c2e906001600160a01b0384811691161462001c0f5761011e5462010000900460ff161562001953565b61011e54610100900460ff16158062000c8b5750620019653362000b12565b62001c386200276a565b62001c4262003141565b5060d4546001600160a01b03168362001c645762001c61338462003e0c565b93505b62001c70848462003e81565b915062001c7c62003ea3565b1562001d82576000816001600160a01b031663d7bff5386040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001cc3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001ce9919062004c9d565b9050610125548162001cfc919062004cb7565b61012454111562001d8057604051630a198c7f60e21b81526001600160a01b0383169063286631fc9062001d37908690339060040162004c66565b600060405180830381600087803b15801562001d5257600080fd5b505af115801562001d67573d6000803e3d6000fd5b5050505062001d7885848662003ec6565b505062001442565b505b8160008062001d92838762003f8d565b91509150600062001da4848462004078565b90508062001db3848662004cb7565b62001dbf919062004bfd565b955080610126600082825462001dd6919062004cb7565b925050819055508161012c600082825462001df2919062004eef565b909155505060405163f16c6bf160e01b815260048101879052336024820152604481018590526001600160a01b0386169063f16c6bf190606401600060405180830381600087803b15801562001e4757600080fd5b505af115801562001e5c573d6000803e3d6000fd5b5050505062001e6d88858962003ec6565b505050505092915050565b62001e826200266f565b60f05462001eb09060ff168062001e9d575061011e5460ff16155b8062000c8b57506101235442106200272a565b60d4546001600160a01b0316600062001ec862002e46565b604051638ed8f57560e01b8152600481018290529091503090638ed8f57590602401600060405180830381600087803b15801562001f0557600080fd5b505af192505050801562001f17575060015b62001f275762000a368162002f81565b6040516303c96c4560e61b8152600481018290526001600160a01b0383169063f25b114090602401600060405180830381600087803b15801562001f6a57600080fd5b505af115801562001f7f573d6000803e3d6000fd5b5050610128805460ff1916600117905550505050565b62001f9f6200266f565b62001fa96200276a565b60d45460405163746f7a3360e01b81526000916001600160a01b03169063746f7a339062001fde908690869060040162004c66565b6020604051808303816000875af115801562001ffe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002024919062004c9d565b600060e381905560f181905560e1554260cc5560df81905560d554909150819062002058906001600160a01b031662002e91565b62002064919062004bfd565b60de556200207162002793565b600061012181905561012681905561011e805462ffff00191662010100179055610128805461ffff191661010117905561011f819055610122819055620020b89062003dc5565b505050565b62000a368282600062003445565b60e15460cf5460009190620020e9906001600160a01b031662002e91565b60d55462002100906001600160a01b031662002e91565b6200210c919062004cb7565b62000a48919062004bfd565b620021473362002127620028ed565b6001600160a01b031614158062000c8b575061011e5460ff16156200272a565b620021528162003087565b6200215c6200276a565b60006200216a838362003e81565b90506000806200217b838562003f8d565b91509150600061011f5490508061012a548262002199919062004cb7565b620021a5848662004eef565b620021b1919062004c17565b620021bd919062004c4f565b9250620021cc86858762003ec6565b60d454604051633e81a73360e01b8152600481018690526001600160a01b0390911690633e81a73390602401600060405180830381600087803b1580156200221357600080fd5b505af115801562002228573d6000803e3d6000fd5b5050505082610121600082825462002241919062004bfd565b9091555050505050505050565b60f254600090620022639060ff1615620040b3565b60d754620014429083906001600160a01b031662003056565b6000620022956200228e848462003e0c565b8362003e81565b9050620022b28160cc5442620022ac919062004bfd565b620032bc565b620022be908262004bfd565b90506000620022ce828462003f8d565b509050620022dd828262004078565b620022e9828462004cb7565b62000aa5919062004bfd565b620022ff620027d8565b6001600160a01b038116620023665760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000feb565b62000c28816200283b565b6200237b6200266f565b61012854620023b89062010000900460ff16806200239c575061011e5460ff165b80620023a6575082155b8062000c8b575061011f54156200272a565b61011f9190915561012a55565b620023cf620023e2565b60f2805460ff1916911515919091179055565b62000c4133620023f162000e51565b6001600160a01b03161415620040b3565b620020b88363a9059cbb60e01b84846040516024016200242492919062004f36565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152620040d3565b600062004948826200247257620041af62002477565b620041e85b60d65490915060009062002497906001600160a01b031663ffffffff8416565b60d754909150600090620024b7906001600160a01b031663ffffffff8516565b620024c3908362004cb7565b905080620024d657506000949350505050565b8062000af0620186a08462004c17565b60d45460408051632116f20160e21b815290516000926001600160a01b03169163845bc8049160048083019260209291908290030181865afa15801562002531573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a48919062004c9d565b60d05462000c41906001600160a01b031633148015906200259357506200257d62000e51565b6001600160a01b0316336001600160a01b031614155b620040b3565b60335460ff16620025ae57620025ae6200288d565b80620025c15761011e805461ff00191690555b5061011e805462ff00001916905560d3805460ff60b81b1916600160b81b179055565b6101285462000c419062010000900460ff168062002605575061011e5460ff165b8062000c8b575060d354600160b81b900460ff166200272a565b62002629620041fe565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405162002665919062004a4a565b60405180910390a1565b62000c416200267d62000e51565b6001600160a01b0316336001600160a01b03161415801562000c8b575060d460009054906101000a90046001600160a01b03166001600160a01b031663481c6a756040518163ffffffff1660e01b8152600401602060405180830381865afa158015620026ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002714919062004cd2565b6001600160a01b0316336001600160a01b031614155b801562000c2857604051631eb49d6d60e11b815260040160405180910390fd5b801562000c285760405163fd7850ad60e01b815260040160405180910390fd5b60e45460cf5462000c41916001600160a01b03908116916200278d911662002e91565b62002d92565b60d38054600160b81b60ff60b81b19821681179092550460ff16620027b762003141565b62000c285760d38054821515600160b81b0260ff60b81b1990911617905550565b33620027e362000e51565b6001600160a01b03161462000c415760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000feb565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6200289762004249565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258620026563390565b801562000c28576040516321e7594160e21b815260040160405180910390fd5b60d45460408051637df1f1b960e01b815290516000926001600160a01b031691637df1f1b99160048083019260209291908290030181865afa15801562002938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a48919062004cd2565b806200296957505050565b60cf54620020b8906001600160a01b031684848462004291565b620029a062002991620029be565b60cc54620022ac904262004bfd565b60e16000828254620029b3919062004cb7565b90915550504260cc55565b60d5546000908190620029da906001600160a01b031662002e91565b60e154909150808211620029f0576000620029fc565b620029fc818362004bfd565b9250505090565b60d6546000906001600160a01b0383811691161462002a255760df5462001442565b505060de5490565b600080600062002a3d88620030be565b90508062002a5457505060d1549050600062002bfa565b8515801562002a61575086155b1562002a7557600080925092505062002bfa565b600062002a83878962004f4f565b90508015801562002a9e575060d354600160b81b900460ff16155b1562002abd5762002aaf8962002db5565b600093509350505062002bfa565b600081131562002af657620186a060e3548262002adb919062004f94565b62002ae7919062005025565b62002af3908262004f4f565b90505b60d6546001600160a01b038a81169116148662002b17576000935062002bc6565b8688141562002b295781935062002bc6565b600082131562002b81576000620186a062002b45888262004bfd565b62002b51908562004f94565b62002b5d919062005025565b90508162002b6c578062002b78565b62002b78818462004f4f565b94505062002bc6565b600060df5462002b919062005059565b9050600081841362002ba4578162002ba6565b835b90508262002bb5578062002bc1565b62002bc1818562004f4f565b955050505b82670de0b6b3a764000062002bdc868a62004eef565b62002be8919062004c17565b62002bf4919062004c4f565b94505050505b9550959350505050565b6001600160a01b03163b151590565b600054610100900460ff1662002c3d5760405162461bcd60e51b815260040162000feb9062005079565b62000c41620042cb565b62002c6e6001600160a01b03831615806200106457506001600160a01b03821615620028cd565b62002c7862004301565b62002c8262004335565b60c983905560ca80546001600160a01b0319166001600160a01b038416179055620020b881620022f5565b600062002cbb848362004369565b62002cc7848462004369565b60405162002cd59062004952565b62002ce2929190620050f2565b604051809103906000f08015801562002cff573d6000803e3d6000fd5b50949350505050565b62000a366001600160a01b0383168260001962004397565b60ea805460ff1916905562278d0061011f556206978061012a81905562002d48904262004bfd565b6101225561011e80546201010062ffff0019909116179055610128805461ff00191661010017905561012d805460ff1916600117905562000c4162002d8c620024e6565b62003dc5565b8062002d9c575050565b60cf5462000a36906001600160a01b0316838362002402565b600062002dc282620030be565b62002dcf57505060d15490565b60d6546001600160a01b0383811691161462002dee5760dd5462001442565b505060dc5490565b60f05462000c419060ff16801562000c8b575061012d54610100900460ff16158062000c8b575062002e2762002e46565b15156200272a565b6000620014428262002e40620024e6565b6200443d565b60d45460408051631e2af12360e31b815290516000926001600160a01b03169163f15789189160048083019260209291908290030181865afa15801562002531573d6000803e3d6000fd5b6040516370a0823160e01b81526000906001600160a01b038316906370a082319062002ec290309060040162004a4a565b602060405180830381865afa15801562002ee0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001442919062004c9d565b60f05460ff161562000c285762002f1c620028ed565b6001600160a01b0316631d859d73826040518263ffffffff1660e01b815260040162002f4a91815260200190565b600060405180830381600087803b15801562002f6557600080fd5b505af115801562002f7a573d6000803e3d6000fd5b5050505050565b610128805462ff000019166201000017905560f05460ff161562002ffe5762002fa9620028ed565b6001600160a01b0316636febd5436040518163ffffffff1660e01b8152600401600060405180830381600087803b15801562002fe457600080fd5b505af115801562002ff9573d6000803e3d6000fd5b505050505b60335460ff166200301357620030136200288d565b61011e805462ffffff191690556040518181527fddeda4ec7ef5a5761f0a329088482bf17d717987d67aaad5a3c4535ab7da29099060200160405180910390a150565b60006200306262004249565b62003071620019653362000b12565b6200307b6200276a565b62000ba9838362004474565b60d65462000c28906001600160a01b0383811691161480159062000c8b575060d7546001600160a01b03838116911614156200272a565b6000816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002ee0573d6000803e3d6000fd5b60c954801562000a3657808262003115620020cb565b62003121919062004cb7565b111562000a3657604051630d45dcb760e11b815260040160405180910390fd5b60006200314d62002983565b60de5460df54600062003161828462004cb7565b905060006200316f620020cb565b60da5490915082821115620031c35760e354620186a09062003192858562004bfd565b6200319e919062004c17565b620031aa919062004c4f565b60e16000828254620031bd919062004cb7565b90915550505b60d6546000908190620031e3906001600160a01b031685878a8762002a2d565b60d7549193509150600090819062003208906001600160a01b031687898b8962002a2d565b909250905062003219838a62004eef565b60de5562003228818962004eef565b60df5560008112801562003246575087620032438262005059565b12155b806200325b575086158015906200325b575085155b15620032a75760d35460019a50600160b81b900460ff16620032905760405163064e30f160e51b815260040160405180910390fd5b856200329b57600093505b620032a7600162002599565b5060dc929092555060dd555093949350505050565b60006502de413530008260f15485620032d6919062004c17565b620032e2919062004c17565b62000ba9919062004c4f565b6000828210620032fe5762001442565b6200330a828462004bfd565b9250620186a060e3548462003320919062004c17565b6200332c919062004c4f565b62000ba9908462004bfd565b60da5460d65460009190620186a0906001600160a01b038581169116146200336f576200336982620186a062004bfd565b62003371565b815b6200337d908662004c17565b62000aa5919062004c4f565b6040516340c10f1960e01b81526001600160a01b038516906340c10f1990620033b9908690869060040162004f36565b600060405180830381600087803b158015620033d457600080fd5b505af1158015620033e9573d6000803e3d6000fd5b505060d6546001600160a01b03878116911614159150620034269050578060de60008282546200341a919062004cb7565b909155506200140c9050565b8060df60008282546200343a919062004cb7565b909155505050505050565b6200344f6200266f565b600182146200345d62002df6565b60d4546101265461011e546001600160a01b0390921691620034d99060ff1615806200348b57506101225442105b806200349f57506200349c62002e46565b15155b80620034c05750600186118015620034c0575081861080620034c057508615155b8062000c8b575083801562000c8b57508415156200272a565b6000620034e56200276a565b620034f0866200457b565b60405163bb42b77360e01b8152600481018290529096506000906001600160a01b0385169063bb42b7739060240160408051808303816000875af11580156200353d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200356391906200511b565b80945081925050506000846001600160a01b031663a9a949686040518163ffffffff1660e01b8152600401602060405180830381865afa158015620035ac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620035d2919062004c9d565b905085156200360f5760d554620035f2906001600160a01b031662002e91565b620035fe908462004cb7565b92506200360c838362004cb7565b91505b6000866200361e57826200362a565b6200362a848462004bfd565b61012d54909150600090610100900460ff16801562003647575087155b90506000816200365857846200365b565b60005b90508180156200366b575060018b115b1562003715576000886001600160a01b03166392093b366040518163ffffffff1660e01b8152600401602060405180830381865afa158015620036b2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620036d8919062004c9d565b905062003713811580159062000c8b575088620036ff620036f8620020cb565b846200443d565b6200370b919062004cb7565b85116200272a565b505b6200371f62002983565b6101218390556101268790556040516349b38c9360e01b8152600481018b90526001600160a01b038916906349b38c93906024016040805180830381865afa15801562003770573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200379691906200511b565b60f054909b5090945060ff16156200386257620037b2620028ed565b6001600160a01b0316639b8e712b620037cc868462004cb7565b6040516001600160e01b031960e084901b16815260048101919091528b151560248201526044016020604051808303816000875af115801562003813573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003839919062004c7d565b6200386257620038546200384e858362004cb7565b62002f81565b505050505050505050505050565b30638ed8f57562003874868462004cb7565b6040518263ffffffff1660e01b81526004016200389391815260200190565b600060405180830381600087803b158015620038ae57600080fd5b505af1925050508015620038c0575060015b620038db57620038d56200384e858362004cb7565b62003854565b604051638b80c89d60e01b8152600481018590526001600160a01b03891690638b80c89d90602401600060405180830381600087803b1580156200391e57600080fd5b505af115801562003933573d6000803e3d6000fd5b5050505081801562003947575060f05460ff165b15620039ac5762003957620028ed565b6001600160a01b0316632512529b6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200399257600080fd5b505af1158015620039a7573d6000803e3d6000fd5b505050505b81620039bd57620039bd87620045e4565b8815620039d057620039d0888762002d92565b811562003a5557821562003a3b57604051633ec701eb60e01b8152600481018490526001600160a01b03891690633ec701eb90602401600060405180830381600087803b15801562003a2157600080fd5b505af115801562003a36573d6000803e3d6000fd5b505050505b8660e1600082825462003a4f919062004cb7565b90915550505b62003a5f62003141565b5060e154821562003af457801562003aee57600062003a7e8262004626565b9050801562003aa95760e45460d65462003aa79183916001600160a01b0391821691166200463c565b505b62003ad562003ab9828462004bfd565b62003ac362000e51565b60d6546001600160a01b03166200463c565b5062003aec62003ae660016200245c565b62004679565b505b62003b2e565b600088851162003b0657600062003b12565b62003b12898662004bfd565b90508082111562003b21578091505b62003b2c82620045e4565b505b8060e1600082825462003b42919062004bfd565b90915550600090508362003b57578862003b5a565b60005b62003b66908362004cb7565b9050600081861162003b7a57600062003b86565b62003b86828762004bfd565b61012781905590506001600160a01b038b1663b6b55f258662003baa578262003bad565b60005b6040518263ffffffff1660e01b815260040162003bcc91815260200190565b6020604051808303816000875af115801562003bec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003c12919062004c9d565b508a6001600160a01b031663d7bff5386040518163ffffffff1660e01b8152600401602060405180830381865afa15801562003c52573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003c78919062004c9d565b6101245562003c878f62003dc5565b61011e805460ff1916905560006101218190556101265560d354600160b81b900460ff1662003ccd5762003cba6200261f565b61011e805462ffff001916620101001790555b610128805460ff19168d1580159190911790915562003d0357610128805461ff001916610100179055600061011f819055610122555b7ff66f28b40975dbb933913542c7e6a0f50a1d0f20aa74ea6e0efe65ab616323ec62003d308a8a62004bfd565b60408051918252602082018590520160405180910390a18c1562003db457604051633e81a73360e01b8152600481018e90526001600160a01b038c1690633e81a73390602401600060405180830381600087803b15801562003d9157600080fd5b505af115801562003da6573d6000803e3d6000fd5b5050505062003db462002793565b505050505050505050505050505050565b60d45461011f5461012a546040516320769c1360e21b815260048101859052602481019290925260448201526001600160a01b03909116906381da704c9060640162002f4a565b6040516370a0823160e01b81526000906001600160a01b038316906370a082319062003e3d90869060040162004a4a565b602060405180830381865afa15801562003e5b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000ba9919062004c9d565b6000670de0b6b3a764000062003e978362002db5565b620032e2908562004c17565b61012854600090610100900460ff1615801562000a4857505060f05460ff161590565b604051632770a7eb60e21b81526001600160a01b03821690639dc29fac9062003ef6903390879060040162004f36565b600060405180830381600087803b15801562003f1157600080fd5b505af115801562003f26573d6000803e3d6000fd5b505060d6546001600160a01b0384811691161415915062003f639050578160de600082825462003f57919062004bfd565b9091555062003f7d9050565b8160df600082825462003f77919062004bfd565b90915550505b620020b862003ae660016200245c565b61011f5460009081908062003fa3575062004071565b61012a54600062003fb5828462004cb7565b8362003fc46200152e620029be565b62003fd0919062004c17565b62003fdc919062004c4f565b9050600062003fec828862003338565b9050600062003ffb8862002a03565b9050801562004023578062004011838b62004c17565b6200401d919062004c4f565b62004026565b60005b9650600062004036858762004cb7565b86620040428c62002e2f565b6200404e919062004c17565b6200405a919062004c4f565b905062004068888262004f4f565b96505050505050505b9250929050565b6000806200408a84620022ac62004704565b90508281101562000ba957620040a18382620032ee565b620040ad908462004bfd565b62000aa5565b801562000c285760405163ea8e4eb560e01b815260040160405180910390fd5b60006200412a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200474a9092919063ffffffff16565b90508051600014806200414e5750808060200190518101906200414e919062004c7d565b620020b85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000feb565b6000670de0b6b3a7640000620041c58362000f07565b620041d084620030be565b620041dc919062004c17565b62001442919062004c4f565b6000670de0b6b3a7640000620041c58362002db5565b60335460ff1662000c415760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640162000feb565b60335460ff161562000c415760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640162000feb565b6040516001600160a01b03808516602483015283166044820152606481018290526200140c9085906323b872dd60e01b9060840162002424565b600054610100900460ff16620042f55760405162461bcd60e51b815260040162000feb9062005079565b6033805460ff19169055565b600054610100900460ff166200432b5760405162461bcd60e51b815260040162000feb9062005079565b62000c416200475b565b600054610100900460ff166200435f5760405162461bcd60e51b815260040162000feb9062005079565b62000c4162004790565b606082826040516020016200438092919062005140565b604051602081830303815290604052905092915050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015620043e8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200440e919062004c9d565b90506200140c8463095ea7b360e01b856200442a868662004cb7565b6040516024016200242492919062004f36565b600062004457670de0b6b3a76400006301e1338062004c17565b61011f546200446860648562004c4f565b620032d6908662004c17565b60006200448062004249565b826200448c5762001442565b6200449783620030ff565b620044a162003141565b5060cf546001600160a01b03166000620044bb8262002e91565b9050620044ca3330876200295e565b620044ee81620044da8462002e91565b620044e6919062004bfd565b33866200463c565b92506200450062003ae660016200245c565b60d45460405163b6b55f2560e01b8152600481018790526001600160a01b039091169063b6b55f25906024016020604051808303816000875af11580156200454c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062004572919062004c9d565b50505092915050565b60f05460009060ff1615620045e05762004598600183116200272a565b620045a2620028ed565b6001600160a01b0316630ceff3da6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002ee0573d6000803e3d6000fd5b5090565b6000620045f18262004626565b60e4549091506200460c906001600160a01b03168262002d92565b62000a366200461a62000e51565b6200278d838562004bfd565b6000620186a060e95483620041dc919062004c17565b6000620046498262002db5565b6200465d670de0b6b3a76400008662004c17565b62004669919062004c4f565b905062000ba98284838762003389565b60ec5480156200468a57806200468e565b61c3505b60ea5490915060ff161562000a36576000620182b88310620046cc57620186a08314620046bf57620182b8620046c4565b620186a05b9050620046e0565b81831115620046dd575081620046e0565b50805b620186a0620046f0848362004c17565b620046fc919062004c4f565b60da55505050565b60008061012a54610122546200471b919062004cb7565b905061011f54915080421015620045e05762004738428262004bfd565b62004744908362004cb7565b91505090565b606062000aa58484600085620047c1565b600054610100900460ff16620047855760405162461bcd60e51b815260040162000feb9062005079565b62000c41336200283b565b600054610100900460ff16620047ba5760405162461bcd60e51b815260040162000feb9062005079565b6001609755565b606082471015620048245760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000feb565b600080866001600160a01b0316858760405162004842919062005173565b60006040518083038185875af1925050503d806000811462004881576040519150601f19603f3d011682016040523d82523d6000602084013e62004886565b606091505b50915091506200489987838387620048a4565b979650505050505050565b60608315620049155782516200490d57620048bf8562002c04565b6200490d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000feb565b508162000aa5565b62000aa583838151156200492c5781518083602001fd5b8060405162461bcd60e51b815260040162000feb919062005191565b62000c41620051a6565b610e0d80620051bd83390190565b801515811462000c2857600080fd5b6000602082840312156200498257600080fd5b813562000ba98162004960565b6001600160a01b038116811462000c2857600080fd5b60008060408385031215620049b957600080fd5b8235620049c6816200498f565b946020939093013593505050565b600060208284031215620049e757600080fd5b813562000ba9816200498f565b60006020828403121562004a0757600080fd5b5035919050565b60008060006060848603121562004a2457600080fd5b8335925060208401359150604084013562004a3f8162004960565b809150509250925092565b6001600160a01b0391909116815260200190565b6000806000806080858703121562004a7557600080fd5b843562004a82816200498f565b966020860135965060408601359560600135945092505050565b600080600080600080600060e0888a03121562004ab857600080fd5b87359650602088013562004acc816200498f565b9550604088013562004ade816200498f565b9450606088013562004af0816200498f565b9350608088013562004b02816200498f565b925060a088013562004b14816200498f565b8092505060c0880135905092959891949750929550565b6000806040838503121562004b3f57600080fd5b82359150602083013562004b53816200498f565b809150509250929050565b6000806000806080858703121562004b7557600080fd5b5050823594602084013594506040840135936060013592509050565b6000806040838503121562004ba557600080fd5b50508035926020909101359150565b6000806040838503121562004bc857600080fd5b823562004bd5816200498f565b9150602083013562004b53816200498f565b634e487b7160e01b600052601160045260246000fd5b60008282101562004c125762004c1262004be7565b500390565b600081600019048311821515161562004c345762004c3462004be7565b500290565b634e487b7160e01b600052601260045260246000fd5b60008262004c615762004c6162004c39565b500490565b9182526001600160a01b0316602082015260400190565b60006020828403121562004c9057600080fd5b815162000ba98162004960565b60006020828403121562004cb057600080fd5b5051919050565b6000821982111562004ccd5762004ccd62004be7565b500190565b60006020828403121562004ce557600080fd5b815162000ba9816200498f565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562004d2557818101518382015260200162004d0b565b838111156200140c5750506000910152565b60006020828403121562004d4a57600080fd5b81516001600160401b038082111562004d6257600080fd5b818401915084601f83011262004d7757600080fd5b81518181111562004d8c5762004d8c62004cf2565b604051601f8201601f19908116603f0116810190838211818310171562004db75762004db762004cf2565b8160405282815287602084870101111562004dd157600080fd5b6200489983602083016020880162004d08565b600181815b8085111562004e2557816000190482111562004e095762004e0962004be7565b8085161562004e1757918102915b93841c939080029062004de9565b509250929050565b60008262004e3e5750600162001442565b8162004e4d5750600062001442565b816001811462004e66576002811462004e715762004e91565b600191505062001442565b60ff84111562004e855762004e8562004be7565b50506001821b62001442565b5060208310610133831016604e8410600b841016171562004eb6575081810a62001442565b62004ec2838362004de4565b806000190482111562004ed95762004ed962004be7565b029392505050565b600062000ba9838362004e2d565b600080821280156001600160ff1b038490038513161562004f145762004f1462004be7565b600160ff1b839003841281161562004f305762004f3062004be7565b50500190565b6001600160a01b03929092168252602082015260400190565b60008083128015600160ff1b85018412161562004f705762004f7062004be7565b6001600160ff1b038401831381161562004f8e5762004f8e62004be7565b50500390565b60006001600160ff1b038184138284138082168684048611161562004fbd5762004fbd62004be7565b600160ff1b600087128281168783058912161562004fdf5762004fdf62004be7565b6000871292508782058712848416161562004ffe5762004ffe62004be7565b8785058712818416161562005017576200501762004be7565b505050929093029392505050565b60008262005037576200503762004c39565b600160ff1b82146000198414161562005054576200505462004be7565b500590565b6000600160ff1b82141562005072576200507262004be7565b5060000390565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008151808452620050de81602086016020860162004d08565b601f01601f19169290920160200192915050565b604081526000620051076040830185620050c4565b828103602084015262000afc8185620050c4565b600080604083850312156200512f57600080fd5b505080516020909101519092909150565b600083516200515481846020880162004d08565b8351908301906200516a81836020880162004d08565b01949350505050565b600082516200518781846020870162004d08565b9190910192915050565b60208152600062000ba96020830184620050c4565b634e487b7160e01b600052605160045260246000fdfe60806040523480156200001157600080fd5b5060405162000e0d38038062000e0d8339810160408190526200003491620001f4565b8151829082906200004d90600390602085019062000081565b5080516200006390600490602084019062000081565b5050600580546001600160a01b03191633179055506200029b915050565b8280546200008f906200025e565b90600052602060002090601f016020900481019282620000b35760008555620000fe565b82601f10620000ce57805160ff1916838001178555620000fe565b82800160010185558215620000fe579182015b82811115620000fe578251825591602001919060010190620000e1565b506200010c92915062000110565b5090565b5b808211156200010c576000815560010162000111565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200014f57600080fd5b81516001600160401b03808211156200016c576200016c62000127565b604051601f8301601f19908116603f0116810190828211818310171562000197576200019762000127565b81604052838152602092508683858801011115620001b457600080fd5b600091505b83821015620001d85785820183015181830184015290820190620001b9565b83821115620001ea5760008385830101525b9695505050505050565b600080604083850312156200020857600080fd5b82516001600160401b03808211156200022057600080fd5b6200022e868387016200013d565b935060208501519150808211156200024557600080fd5b5062000254858286016200013d565b9150509250929050565b600181811c908216806200027357607f821691505b602082108114156200029557634e487b7160e01b600052602260045260246000fd5b50919050565b610b6280620002ab6000396000f3fe608060405234801561001057600080fd5b50600436106100ba5760003560e01c806306fdde03146100bf57806307546172146100dd578063095ea7b31461010857806318160ddd1461012b57806323b872dd1461013d578063313ce56714610150578063395093511461015f57806340c10f191461017257806370a082311461018757806395d89b41146101b05780639dc29fac146101b8578063a457c2d7146101cb578063a9059cbb146101de578063dd62ed3e146101f1575b600080fd5b6100c7610204565b6040516100d49190610945565b60405180910390f35b6005546100f0906001600160a01b031681565b6040516001600160a01b0390911681526020016100d4565b61011b6101163660046109b6565b610296565b60405190151581526020016100d4565b6002545b6040519081526020016100d4565b61011b61014b3660046109e0565b6102ae565b604051601281526020016100d4565b61011b61016d3660046109b6565b6102d2565b6101856101803660046109b6565b6102f4565b005b61012f610195366004610a1c565b6001600160a01b031660009081526020819052604090205490565b6100c7610358565b6101856101c63660046109b6565b610367565b61011b6101d93660046109b6565b61039b565b61011b6101ec3660046109b6565b610416565b61012f6101ff366004610a3e565b610424565b60606003805461021390610a71565b80601f016020809104026020016040519081016040528092919081815260200182805461023f90610a71565b801561028c5780601f106102615761010080835404028352916020019161028c565b820191906000526020600020905b81548152906001019060200180831161026f57829003601f168201915b5050505050905090565b6000336102a481858561044f565b5060019392505050565b6000336102bc858285610574565b6102c78585856105ee565b506001949350505050565b6000336102a48185856102e58383610424565b6102ef9190610ac2565b61044f565b6005546001600160a01b031633146103275760405162461bcd60e51b815260040161031e90610ada565b60405180910390fd5b60025461034a5761033b60016103e8610780565b6103476103e882610af5565b90505b6103548282610780565b5050565b60606004805461021390610a71565b6005546001600160a01b031633146103915760405162461bcd60e51b815260040161031e90610ada565b610354828261082d565b600033816103a98286610424565b9050838110156104095760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161031e565b6102c7828686840361044f565b6000336102a48185856105ee565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166104b15760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161031e565b6001600160a01b0382166105125760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161031e565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006105808484610424565b905060001981146105e857818110156105db5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161031e565b6105e8848484840361044f565b50505050565b6001600160a01b0383166106525760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161031e565b6001600160a01b0382166106b45760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161031e565b6001600160a01b0383166000908152602081905260409020548181101561072c5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161031e565b6001600160a01b0384811660008181526020818152604080832087870390559387168083529184902080548701905592518581529092600080516020610b0d833981519152910160405180910390a36105e8565b6001600160a01b0382166107d65760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161031e565b80600260008282546107e89190610ac2565b90915550506001600160a01b03821660008181526020818152604080832080548601905551848152600080516020610b0d833981519152910160405180910390a35050565b6001600160a01b03821661088d5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161031e565b6001600160a01b038216600090815260208190526040902054818110156109015760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161031e565b6001600160a01b038316600081815260208181526040808320868603905560028054879003905551858152919291600080516020610b0d8339815191529101610567565b600060208083528351808285015260005b8181101561097257858101830151858201604001528201610956565b81811115610984576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b03811681146109b157600080fd5b919050565b600080604083850312156109c957600080fd5b6109d28361099a565b946020939093013593505050565b6000806000606084860312156109f557600080fd5b6109fe8461099a565b9250610a0c6020850161099a565b9150604084013590509250925092565b600060208284031215610a2e57600080fd5b610a378261099a565b9392505050565b60008060408385031215610a5157600080fd5b610a5a8361099a565b9150610a686020840161099a565b90509250929050565b600181811c90821680610a8557607f821691505b60208210811415610aa657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b60008219821115610ad557610ad5610aac565b500190565b6020808252600190820152601b60f91b604082015260600190565b600082821015610b0757610b07610aac565b50039056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122016ad045cd256bbeefe5c1c4ac397061aa6870f2735b3206f6890eabe4f7c209a64736f6c634300080a0033a2646970667358221220ae2274305cf64aa0a80854a46405db2f40d72fb22b064a1294b508ecf5c1285964736f6c634300080a0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"optimizer":{"enabled":true,"runs":1}},"optimization_runs":1,"sourcify_repo_url":null,"decoded_constructor_args":null,"compiler_version":"0.8.10+commit.fc410830","is_verified_via_verifier_alliance":true,"verified_at":"2026-09-22T02:12:20.658538Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x608060405234801561001057600080fd5b5060cf80546001600160a01b0319166001179055615fff80620000346000396000f3fe60806040523480156200001157600080fd5b50600436106200042a5760003560e01c80630553c2e7146200042f578063085a2b78146200044d578063088f4b7814620004575780631072cbea146200047057806312361ac214620004875780632544e841146200049157806325cdd860146200049c57806329811ee514620004a65780632e02cd5e14620004bd5780632e2452ab14620004e557806333986ffa14620004f357806333f0f80014620004fd5780633403c2fc14620005085780633f4ba83a1462000512578063400f7d32146200051c578063408f3a30146200052657806340a2029e146200053d578063435d44d9146200055457806343848aed146200056b57806344966ba01462000576578063494347e714620005995780634954380b14620005a35780634da4f60314620005b15780634ff0876a14620005c5578063514b6dbd14620005d057806358cdd22b14620005e75780635b4a346214620005fb5780635c975abb14620006125780635f0b472a146200061e57806362adade5146200062d5780636373ea691462000637578063655c9a5314620006415780636736d616146200064c57806369e25ec114620006635780636bd7b30114620006785780636c4321eb1462000687578063715018a6146200069c578063734d828714620006a6578063747efea114620006b057806375d1497b14620006c457806381f5ae7e14620006cf5780638260dbba14620006d957806383975b6714620006e45780638456cb5914620006ee5780638a0dac4a14620006f85780638da5cb5b146200070f5780638ed8f575146200071957806391b900ef14620007305780639290d427146200074757806396164236146200075e5780639638529c1462000772578063991052b714620007895780639a4d360814620007935780639ed9de9414620007aa578063a219d21814620007c6578063a2454e5514620007dd578063a27eccc114620007f4578063a2c8b17714620007fe578063a4d66daf1462000808578063a6f7f5d61462000812578063a8c62e76146200081c578063b3f006741462000830578063b450dfce1462000844578063c5c75098146200085b578063c61e3faa146200086a578063c88e84471462000881578063c9aba3561462000898578063ccc143b814620008a8578063cfa5656714620008bf578063d19d3bdc14620008c9578063d48099ad14620008e0578063d636b05f14620008f7578063dc82697c1462000902578063ddca3f43146200090c578063dee7c2cb1462000916578063dfd5b1c9146200092d578063dfefc7f81462000938578063e2988e6e1462000943578063e3e39368146200094e578063e70875ad1462000962578063ef191b7f1462000979578063f2fde38b1462000990578063fa69d17714620009a7578063fc0c546a14620009be578063fde4ebe414620009d2578063fe81a02414620009e9575b600080fd5b6200043a61012a5481565b6040519081526020015b60405180910390f35b6200043a60da5481565b6200046e620004683660046200496f565b620009f3565b005b6200046e62000481366004620049a5565b62000a10565b6200043a60dc5481565b6200043a6101245481565b6200043a62000a3a565b6200043a620004b7366004620049d4565b62000a4d565b620004d4620004ce366004620049d4565b62000b12565b604051901515815260200162000444565b60f054620004d49060ff1681565b6200046e62000bb0565b6200043a6101255481565b6200046e62000c2b565b6200046e62000c43565b6200043a60dd5481565b6200046e62000537366004620049f4565b62000c61565b6200046e6200054e36600462004a0e565b62000c70565b6200046e62000565366004620049f4565b62000cb7565b6200043a6101275481565b60d6546200058a906001600160a01b031681565b60405162000444919062004a4a565b6200046e62000cd6565b60f254620004d49060ff1681565b61011e54620004d490610100900460ff1681565b6200043a61011f5481565b6200046e620005e13660046200496f565b62000cf4565b61012854620004d490610100900460ff1681565b6200046e6200060c3660046200496f565b62000d23565b60335460ff16620004d4565b61012d54620004d49060ff1681565b6200043a60de5481565b6200043a60e95481565b6200043a6101265481565b6200046e6200065d3660046200496f565b62000d41565b61012854620004d49062010000900460ff1681565b61012854620004d49060ff1681565b61011e54620004d49062010000900460ff1681565b6200046e62000d80565b6200043a60e15481565b60d5546200058a906001600160a01b031681565b6200043a6101225481565b6200043a60cc5481565b6200043a6101205481565b6200046e62000d96565b6200046e62000e09565b6200046e62000709366004620049d4565b62000e1d565b6200058a62000e51565b6200046e6200072a366004620049f4565b62000e60565b6200046e6200074136600462004a5e565b62000e84565b6200043a62000758366004620049d4565b62000f07565b61012d54620004d490610100900460ff1681565b6200046e6200078336600462004a9c565b62000f45565b6200046e62001397565b6200046e620007a4366004620049f4565b62001412565b610128546200058a90630100000090046001600160a01b031681565b6200043a620007d7366004620049d4565b62001435565b6200046e620007ee366004620049a5565b62001448565b6200043a60d15481565b6200046e62001484565b6200043a60c95481565b6200043a60f15481565b60d4546200058a906001600160a01b031681565b60e4546200058a906001600160a01b031681565b6200043a62000855366004620049f4565b620018a5565b61011e54620004d49060ff1681565b6200043a6200087b36600462004b2b565b620018c1565b6200046e6200089236600462004b5e565b62001b84565b6200043a670de0b6b3a764000081565b6200043a620008b936600462004b2b565b62001bd3565b6200046e62001e78565b6200046e620008da36600462004b2b565b62001f95565b6200046e620008f136600462004b91565b620020bd565b6200043a6101295481565b6200043a620020cb565b6200043a60e35481565b6200046e6200092736600462004b2b565b62002118565b6200043a620186a081565b6200043a6101235481565b6200043a6101215481565b60d7546200058a906001600160a01b031681565b6200043a62000973366004620049f4565b6200224e565b6200043a6200098a36600462004bb4565b6200227c565b6200046e620009a1366004620049d4565b620022f5565b6200046e620009b836600462004b91565b62002371565b60cf546200058a906001600160a01b031681565b6200046e620009e33660046200496f565b620023c5565b6200043a60df5481565b620009fd620023e2565b60ea805460ff1916911515919091179055565b62000a1a620023e2565b60ca5462000a36906001600160a01b0384811691168362002402565b5050565b600062000a4860006200245c565b905090565b60008062000a5c60006200245c565b9050600062000a6a620024e6565b905081158062000a7c5750620186a082145b1562000aad5760d6546001600160a01b0385811691161482151462000aa2578062000aa5565b60005b949350505050565b60da5460d6546001600160a01b0386811691161462000b055762000ad583620186a062004bfd565b62000ae482620186a062004bfd565b62000af0908462004c17565b62000afc919062004c4f565b95945050505050565b8262000af0828462004c17565b61012854600090630100000090046001600160a01b031680158062000ba957506101295460405163043bb58960e51b81526001600160a01b03831691638776b1209162000b659190879060040162004c66565b602060405180830381865afa15801562000b83573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000ba9919062004c7d565b9392505050565b60d45460405163370a95eb60e21b81526001600160a01b039091169063dc2a57ac9062000be290339060040162004a4a565b6020604051808303816000875af115801562000c02573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c28919062004c9d565b50565b62000c3562002557565b62000c41600062002599565b565b62000c4d62002557565b62000c57620025e4565b62000c416200261f565b62000c6b620023e2565b60c955565b62000c7a6200266f565b62000c9162000c8b60335460ff1690565b6200272a565b610120929092556101255561012880549115156101000261ff0019909216919091179055565b62000cc1620023e2565b62000c28620186a08260ec819055116200274a565b62000ce062002557565b62000cea6200276a565b62000c4162002793565b62000cfe620023e2565b61011e5462000d109060ff166200272a565b60f0805460ff1916911515919091179055565b62000d2d6200266f565b61012d805460ff1916911515919091179055565b62000d4b620023e2565b62000d658115801562000c8b575060f05460ff166200272a565b61012d80549115156101000261ff0019909216919091179055565b62000d8a620027d8565b62000c4160006200283b565b62000da0620023e2565b6101285462000dc39062010000900460ff168062000c8b575060dc54156200272a565b60d3805460ff60b81b1916905561011e5460ff161562000ddf57565b60335460ff161562000df55762000df56200261f565b61011e805462ffff00191662010100179055565b62000e1362002557565b62000c416200288d565b62000e27620023e2565b60d080546001600160a01b0319166001600160a01b03831690811790915562000c289015620028cd565b6065546001600160a01b031690565b62000e6e333014156200272a565b62000c2862000e7c620028ed565b30836200295e565b62000e8e620023e2565b62000ec4614e2084118062000ea55750620186a083115b8062000ebe575062000ebb600a614e2062004c4f565b82115b6200274a565b60e480546001600160a01b0319166001600160a01b03861690811790915562000eee9015620028cd565b62000ef862002983565b60e39290925560e95560f15550565b600062000f3e8262000f18620029be565b60df5460de5462000f2a919062004cb7565b62000f358662002a03565b60da5462002a2d565b5092915050565b600054610100900460ff161580801562000f665750600054600160ff909116105b8062000f8b575062000f783062002c04565b15801562000f8b575060005460ff166001145b62000ff45760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801562001018576000805461ff0019166101001790555b60cf546001600160a01b031615620010425760405162dc149f60e41b815260040160405180910390fd5b6200106a6001600160a01b03841615806200106457506001600160a01b038816155b620028cd565b6200107a620186a083116200274a565b6200108462002c13565b6200109188878762002c47565b6000836001600160a01b031663747efea16040518163ffffffff1660e01b8152600401602060405180830381865afa158015620010d2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620010f8919062004cd2565b90506000816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156200113b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001165919081019062004d37565b9050620011ac6040518060400160405280600781526020016602830b932ba37960cd1b815250604051806040016040528060018152602001600760fc1b8152508362002cad565b60d660006101000a8154816001600160a01b0302191690836001600160a01b031602179055506200121d6040518060400160405280600a81526020016902830b932ba37902121160b51b815250604051806040016040528060048152602001637042425f60e01b8152508362002cad565b60d780546001600160a01b03199081166001600160a01b039384161790915560cf805482168c841690811790915560d48054831689851617905560d5805490921692851692909217905560da8590556040805163313ce56760e01b815290516000929163313ce5679160048083019260209291908290030181865afa158015620012ab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620012d1919062004c9d565b620012de90600a62004ee1565b60d181905560dc81905560dd8190559050620012fb8a8762002d08565b62001307838762002d08565b60d080546001600160a01b0319166001600160a01b038a1617905560ea805460ff1916600117905561c35060ec554260cc556200134362002d20565b50505080156200138d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b61012854620013aa9060ff16156200272a565b60d4546040516347e9887560e11b81526001600160a01b0390911690638fd310ea90620013dc90339060040162004a4a565b600060405180830381600087803b158015620013f757600080fd5b505af11580156200140c573d6000803e3d6000fd5b50505050565b62001420333014156200272a565b62000c286200142e620028ed565b8262002d92565b6000620014428262002db5565b92915050565b620014526200266f565b61012880546001600160a01b039093166301000000026301000000600160b81b03199093169290921790915561012955565b6200148e6200266f565b61011f5461012854620014d19062010000900460ff1680620014c2575061012a5461012254620014bf919062004cb7565b42105b8062000c8b575081156200272a565b620014db62002df6565b620014e56200276a565b61011e805460ff19166001179055620014fd6200288d565b61011e805462ffff001916905560d45461012c546001600160a01b0390911690600090620015346200152e620020cb565b62002e2f565b62001540919062004eef565b9050600081121562001550575060005b806101265462001561919062004cb7565b61012155600061012c5562001577834262004cb7565b61012255610120546200158b904262004cb7565b610123819055506000826001600160a01b031663efda7e076040518163ffffffff1660e01b8152600401602060405180830381865afa158015620015d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620015f9919062004c9d565b61012d54909150600090610100900460ff166200162757816101275462001621919062004cb7565b62001629565b815b6040516001625a42ed60e11b03198152600481018290529091506001600160a01b0385169063ff4b7a2690602401600060405180830381600087803b1580156200167257600080fd5b505af115801562001687573d6000803e3d6000fd5b5050505060006200169762002e46565b60cf54909150600090620016b4906001600160a01b031662002e91565b90506000866001600160a01b031663a9a949686040518163ffffffff1660e01b8152600401602060405180830381865afa158015620016f7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200171d919062004c9d565b9050866001600160a01b031663f25b11408385116200173d57846200173f565b835b6040518263ffffffff1660e01b81526004016200175e91815260200190565b600060405180830381600087803b1580156200177957600080fd5b505af11580156200178e573d6000803e3d6000fd5b5050505081831115620017a6576200138d8162002f06565b610128805460ff191660011790556000620017c2848462004bfd565b604051631349a6c160e31b8152600481018290529091503090639a4d360890602401600060405180830381600087803b158015620017ff57600080fd5b505af192505050801562001811575060015b6200188f5762001822888262002d92565b60405163e41ee1b360e01b8152600481018290526001600160a01b0389169063e41ee1b390602401600060405180830381600087803b1580156200186557600080fd5b505af11580156200187a573d6000803e3d6000fd5b50505050620018898162002f81565b6200189a565b6200189a8262002f06565b505050505050505050565b60d654600090620014429083906001600160a01b031662003056565b6000620018ce8262003087565b60d7546200196c906001600160a01b038481169116148015620018f4575060f25460ff16155b8062001903575061012d5460ff165b8062001918575060d354600160b81b900460ff165b8062001926575060f05460ff165b8062001934575060ea5460ff165b8062001944575061011e5460ff16155b80620019535750610122544210155b8062000c8b5750620019653362000b12565b156200272a565b82620019785762001442565b60006200198583620030be565b90506200199381156200272a565b6200199d6200276a565b620019a884620030ff565b620019b262003141565b50620019c03330866200295e565b61012a5461012254600090620019d890429062004bfd565b905060008261011f54620019ed919062004cb7565b620019f9848462004cb7565b62001a048962002e2f565b62001a10919062004c17565b62001a1c919062004c4f565b61012154610126549192509060008183111562001a745762001a7162001a6a62001a47848662004bfd565b62001a6460df5460de5462001a5d919062004cb7565b89620032bc565b620032ee565b8a62003338565b90505b600062001a9262001a8b8662001a648e8a620032bc565b8b62003338565b905060008262001aa28c62002a03565b62001aae919062004cb7565b9050808962001abe848f62004cb7565b62001aca919062004c17565b62001ad6919062004c4f565b995062001ae68b338c8f62003389565b85610121600082825462001afb919062004cb7565b909155505060d454604051633ec701eb60e01b8152600481018e90526001600160a01b0390911690633ec701eb90602401600060405180830381600087803b15801562001b4757600080fd5b505af115801562001b5c573d6000803e3d6000fd5b5050505062001b7562001b6e620028ed565b8d62002d92565b50505050505050505092915050565b62001b9184848362003445565b8260011415801562001bad57506101285462010000900460ff16155b1562001bcd5762001bc28261012a5462002371565b62001bcd8462003dc5565b6200140c565b600062001be08262003087565b60d65462001c2e906001600160a01b0384811691161462001c0f5761011e5462010000900460ff161562001953565b61011e54610100900460ff16158062000c8b5750620019653362000b12565b62001c386200276a565b62001c4262003141565b5060d4546001600160a01b03168362001c645762001c61338462003e0c565b93505b62001c70848462003e81565b915062001c7c62003ea3565b1562001d82576000816001600160a01b031663d7bff5386040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001cc3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001ce9919062004c9d565b9050610125548162001cfc919062004cb7565b61012454111562001d8057604051630a198c7f60e21b81526001600160a01b0383169063286631fc9062001d37908690339060040162004c66565b600060405180830381600087803b15801562001d5257600080fd5b505af115801562001d67573d6000803e3d6000fd5b5050505062001d7885848662003ec6565b505062001442565b505b8160008062001d92838762003f8d565b91509150600062001da4848462004078565b90508062001db3848662004cb7565b62001dbf919062004bfd565b955080610126600082825462001dd6919062004cb7565b925050819055508161012c600082825462001df2919062004eef565b909155505060405163f16c6bf160e01b815260048101879052336024820152604481018590526001600160a01b0386169063f16c6bf190606401600060405180830381600087803b15801562001e4757600080fd5b505af115801562001e5c573d6000803e3d6000fd5b5050505062001e6d88858962003ec6565b505050505092915050565b62001e826200266f565b60f05462001eb09060ff168062001e9d575061011e5460ff16155b8062000c8b57506101235442106200272a565b60d4546001600160a01b0316600062001ec862002e46565b604051638ed8f57560e01b8152600481018290529091503090638ed8f57590602401600060405180830381600087803b15801562001f0557600080fd5b505af192505050801562001f17575060015b62001f275762000a368162002f81565b6040516303c96c4560e61b8152600481018290526001600160a01b0383169063f25b114090602401600060405180830381600087803b15801562001f6a57600080fd5b505af115801562001f7f573d6000803e3d6000fd5b5050610128805460ff1916600117905550505050565b62001f9f6200266f565b62001fa96200276a565b60d45460405163746f7a3360e01b81526000916001600160a01b03169063746f7a339062001fde908690869060040162004c66565b6020604051808303816000875af115801562001ffe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002024919062004c9d565b600060e381905560f181905560e1554260cc5560df81905560d554909150819062002058906001600160a01b031662002e91565b62002064919062004bfd565b60de556200207162002793565b600061012181905561012681905561011e805462ffff00191662010100179055610128805461ffff191661010117905561011f819055610122819055620020b89062003dc5565b505050565b62000a368282600062003445565b60e15460cf5460009190620020e9906001600160a01b031662002e91565b60d55462002100906001600160a01b031662002e91565b6200210c919062004cb7565b62000a48919062004bfd565b620021473362002127620028ed565b6001600160a01b031614158062000c8b575061011e5460ff16156200272a565b620021528162003087565b6200215c6200276a565b60006200216a838362003e81565b90506000806200217b838562003f8d565b91509150600061011f5490508061012a548262002199919062004cb7565b620021a5848662004eef565b620021b1919062004c17565b620021bd919062004c4f565b9250620021cc86858762003ec6565b60d454604051633e81a73360e01b8152600481018690526001600160a01b0390911690633e81a73390602401600060405180830381600087803b1580156200221357600080fd5b505af115801562002228573d6000803e3d6000fd5b5050505082610121600082825462002241919062004bfd565b9091555050505050505050565b60f254600090620022639060ff1615620040b3565b60d754620014429083906001600160a01b031662003056565b6000620022956200228e848462003e0c565b8362003e81565b9050620022b28160cc5442620022ac919062004bfd565b620032bc565b620022be908262004bfd565b90506000620022ce828462003f8d565b509050620022dd828262004078565b620022e9828462004cb7565b62000aa5919062004bfd565b620022ff620027d8565b6001600160a01b038116620023665760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000feb565b62000c28816200283b565b6200237b6200266f565b61012854620023b89062010000900460ff16806200239c575061011e5460ff165b80620023a6575082155b8062000c8b575061011f54156200272a565b61011f9190915561012a55565b620023cf620023e2565b60f2805460ff1916911515919091179055565b62000c4133620023f162000e51565b6001600160a01b03161415620040b3565b620020b88363a9059cbb60e01b84846040516024016200242492919062004f36565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152620040d3565b600062004948826200247257620041af62002477565b620041e85b60d65490915060009062002497906001600160a01b031663ffffffff8416565b60d754909150600090620024b7906001600160a01b031663ffffffff8516565b620024c3908362004cb7565b905080620024d657506000949350505050565b8062000af0620186a08462004c17565b60d45460408051632116f20160e21b815290516000926001600160a01b03169163845bc8049160048083019260209291908290030181865afa15801562002531573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a48919062004c9d565b60d05462000c41906001600160a01b031633148015906200259357506200257d62000e51565b6001600160a01b0316336001600160a01b031614155b620040b3565b60335460ff16620025ae57620025ae6200288d565b80620025c15761011e805461ff00191690555b5061011e805462ff00001916905560d3805460ff60b81b1916600160b81b179055565b6101285462000c419062010000900460ff168062002605575061011e5460ff165b8062000c8b575060d354600160b81b900460ff166200272a565b62002629620041fe565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405162002665919062004a4a565b60405180910390a1565b62000c416200267d62000e51565b6001600160a01b0316336001600160a01b03161415801562000c8b575060d460009054906101000a90046001600160a01b03166001600160a01b031663481c6a756040518163ffffffff1660e01b8152600401602060405180830381865afa158015620026ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002714919062004cd2565b6001600160a01b0316336001600160a01b031614155b801562000c2857604051631eb49d6d60e11b815260040160405180910390fd5b801562000c285760405163fd7850ad60e01b815260040160405180910390fd5b60e45460cf5462000c41916001600160a01b03908116916200278d911662002e91565b62002d92565b60d38054600160b81b60ff60b81b19821681179092550460ff16620027b762003141565b62000c285760d38054821515600160b81b0260ff60b81b1990911617905550565b33620027e362000e51565b6001600160a01b03161462000c415760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000feb565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6200289762004249565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258620026563390565b801562000c28576040516321e7594160e21b815260040160405180910390fd5b60d45460408051637df1f1b960e01b815290516000926001600160a01b031691637df1f1b99160048083019260209291908290030181865afa15801562002938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a48919062004cd2565b806200296957505050565b60cf54620020b8906001600160a01b031684848462004291565b620029a062002991620029be565b60cc54620022ac904262004bfd565b60e16000828254620029b3919062004cb7565b90915550504260cc55565b60d5546000908190620029da906001600160a01b031662002e91565b60e154909150808211620029f0576000620029fc565b620029fc818362004bfd565b9250505090565b60d6546000906001600160a01b0383811691161462002a255760df5462001442565b505060de5490565b600080600062002a3d88620030be565b90508062002a5457505060d1549050600062002bfa565b8515801562002a61575086155b1562002a7557600080925092505062002bfa565b600062002a83878962004f4f565b90508015801562002a9e575060d354600160b81b900460ff16155b1562002abd5762002aaf8962002db5565b600093509350505062002bfa565b600081131562002af657620186a060e3548262002adb919062004f94565b62002ae7919062005025565b62002af3908262004f4f565b90505b60d6546001600160a01b038a81169116148662002b17576000935062002bc6565b8688141562002b295781935062002bc6565b600082131562002b81576000620186a062002b45888262004bfd565b62002b51908562004f94565b62002b5d919062005025565b90508162002b6c578062002b78565b62002b78818462004f4f565b94505062002bc6565b600060df5462002b919062005059565b9050600081841362002ba4578162002ba6565b835b90508262002bb5578062002bc1565b62002bc1818562004f4f565b955050505b82670de0b6b3a764000062002bdc868a62004eef565b62002be8919062004c17565b62002bf4919062004c4f565b94505050505b9550959350505050565b6001600160a01b03163b151590565b600054610100900460ff1662002c3d5760405162461bcd60e51b815260040162000feb9062005079565b62000c41620042cb565b62002c6e6001600160a01b03831615806200106457506001600160a01b03821615620028cd565b62002c7862004301565b62002c8262004335565b60c983905560ca80546001600160a01b0319166001600160a01b038416179055620020b881620022f5565b600062002cbb848362004369565b62002cc7848462004369565b60405162002cd59062004952565b62002ce2929190620050f2565b604051809103906000f08015801562002cff573d6000803e3d6000fd5b50949350505050565b62000a366001600160a01b0383168260001962004397565b60ea805460ff1916905562278d0061011f556206978061012a81905562002d48904262004bfd565b6101225561011e80546201010062ffff0019909116179055610128805461ff00191661010017905561012d805460ff1916600117905562000c4162002d8c620024e6565b62003dc5565b8062002d9c575050565b60cf5462000a36906001600160a01b0316838362002402565b600062002dc282620030be565b62002dcf57505060d15490565b60d6546001600160a01b0383811691161462002dee5760dd5462001442565b505060dc5490565b60f05462000c419060ff16801562000c8b575061012d54610100900460ff16158062000c8b575062002e2762002e46565b15156200272a565b6000620014428262002e40620024e6565b6200443d565b60d45460408051631e2af12360e31b815290516000926001600160a01b03169163f15789189160048083019260209291908290030181865afa15801562002531573d6000803e3d6000fd5b6040516370a0823160e01b81526000906001600160a01b038316906370a082319062002ec290309060040162004a4a565b602060405180830381865afa15801562002ee0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001442919062004c9d565b60f05460ff161562000c285762002f1c620028ed565b6001600160a01b0316631d859d73826040518263ffffffff1660e01b815260040162002f4a91815260200190565b600060405180830381600087803b15801562002f6557600080fd5b505af115801562002f7a573d6000803e3d6000fd5b5050505050565b610128805462ff000019166201000017905560f05460ff161562002ffe5762002fa9620028ed565b6001600160a01b0316636febd5436040518163ffffffff1660e01b8152600401600060405180830381600087803b15801562002fe457600080fd5b505af115801562002ff9573d6000803e3d6000fd5b505050505b60335460ff166200301357620030136200288d565b61011e805462ffffff191690556040518181527fddeda4ec7ef5a5761f0a329088482bf17d717987d67aaad5a3c4535ab7da29099060200160405180910390a150565b60006200306262004249565b62003071620019653362000b12565b6200307b6200276a565b62000ba9838362004474565b60d65462000c28906001600160a01b0383811691161480159062000c8b575060d7546001600160a01b03838116911614156200272a565b6000816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002ee0573d6000803e3d6000fd5b60c954801562000a3657808262003115620020cb565b62003121919062004cb7565b111562000a3657604051630d45dcb760e11b815260040160405180910390fd5b60006200314d62002983565b60de5460df54600062003161828462004cb7565b905060006200316f620020cb565b60da5490915082821115620031c35760e354620186a09062003192858562004bfd565b6200319e919062004c17565b620031aa919062004c4f565b60e16000828254620031bd919062004cb7565b90915550505b60d6546000908190620031e3906001600160a01b031685878a8762002a2d565b60d7549193509150600090819062003208906001600160a01b031687898b8962002a2d565b909250905062003219838a62004eef565b60de5562003228818962004eef565b60df5560008112801562003246575087620032438262005059565b12155b806200325b575086158015906200325b575085155b15620032a75760d35460019a50600160b81b900460ff16620032905760405163064e30f160e51b815260040160405180910390fd5b856200329b57600093505b620032a7600162002599565b5060dc929092555060dd555093949350505050565b60006502de413530008260f15485620032d6919062004c17565b620032e2919062004c17565b62000ba9919062004c4f565b6000828210620032fe5762001442565b6200330a828462004bfd565b9250620186a060e3548462003320919062004c17565b6200332c919062004c4f565b62000ba9908462004bfd565b60da5460d65460009190620186a0906001600160a01b038581169116146200336f576200336982620186a062004bfd565b62003371565b815b6200337d908662004c17565b62000aa5919062004c4f565b6040516340c10f1960e01b81526001600160a01b038516906340c10f1990620033b9908690869060040162004f36565b600060405180830381600087803b158015620033d457600080fd5b505af1158015620033e9573d6000803e3d6000fd5b505060d6546001600160a01b03878116911614159150620034269050578060de60008282546200341a919062004cb7565b909155506200140c9050565b8060df60008282546200343a919062004cb7565b909155505050505050565b6200344f6200266f565b600182146200345d62002df6565b60d4546101265461011e546001600160a01b0390921691620034d99060ff1615806200348b57506101225442105b806200349f57506200349c62002e46565b15155b80620034c05750600186118015620034c0575081861080620034c057508615155b8062000c8b575083801562000c8b57508415156200272a565b6000620034e56200276a565b620034f0866200457b565b60405163bb42b77360e01b8152600481018290529096506000906001600160a01b0385169063bb42b7739060240160408051808303816000875af11580156200353d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200356391906200511b565b80945081925050506000846001600160a01b031663a9a949686040518163ffffffff1660e01b8152600401602060405180830381865afa158015620035ac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620035d2919062004c9d565b905085156200360f5760d554620035f2906001600160a01b031662002e91565b620035fe908462004cb7565b92506200360c838362004cb7565b91505b6000866200361e57826200362a565b6200362a848462004bfd565b61012d54909150600090610100900460ff16801562003647575087155b90506000816200365857846200365b565b60005b90508180156200366b575060018b115b1562003715576000886001600160a01b03166392093b366040518163ffffffff1660e01b8152600401602060405180830381865afa158015620036b2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620036d8919062004c9d565b905062003713811580159062000c8b575088620036ff620036f8620020cb565b846200443d565b6200370b919062004cb7565b85116200272a565b505b6200371f62002983565b6101218390556101268790556040516349b38c9360e01b8152600481018b90526001600160a01b038916906349b38c93906024016040805180830381865afa15801562003770573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200379691906200511b565b60f054909b5090945060ff16156200386257620037b2620028ed565b6001600160a01b0316639b8e712b620037cc868462004cb7565b6040516001600160e01b031960e084901b16815260048101919091528b151560248201526044016020604051808303816000875af115801562003813573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003839919062004c7d565b6200386257620038546200384e858362004cb7565b62002f81565b505050505050505050505050565b30638ed8f57562003874868462004cb7565b6040518263ffffffff1660e01b81526004016200389391815260200190565b600060405180830381600087803b158015620038ae57600080fd5b505af1925050508015620038c0575060015b620038db57620038d56200384e858362004cb7565b62003854565b604051638b80c89d60e01b8152600481018590526001600160a01b03891690638b80c89d90602401600060405180830381600087803b1580156200391e57600080fd5b505af115801562003933573d6000803e3d6000fd5b5050505081801562003947575060f05460ff165b15620039ac5762003957620028ed565b6001600160a01b0316632512529b6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200399257600080fd5b505af1158015620039a7573d6000803e3d6000fd5b505050505b81620039bd57620039bd87620045e4565b8815620039d057620039d0888762002d92565b811562003a5557821562003a3b57604051633ec701eb60e01b8152600481018490526001600160a01b03891690633ec701eb90602401600060405180830381600087803b15801562003a2157600080fd5b505af115801562003a36573d6000803e3d6000fd5b505050505b8660e1600082825462003a4f919062004cb7565b90915550505b62003a5f62003141565b5060e154821562003af457801562003aee57600062003a7e8262004626565b9050801562003aa95760e45460d65462003aa79183916001600160a01b0391821691166200463c565b505b62003ad562003ab9828462004bfd565b62003ac362000e51565b60d6546001600160a01b03166200463c565b5062003aec62003ae660016200245c565b62004679565b505b62003b2e565b600088851162003b0657600062003b12565b62003b12898662004bfd565b90508082111562003b21578091505b62003b2c82620045e4565b505b8060e1600082825462003b42919062004bfd565b90915550600090508362003b57578862003b5a565b60005b62003b66908362004cb7565b9050600081861162003b7a57600062003b86565b62003b86828762004bfd565b61012781905590506001600160a01b038b1663b6b55f258662003baa578262003bad565b60005b6040518263ffffffff1660e01b815260040162003bcc91815260200190565b6020604051808303816000875af115801562003bec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003c12919062004c9d565b508a6001600160a01b031663d7bff5386040518163ffffffff1660e01b8152600401602060405180830381865afa15801562003c52573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003c78919062004c9d565b6101245562003c878f62003dc5565b61011e805460ff1916905560006101218190556101265560d354600160b81b900460ff1662003ccd5762003cba6200261f565b61011e805462ffff001916620101001790555b610128805460ff19168d1580159190911790915562003d0357610128805461ff001916610100179055600061011f819055610122555b7ff66f28b40975dbb933913542c7e6a0f50a1d0f20aa74ea6e0efe65ab616323ec62003d308a8a62004bfd565b60408051918252602082018590520160405180910390a18c1562003db457604051633e81a73360e01b8152600481018e90526001600160a01b038c1690633e81a73390602401600060405180830381600087803b15801562003d9157600080fd5b505af115801562003da6573d6000803e3d6000fd5b5050505062003db462002793565b505050505050505050505050505050565b60d45461011f5461012a546040516320769c1360e21b815260048101859052602481019290925260448201526001600160a01b03909116906381da704c9060640162002f4a565b6040516370a0823160e01b81526000906001600160a01b038316906370a082319062003e3d90869060040162004a4a565b602060405180830381865afa15801562003e5b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000ba9919062004c9d565b6000670de0b6b3a764000062003e978362002db5565b620032e2908562004c17565b61012854600090610100900460ff1615801562000a4857505060f05460ff161590565b604051632770a7eb60e21b81526001600160a01b03821690639dc29fac9062003ef6903390879060040162004f36565b600060405180830381600087803b15801562003f1157600080fd5b505af115801562003f26573d6000803e3d6000fd5b505060d6546001600160a01b0384811691161415915062003f639050578160de600082825462003f57919062004bfd565b9091555062003f7d9050565b8160df600082825462003f77919062004bfd565b90915550505b620020b862003ae660016200245c565b61011f5460009081908062003fa3575062004071565b61012a54600062003fb5828462004cb7565b8362003fc46200152e620029be565b62003fd0919062004c17565b62003fdc919062004c4f565b9050600062003fec828862003338565b9050600062003ffb8862002a03565b9050801562004023578062004011838b62004c17565b6200401d919062004c4f565b62004026565b60005b9650600062004036858762004cb7565b86620040428c62002e2f565b6200404e919062004c17565b6200405a919062004c4f565b905062004068888262004f4f565b96505050505050505b9250929050565b6000806200408a84620022ac62004704565b90508281101562000ba957620040a18382620032ee565b620040ad908462004bfd565b62000aa5565b801562000c285760405163ea8e4eb560e01b815260040160405180910390fd5b60006200412a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200474a9092919063ffffffff16565b90508051600014806200414e5750808060200190518101906200414e919062004c7d565b620020b85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000feb565b6000670de0b6b3a7640000620041c58362000f07565b620041d084620030be565b620041dc919062004c17565b62001442919062004c4f565b6000670de0b6b3a7640000620041c58362002db5565b60335460ff1662000c415760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640162000feb565b60335460ff161562000c415760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640162000feb565b6040516001600160a01b03808516602483015283166044820152606481018290526200140c9085906323b872dd60e01b9060840162002424565b600054610100900460ff16620042f55760405162461bcd60e51b815260040162000feb9062005079565b6033805460ff19169055565b600054610100900460ff166200432b5760405162461bcd60e51b815260040162000feb9062005079565b62000c416200475b565b600054610100900460ff166200435f5760405162461bcd60e51b815260040162000feb9062005079565b62000c4162004790565b606082826040516020016200438092919062005140565b604051602081830303815290604052905092915050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015620043e8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200440e919062004c9d565b90506200140c8463095ea7b360e01b856200442a868662004cb7565b6040516024016200242492919062004f36565b600062004457670de0b6b3a76400006301e1338062004c17565b61011f546200446860648562004c4f565b620032d6908662004c17565b60006200448062004249565b826200448c5762001442565b6200449783620030ff565b620044a162003141565b5060cf546001600160a01b03166000620044bb8262002e91565b9050620044ca3330876200295e565b620044ee81620044da8462002e91565b620044e6919062004bfd565b33866200463c565b92506200450062003ae660016200245c565b60d45460405163b6b55f2560e01b8152600481018790526001600160a01b039091169063b6b55f25906024016020604051808303816000875af11580156200454c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062004572919062004c9d565b50505092915050565b60f05460009060ff1615620045e05762004598600183116200272a565b620045a2620028ed565b6001600160a01b0316630ceff3da6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002ee0573d6000803e3d6000fd5b5090565b6000620045f18262004626565b60e4549091506200460c906001600160a01b03168262002d92565b62000a366200461a62000e51565b6200278d838562004bfd565b6000620186a060e95483620041dc919062004c17565b6000620046498262002db5565b6200465d670de0b6b3a76400008662004c17565b62004669919062004c4f565b905062000ba98284838762003389565b60ec5480156200468a57806200468e565b61c3505b60ea5490915060ff161562000a36576000620182b88310620046cc57620186a08314620046bf57620182b8620046c4565b620186a05b9050620046e0565b81831115620046dd575081620046e0565b50805b620186a0620046f0848362004c17565b620046fc919062004c4f565b60da55505050565b60008061012a54610122546200471b919062004cb7565b905061011f54915080421015620045e05762004738428262004bfd565b62004744908362004cb7565b91505090565b606062000aa58484600085620047c1565b600054610100900460ff16620047855760405162461bcd60e51b815260040162000feb9062005079565b62000c41336200283b565b600054610100900460ff16620047ba5760405162461bcd60e51b815260040162000feb9062005079565b6001609755565b606082471015620048245760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000feb565b600080866001600160a01b0316858760405162004842919062005173565b60006040518083038185875af1925050503d806000811462004881576040519150601f19603f3d011682016040523d82523d6000602084013e62004886565b606091505b50915091506200489987838387620048a4565b979650505050505050565b60608315620049155782516200490d57620048bf8562002c04565b6200490d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000feb565b508162000aa5565b62000aa583838151156200492c5781518083602001fd5b8060405162461bcd60e51b815260040162000feb919062005191565b62000c41620051a6565b610e0d80620051bd83390190565b801515811462000c2857600080fd5b6000602082840312156200498257600080fd5b813562000ba98162004960565b6001600160a01b038116811462000c2857600080fd5b60008060408385031215620049b957600080fd5b8235620049c6816200498f565b946020939093013593505050565b600060208284031215620049e757600080fd5b813562000ba9816200498f565b60006020828403121562004a0757600080fd5b5035919050565b60008060006060848603121562004a2457600080fd5b8335925060208401359150604084013562004a3f8162004960565b809150509250925092565b6001600160a01b0391909116815260200190565b6000806000806080858703121562004a7557600080fd5b843562004a82816200498f565b966020860135965060408601359560600135945092505050565b600080600080600080600060e0888a03121562004ab857600080fd5b87359650602088013562004acc816200498f565b9550604088013562004ade816200498f565b9450606088013562004af0816200498f565b9350608088013562004b02816200498f565b925060a088013562004b14816200498f565b8092505060c0880135905092959891949750929550565b6000806040838503121562004b3f57600080fd5b82359150602083013562004b53816200498f565b809150509250929050565b6000806000806080858703121562004b7557600080fd5b5050823594602084013594506040840135936060013592509050565b6000806040838503121562004ba557600080fd5b50508035926020909101359150565b6000806040838503121562004bc857600080fd5b823562004bd5816200498f565b9150602083013562004b53816200498f565b634e487b7160e01b600052601160045260246000fd5b60008282101562004c125762004c1262004be7565b500390565b600081600019048311821515161562004c345762004c3462004be7565b500290565b634e487b7160e01b600052601260045260246000fd5b60008262004c615762004c6162004c39565b500490565b9182526001600160a01b0316602082015260400190565b60006020828403121562004c9057600080fd5b815162000ba98162004960565b60006020828403121562004cb057600080fd5b5051919050565b6000821982111562004ccd5762004ccd62004be7565b500190565b60006020828403121562004ce557600080fd5b815162000ba9816200498f565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562004d2557818101518382015260200162004d0b565b838111156200140c5750506000910152565b60006020828403121562004d4a57600080fd5b81516001600160401b038082111562004d6257600080fd5b818401915084601f83011262004d7757600080fd5b81518181111562004d8c5762004d8c62004cf2565b604051601f8201601f19908116603f0116810190838211818310171562004db75762004db762004cf2565b8160405282815287602084870101111562004dd157600080fd5b6200489983602083016020880162004d08565b600181815b8085111562004e2557816000190482111562004e095762004e0962004be7565b8085161562004e1757918102915b93841c939080029062004de9565b509250929050565b60008262004e3e5750600162001442565b8162004e4d5750600062001442565b816001811462004e66576002811462004e715762004e91565b600191505062001442565b60ff84111562004e855762004e8562004be7565b50506001821b62001442565b5060208310610133831016604e8410600b841016171562004eb6575081810a62001442565b62004ec2838362004de4565b806000190482111562004ed95762004ed962004be7565b029392505050565b600062000ba9838362004e2d565b600080821280156001600160ff1b038490038513161562004f145762004f1462004be7565b600160ff1b839003841281161562004f305762004f3062004be7565b50500190565b6001600160a01b03929092168252602082015260400190565b60008083128015600160ff1b85018412161562004f705762004f7062004be7565b6001600160ff1b038401831381161562004f8e5762004f8e62004be7565b50500390565b60006001600160ff1b038184138284138082168684048611161562004fbd5762004fbd62004be7565b600160ff1b600087128281168783058912161562004fdf5762004fdf62004be7565b6000871292508782058712848416161562004ffe5762004ffe62004be7565b8785058712818416161562005017576200501762004be7565b505050929093029392505050565b60008262005037576200503762004c39565b600160ff1b82146000198414161562005054576200505462004be7565b500590565b6000600160ff1b82141562005072576200507262004be7565b5060000390565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008151808452620050de81602086016020860162004d08565b601f01601f19169290920160200192915050565b604081526000620051076040830185620050c4565b828103602084015262000afc8185620050c4565b600080604083850312156200512f57600080fd5b505080516020909101519092909150565b600083516200515481846020880162004d08565b8351908301906200516a81836020880162004d08565b01949350505050565b600082516200518781846020870162004d08565b9190910192915050565b60208152600062000ba96020830184620050c4565b634e487b7160e01b600052605160045260246000fdfe60806040523480156200001157600080fd5b5060405162000e0d38038062000e0d8339810160408190526200003491620001f4565b8151829082906200004d90600390602085019062000081565b5080516200006390600490602084019062000081565b5050600580546001600160a01b03191633179055506200029b915050565b8280546200008f906200025e565b90600052602060002090601f016020900481019282620000b35760008555620000fe565b82601f10620000ce57805160ff1916838001178555620000fe565b82800160010185558215620000fe579182015b82811115620000fe578251825591602001919060010190620000e1565b506200010c92915062000110565b5090565b5b808211156200010c576000815560010162000111565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200014f57600080fd5b81516001600160401b03808211156200016c576200016c62000127565b604051601f8301601f19908116603f0116810190828211818310171562000197576200019762000127565b81604052838152602092508683858801011115620001b457600080fd5b600091505b83821015620001d85785820183015181830184015290820190620001b9565b83821115620001ea5760008385830101525b9695505050505050565b600080604083850312156200020857600080fd5b82516001600160401b03808211156200022057600080fd5b6200022e868387016200013d565b935060208501519150808211156200024557600080fd5b5062000254858286016200013d565b9150509250929050565b600181811c908216806200027357607f821691505b602082108114156200029557634e487b7160e01b600052602260045260246000fd5b50919050565b610b6280620002ab6000396000f3fe608060405234801561001057600080fd5b50600436106100ba5760003560e01c806306fdde03146100bf57806307546172146100dd578063095ea7b31461010857806318160ddd1461012b57806323b872dd1461013d578063313ce56714610150578063395093511461015f57806340c10f191461017257806370a082311461018757806395d89b41146101b05780639dc29fac146101b8578063a457c2d7146101cb578063a9059cbb146101de578063dd62ed3e146101f1575b600080fd5b6100c7610204565b6040516100d49190610945565b60405180910390f35b6005546100f0906001600160a01b031681565b6040516001600160a01b0390911681526020016100d4565b61011b6101163660046109b6565b610296565b60405190151581526020016100d4565b6002545b6040519081526020016100d4565b61011b61014b3660046109e0565b6102ae565b604051601281526020016100d4565b61011b61016d3660046109b6565b6102d2565b6101856101803660046109b6565b6102f4565b005b61012f610195366004610a1c565b6001600160a01b031660009081526020819052604090205490565b6100c7610358565b6101856101c63660046109b6565b610367565b61011b6101d93660046109b6565b61039b565b61011b6101ec3660046109b6565b610416565b61012f6101ff366004610a3e565b610424565b60606003805461021390610a71565b80601f016020809104026020016040519081016040528092919081815260200182805461023f90610a71565b801561028c5780601f106102615761010080835404028352916020019161028c565b820191906000526020600020905b81548152906001019060200180831161026f57829003601f168201915b5050505050905090565b6000336102a481858561044f565b5060019392505050565b6000336102bc858285610574565b6102c78585856105ee565b506001949350505050565b6000336102a48185856102e58383610424565b6102ef9190610ac2565b61044f565b6005546001600160a01b031633146103275760405162461bcd60e51b815260040161031e90610ada565b60405180910390fd5b60025461034a5761033b60016103e8610780565b6103476103e882610af5565b90505b6103548282610780565b5050565b60606004805461021390610a71565b6005546001600160a01b031633146103915760405162461bcd60e51b815260040161031e90610ada565b610354828261082d565b600033816103a98286610424565b9050838110156104095760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161031e565b6102c7828686840361044f565b6000336102a48185856105ee565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166104b15760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161031e565b6001600160a01b0382166105125760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161031e565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006105808484610424565b905060001981146105e857818110156105db5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161031e565b6105e8848484840361044f565b50505050565b6001600160a01b0383166106525760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161031e565b6001600160a01b0382166106b45760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161031e565b6001600160a01b0383166000908152602081905260409020548181101561072c5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161031e565b6001600160a01b0384811660008181526020818152604080832087870390559387168083529184902080548701905592518581529092600080516020610b0d833981519152910160405180910390a36105e8565b6001600160a01b0382166107d65760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161031e565b80600260008282546107e89190610ac2565b90915550506001600160a01b03821660008181526020818152604080832080548601905551848152600080516020610b0d833981519152910160405180910390a35050565b6001600160a01b03821661088d5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161031e565b6001600160a01b038216600090815260208190526040902054818110156109015760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161031e565b6001600160a01b038316600081815260208181526040808320868603905560028054879003905551858152919291600080516020610b0d8339815191529101610567565b600060208083528351808285015260005b8181101561097257858101830151858201604001528201610956565b81811115610984576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b03811681146109b157600080fd5b919050565b600080604083850312156109c957600080fd5b6109d28361099a565b946020939093013593505050565b6000806000606084860312156109f557600080fd5b6109fe8461099a565b9250610a0c6020850161099a565b9150604084013590509250925092565b600060208284031215610a2e57600080fd5b610a378261099a565b9392505050565b60008060408385031215610a5157600080fd5b610a5a8361099a565b9150610a686020840161099a565b90509250929050565b600181811c90821680610a8557607f821691505b60208210811415610aa657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b60008219821115610ad557610ad5610aac565b500190565b6020808252600190820152601b60f91b604082015260600190565b600082821015610b0757610b07610aac565b50039056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122016ad045cd256bbeefe5c1c4ac397061aa6870f2735b3206f6890eabe4f7c209a64736f6c634300080a0033a2646970667358221220ae2274305cf64aa0a80854a46405db2f40d72fb22b064a1294b508ecf5c1285964736f6c634300080a0033","name":"IdleCDOEpochVariant","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"default","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// 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"},{"file_path":"@openzeppelin/contracts/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (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    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},{"file_path":"@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol","source_code":"pragma solidity >=0.6.2;\n\ninterface IUniswapV2Router01 {\n    function factory() external pure returns (address);\n    function WETH() external pure returns (address);\n\n    function addLiquidity(\n        address tokenA,\n        address tokenB,\n        uint amountADesired,\n        uint amountBDesired,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountA, uint amountB, uint liquidity);\n    function addLiquidityETH(\n        address token,\n        uint amountTokenDesired,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);\n    function removeLiquidity(\n        address tokenA,\n        address tokenB,\n        uint liquidity,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountA, uint amountB);\n    function removeLiquidityETH(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountToken, uint amountETH);\n    function removeLiquidityWithPermit(\n        address tokenA,\n        address tokenB,\n        uint liquidity,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountA, uint amountB);\n    function removeLiquidityETHWithPermit(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountToken, uint amountETH);\n    function swapExactTokensForTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n    function swapTokensForExactTokens(\n        uint amountOut,\n        uint amountInMax,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)\n        external\n        payable\n        returns (uint[] memory amounts);\n    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)\n        external\n        returns (uint[] memory amounts);\n    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)\n        external\n        returns (uint[] memory amounts);\n    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)\n        external\n        payable\n        returns (uint[] memory amounts);\n\n    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);\n    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);\n    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);\n    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);\n    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);\n}\n"},{"file_path":"contracts/interfaces/keyring/IKeyring.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.10;\n\ninterface IKeyring {\n  function checkCredential(uint256 policyId, address entity) external view returns (bool);\n}"},{"file_path":"contracts/strategies/idle/IdleCreditVault.sol","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.10;\n\nimport \"../../interfaces/IIdleCDOStrategy.sol\";\nimport \"../../interfaces/IERC20Detailed.sol\";\n\nimport '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\n\ninterface IIdleCDOEpochVariant {\n  function isEpochRunning() external view returns (bool);\n  function epochEndDate() external view returns (uint256);\n  function expectedEpochInterest() external view returns (uint256);\n  function pendingWithdrawFees() external view returns (uint256);\n  function fee() external view returns (uint256);\n  function isInterestMinted() external view returns (bool);\n  function getContractValue() external view returns (uint256);\n  function lastNAVAA() external view returns (uint256);\n  function lastNAVBB() external view returns (uint256);\n  function trancheAPRSplitRatio() external view returns (uint256);\n  function defaulted() external view returns (bool);\n}\n\nerror NotAllowed();\n\ncontract IdleCreditVault is\n  Initializable,\n  OwnableUpgradeable,\n  ERC20Upgradeable,\n  ReentrancyGuardUpgradeable,\n  IIdleCDOStrategy\n{\n  using SafeERC20Upgradeable for IERC20Detailed;\n\n  /// @notice underlying token address (pool currency for Clearpool)\n  address public override token;\n  /// @notice decimals of the underlying asset\n  uint256 public override tokenDecimals;\n  /// @notice one underlying token\n  uint256 public override oneToken;\n  /// @notice underlying ERC20 token contract (pool currency for Clearpool)\n  IERC20Detailed public underlyingToken;\n  /// @notice address of the IdleCDO\n  address public idleCDO;\n  /// @notice one year, used to calculate the APR\n  uint256 public constant YEAR = 365 days;\n  /// @notice latest saved apr, already scaled to include the buffer period\n  uint256 public lastApr;\n  /// @notice address of the borrower\n  address public borrower;\n  /// @notice address of the manager\n  address public manager;\n  /// @notice user withdraw requests\n  mapping (address => uint256) public withdrawsRequests;\n  /// @notice user instant withdraw requests\n  mapping (address => uint256) public instantWithdrawsRequests;\n  /// @notice total withdraw requests\n  uint256 public pendingWithdraws;\n  /// @notice pending instant withdraw requests\n  uint256 public pendingInstantWithdraws;\n  /// @notice counter for epoch deposits\n  uint256 public totEpochDeposits;\n  /// @notice deprecated transfer flag retained for storage compatibility\n  bool public canTransfer;\n  /// @notice last withdraw request epoch for a user\n  mapping (address => uint256) public lastWithdrawRequest;\n  /// @notice current epoch number\n  uint256 public epochNumber;\n  /// @notice unscaled apr\n  uint256 public unscaledApr;\n  /// @notice constant representing a 100% fee used for accounting\n  uint256 private constant FULL_ALLOC = 100_000;\n  /// @notice total principal for APR=0 requests in the current epoch\n  uint256 public apr0TotalPrincipal;\n  struct Apr0UserData {\n    uint256 principal;\n    uint256 principalEpoch;\n    uint256 settledPrincipal;\n    uint256 settledInterest;\n  }\n  /// @notice APR=0 withdraw data per user\n  mapping (address => Apr0UserData) public apr0Users;\n  /// @notice net APR=0 interest rate per epoch, scaled by 1e18\n  mapping (uint256 => uint256) public apr0RateByEpoch;\n  /// @notice default maximum allowed scaled apr\n  uint256 public constant DEFAULT_MAX_APR = 20e18;\n  /// @notice maximum allowed scaled apr, 0 disables the cap\n  uint256 public maxApr;\n  /// @notice underlying reserved for finalized post-default recovery claims\n  uint256 public defaultRecoveryReserve;\n  /// @notice post-default recovery ratio, scaled by 1e18\n  uint256 public defaultRecoveryPrice;\n  /// @notice strategy epoch that defaulted and was finalized for recovery\n  uint256 public defaultRecoveryEpoch;\n  /// @notice true once the CDO finalized default recovery accounting\n  bool public defaultRecoveryFinalized;\n  /// @notice true when unfunded default-epoch instant receipts were included in recovery accounting\n  bool public defaultInstantWithdrawsFinalized;\n  /// @notice normal withdraw receipt basis by user and request epoch\n  mapping(address => mapping(uint256 => uint256)) public withdrawsRequestsByEpoch;\n  /// @notice post-default withdraw requests that are already backed by default recovery reserve\n  mapping(address => uint256) public postDefaultRequests;\n  /// @notice instant withdraw receipt basis by user and request epoch\n  mapping(address => mapping(uint256 => uint256)) public instantWithdrawsRequestsByEpoch;\n  /// @notice total outstanding instant-withdraw receipt basis per request epoch\n  mapping(uint256 => uint256) public instantWithdrawClaimsByEpoch;\n  /// @notice funded recovery ratio for pending withdraw receipts haircutted by stopEpochWithDuration loss\n  mapping(uint256 => uint256) public lossRecoveryPriceByEpoch;\n  /// @notice true once default-recovery request accounting is initialized for this strategy\n  bool public defaultRecoveryInitialized;\n  /// @notice full recovery ratio scale\n  uint256 private constant RECOVERY_FULL = 1e18;\n\n  /// @custom:oz-upgrades-unsafe-allow constructor\n  constructor() {\n    token = address(1);\n  }\n\n  /// @notice can be only called once\n  /// @param _underlyingToken address of the underlying token (pool currency)\n  function initialize(\n    address _underlyingToken,\n    address _owner,\n    address _manager,\n    address _borrower,\n    string memory borrowerName,\n    uint256 _apr\n  ) public virtual initializer {\n    OwnableUpgradeable.__Ownable_init();\n    ReentrancyGuardUpgradeable.__ReentrancyGuard_init();\n    require(token == address(0), \"Token is already initialized\");\n\n    //----- // -------//\n    token = _underlyingToken;\n    underlyingToken = IERC20Detailed(token);\n    tokenDecimals = underlyingToken.decimals();\n    oneToken = 10**(tokenDecimals);\n    borrower = _borrower;\n    manager = _manager;\n    maxApr = DEFAULT_MAX_APR;\n    // on the first setup we set the lastApr equal to the unscaledApr\n    lastApr = _apr;\n    unscaledApr = _apr;\n    defaultRecoveryInitialized = true;\n\n    // name will be like: Pareto Credit Vault Borrower\n    // symbol will be like: Borrower\n    ERC20Upgradeable.__ERC20_init(\n      _concat(string(\"Pareto Credit Vault \"), borrowerName),\n      borrowerName\n    );\n    //------//-------//\n\n    transferOwnership(_owner);\n  }\n\n  /// @notice strategy token decimals\n  /// @dev equal to underlying token decimals\n  /// @return number of decimals\n  function decimals() public view override returns (uint8) {\n    return uint8(tokenDecimals);\n  }\n\n  /// @notice strategy token address\n  function strategyToken() external view override returns (address) {\n    return address(this);\n  }\n\n  /// @notice return strategy token price which is always 1\n  /// @return price in underlyings\n  function price() public view virtual override returns (uint256) {\n    return oneToken;\n  }\n\n  /// @notice current fixed apr for the epoch\n  function getApr() external view returns (uint256) {\n    return lastApr;\n  }\n\n  /// @notice set manager address\n  /// @param _manager address of the new manager\n  function setManager(address _manager) external onlyOwner {\n    manager = _manager;\n  }\n\n  /// @notice set borrower address\n  /// @param _borrower address of the new borrower\n  function setBorrower(address _borrower) external onlyOwner {\n    require(_borrower != address(0), \"IS_0\");\n    borrower = _borrower;\n  }\n\n  /// @notice set maximum allowed scaled apr, 0 disables the cap\n  /// @param _maxApr new max apr\n  function setMaxApr(uint256 _maxApr) external onlyOwner {\n    maxApr = _maxApr;\n  }\n\n  /// @notice set both the scaled and unscaled apr\n  /// @dev only cdo and manager can set the apr.\n  /// @param _unscaledApr unscaled apr\n  /// @param _apr scaled apr\n  function setAprs(uint256 _unscaledApr, uint256 _apr) external {\n    unscaledApr = _unscaledApr;\n    // here we also check that msg.sender is allowed\n    setApr(_apr);\n  }\n\n  /// @notice set both the unscaled APR and APR scaled by epoch plus buffer duration.\n  /// @dev only CDO and manager can set the APR through `setApr`.\n  /// @param _unscaledApr unscaled APR\n  /// @param _duration epoch duration\n  /// @param _buffer buffer duration\n  function setAprsWithBuffer(uint256 _unscaledApr, uint256 _duration, uint256 _buffer) external {\n    unscaledApr = _unscaledApr;\n    setApr(_duration == 0 ? _unscaledApr : _unscaledApr * (_duration + _buffer) / _duration);\n  }\n\n  /// @notice set the fixed apr\n  /// @dev only cdo and manager can set the apr. If manager manually set apr from \n  /// here it will not be scaled to include the buffer period\n  function setApr(uint256 _apr) public {\n    address _cdo = idleCDO;\n\n    // if cdo is not yet set we skip the check (this can happen only during the setup)\n    if (_cdo != address(0)) {\n      if (msg.sender != _cdo && msg.sender != manager) revert NotAllowed();\n    }\n    uint256 _maxApr = maxApr;\n    if (_maxApr != 0 && _apr > _maxApr) revert NotAllowed();\n    lastApr = _apr;\n  }\n\n  /// @notice request withdraw of underlying token from the vault\n  /// @dev We don't burn strategy tokens here, but we increase the withdraw requests. A user must\n  /// claim a loss-adjusted receipt before opening a later request so its recovery epoch is preserved.\n  /// @param _amount number of tokens claimable by the user\n  /// @param _user address of the user\n  /// @param _principal principal amount backing the withdraw request\n  function requestWithdraw(uint256 _amount, address _user, uint256 _principal) external {\n    _onlyIdleCDO();\n    _ensureDefaultRecoveryInitialized();\n    if (_amount == 0) return;\n    if (defaultRecoveryFinalized) {\n      // user should first claim old already-funded withdraw requests before requesting new ones after default\n      if (_hasWithdrawRequest(_user) || instantWithdrawsRequests[_user] != 0 || postDefaultRequests[_user] != 0) {\n        revert NotAllowed();\n      }\n      // Preserve request/claim UX after default without increasing borrower-facing pendingWithdraws.\n      // The CDO passes an already-haircut amount because finalization lowered virtualPrice first.\n      _burn(msg.sender, _amount);\n      _mint(_user, _amount);\n      postDefaultRequests[_user] = _amount;\n      return;\n    }\n    bool isClosed = IIdleCDOEpochVariant(idleCDO).epochEndDate() == 0;\n    uint256 currentEpoch = epochNumber;\n    uint256 lossEpoch = lastWithdrawRequest[_user];\n    uint256 lossRecoveryPrice = lossRecoveryPriceByEpoch[lossEpoch];\n    if (\n      lossRecoveryPrice != 0 &&\n      (withdrawsRequestsByEpoch[_user][lossEpoch] != 0 ||\n      (apr0Users[_user].principal != 0 && apr0Users[_user].principalEpoch == lossEpoch))\n    ) {\n      // A loss-adjusted receipt must be claimed before opening a later request, otherwise\n      // `lastWithdrawRequest` would stop pointing to the epoch that stores its haircut.\n      revert NotAllowed();\n    }\n    // burn strategy tokens from cdo (we don't burn future interest here, only the principal)\n    _burn(msg.sender, _principal);\n    // mint equal amount of strategy tokens to the user as receipt (interest included), useful in case of default\n    _mint(_user, _amount);\n    // A successfully closed pool already recalled all funds and has no later stopEpoch.\n    if (!isClosed) {\n      // Global amount that stopEpoch must source from borrower/strategy for all pending receipts.\n      pendingWithdraws += _amount;\n    }\n    // save the epoch of the last withdraw request (buffer + epochDuration is 1 epoch)\n    lastWithdrawRequest[_user] = currentEpoch;\n    // APR=0 requests keep separate accounting and settle interest at stopEpoch.\n    // `_amount` here is the post-management-fee principal bucket for that flow.\n    if (unscaledApr == 0 && !isClosed) {\n      _requestWithdrawApr0(_amount, _user);\n    } else {\n      // increase the withdraw requests for the user\n      // we record both per-user (old, kept for compatibility) and per-epoch so\n      // on finalization we can distinguish \"default-epoch pending receipts\"\n      // from old funded receipts.\n      withdrawsRequests[_user] += _amount;\n      withdrawsRequestsByEpoch[_user][currentEpoch] += _amount;\n    }\n  }\n\n  /// @notice claim the withdraw request\n  /// @dev we burn the strategy tokens and transfer the underlying tokens\n  /// @param _user address of the user\n  /// @return amount number of tokens claimed\n  function claimWithdrawRequest(address _user) external returns (uint256 amount) {\n    _onlyIdleCDO();\n    if (defaultRecoveryFinalized) {\n      // Post-default requests are already priced after the haircut and backed by the reserve,\n      // so they must not fall through to the defaulted-epoch receipt logic.\n      amount = _claimPostDefaultWithdrawRequest(_user);\n      if (amount != 0) return amount;\n      // Only receipts created in the defaulted epoch are haircutted here; old fulfilled\n      // receipts are handled below at par if they were already funded before default.\n      amount = _claimDefaultedWithdrawRequest(_user);\n    }\n    amount += _claimLossAdjustedWithdrawRequest(_user);\n    return amount + _claimFundedWithdrawRequest(_user);\n  }\n\n  /// @notice Claim a funded non-default withdraw request at par.\n  /// @param _user address of the user\n  /// @return amount amount claimed\n  function _claimFundedWithdrawRequest(address _user) internal returns (uint256 amount) {\n    // User should wait at least an epoch before claiming the withdraw. Once the epoch is over user can withdraw \n    // at any time even if a new epoch started. \n    // So if epochNumber is the same as the last withdraw request then we revert. Epoch number is increased at stopEpoch\n    // NOTE: If a user does not claim a withdraw request and instead requests another withdraw, he will have to wait\n    // for another epoch to claim both requests.\n    // NOTE 2: if borrower defaults, old withdraw requests can still be claimed\n    if (IIdleCDOEpochVariant(idleCDO).epochEndDate() != 0 && (epochNumber <= lastWithdrawRequest[_user])) {\n      revert NotAllowed();\n    }\n    // settle APR=0 requests once the related epoch has ended\n    _settleApr0(_user);\n    Apr0UserData storage _apr0User = apr0Users[_user];\n    // Claim includes:\n    // - settled APR0 principal from finalized epochs\n    // - still-open APR0 principal: if pool-close mode was used (_interest == 1), IdleCDO sets\n    //   epochEndDate = 0 and claims can be immediate, while _settleApr0 can still skip settlement\n    //   for the current request epoch (reqEpoch >= epochNumber).\n    // - settled APR0 interest\n    uint256 normalAmount = withdrawsRequests[_user];\n    uint256 apr0PrincipalAmount = _apr0User.settledPrincipal + _apr0User.principal;\n    uint256 apr0InterestAmount = _apr0User.settledInterest;\n    amount = normalAmount + apr0PrincipalAmount + apr0InterestAmount;\n    // burn strategy tokens 1:1 with the principal only (normal amount already includes interest)\n    _burn(_user, normalAmount + apr0PrincipalAmount);\n    withdrawsRequests[_user] = 0;\n    lastWithdrawRequest[_user] = 0;\n    if (apr0PrincipalAmount != 0 || apr0InterestAmount != 0) {\n      delete apr0Users[_user];\n    }\n    _transferFundedClaim(_user, amount);\n  }\n\n  /// @notice request instant withdraw of underlying token from the vault\n  /// @dev we burn strategy tokens here, and we increase the instant withdraw requests\n  /// @param _amount number of tokens to withdraw\n  /// @param _user address of the user\n  function requestInstantWithdraw(uint256 _amount, address _user) external {\n    _onlyIdleCDO();\n    _ensureDefaultRecoveryInitialized();\n    // burn strategy tokens from cdo\n    _burn(msg.sender, _amount);\n  \n    // mint equal amount of strategy tokens to the user as receipt, useful in case of default\n    _mint(_user, _amount);\n\n    // increase the instant withdraw requests for the user\n    instantWithdrawsRequests[_user] += _amount;\n    uint256 currentEpoch = epochNumber;\n    // we record both per-user (old, kept for compatibility) and per-epoch so on\n    // finalization we can distinguish \"default-epoch pending instant receipts\"\n    // from old funded instant receipts.\n    instantWithdrawsRequestsByEpoch[_user][currentEpoch] += _amount;\n    instantWithdrawClaimsByEpoch[currentEpoch] += _amount;\n    // increase the total instant withdraw requests\n    pendingInstantWithdraws += _amount;\n  }\n\n  /// @notice claim the instant withdraw request\n  /// @dev we transfer the underlying tokens\n  /// @param _user address of the user\n  function claimInstantWithdrawRequest(address _user) external {\n    _onlyIdleCDO();\n    if (defaultRecoveryFinalized && defaultInstantWithdrawsFinalized) {\n      // Clear the defaulted-epoch instant receipt first, then continue so the same call can\n      // also pay any older instant receipt that was already funded before default finalization.\n      _claimDefaultedInstantWithdrawRequest(_user);\n    }\n    uint256 amount = instantWithdrawsRequests[_user];\n    // burn strategy tokens from user\n    _burn(_user, amount);\n\n    instantWithdrawsRequests[_user] = 0;\n    _transferFundedClaim(_user, amount);\n  }\n\n  /// @notice collect the instant withdraw funds\n  /// @dev only IdleCDO can call this function\n  /// @param _amount number of tokens to collect\n  function collectInstantWithdrawFunds(uint256 _amount) external {\n    _onlyIdleCDO();\n    if (_amount == 0) return;\n    pendingInstantWithdraws -= _amount;\n    underlyingToken.safeTransferFrom(idleCDO, address(this), _amount);\n  }\n\n  /// @notice collect borrower-funded withdraw receipt funds\n  /// @dev Only IdleCDO can call this function. When `_amount` is lower than the\n  /// pending basis, the difference is a stopEpochWithDuration loss assigned to\n  /// pending receipts and users later claim through `lossRecoveryPriceByEpoch`.\n  /// Reverts if the resulting recovery price rounds to zero at `RECOVERY_FULL` precision.\n  /// @param _amount number of funded tokens to collect\n  function collectWithdrawFunds(uint256 _amount) external {\n    _onlyIdleCDO();\n    uint256 pendingBasis = pendingWithdraws;\n    if (_amount < pendingBasis) {\n      // Legacy receipts do not have per-epoch ownership data, so they can only be fully funded.\n      if (!defaultRecoveryInitialized) revert NotAllowed();\n      uint256 lossRecoveryPrice = _amount * RECOVERY_FULL / pendingBasis;\n      // Avoid storing a zero price, which is indistinguishable from \"no loss-adjusted epoch\".\n      if (lossRecoveryPrice == 0) revert NotAllowed();\n      pendingWithdraws = 0;\n      lossRecoveryPriceByEpoch[epochNumber] = lossRecoveryPrice;\n    } else {\n      // A plain implementation upgrade may leave legacy normal receipts pending. Their next\n      // successful stop can fully fund the aggregate before lazy initialization occurs.\n      pendingWithdraws = pendingBasis - _amount;\n    }\n    if (_amount != 0) {\n      underlyingToken.safeTransferFrom(idleCDO, address(this), _amount);\n    }\n  }\n\n  /// @notice Preview how a realized stop-epoch loss is split between active LPs and pending receipts.\n  /// @dev Without pending receipts, a loss cannot exceed its active basis. When pending receipts\n  /// exist, all pending receipts share their aggregate portion of the loss pro rata because the\n  /// pending bucket does not retain tranche identity. The remaining active loss is later applied\n  /// by the CDO through its ordinary BB-first waterfall.\n  /// @param _lossAmount realized loss amount\n  /// @return pendingToFund amount of pending withdrawals that should be funded by the borrower\n  /// @return activeLoss amount of loss that remains assigned to active LPs\n  function previewLossAdjustedWithdrawFunds(uint256 _lossAmount) external view returns (uint256 pendingToFund, uint256 activeLoss) {\n    uint256 pendingBasis = pendingWithdraws;\n    // Full zero-loss funding is safe for legacy aggregate receipts and needs no migration call.\n    if (_lossAmount == 0) return (pendingBasis, _lossAmount);\n\n    IIdleCDOEpochVariant cdo = IIdleCDOEpochVariant(idleCDO);\n    uint256 activeBasis = _lossActiveBasis(cdo);\n    if (pendingBasis == 0) {\n      if (_lossAmount > activeBasis) revert NotAllowed();\n      return (0, _lossAmount);\n    }\n\n    // Legacy pending receipts do not have the per-epoch ownership data needed to store a haircut.\n    if (!defaultRecoveryInitialized) revert NotAllowed();\n    uint256 totalBasis = activeBasis + pendingBasis;\n    if (_lossAmount >= totalBasis) revert NotAllowed();\n\n    uint256 pendingLoss = _lossAmount * pendingBasis / totalBasis;\n    pendingToFund = pendingBasis - pendingLoss;\n    activeLoss = _lossAmount - pendingLoss;\n  }\n\n  /// @notice Calculate the active basis used to split a successful stop-epoch loss.\n  /// @dev Minted fee shares remain backed by CDO-held strategy tokens and therefore join the\n  /// active-side loss. Cash mode mirrors CDO accounting: management fees are already accrued,\n  /// then performance fees apply only to gain above the last saved AA plus BB NAV.\n  /// @param _cdo epoch CDO interface\n  /// @return activeBasis active strategy-token basis participating in the loss\n  function _lossActiveBasis(IIdleCDOEpochVariant _cdo) internal view returns (uint256 activeBasis) {\n    if (_cdo.isInterestMinted()) {\n      // Accrued fees become AA shares before the loss burn, so the full CDO strategy-token\n      // balance plus gross minted interest participates on the active side.\n      return balanceOf(idleCDO) + _cdo.expectedEpochInterest();\n    }\n    uint256 activeBasisBeforePerfFee = _cdo.getContractValue();\n    uint256 expectedInterest = _cdo.expectedEpochInterest();\n    uint256 pendingFees = _cdo.pendingWithdrawFees();\n    if (expectedInterest > pendingFees) {\n      activeBasisBeforePerfFee += expectedInterest - pendingFees;\n    }\n    uint256 savedNAV = _cdo.lastNAVAA() + _cdo.lastNAVBB();\n    activeBasis = activeBasisBeforePerfFee > savedNAV ? \n      activeBasisBeforePerfFee - ((activeBasisBeforePerfFee - savedNAV) * _cdo.fee() / FULL_ALLOC) : \n      activeBasisBeforePerfFee;\n  }\n\n  /// @notice compute and apply APR=0 epoch deltas for stopEpoch\n  /// @param _interest stopEpoch override interest (0 = expected epoch interest, 1 = repay all)\n  /// @return _expInterest stopEpoch interest after APR0 adjustments\n  /// @return _adjPendingWithdrawFees pending withdraw fees after APR0 adjustments\n  function prepareStopEpochWithApr0(uint256 _interest) external returns (uint256 _expInterest, uint256 _adjPendingWithdrawFees) {\n    _onlyIdleCDO();\n    IIdleCDOEpochVariant _cdo = IIdleCDOEpochVariant(idleCDO);\n    uint256 _pendingFees = _cdo.pendingWithdrawFees();\n    uint256 _tvl = _cdo.getContractValue();\n    _expInterest = _interest > 1 ? _interest : _cdo.expectedEpochInterest();\n    _adjPendingWithdrawFees = _pendingFees;\n    // Principal currently waiting for withdraw that was requested while APR was 0,\n    // net of the upfront management fee charged at request time.\n    uint256 _principal = apr0TotalPrincipal;\n\n    // Fast path: no APR0 accounting needed.\n    if (_principal == 0) {\n      return (_expInterest, _adjPendingWithdrawFees);\n    }\n    // APR0 principal is only valid while APR is 0 for that request lifecycle.\n    if (unscaledApr != 0) {\n      revert NotAllowed();\n    }\n\n    uint256 _apr0NetInterest;\n    // APR0 allocation is computed only when stopEpoch receives a real override interest.\n    // _expectedInterest == 1 is the \"request all funds back\" sentinel and is handled in IdleCDO.\n    if (_expInterest > 1 && _expInterest > _pendingFees) {\n      // Remove already booked withdraw fees from the interest base before splitting.\n      uint256 _interestNetOfFees = _expInterest - _pendingFees;\n      // Total principal used for the pro-rata split:\n      // IdleCDO TVL (which excludes APR0 requested principal) + APR0 principal bucket.\n      uint256 _totalPrincipalForSplit = _tvl + _principal;\n      if (_totalPrincipalForSplit != 0) {\n        // APR0 users get a pro-rata share of realized interest.\n        uint256 _apr0InterestGross = _interestNetOfFees * _principal / _totalPrincipalForSplit;\n        if (_apr0InterestGross != 0) {\n          // Same fee model as normal withdraw interest.\n          uint256 _apr0Fee = _apr0InterestGross * _cdo.fee() / FULL_ALLOC;\n          _apr0NetInterest = _apr0InterestGross - _apr0Fee;\n          _adjPendingWithdrawFees += _apr0Fee;\n          _expInterest -= _apr0NetInterest;\n        }\n      }\n    }\n\n    // Finalize one-epoch APR0 interest for current epoch only.\n    if (_apr0NetInterest != 0) {\n      // Funds owed to withdraw requesters increase by APR0 net interest.\n      pendingWithdraws += _apr0NetInterest;\n      // Save per-epoch net rate; each APR0 request accrues exactly once on its request epoch.\n      apr0RateByEpoch[epochNumber] = (_apr0NetInterest * 1e18) / _principal;\n    }\n    // Close current APR0 bucket so it cannot accrue again on later stopEpoch calls.\n    apr0TotalPrincipal = 0;\n  }\n\n  /// @notice settle APR=0 requests for a user once their epoch is finalized\n  /// @param _user address of the user\n  function _settleApr0(address _user) internal {\n    Apr0UserData storage _apr0User = apr0Users[_user];\n    uint256 _principal = _apr0User.principal;\n    if (_principal == 0) {\n      return;\n    }\n    uint256 _reqEpoch = _apr0User.principalEpoch;\n    // Settle only after stopEpoch bumped epochNumber (ie after one full wait epoch).\n    if (_reqEpoch >= epochNumber) {\n      return;\n    }\n    // Move principal from \"open APR0 bucket\" to \"settled bucket\" (same principal, not duplicated).\n    _apr0User.settledPrincipal += _principal;\n    uint256 _rate = apr0RateByEpoch[_reqEpoch];\n    if (_rate != 0) {\n      // Convert per-epoch rate to claimable underlying interest.\n      _apr0User.settledInterest += (_principal * _rate) / 1e18;\n    }\n    _apr0User.principal = 0;\n    _apr0User.principalEpoch = 0;\n  }\n\n  function _requestWithdrawApr0(uint256 _amount, address _user) internal {\n    // Settle any previous APR0 request first, then start/update current epoch bucket.\n    _settleApr0(_user);\n    Apr0UserData storage _apr0User = apr0Users[_user];\n    if (_apr0User.principal == 0) {\n      _apr0User.principalEpoch = epochNumber;\n    }\n    _apr0User.principal += _amount;\n    // Epoch-level APR0 principal used only to compute stopEpoch APR0 pro-rata interest.\n    apr0TotalPrincipal += _amount;\n  }\n\n  /// @notice Send funds to the IdleCDO\n  /// @param _amount number of underlyings to transfer\n  function sendInterestAndDeposits(uint256 _amount) external {\n    _onlyIdleCDO();\n    if (_amount == 0) return;\n    IERC20Detailed(token).safeTransfer(idleCDO, _amount);\n  }\n\n  /// @notice Burn strategy tokens from the CDO\n  /// @param _amount number of strategy tokens (1:1 with underlyings) to burn\n  function burnStrategyTokens(uint256 _amount) external {\n    _onlyIdleCDO();\n    _burn(msg.sender, _amount);\n  }\n\n  /// @notice Get funds from IdleCDO and mint strategy tokens. Funds are not sent to the borrower here\n  /// @param _amount number of underlyings to transfer\n  function deposit(uint256 _amount)\n    external\n    virtual\n    override\n    returns (uint256) {\n    _onlyIdleCDO();\n    if (_amount > 0) {\n      underlyingToken.safeTransferFrom(msg.sender, address(this), _amount);\n      _mint(msg.sender, _amount);\n    }\n\n    if (IIdleCDOEpochVariant(idleCDO).isEpochRunning()) {\n      // deposit done on stopEpoch (before setting the var to false) so we reset the counter\n      totEpochDeposits = 0;\n      epochNumber += 1;\n    } else {\n      // deposit done between epochs so we increase the counter\n      totEpochDeposits += _amount;\n    }\n\n    return _amount;\n  }\n\n  /// @notice Mint strategy tokens to the CDO without moving underlyings\n  /// @dev Used for mid-epoch deposits that send funds directly to the borrower\n  function mintStrategyTokens(uint256 _amount) external {\n    _onlyIdleCDO();\n    _mint(msg.sender, _amount);\n  }\n\n  /// @notice Reserve already-held underlying for a later finalized default recovery.\n  /// @dev Called by the CDO when borrower funding fails after funds were already returned here.\n  /// @param _amount amount of underlying already held by this strategy for default recovery\n  function reserveDefaultRecovery(uint256 _amount) external {\n    _onlyIdleCDO();\n    if (defaultRecoveryFinalized) revert NotAllowed();\n    defaultRecoveryReserve += _amount;\n  }\n\n  /// @notice Total claim basis that should be haircut by default finalization.\n  /// @dev Normal pending withdraws are already tracked globally. Current-epoch instant receipts\n  /// join recovery only if `pendingInstantWithdraws` is still non-zero at finalization. This can\n  /// happen when startEpoch moved the CDO's available cash to the strategy but that cash covered\n  /// only part of the instant queue. The full current-epoch instant claim is included as basis,\n  /// while the already-funded part is added to the reserve by `_defaultPrefundedInstantReserve()`.\n  /// Receipt accounting is aggregate and does not retain AA/BB identity. IdleCDOEpochVariant\n  /// therefore applies one recovery multiplier to both tranche classes.\n  /// @return basis amount of defaulted receipt claims in underlying units\n  function defaultPendingClaimBasis() public view returns (uint256 basis) {\n    basis = pendingWithdraws;\n    if (pendingInstantWithdraws != 0) {\n      basis += instantWithdrawClaimsByEpoch[epochNumber];\n    }\n  }\n\n  /// @notice Finalize strategy-side default recovery accounting.\n  /// @dev Called by the CDO. `_recoverySource` must approve this strategy for `_recoveredAmount`.\n  /// `_recoveredAmount` is the exact external recovery to pull; already-held strategy funds\n  /// are added separately because they should not be pulled from `_recoverySource` again.\n  /// A zero or subprecision aggregate recovery finalizes at price zero. Active tranche prices are\n  /// then zero and pending receipts can be cleared without a payout; any positive reserve too small\n  /// to represent at `RECOVERY_FULL` precision remains isolated as recovery dust.\n  /// @param _recoveredAmount exact amount of recovered underlying supplied by `_recoverySource`\n  /// @param _recoverySource address that supplies recovered underlying\n  /// @return defaultBBNav BB's final recovered active NAV\n  function finalizeDefaultRecovery(uint256 _recoveredAmount, address _recoverySource) external returns (uint256 defaultBBNav) {\n    _onlyIdleCDO();\n    _ensureDefaultRecoveryInitialized();\n\n    IIdleCDOEpochVariant cdo = IIdleCDOEpochVariant(idleCDO);\n    if (defaultRecoveryFinalized || !cdo.defaulted()) revert NotAllowed();\n    if (_recoveredAmount != 0 && _recoverySource == address(0)) revert NotAllowed();\n\n    // Active holders are still represented by strategy tokens owned by the CDO. Add the\n    // default-epoch net interest so they use the same claim basis as pending redeemers.\n    // Split gross backing by saved NAV and default interest by the configured APR split.\n    // The CDO strategy-token balance is its gross active value before `unclaimedFees`.\n    // Using it directly restores those waived unpaid fees to active recovery basis.\n    uint256 activeBalance = balanceOf(idleCDO);\n    uint256 activeInterest = _defaultActiveInterestBasis(cdo);\n    uint256 activeBasis = activeBalance + activeInterest;\n    defaultBBNav = _defaultBBBasis(cdo, activeBalance, activeInterest);\n    // Pending receipts have already left active CDO NAV, so they are added as a separate basis.\n    uint256 pendingBasis = defaultPendingClaimBasis();\n    uint256 totalBasis = activeBasis + pendingBasis;\n    if (totalBasis == 0) revert NotAllowed();\n\n    // Some recovery funds may already be in this strategy: partially prefunded instant requests\n    // and borrower-send funds that failed at epoch start. Count both without pulling them again.\n    uint256 prefundedReserve = _defaultPrefundedInstantReserve();\n    uint256 reserveAmount = _recoveredAmount + prefundedReserve + defaultRecoveryReserve;\n    // Recovery can be above par if the recovered funds exceed the computed basis.\n    uint256 recoveryPrice = reserveAmount * RECOVERY_FULL / totalBasis;\n\n    defaultRecoveryFinalized = true;\n    defaultRecoveryReserve = reserveAmount;\n    defaultRecoveryPrice = recoveryPrice;\n    defaultRecoveryEpoch = epochNumber;\n    // A non-zero pending instant bucket means current-epoch instant receipts were not fully funded\n    // and must be paid through the same recovery ratio as normal pending receipts.\n    defaultInstantWithdrawsFinalized = pendingInstantWithdraws != 0;\n    // Bring active CDO NAV to the same recovery ratio. IdleCDOEpochVariant then calls\n    // _forceUpdateAccounting so tranche prices/virtualPrice expose the crystallized loss.\n    uint256 activeFinalNAV = (activeBasis * recoveryPrice) / RECOVERY_FULL;\n    defaultBBNav = defaultBBNav * recoveryPrice / RECOVERY_FULL;\n    if (activeBalance > activeFinalNAV) {\n      _burn(idleCDO, activeBalance - activeFinalNAV);\n    } else if (activeFinalNAV > activeBalance) {\n      _mint(idleCDO, activeFinalNAV - activeBalance);\n    }\n    if (_recoveredAmount != 0) {\n      // Pull external recovery last: if the transfer fails, the whole finalization reverts.\n      underlyingToken.safeTransferFrom(_recoverySource, address(this), _recoveredAmount);\n    }\n  }\n\n  /// @notice Get current-epoch instant-withdraw funds already collected before default finalization.\n  /// @dev `pendingInstantWithdraws` is the still-unfunded remainder. If it is lower than the\n  /// current-epoch claim basis, the difference is already-held underlying reserved for those claims.\n  /// @return prefundedReserve amount of current instant claims already backed by strategy underlyings\n  function _defaultPrefundedInstantReserve() internal view returns (uint256 prefundedReserve) {\n    uint256 pendingInstant = pendingInstantWithdraws;\n    if (pendingInstant == 0) return prefundedReserve;\n    uint256 instantBasis = instantWithdrawClaimsByEpoch[epochNumber];\n    if (instantBasis > pendingInstant) {\n      prefundedReserve = instantBasis - pendingInstant;\n    }\n  }\n\n  /// @notice Calculate default-epoch net interest basis for active LPs.\n  /// @param _cdo epoch CDO interface\n  /// @return activeInterest net interest basis for active LPs\n  function _defaultActiveInterestBasis(IIdleCDOEpochVariant _cdo) internal view returns (uint256 activeInterest) {\n    uint256 expectedInterest = _cdo.expectedEpochInterest();\n    uint256 pendingFees = _cdo.pendingWithdrawFees();\n    if (expectedInterest <= pendingFees) return activeInterest;\n    // Pending redeemers already include their net interest in pendingWithdraws; active LPs need\n    // the same borrower-owed interest basis, net of performance fees, before applying recovery.\n    activeInterest = expectedInterest - pendingFees;\n    activeInterest -= activeInterest * _cdo.fee() / FULL_ALLOC;\n  }\n\n  /// @notice Calculate BB's active claim basis before applying the default recovery multiplier.\n  /// @dev Gross active backing is split by saved NAV, while interest follows the configured APR split.\n  /// @param _cdo epoch CDO interface\n  /// @param _activeBalance gross active strategy-token backing\n  /// @param _activeInterest net active default-epoch interest\n  /// @return bbBasis BB's active claim basis before recovery\n  function _defaultBBBasis(IIdleCDOEpochVariant _cdo, uint256 _activeBalance, uint256 _activeInterest) internal view returns (uint256 bbBasis) {\n    uint256 savedAA = _cdo.lastNAVAA();\n    uint256 savedBB = _cdo.lastNAVBB();\n    uint256 activeBasis = _activeBalance + _activeInterest;\n    if (savedBB == 0 || activeBasis == 0) return bbBasis;\n    if (savedAA == 0) return activeBasis;\n\n    uint256 savedNAV = savedAA + savedBB;\n    uint256 grossBBBasis = _activeBalance * savedBB / savedNAV;\n    uint256 bbInterest = _activeInterest * (FULL_ALLOC - _cdo.trancheAPRSplitRatio()) / FULL_ALLOC;\n    bbBasis = grossBBBasis + bbInterest;\n  }\n\n  /// @notice Claim an already-funded post-default withdraw request.\n  /// @param _user address of the user\n  /// @return amount amount claimed from default recovery reserve\n  function _claimPostDefaultWithdrawRequest(address _user) internal returns (uint256 amount) {\n    amount = postDefaultRequests[_user];\n    if (amount == 0) return amount;\n    postDefaultRequests[_user] = 0;\n    // Post-default receipts are paid 1:1 because the haircut was applied when the request was made.\n    _burn(_user, amount);\n    _transferDefaultRecovery(_user, amount);\n  }\n\n  /// @notice Claim a defaulted normal withdraw receipt with the finalized recovery haircut.\n  /// @param _user address of the user\n  /// @return amount amount paid from default recovery reserve\n  function _claimDefaultedWithdrawRequest(address _user) internal returns (uint256 amount) {\n    uint256 defaultEpoch = defaultRecoveryEpoch;\n    (uint256 claimBasis, uint256 burnAmount) = _clearWithdrawClaimForEpoch(_user, defaultEpoch, true);\n    if (claimBasis == 0) return amount;\n\n    // pendingWithdraws stores the claim basis owed by the borrower, including APR0 interest.\n    pendingWithdraws -= claimBasis;\n    // Only receipt principal exists as strategy tokens. APR0 interest is included in claimBasis\n    // but was never minted as a user strategy-token receipt.\n    _burn(_user, burnAmount);\n    amount = (claimBasis * defaultRecoveryPrice) / RECOVERY_FULL;\n    _transferDefaultRecovery(_user, amount);\n  }\n\n  /// @notice Claim a stopEpochWithDuration loss-adjusted withdraw receipt.\n  /// @param _user address of the user\n  /// @return amount amount paid from funded strategy underlyings\n  function _claimLossAdjustedWithdrawRequest(address _user) internal returns (uint256 amount) {\n    uint256 lossEpoch = lastWithdrawRequest[_user];\n    uint256 lossRecoveryPrice = lossRecoveryPriceByEpoch[lossEpoch];\n    if (lossRecoveryPrice == 0) return amount;\n\n    (uint256 claimBasis, uint256 burnAmount) = _clearWithdrawClaimForEpoch(_user, lossEpoch, false);\n    if (claimBasis == 0) return amount;\n\n    // pendingWithdraws was already cleared when the borrower funded the loss-adjusted amount.\n    _burn(_user, burnAmount);\n    amount = (claimBasis * lossRecoveryPrice) / RECOVERY_FULL;\n    _transferFundedClaim(_user, amount);\n  }\n\n  /// @notice Clear a normal/APR0 withdraw receipt for one request epoch.\n  /// @dev This does not move funds or burn receipt tokens. Default claims also decrease\n  /// `apr0TotalPrincipal`; loss-adjusted claims do not because stopEpoch already closed that bucket.\n  /// @param _user address of the user\n  /// @param _claimEpoch epoch whose receipt should be cleared\n  /// @param _isClearingApr0 true when clearing an open APR0 default claim\n  /// @return claimBasis claim amount before applying the recovery ratio\n  /// @return burnAmount strategy-token receipt amount to burn\n  function _clearWithdrawClaimForEpoch(address _user, uint256 _claimEpoch, bool _isClearingApr0) internal returns (uint256 claimBasis, uint256 burnAmount) {\n    (claimBasis, burnAmount) = _withdrawClaimAmountsForEpoch(_user, _claimEpoch);\n    if (claimBasis == 0) return (claimBasis, burnAmount);\n\n    uint256 normalAmount = withdrawsRequestsByEpoch[_user][_claimEpoch];\n    if (normalAmount != 0) {\n      withdrawsRequestsByEpoch[_user][_claimEpoch] = 0;\n      // The aggregate may also include older funded receipts; clear only this epoch's piece.\n      withdrawsRequests[_user] -= normalAmount;\n    }\n    Apr0UserData storage apr0User = apr0Users[_user];\n    if (apr0User.principal != 0 && apr0User.principalEpoch == _claimEpoch) {\n      if (_isClearingApr0) {\n        uint256 apr0Principal = apr0User.principal;\n        uint256 totalApr0Principal = apr0TotalPrincipal;\n        // prepareStopEpochWithApr0 may already close the global APR0 bucket before default finalization.\n        apr0TotalPrincipal = apr0Principal >= totalApr0Principal ? 0 : totalApr0Principal - apr0Principal;\n      }\n      apr0User.principal = 0;\n      apr0User.principalEpoch = 0;\n    }\n    if (lastWithdrawRequest[_user] == _claimEpoch) {\n      // The cleared epoch was the latest request marker. Any remaining normal/APR0 receipt\n      // is older and already funded, so it can continue to the funded-claim path.\n      lastWithdrawRequest[_user] = 0;\n    }\n  }\n\n  /// @notice Claim a defaulted instant-withdraw receipt with the finalized recovery haircut.\n  /// @param _user address of the user\n  /// @return claimBasis amount of instant-withdraw basis cleared\n  function _claimDefaultedInstantWithdrawRequest(address _user) internal returns (uint256 claimBasis) {\n    uint256 defaultEpoch = defaultRecoveryEpoch;\n    claimBasis = instantWithdrawsRequestsByEpoch[_user][defaultEpoch];\n    if (claimBasis == 0) return claimBasis;\n\n    instantWithdrawsRequestsByEpoch[_user][defaultEpoch] = 0;\n    instantWithdrawsRequests[_user] -= claimBasis;\n    uint256 pending = pendingInstantWithdraws;\n    // `pendingInstantWithdraws` is only the unfunded remainder. If this user's claim is larger,\n    // the extra amount was already counted as prefunded reserve during default finalization.\n    pendingInstantWithdraws = claimBasis >= pending ? 0 : pending - claimBasis;\n    instantWithdrawClaimsByEpoch[defaultEpoch] -= claimBasis;\n    _burn(_user, claimBasis);\n    _transferDefaultRecovery(_user, (claimBasis * defaultRecoveryPrice) / RECOVERY_FULL);\n  }\n\n  /// @notice Get defaulted normal/APR0 withdraw claim basis and receipt burn amount.\n  /// @param _user address of the user\n  /// @return claimBasis claim amount before recovery haircut\n  /// @return burnAmount strategy-token receipt amount to burn\n  function _withdrawClaimAmountsForEpoch(address _user, uint256 _claimEpoch) internal view returns (uint256 claimBasis, uint256 burnAmount) {\n    // We calculate what the user is owed in underlyings (claimBasis) and how many strategy tokens to burn (burnAmount).\n    // the amount owned is the sum of the normal withdraw request and the APR0 principal and interest if any.\n    uint256 normalAmount = withdrawsRequestsByEpoch[_user][_claimEpoch];\n    Apr0UserData storage _apr0User = apr0Users[_user];\n    uint256 apr0PrincipalAmount;\n    uint256 apr0InterestAmount;\n    uint256 principal = _apr0User.principal;\n    uint256 principalEpoch = _apr0User.principalEpoch;\n    if (principal != 0 && principalEpoch == _claimEpoch) {\n      apr0PrincipalAmount = principal;\n      uint256 rate = apr0RateByEpoch[principalEpoch];\n      if (rate != 0) {\n        // APR0 interest increases the user's default claim basis, but not the receipt burn amount.\n        apr0InterestAmount += (principal * rate) / RECOVERY_FULL;\n      }\n    }\n    claimBasis = normalAmount + apr0PrincipalAmount + apr0InterestAmount;\n    burnAmount = normalAmount + apr0PrincipalAmount;\n  }\n\n  /// @notice Check if a user has a normal or APR0 withdraw request.\n  /// @param _user address of the user\n  /// @return true if a normal or APR0 request exists\n  function _hasWithdrawRequest(address _user) internal view returns (bool) {\n    Apr0UserData storage data = apr0Users[_user];\n    return withdrawsRequests[_user] != 0 ||\n      data.principal != 0 ||\n      data.settledPrincipal != 0 ||\n      data.settledInterest != 0;\n  }\n\n  /// @notice Transfer a funded claim without spending default recovery reserve.\n  /// @param _user claim receiver\n  /// @param _amount amount to transfer\n  function _transferFundedClaim(address _user, uint256 _amount) internal {\n    if (_amount == 0) return;\n    uint256 reserve = defaultRecoveryReserve;\n    if (reserve != 0) {\n      uint256 balance = underlyingToken.balanceOf(address(this));\n      // This should be unreachable when accounting is consistent. Keep the guard so old funded\n      // receipts can never spend underlyings reserved for default recovery claimants.\n      if (balance < reserve || balance - reserve < _amount) revert NotAllowed();\n    }\n    underlyingToken.safeTransfer(_user, _amount);\n  }\n\n  /// @notice Transfer default recovery reserve to a user.\n  /// @param _user claim receiver\n  /// @param _amount amount to transfer\n  function _transferDefaultRecovery(address _user, uint256 _amount) internal {\n    if (_amount == 0) return;\n    // Every defaulted or post-default claim consumes the isolated recovery reserve.\n    defaultRecoveryReserve -= _amount;\n    underlyingToken.safeTransfer(_user, _amount);\n  }\n\n  /// @notice Lazily initialize recovery accounting for an upgraded strategy.\n  /// @dev Legacy pending receipts must first be fully funded because their per-epoch ownership\n  /// cannot be reconstructed after an implementation upgrade. A successfully closed vault has\n  /// already recalled all funds, so stale normal/APR0 aggregate counters can be normalized there.\n  /// Pending instant withdrawals are never cleared automatically.\n  function _ensureDefaultRecoveryInitialized() internal {\n    if (defaultRecoveryInitialized) return;\n    if (pendingInstantWithdraws != 0) revert NotAllowed();\n    if (pendingWithdraws != 0) {\n      IIdleCDOEpochVariant cdo = IIdleCDOEpochVariant(idleCDO);\n      if (cdo.epochEndDate() != 0 || cdo.defaulted()) revert NotAllowed();\n      pendingWithdraws = 0;\n      apr0TotalPrincipal = 0;\n    }\n    defaultRecoveryInitialized = true;\n    canTransfer = false;\n  }\n\n  /// @inheritdoc ERC20Upgradeable\n  /// @dev Receipt claims are address-bound, so only the IdleCDO can move strategy tokens.\n  function _transfer(address sender, address recipient, uint256 amount) internal virtual override {\n    if (msg.sender != idleCDO) revert NotAllowed();\n    super._transfer(sender, recipient, amount);\n  }\n\n  /// @notice Clear the deprecated receipt-token transfer flag.\n  /// @dev Kept for upgrade compatibility. Enabling transfers is permanently disabled because\n  /// receipt claims are address-bound; the manager may only clear a legacy `true` value.\n  /// @param _canTransfer must be false\n  function setCanTransfer(bool _canTransfer) external {\n    if (msg.sender != manager || _canTransfer) revert NotAllowed();\n    canTransfer = false;\n  }\n\n  /// @notice allow to update whitelisted address\n  function setWhitelistedCDO(address _cdo) external onlyOwner {\n    require(_cdo != address(0), \"IS_0\");\n    idleCDO = _cdo;\n  }\n\n  /// @notice Emergency method to rescue funds\n  /// @param _token address of the token to transfer\n  /// @param value amount of `_token` to transfer\n  /// @param _to receiver address\n  function transferToken(address _token, uint256 value, address _to) external onlyOwner {\n    IERC20Detailed(_token).safeTransfer(_to, value);\n  }\n\n  /// @notice Modifier to make sure that caller os only the idleCDO contract\n  function _onlyIdleCDO() internal view {\n    if (msg.sender != idleCDO) {\n      revert NotAllowed();\n    }\n  }\n\n  /// @notice concat 2 strings in a single one\n  /// @param a first string\n  /// @param b second string\n  /// @return new string with a and b concatenated\n  function _concat(string memory a, string memory b) internal pure returns (string memory) {\n    return string(abi.encodePacked(a, b));\n  }\n\n  /// @notice Not used as redeems happens only via requestWithdraw and requestInstantWithdraw\n  function redeem(uint256 _amount)\n    external\n    override\n    returns (uint256) {}\n\n  /// @notice Not used as redeems happens only via requestWithdraw and requestInstantWithdraw\n  function redeemUnderlying(uint256)\n    external\n    returns (uint256) {}\n\n  /// @notice not used in this strategy\n  function pullStkAAVE()\n    external\n    pure\n    override\n    returns (uint256) {}\n\n  /// @notice not used for this strategy\n  function getRewardTokens()\n    external\n    view\n    override\n    returns (address[] memory) {}\n\n  /// @notice not used for this strategy\n  function redeemRewards(bytes calldata)\n    external\n    override\n    returns (uint256[] memory rewards) {}\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/ERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.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 * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract 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     * 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 default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface 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(address from, address to, uint256 amount) external returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n     * constructor.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = !_initializing;\n        require(\n            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n            \"Initializable: contract is already initialized\"\n        );\n        _initialized = 1;\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: setting the version to 255 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint8 version) {\n        require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n        _initialized = version;\n        _initializing = true;\n        _;\n        _initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        require(_initializing, \"Initializable: contract is not initializing\");\n        _;\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        require(!_initializing, \"Initializable: contract is initializing\");\n        if (_initialized != type(uint8).max) {\n            _initialized = type(uint8).max;\n            emit Initialized(type(uint8).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint8) {\n        return _initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _initializing;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract PausableUpgradeable is Initializable, ContextUpgradeable {\n    /**\n     * @dev Emitted when the pause is triggered by `account`.\n     */\n    event Paused(address account);\n\n    /**\n     * @dev Emitted when the pause is lifted by `account`.\n     */\n    event Unpaused(address account);\n\n    bool private _paused;\n\n    /**\n     * @dev Initializes the contract in unpaused state.\n     */\n    function __Pausable_init() internal onlyInitializing {\n        __Pausable_init_unchained();\n    }\n\n    function __Pausable_init_unchained() internal onlyInitializing {\n        _paused = false;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is not paused.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    modifier whenNotPaused() {\n        _requireNotPaused();\n        _;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is paused.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    modifier whenPaused() {\n        _requirePaused();\n        _;\n    }\n\n    /**\n     * @dev Returns true if the contract is paused, and false otherwise.\n     */\n    function paused() public view virtual returns (bool) {\n        return _paused;\n    }\n\n    /**\n     * @dev Throws if the contract is paused.\n     */\n    function _requireNotPaused() internal view virtual {\n        require(!paused(), \"Pausable: paused\");\n    }\n\n    /**\n     * @dev Throws if the contract is not paused.\n     */\n    function _requirePaused() internal view virtual {\n        require(paused(), \"Pausable: not paused\");\n    }\n\n    /**\n     * @dev Triggers stopped state.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    function _pause() internal virtual whenNotPaused {\n        _paused = true;\n        emit Paused(_msgSender());\n    }\n\n    /**\n     * @dev Returns to normal state.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    function _unpause() internal virtual whenPaused {\n        _paused = false;\n        emit Unpaused(_msgSender());\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    function __ReentrancyGuard_init() internal onlyInitializing {\n        __ReentrancyGuard_init_unchained();\n    }\n\n    function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20Upgradeable.sol\";\nimport \"./extensions/IERC20MetadataUpgradeable.sol\";\nimport \"../../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\n        __ERC20_init_unchained(name_, symbol_);\n    }\n\n    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[45] private __gap;\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20MetadataUpgradeable is IERC20Upgradeable {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20PermitUpgradeable {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n    using AddressUpgradeable for address;\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20PermitUpgradeable token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[50] private __gap;\n}\n"},{"file_path":"@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol","source_code":"pragma solidity >=0.6.2;\n\nimport './IUniswapV2Router01.sol';\n\ninterface IUniswapV2Router02 is IUniswapV2Router01 {\n    function removeLiquidityETHSupportingFeeOnTransferTokens(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountETH);\n    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountETH);\n\n    function swapExactTokensForTokensSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external;\n    function swapExactETHForTokensSupportingFeeOnTransferTokens(\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external payable;\n    function swapExactTokensForETHSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external;\n}\n"},{"file_path":"contracts/GuardedLaunchUpgradable.sol","source_code":"//SPDX-License-Identifier: Apache 2.0\npragma solidity 0.8.10;\n\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/// @notice This abstract contract is used to add an updatable limit on the total value locked\n/// that the contract can have. It also have an emergency method that allows the owner to pull\n/// funds into predefined recovery address\n/// @dev Inherit this contract and add the _guarded method to the child contract\nabstract contract GuardedLaunchUpgradable is Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable {\n  using SafeERC20Upgradeable for IERC20Upgradeable;\n\n  // ERROR MESSAGES:\n  error Is0();\n  error ContractLimitReached();\n  error NotAuthorized();\n\n  // TVL limit in underlying value\n  uint256 public limit;\n  // recovery address\n  address internal governanceRecoveryFund;\n\n  /// @param _limit TVL limit. (0 means unlimited)\n  /// @param _governanceRecoveryFund recovery address\n  /// @param _owner owner address\n  function __GuardedLaunch_init(uint256 _limit, address _governanceRecoveryFund, address _owner) internal {\n    _checkIs0(_governanceRecoveryFund == address(0) || _owner == address(0));\n    // Initialize inherited contracts\n    OwnableUpgradeable.__Ownable_init();\n    ReentrancyGuardUpgradeable.__ReentrancyGuard_init();\n    // Initialize state variables\n    limit = _limit;\n    governanceRecoveryFund = _governanceRecoveryFund;\n    // Transfer ownership\n    transferOwnership(_owner);\n  }\n\n  /// @notice this check should be called inside the child contract on deposits to check that the\n  /// TVL didn't exceed a threshold\n  /// @param _amount new amount to deposit\n  function _guarded(uint256 _amount) internal view {\n    uint256 _limit = limit;\n    if (_limit > 0) {\n      if (getContractValue() + _amount > _limit) revert ContractLimitReached();\n    }\n  }\n\n  /// @dev Check that the second function is not called in the same tx from the same tx.origin\n  function _checkOnlyOwner() internal view {\n    _checkNotAuthorized(owner() != msg.sender);\n  }\n\n  /// @notice abstract method, should return the TVL in underlyings\n  function getContractValue() public virtual view returns (uint256);\n\n  /// @notice set contract TVL limit\n  /// @param _limit limit in underlying value, 0 means no limit\n  function _setLimit(uint256 _limit) external {\n    _checkOnlyOwner();\n    limit = _limit;\n  }\n\n  /// @notice Emergency method, tokens gets transferred to the governanceRecoveryFund address\n  /// @param _token address of the token to transfer\n  /// @param _value amount to transfer\n  function transferToken(address _token, uint256 _value) external {\n    _checkOnlyOwner();\n    IERC20Upgradeable(_token).safeTransfer(governanceRecoveryFund, _value);\n  }\n\n  /// @notice check revert condition and revert with Is0 error\n  /// @param _revertCondition condition to check\n  function _checkIs0(bool _revertCondition) internal pure {\n    if (_revertCondition) revert Is0();\n  }\n\n  /// @notice check revert condition and revert with NotAuthorized error\n  /// @param _revertCondition condition to check\n  function _checkNotAuthorized(bool _revertCondition) internal pure {\n    if (_revertCondition) revert NotAuthorized();\n  }\n}\n"},{"file_path":"contracts/IdleCDOCreditVault.sol","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.10;\n\nimport \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\nimport \"./interfaces/IIdleCDOStrategy.sol\";\nimport \"./interfaces/IERC20Detailed.sol\";\n\nimport \"./GuardedLaunchUpgradable.sol\";\nimport \"./IdleCDOTranche.sol\";\nimport \"./IdleCDOStorage.sol\";\n\n/// @title IdleCDO fork for credit vaults\n/// @author Idle Labs Inc.\n/// @notice Credit vault specific CDO runtime without legacy tranche/reward methods.\n/// @dev Storage layout intentionally matches IdleCDO so existing epoch-vault proxies can upgrade safely.\ncontract IdleCDOCreditVault is PausableUpgradeable, GuardedLaunchUpgradable, IdleCDOStorage {\n  using SafeERC20Upgradeable for IERC20Detailed;\n\n  // ERROR MESSAGES:\n  error AlreadyInitialized();\n  error Default();\n  error AmountTooHigh();\n\n  // Used to prevent initialization of the implementation contract\n  /// @custom:oz-upgrades-unsafe-allow constructor\n  constructor() {\n    token = address(1);\n  }\n\n  // ###################\n  // Initializer\n  // ###################\n\n  /// @notice can only be called once\n  /// @dev Initialize the upgradable contract\n  /// @param _limit contract value limit, can be 0\n  /// @param _guardedToken underlying token\n  /// @param _governanceFund address where funds will be sent in case of emergency\n  /// @param _owner guardian address (can pause, unpause and call emergencyShutdown)\n  /// @param _strategy strategy address\n  /// @param _trancheAPRSplitRatio trancheAPRSplitRatio value\n  function initialize(\n    uint256 _limit, \n    address _guardedToken, \n    address _governanceFund, \n    address _owner, // GuardedLaunch args\n    address,\n    address _strategy,\n    uint256 _trancheAPRSplitRatio// for AA tranches, so eg 10000 means 10% interest to AA and 90% BB\n  ) external virtual initializer {\n    if (token != address(0)) revert AlreadyInitialized();\n    _checkIs0(_strategy == address(0) || _guardedToken == address(0));\n    _checkAmountTooHigh(_trancheAPRSplitRatio > FULL_ALLOC);\n    // Initialize contracts\n    PausableUpgradeable.__Pausable_init();\n    // check for _governanceFund and _owner != address(0) are inside GuardedLaunchUpgradable\n    GuardedLaunchUpgradable.__GuardedLaunch_init(_limit, _governanceFund, _owner);\n    // Deploy Tranches tokens\n    address _strategyToken = IIdleCDOStrategy(_strategy).strategyToken();\n    // get strategy token symbol (eg. idleDAI)\n    string memory _symbol = IERC20Detailed(_strategyToken).symbol();\n    // create tranche tokens (concat strategy token symbol in the name and symbol of the tranche tokens)\n    AATranche = _deployTranche(string(\"Pareto \"), string(\"p\"), _symbol);\n    BBTranche = _deployTranche(string(\"Pareto BB \"), string(\"pBB_\"), _symbol);\n    // Set CDO params\n    token = _guardedToken;\n    strategy = _strategy;\n    strategyToken = _strategyToken;\n    trancheAPRSplitRatio = _trancheAPRSplitRatio;\n    uint256 _oneToken = 10**(IERC20Detailed(_guardedToken).decimals());\n    oneToken = _oneToken;\n    priceAA = _oneToken;\n    priceBB = _oneToken;\n    // skipDefaultCheck = false is the default value\n    // Set allowance for strategy\n    _allowUnlimitedSpend(_guardedToken, _strategy);\n    _allowUnlimitedSpend(_strategyToken, _strategy);\n    guardian = _owner;\n    isAYSActive = true; // adaptive yield split\n    minAprSplitAYS = AA_RATIO_LIM_DOWN; // AA tranche will get min 50% of the yield\n    // Credit vaults reuse this legacy slot as the management-fee checkpoint timestamp.\n    latestHarvestBlock = block.timestamp;\n    _additionalInit();\n  }\n\n  /// @notice used by child contracts (cdo variants) if anything needs to be done on/after init\n  function _additionalInit() internal virtual {}\n\n  // ###############\n  // Public methods\n  // ###############\n\n  /// @notice pausable\n  /// @dev msg.sender should approve this contract first to spend `_amount` of `token`\n  /// @param _amount amount of `token` to deposit\n  /// @return AA tranche tokens minted\n  function depositAA(uint256 _amount) external returns (uint256) {\n    return _deposit(_amount, AATranche);\n  }\n\n  /// @notice pausable in _deposit\n  /// @dev msg.sender should approve this contract first to spend `_amount` of `token`\n  /// @param _amount amount of `token` to deposit\n  /// @return BB tranche tokens minted\n  function depositBB(uint256 _amount) external returns (uint256) {\n    _checkNotAuthorized(!isBBDepositEnabled);\n    return _deposit(_amount, BBTranche);\n  }\n\n  // ###############\n  // Views\n  // ###############\n\n  /// @param _tranche tranche address\n  /// @return tranche price, in underlyings, at the last interaction (not considering interest earned \n  /// since last interaction)\n  function tranchePrice(address _tranche) external view returns (uint256) {\n    return _tranchePrice(_tranche);\n  }\n\n  /// @notice calculates the current net TVL (in `token` terms)\n  /// @dev `unclaimedFees` are not counted.\n  function getContractValue() public override view returns (uint256) {\n    // Credit vault strategy tokens are minted 1:1 with underlyings and use the same decimals.\n    return _contractTokenBalance(strategyToken) + _contractTokenBalance(token) - unclaimedFees;\n  }\n\n  /// @notice Calculates the current managed net TVL.\n  /// @dev Raw underlyings held by the CDO are excluded because unsolicited transfers are skimmed on interactions.\n  /// @return Strategy-token-backed TVL net of accrued fees.\n  function _managedContractValue() internal virtual view returns (uint256) {\n    uint256 strategyTokenBalance = _contractTokenBalance(strategyToken);\n    uint256 fees = unclaimedFees;\n    return strategyTokenBalance > fees ? strategyTokenBalance - fees : 0;\n  }\n\n  /// @param _tranche tranche address\n  /// @return actual apr given current ratio between AA and BB tranches\n  function getApr(address _tranche) external view returns (uint256) {\n    uint256 _AATrancheSplitRatio = _getAARatio(false);\n    uint256 stratApr = _getStrategyApr();\n    if (_AATrancheSplitRatio == 0 || _AATrancheSplitRatio == FULL_ALLOC) {\n      // with only one initialized tranche, it receives all apr and the empty tranche receives zero\n      return (_tranche == AATranche) == (_AATrancheSplitRatio == 0) ? 0 : stratApr;\n    }\n    uint256 _trancheAPRSplitRatio = trancheAPRSplitRatio;\n    if (_tranche != AATranche) {\n      // BB apr is: stratApr * BBaprSplitRatio / BBSplitRatio -> where\n      // BBaprSplitRatio is: (FULL_ALLOC - _trancheAPRSplitRatio) and\n      // BBSplitRatio is: (FULL_ALLOC - _AATrancheSplitRatio)\n      return stratApr * (FULL_ALLOC - _trancheAPRSplitRatio) / (FULL_ALLOC - _AATrancheSplitRatio);\n    }\n    // AA apr is: stratApr * AAaprSplitRatio / AASplitRatio\n    return stratApr * _trancheAPRSplitRatio / _AATrancheSplitRatio;\n  }\n\n  /// @notice calculates the current AA tranches ratio\n  /// @dev _virtualBalance is used to have a more accurate/recent value for the AA ratio\n  /// because it calculates the balance after splitting the accrued interest since the\n  /// last depositXX/withdrawXX\n  /// @return AA tranches ratio (in underlying value) considering all interest\n  function getCurrentAARatio() external view returns (uint256) {\n    return _getAARatio(false);\n  }\n\n  /// @notice calculates the current tranches price considering the interest/loss that is yet to be splitted\n  /// ie the interest/loss generated since the last update of priceAA and priceBB (done on depositXX/withdrawXX)\n  /// @param _tranche address of the requested tranche\n  /// @return _virtualPrice tranche price considering all interest/losses\n  function virtualPrice(address _tranche) public virtual view returns (uint256 _virtualPrice) {\n    (_virtualPrice, ) = _virtualPriceAux(\n      _tranche,\n      _managedContractValue(), // nav\n      lastNAVAA + lastNAVBB, // lastNAV\n      _lastSavedNAV(_tranche), // lastTrancheNAV\n      trancheAPRSplitRatio\n    );\n  }\n\n  // ###############\n  // Internal\n  // ###############\n\n  /// @notice method used to deposit `token` and mint tranche tokens\n  /// @dev this contract must be approved to spend at least _amount of `token` before calling this method\n  /// @param _amount amount of underlyings (`token`) to deposit\n  /// @param _tranche tranche address\n  /// @return _minted number of tranche tokens minted\n  function _deposit(uint256 _amount, address _tranche) internal virtual whenNotPaused returns (uint256 _minted) {\n    if (_amount == 0) {\n      return _minted;\n    }\n    // check that we are not depositing more than the contract available limit\n    _guarded(_amount);\n    // interest accrued since last depositXX/withdrawXX is splitted between AA and BB\n    // according to trancheAPRSplitRatio. NAVs of AA and BB are updated and tranche\n    // prices adjusted accordingly\n    _updateAccounting();\n    // get underlyings from sender\n    address _token = token;\n    uint256 _preBal = _contractTokenBalance(_token);\n    _transferUnderlyingsFrom(msg.sender, address(this), _amount);\n    // mint tranche tokens according to the current tranche price\n    _minted = _mintSharesAtCurrPrice(_contractTokenBalance(_token) - _preBal, msg.sender, _tranche);\n    // update trancheAPRSplitRatio\n    _updateSplitRatio(_getAARatio(true));\n\n    // direct deposit in the strategy\n    IIdleCDOStrategy(strategy).deposit(_amount);\n  }\n\n  /// @notice this method is called on depositXX/withdrawXX and\n  /// updates the accounting of the contract and effectively splits the yield/loss between the\n  /// AA and BB tranches\n  /// @dev this method:\n  /// - update tranche prices (priceAA and priceBB)\n  /// - update net asset value for both tranches (lastNAVAA and lastNAVBB)\n  /// - update fee accounting (unclaimedFees)\n  /// @return shutdown true when a loss exhausted BB or fully wiped an AA-only vault\n  function _updateAccounting() internal virtual returns (bool shutdown) {\n    _accrueManagementFee();\n    uint256 _lastNAVAA = lastNAVAA;\n    uint256 _lastNAVBB = lastNAVBB;\n    uint256 _lastNAV = _lastNAVAA + _lastNAVBB;\n    uint256 nav = getContractValue();\n    uint256 _aprSplitRatio = trancheAPRSplitRatio;\n    // If gain is > 0, then collect some fees in `unclaimedFees`\n    if (nav > _lastNAV) {\n      unclaimedFees += (nav - _lastNAV) * fee / FULL_ALLOC;\n    }\n    (uint256 _priceAA, int256 _totalAAGain) = _virtualPriceAux(AATranche, nav, _lastNAV, _lastNAVAA, _aprSplitRatio);\n    (uint256 _priceBB, int256 _totalBBGain) = _virtualPriceAux(BBTranche, nav, _lastNAV, _lastNAVBB, _aprSplitRatio);\n    lastNAVAA = uint256(int256(_lastNAVAA) + _totalAAGain);\n    lastNAVBB = uint256(int256(_lastNAVBB) + _totalBBGain);\n\n    // Ordinary losses exhaust BB before reducing AA. Stop normal interactions once BB is wiped,\n    // or when an AA-only vault is fully wiped, so the loss must be crystallized explicitly.\n    if ((_totalBBGain < 0 && -_totalBBGain >= int256(_lastNAVBB)) || (_lastNAV != 0 && nav == 0)) {\n      shutdown = true;\n      if (!skipDefaultCheck) revert Default();\n      // Keep a total wipe distinguishable from an uninitialized vault when no BB NAV existed.\n      if (nav == 0) _priceAA = 0;\n      _emergencyShutdown(true);\n    }\n    priceAA = _priceAA;\n    priceBB = _priceBB;\n  }\n\n  /// @notice calculates the NAV for a tranche considering the interest that is yet to be splitted\n  /// @param _tranche address of the requested tranche\n  /// @return net asset value, in underlying tokens, for _tranche considering all nav\n  function _virtualBalance(address _tranche) internal view returns (uint256) {\n    // balance is: tranche supply * virtual tranche price\n    return _trancheSupply(_tranche) * virtualPrice(_tranche) / ONE_TRANCHE_TOKEN;\n  }\n\n  /// @notice calculates the NAV for a tranche without considering the interest that is yet to be splitted\n  /// @param _tranche address of the requested tranche\n  /// @return net asset value, in underlying tokens, for _tranche\n  function _instantBalance(address _tranche) internal view returns (uint256) {\n    return _trancheSupply(_tranche) * _tranchePrice(_tranche) / ONE_TRANCHE_TOKEN;\n  }\n\n  /// @notice gets total supply for a specific tranche\n  /// @param _tranche address of the requested tranche\n  function _trancheSupply(address _tranche) internal view returns (uint256) {\n    return IdleCDOTranche(_tranche).totalSupply();\n  }\n\n  /// @notice gets last saved NAV for a specific tranche\n  /// @param _tranche address of the requested tranche\n  function _lastSavedNAV(address _tranche) internal view returns (uint256) {\n    return _tranche == AATranche ? lastNAVAA : lastNAVBB;\n  }\n\n  /// @notice Calculates the current tranche price and gain or loss since the last accounting update.\n  /// @dev Gains follow `trancheAPRSplitRatio`; ordinary losses exhaust BB before reducing AA.\n  /// @param _tranche address of the requested tranche\n  /// @param _nav current NAV\n  /// @param _lastNAV last saved NAV\n  /// @param _lastTrancheNAV last saved tranche NAV\n  /// @param _trancheAPRSplitRatio APR split ratio for AA tranche\n  /// @return _virtualPrice tranche price considering all interest\n  /// @return _totalTrancheGain (int256) tranche gain/loss since last update\n  function _virtualPriceAux(\n    address _tranche,\n    uint256 _nav,\n    uint256 _lastNAV,\n    uint256 _lastTrancheNAV,\n    uint256 _trancheAPRSplitRatio\n  ) internal virtual view returns (uint256 _virtualPrice, int256 _totalTrancheGain) {\n    // A zero supply identifies a tranche that was never initialized. A non-zero supply with\n    // zero NAV is an economically wiped tranche and must keep its saved zero price.\n    uint256 trancheSupply = _trancheSupply(_tranche);\n    if (trancheSupply == 0) return (oneToken, 0);\n    if (_lastNAV == 0 && _nav == 0) return (0, 0);\n\n    // In order to correctly split the interest generated between AA and BB tranche holders\n    // (according to the trancheAPRSplitRatio) we need to know how much interest/loss we gained\n    // since the last price update (during a depositXX/withdrawXX)\n    // To do that we need to get the current value of the assets in this contract\n    // and the last saved one (always during a depositXX/withdrawXX)\n    // Calculate the total gain/loss\n    int256 totalGain = int256(_nav) - int256(_lastNAV);\n    // Ordinary zero-delta interactions keep their saved price for compatibility. Forced\n    // accounting recomputes NAV per share, which is required after discounted mid-epoch deposits.\n    if (totalGain == 0 && !skipDefaultCheck) return (_tranchePrice(_tranche), 0);\n\n    // Remove performance fee for gains\n    if (totalGain > 0) {\n      totalGain -= totalGain * int256(fee) / int256(FULL_ALLOC);\n    }\n\n    bool _isAATranche = _tranche == AATranche;\n    // A class with no saved NAV cannot be revived by later gains. If only this class has saved\n    // NAV, it receives the full gain or loss; otherwise both classes participate.\n    if (_lastTrancheNAV == 0) {\n      _totalTrancheGain = 0;\n    } else if (_lastNAV == _lastTrancheNAV) {\n      _totalTrancheGain = totalGain;\n    } else {\n      if (totalGain > 0) {\n        // Split the net gain, according to _trancheAPRSplitRatio, with precision loss favoring the AA tranche.\n        int256 totalBBGain = totalGain * int256(FULL_ALLOC - _trancheAPRSplitRatio) / int256(FULL_ALLOC);\n        // The new NAV for the tranche is old NAV + total gain for the tranche\n        _totalTrancheGain = _isAATranche ? (totalGain - totalBBGain) : totalBBGain;\n      } else {\n        int256 maxBBLoss = -int256(lastNAVBB);\n        int256 totalBBLoss = totalGain > maxBBLoss ? totalGain : maxBBLoss;\n        _totalTrancheGain = _isAATranche ? totalGain - totalBBLoss : totalBBLoss;\n      }\n    }\n    // Split the new NAV (_lastTrancheNAV + _totalTrancheGain) per tranche token\n    _virtualPrice = uint256(int256(_lastTrancheNAV) + _totalTrancheGain) * ONE_TRANCHE_TOKEN / trancheSupply;\n  }\n\n  /// @notice mint tranche tokens at current price and updates tranche last NAV\n  /// @param _amount, in underlyings, to convert in tranche tokens\n  /// @param _to receiver address of the newly minted tranche tokens\n  /// @param _tranche tranche address\n  /// @return _minted number of tranche tokens minted\n  function _mintSharesAtCurrPrice(uint256 _amount, address _to, address _tranche) internal virtual returns (uint256 _minted) {\n    // calculate # of tranche token to mint based on current tranche price: _amount / tranchePrice\n    _minted = _amount * ONE_TRANCHE_TOKEN / _tranchePrice(_tranche);\n    _mintShares(_tranche, _to, _minted, _amount);\n  }\n\n  /// @notice mint tranche tokens and updates tranche last NAV\n  /// @param _tranche tranche address\n  /// @param _to receiver address of the newly minted tranche tokens\n  /// @param _shares number of tranche tokens to mint\n  /// @param _underlyings amount of underlyings added to the tranche\n  function _mintShares(address _tranche, address _to, uint256 _shares, uint256 _underlyings) internal {\n    IdleCDOTranche(_tranche).mint(_to, _shares);\n    // update NAV with the _amount of underlyings added\n    if (_tranche == AATranche) {\n      lastNAVAA += _underlyings;\n    } else {\n      lastNAVBB += _underlyings;\n    }\n  }\n\n  /// @notice Burn tranche tokens and update NAV and trancheAPRSplitRatio\n  /// @param _amount Amount of tranche tokens\n  /// @param _underlyings Amount of underlyings\n  /// @param _tranche Tranche to withdraw from\n  function _withdrawOps(uint256 _amount, uint256 _underlyings, address _tranche) internal {\n    // burn tranche token\n    IdleCDOTranche(_tranche).burn(msg.sender, _amount);\n\n    // update NAV with the _amount of underlyings removed\n    if (_tranche == AATranche) {\n      lastNAVAA -= _underlyings;\n    } else {\n      lastNAVBB -= _underlyings;\n    }\n\n    // update trancheAPRSplitRatio\n    _updateSplitRatio(_getAARatio(true));\n  }\n\n  /// @notice updates trancheAPRSplitRatio based on the current tranches TVL ratio between AA and BB\n  /// @dev the idea here is to limit the min and max APR that the senior tranche can get\n  function _updateSplitRatio(uint256 tvlAARatio) internal virtual {\n    uint256 _minSplit = minAprSplitAYS;\n    _minSplit = _minSplit == 0 ? AA_RATIO_LIM_DOWN : _minSplit;\n\n    if (isAYSActive) {\n      uint256 aux;\n      if (tvlAARatio >= AA_RATIO_LIM_UP) {\n        aux = tvlAARatio == FULL_ALLOC ? FULL_ALLOC : AA_RATIO_LIM_UP;\n      } else if (tvlAARatio > _minSplit) {\n        aux = tvlAARatio;\n      } else {\n        aux = _minSplit;\n      }\n      trancheAPRSplitRatio = aux * tvlAARatio / FULL_ALLOC;\n    }\n  }\n\n  /// @notice calculates the current AA tranches ratio\n  /// @dev it does count accrued interest not yet split since last\n  /// depositXX/withdrawXX only if _instant flag is true\n  /// @param _instant if true, it returns the current ratio without accrued interest\n  /// @return AA tranches ratio (in underlying value) considering all interest\n  function _getAARatio(bool _instant) internal view returns (uint256) {\n    function(address) internal view returns (uint256) _getNAV =\n      _instant ? _instantBalance : _virtualBalance;\n    uint256 AABal = _getNAV(AATranche);\n    uint256 contractVal = AABal + _getNAV(BBTranche);\n    if (contractVal == 0) {\n      return 0;\n    }\n    // Current AA tranche split ratio = AABal * FULL_ALLOC / (AABal + BBBal)\n    return AABal * FULL_ALLOC / contractVal;\n  }\n\n  /// @param _tranche tranche address\n  /// @return last saved tranche price, in underlyings\n  function _tranchePrice(address _tranche) internal view returns (uint256) {\n    if (_trancheSupply(_tranche) == 0) {\n      return oneToken;\n    }\n    return _tranche == AATranche ? priceAA : priceBB;\n  }\n\n  /// @notice internal method used to deploy a new tranche token\n  /// @param _namePrefix prefix for the name of the tranche token\n  /// @param _symbolPrefix prefix for the symbol of the tranche token\n  /// @param _symbol suffix for the symbol of the tranche token\n  /// @return address of the newly deployed tranche token\n  function _deployTranche(string memory _namePrefix, string memory _symbolPrefix, string memory _symbol) internal returns (address) {\n    return address(new IdleCDOTranche(_concat(_namePrefix, _symbol), _concat(_symbolPrefix, _symbol)));\n  }\n\n  // ###################\n  // onlyOwner\n  // ###################\n\n  /// @notice Enable or disable deposits into the BB tranche.\n  /// @param _enabled true to allow BB deposits\n  function setBBDepositEnabled(bool _enabled) external {\n    _checkOnlyOwner();\n    isBBDepositEnabled = _enabled;\n  }\n\n  /// @param _active flag to allow Adaptive Yield Split\n  function setIsAYSActive(bool _active) external virtual {\n    _checkOnlyOwner();\n    isAYSActive = _active;\n  }\n\n  /// @param _feeReceiver fee receiver address. It gets the portion of fees specified by `_feeSplit`.\n  /// The remaining fee portion goes to `owner()`.\n  /// @dev Reverts if `_feeReceiver` is address(0). Use `_feeSplit = 0` to route all fees to `owner()`.\n  /// @param _fee new performance fee value (in % with 100000 = 100%)\n  /// @param _feeSplit portion of collected fees sent to `_feeReceiver` (100000 = 100%)\n  /// @param _managementFee annualized management fee (in % with 100000 = 100%)\n  function setFeeParams(address _feeReceiver, uint256 _fee, uint256 _feeSplit, uint256 _managementFee) external {\n    _checkOnlyOwner();\n    _checkAmountTooHigh(_fee > MAX_FEE || _feeSplit > FULL_ALLOC || _managementFee > MAX_FEE / 10);\n    _checkIs0((feeReceiver = _feeReceiver) == address(0));\n\n    _accrueManagementFee();\n    fee = _fee;\n    feeSplit = _feeSplit;\n    managementFee = _managementFee;\n  }\n\n  /// @param _guardian new guardian (pauser) address\n  function setGuardian(address _guardian) external {\n    _checkOnlyOwner();\n    _checkIs0((guardian = _guardian) == address(0));\n  }\n\n  /// @param _aprSplit min apr split for AA, considering FULL_ALLOC = 100%\n  function setMinAprSplitAYS(uint256 _aprSplit) external virtual {\n    _checkOnlyOwner();\n    _checkAmountTooHigh((minAprSplitAYS = _aprSplit) > FULL_ALLOC);\n  }\n\n  /// @notice this method updates the accounting of the contract and effectively splits the yield/loss between the\n  /// AA and BB tranches. This can be called at any time as is called automatically on each deposit/redeem. It's here\n  /// just to be called when a loss exhausted BB, as deposits/redeems are paused, but we need to\n  /// crystallize the BB-first loss.\n  function updateAccounting() external virtual {\n    _checkOnlyOwnerOrGuardian();\n    _forceUpdateAccounting();\n  }\n\n  /// @notice force accounting update without reverting on default path\n  function _forceUpdateAccounting() internal {\n    bool wasSkippingDefaultCheck = skipDefaultCheck;\n    skipDefaultCheck = true;\n    // Preserve an existing emergency shutdown and any wipe reported by accounting.\n    if (!_updateAccounting()) {\n      skipDefaultCheck = wasSkippingDefaultCheck;\n    }\n  }\n\n  /// @notice pause deposits and redeems for all classes of tranches\n  /// @dev can be called by both the owner and the guardian\n  function emergencyShutdown() external {\n    _checkOnlyOwnerOrGuardian();\n    _emergencyShutdown(false);\n  }\n\n  function _emergencyShutdown(bool) internal virtual {}\n\n  /// @notice allow deposits and redeems for all classes of tranches\n  /// @dev can be called by the owner only\n  function restoreOperations() external virtual {}\n\n  /// @notice Pauses deposits\n  /// @dev can be called by both the owner and the guardian\n  function pause() external  {\n    _checkOnlyOwnerOrGuardian();\n    _pause();\n  }\n\n  /// @notice Unpauses deposits\n  /// @dev can be called by both the owner and the guardian\n  function unpause() external {\n    _checkOnlyOwnerOrGuardian();\n    _beforeUnpause();\n    _unpause();\n  }\n\n  /// @notice Hook executed before external unpause.\n  function _beforeUnpause() internal view virtual {}\n\n  // ###################\n  // Helpers\n  // ###################\n\n  /// @dev Check that the msg.sender is the either the owner or the guardian\n  function _checkOnlyOwnerOrGuardian() internal view {\n    _checkNotAuthorized(msg.sender != guardian && msg.sender != owner());\n  }\n\n  /// @notice returns the current balance of this contract for a specific token\n  /// @param _token token address\n  /// @return balance of `_token` for this contract\n  function _contractTokenBalance(address _token) internal view returns (uint256) {\n    return IERC20Detailed(_token).balanceOf(address(this));\n  }\n\n  /// @notice Checkpoint accrued management fees into `unclaimedFees`.\n  /// @dev Raw underlyings are excluded because unsolicited transfers are skimmed instead of managed.\n  function _accrueManagementFee() internal {\n    unclaimedFees += _calculateManagementFee(_managedContractValue(), block.timestamp - latestHarvestBlock);\n    latestHarvestBlock = block.timestamp;\n  }\n\n  /// @notice calculate annualized management fee for a balance over a duration\n  function _calculateManagementFee(uint256 _nav, uint256 _duration) internal view returns (uint256) {\n    // 3153600000000 == FULL_ALLOC * 365 days\n    return _nav * managementFee * _duration / 3153600000000;\n  }\n\n  /// @notice returns the user tranche balance for a specific tranche\n  /// @param _user user address\n  /// @param _tranche tranche address\n  function _userTrancheBal(address _user, address _tranche) internal view returns (uint256) {\n    return IERC20Detailed(_tranche).balanceOf(_user);\n  }\n\n  /// @dev Set allowance for _token to unlimited for _spender\n  /// @param _token token address\n  /// @param _spender spender address\n  function _allowUnlimitedSpend(address _token, address _spender) internal {\n    IERC20Detailed(_token).safeIncreaseAllowance(_spender, type(uint256).max);\n  }\n\n  /// @dev transfer underlyings to a specific address\n  /// @param _to receiver address\n  /// @param _amount amount to transfer\n  function _transferUnderlyings(address _to, uint256 _amount) internal {\n    if (_amount == 0) return;\n    IERC20Detailed(token).safeTransfer(_to, _amount);\n  }\n\n  /// @notice transfer fee to feeReceiver and owner according to feeSplit\n  /// @param _amount total fee amount to split and transfer (in underlyings)\n  function _transferFeeUnderlyings(uint256 _amount) internal {\n    uint256 feeReceiverAmount = _feeReceiverAmount(_amount);\n    _transferUnderlyings(feeReceiver, feeReceiverAmount);\n    _transferUnderlyings(owner(), _amount - feeReceiverAmount);\n  }\n\n  /// @notice calculates the amount to transfer to feeReceiver based on the feeSplit\n  /// @dev `setFeeParams` guarantees a nonzero receiver; a zero split naturally returns zero.\n  /// @param _amount total fee amount to split\n  function _feeReceiverAmount(uint256 _amount) internal view returns (uint256) {\n    return _amount * feeSplit / FULL_ALLOC;\n  }\n\n  /// @dev transfer underlyings from a specific address to another address\n  /// @param _from sender address\n  /// @param _to receiver address\n  /// @param _amount amount to transfer\n  function _transferUnderlyingsFrom(address _from, address _to, uint256 _amount) internal {\n    if (_amount == 0) return;\n    IERC20Detailed(token).safeTransferFrom(_from, _to, _amount);\n  }\n\n  /// @dev Get the current strategy apr\n  function _getStrategyApr() internal view returns (uint256) {\n    return IIdleCDOStrategy(strategy).getApr();\n  }\n\n  /// @notice concat 2 strings in a single one\n  /// @param a first string\n  /// @param b second string\n  /// @return new string with a and b concatenated\n  function _concat(string memory a, string memory b) internal pure returns (string memory) {\n    return string(abi.encodePacked(a, b));\n  }\n\n  /// @notice check revert condition and revert with AmountTooHigh error\n  /// @param _revertCondition condition to check\n  function _checkAmountTooHigh(bool _revertCondition) internal pure {\n    if (_revertCondition) revert AmountTooHigh();\n  }\n}\n"},{"file_path":"contracts/IdleCDOStorage.sol","source_code":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.10;\n\nimport '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';\n\ncontract IdleCDOStorage {\n  // constant to represent 100%\n  uint256 public constant FULL_ALLOC = 100000;\n  // max fee, relative to FULL_ALLOC\n  uint256 internal constant MAX_FEE = 20000;\n  // one token\n  uint256 public constant ONE_TRANCHE_TOKEN = 10**18;\n  // variable used to save the last tx.origin and block.number\n  bytes32 internal _lastCallerBlock;\n  // variable used to save the block of the latest harvest\n  uint256 public latestHarvestBlock;\n  // WETH address\n  address internal weth;\n  // [DEPRECATED] tokens used to incentivize the idle tranche ideal ratio\n  address[] internal incentiveTokens;\n  // underlying token (eg DAI)\n  address public token;\n  // address that can only pause/unpause the contract in case of emergency\n  address internal guardian;\n  // one `token` (eg for DAI 10**18)\n  uint256 public oneToken;\n  // address that can call the 'harvest' method and lend pool assets\n  address internal rebalancer;\n  // address of the uniswap v2 router\n  IUniswapV2Router02 internal uniswapRouterV2;\n\n  // Flag for allowing AA withdraws\n  bool internal allowAAWithdraw;\n  // Flag for allowing BB withdraws\n  bool internal allowBBWithdraw;\n  // Flag for allowing to enable reverting in case the strategy gives back less\n  // amount than the requested one\n  bool internal revertIfTooLow;\n  // Flag to enable the `Default Check` (related to the emergency shutdown)\n  bool internal skipDefaultCheck;\n\n  // address of the strategy used to lend funds\n  address public strategy;\n  // address of the strategy token which represent the position in the lending provider\n  address public strategyToken;\n  // address of AA Tranche token contract\n  address public AATranche;\n  // address of BB Tranche token contract\n  address public BBTranche;\n  // address for stkIDLE gating for AA tranche. addr(0) -> inactive, addr(1) -> active\n  address internal AAStaking;\n  // address for stkIDLE gating for BB tranche. addr(0) -> inactive, addr(1) -> active\n  address internal BBStaking;\n\n  // Apr split ratio for AA tranches\n  // (relative to FULL_ALLOC so 50% => 50000 => 50% of the interest to tranche AA)\n  uint256 public trancheAPRSplitRatio; //\n  // [DEPRECATED] Ideal tranche split ratio in `token` value\n  // (relative to FULL_ALLOC so 50% => 50000 means 50% of tranches (in value) should be AA)\n  uint256 internal trancheIdealWeightRatio;\n  // Price for minting AA tranche, in underlyings\n  uint256 public priceAA;\n  // Price for minting BB tranche, in underlyings\n  uint256 public priceBB;\n  // last saved net asset value (in `token`) for AA tranches\n  uint256 public lastNAVAA;\n  // last saved net asset value (in `token`) for BB tranches\n  uint256 public lastNAVBB;\n  // last saved lending provider price\n  uint256 internal lastStrategyPrice;\n  // Keeps track of unclaimed fees for fee receivers\n  uint256 public unclaimedFees;\n  // Keeps an unlent balance both for cheap redeem and as 'insurance of last resort'\n  uint256 internal unlentPerc;\n\n  // Fee amount (relative to FULL_ALLOC)\n  uint256 public fee;\n  // address receiving the feeSplit portion of collected fees\n  address public feeReceiver;\n\n  // [DEPRECATED] trancheIdealWeightRatio ± idealRanges, used in updateIncentives\n  uint256 internal idealRange;\n  // period, in blocks, for progressively releasing harvested rewards to users\n  uint256 internal releaseBlocksPeriod;\n  // amount of rewards sold in the last harvest (in `token`)\n  uint256 internal harvestedRewards;\n  // stkAave address\n  address internal constant stkAave = address(0x4da27a545c0c5B758a6BA100e3a049001de870f5);\n  // aave address\n  address internal constant AAVE = address(0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9);\n  // if deposits will be put directly in the strategy\n  bool internal directDeposit;\n  // referral address of the strategy developer\n  address internal referral;\n  // portion of collected fees sent to feeReceiver. The rest goes to owner()\n  uint256 public feeSplit;\n\n  // if Adaptive Yield Split is active\n  bool internal isAYSActive;\n  // constant to represent 99% (for ADS AA ratio upper limit)\n  uint256 internal constant AA_RATIO_LIM_UP = 99000;\n  // constant to represent 50% (for ADS AA ratio lower limit)\n  uint256 internal constant AA_RATIO_LIM_DOWN = 50000;\n  // stkIDLE address\n  address internal constant STK_IDLE = address(0xaAC13a116eA7016689993193FcE4BadC8038136f);\n  // liquidity burned at first tranche deposit\n  uint256 internal constant MIN_LIQUIDITY = 10**3;\n\n  // Referral event\n  event Referral(uint256 _amount, address _ref);\n  // tolerance in underlyings when redeeming\n  uint256 internal liquidationTolerance;\n\n  // Add new variables here. For each storage slot\n  // used, reduce the __gap length by 1. \n  // ####################### \n  // Min apr ratio for AA tranches when using AYS\n  uint256 internal minAprSplitAYS;\n  // Max strategy price decrease before triggering a default\n  uint256 internal maxDecreaseDefault;\n  // Legacy IdleCDO loss tolerance; unused by Credit Vaults and retained in their proxy layout.\n  uint256 internal lossToleranceBps;\n  // Amount of stkIDLE required to mint 1 underlying\n  uint256 internal stkIDLEPerUnderlying;\n  // Explicit flag for epoch variants using programmable borrower hooks.\n  // This lives in shared storage so upgrading prefunded epoch variants does not shift child storage.\n  bool public isProgrammableBorrower;\n  // annualized management fee. Max is MAX_FEE / 10\n  uint256 public managementFee;\n  // Explicit owner-controlled opt-in for BB deposits. Disabled by default.\n  bool public isBBDepositEnabled;\n  // uint256 public test;\n\n\n\n  // ####################### \n  // This is empty reserved space in storage that is put \n  // in place in Upgradeable contracts. It allows us to \n  // freely add new state variables in the future without \n  // compromising the storage compatibility with existing \n  // deployments.\n  // The size of the __gap array is calculated so that the \n  // amount of storage used by a contract always adds up to \n  // always the same number, 50 in this case.\n  uint256[43] private __gap;\n  // uint256[42] private __gap; -> after adding `test`\n  // #######################\n  // IMPORTANT: Do not add any variables below `__gap`\n}\n"},{"file_path":"contracts/IdleCDOTranche.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.10;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\n/// @dev ERC20 representing a tranche token\ncontract IdleCDOTranche is ERC20 {\n  // allowed minter address\n  address public minter;\n  // liquidity burned at first tranche deposit\n  uint256 internal constant MIN_LIQUIDITY = 10**3;\n\n  /// @param _name tranche name\n  /// @param _symbol tranche symbol\n  constructor(\n    string memory _name, // eg. IdleDAI\n    string memory _symbol // eg. IDLEDAI\n  ) ERC20(_name, _symbol) {\n    // minter is msg.sender which is IdleCDO (in initialize)\n    minter = msg.sender;\n  }\n\n  /// @param account that should receive the tranche tokens\n  /// @param amount of tranche tokens to mint\n  function mint(address account, uint256 amount) external {\n    require(msg.sender == minter, '6');\n    // burn MIN_LIQUIDITY on first tranche deposit\n    if (totalSupply() == 0) {\n      _mint(address(1), MIN_LIQUIDITY);\n      amount -= MIN_LIQUIDITY;\n    }\n    _mint(account, amount);\n  }\n\n  /// @param account that should have the tranche tokens burned\n  /// @param amount of tranche tokens to burn\n  function burn(address account, uint256 amount) external {\n    require(msg.sender == minter, '6');\n    _burn(account, amount);\n  }\n}\n"},{"file_path":"contracts/interfaces/IERC20Detailed.sol","source_code":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.10;\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\ninterface IERC20Detailed is IERC20Upgradeable {\n  function name() external view returns(string memory);\n  function symbol() external view returns(string memory);\n  function decimals() external view returns(uint256);\n}\n"},{"file_path":"contracts/interfaces/IIdleCDOStrategy.sol","source_code":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.10;\n\ninterface IIdleCDOStrategy {\n  function strategyToken() external view returns(address);\n  function token() external view returns(address);\n  function tokenDecimals() external view returns(uint256);\n  function oneToken() external view returns(uint256);\n  function redeemRewards(bytes calldata _extraData) external returns(uint256[] memory);\n  function pullStkAAVE() external returns(uint256);\n  function price() external view returns(uint256);\n  function getRewardTokens() external view returns(address[] memory);\n  function deposit(uint256 _amount) external returns(uint256);\n  // _amount in `strategyToken`\n  function redeem(uint256 _amount) external returns(uint256);\n  // _amount in `token`\n  function redeemUnderlying(uint256 _amount) external returns(uint256);\n  function getApr() external view returns(uint256);\n}\n"},{"file_path":"contracts/interfaces/IProgrammableBorrower.sol","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.10;\n\n/// @notice Hook surface exposed by programmable borrowers used by `IdleCDOEpochVariant`.\ninterface IProgrammableBorrower {\n  /// @notice Sync borrower-side accounting when a new epoch starts.\n  /// @param _pendingWithdraws Underlyings reserved for withdraw requests at epoch end.\n  function onStartEpoch(uint256 _pendingWithdraws) external;\n\n  /// @notice Free enough liquidity so IdleCDO can pull stop-epoch funds.\n  /// @param _amountRequired Total underlyings IdleCDO will transfer from the borrower.\n  /// @param _isRequestingAllFunds Whether IdleCDO is closing the pool and recalling all funds.\n  /// @return success False when the borrower ledger makes close-pool settlement a real default.\n  function onStopEpoch(uint256 _amountRequired, bool _isRequestingAllFunds) external returns (bool success);\n\n  /// @notice Return the total net interest currently due for the running epoch.\n  /// @dev This is the pool-facing stop-epoch value: borrower contractual interest plus paid\n  /// buffer interest plus positive vault PnL minus vault losses.\n  /// @return Interest amount owed right now.\n  function totalInterestDueNow() external view returns (uint256);\n\n  /// @notice Move accrued borrower interest into settled debt.\n  /// @dev Called only on success path after IdleCDO fronted the interest. This settles the full\n  /// contractual borrower-interest sleeve, independently from vault gains or losses.\n  function settleBorrowerInterest() external;\n\n  /// @notice Abort active epoch accounting after IdleCDO has defaulted the facility.\n  /// @dev Used only on the default path when `onStopEpoch` could not complete successfully.\n  function onDefault() external;\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AmountTooHigh","type":"error"},{"inputs":[],"name":"ContractLimitReached","type":"error"},{"inputs":[],"name":"Default","type":"error"},{"inputs":[],"name":"Is0","type":"error"},{"inputs":[],"name":"NotAllowed","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"interest","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"funds","type":"uint256"}],"name":"BorrowerDefault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_ref","type":"address"}],"name":"Referral","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"AATranche","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BBTranche","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FULL_ALLOC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_TRANCHE_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"_setLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allowAAWithdrawRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowBBWithdrawRequest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowInstantWithdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bufferPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimInstantWithdrawRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimWithdrawRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaulted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositAA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositBB","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tranche","type":"address"}],"name":"depositDuringEpoch","outputs":[{"internalType":"uint256","name":"_minted","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableInstantWithdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyShutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"epochDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epochEndDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"expectedEpochInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeSplit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_recoveredAmount","type":"uint256"},{"internalType":"address","name":"_recoverySource","type":"address"}],"name":"finalizeDefault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tranche","type":"address"}],"name":"getApr","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentAARatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"getFundsFromBorrower","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getInstantWithdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"},{"internalType":"address","name":"_guardedToken","type":"address"},{"internalType":"address","name":"_governanceFund","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"uint256","name":"_trancheAPRSplitRatio","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"instantWithdrawAprDelta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"instantWithdrawDeadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"instantWithdrawDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBBDepositEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isDepositDuringEpochDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isEpochRunning","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isInterestMinted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isProgrammableBorrower","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"isWalletAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keyring","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keyringPolicyId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastEpochApr","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastEpochInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastNAVAA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastNAVBB","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestHarvestBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"limit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managementFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_tranche","type":"address"}],"name":"maxWithdrawable","outputs":[{"internalType":"uint256","name":"currentUnderlyings","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oneToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingWithdrawFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceAA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceBB","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tranche","type":"address"}],"name":"requestWithdraw","outputs":[{"internalType":"uint256","name":"_underlyings","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"restoreOperations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"sendFundsToBorrower","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setBBDepositEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epochDuration","type":"uint256"},{"internalType":"uint256","name":"_bufferPeriod","type":"uint256"}],"name":"setEpochParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeReceiver","type":"address"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_feeSplit","type":"uint256"},{"internalType":"uint256","name":"_managementFee","type":"uint256"}],"name":"setFeeParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_guardian","type":"address"}],"name":"setGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"},{"internalType":"uint256","name":"_aprDelta","type":"uint256"},{"internalType":"bool","name":"_disable","type":"bool"}],"name":"setInstantWithdrawParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_active","type":"bool"}],"name":"setIsAYSActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isDisabled","type":"bool"}],"name":"setIsDepositDuringEpochDisabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isMinted","type":"bool"}],"name":"setIsInterestMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isProgrammable","type":"bool"}],"name":"setIsProgrammableBorrower","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keyring","type":"address"},{"internalType":"uint256","name":"_keyringPolicyId","type":"uint256"}],"name":"setKeyringParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_aprSplit","type":"uint256"}],"name":"setMinAprSplitAYS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newApr","type":"uint256"},{"internalType":"uint256","name":"_interest","type":"uint256"}],"name":"stopEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newApr","type":"uint256"},{"internalType":"uint256","name":"_interest","type":"uint256"},{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"uint256","name":"_lossAmount","type":"uint256"}],"name":"stopEpochWithDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategyToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trancheAPRSplitRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tranche","type":"address"}],"name":"tranchePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unclaimedFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateAccounting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tranche","type":"address"}],"name":"virtualPrice","outputs":[{"internalType":"uint256","name":"_virtualPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tranche","type":"address"}],"name":"writeOffDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":null}